« Поставить закладку » « Сделать стартовой »

« Форумы » « Блоги » « Статьи » « Новости » « Файлы » « Realcoding IRC » « Site map » « Поиск »


Главная Главная
Анонсы Анонсы
Форумы Форумы
Каталог Каталог
Поиск Поиск
Опросы Опросы
Книжный магазин Книжный магазин
Реклама на сайте
Публикации Публикации
Партнеры Партнеры
Карта Карта сайта
Рассылки Рассылки
RSS экспорт
Настройки Настройки
О нас пишут О нас пишут
Контакты Контакты
Гостевая книга Гостевая книга


ПнВтСрЧтПтСбВс
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        
    Популярное
Прямой доступ к базе данных 1С

Качаем файл из Internet

Глава 9. Оператор цикла арифметического типа.

Использование JS для создания «умных» форм

PGP 5.0

Функция AccessResource

Advanced Draw

Функция SetResourceHandler

Написание суммы прописью

Глава 1. Подбираем снаряжение




    Архив файлов



    Сообщества

    Документация

    Кто на сайте
Вы не зарегистрированы.
Имя:

Пароль:

Запомнить

Регистрация позволит Вам пользоваться дополнительными сервисами.
Сейчас на сайте:
Гостей: 222
Пользователей: 0

Статьи:: Интернет технологии :: Perl :: Создание больших web-проектов



отправить ссылку другу версия для печати  Обсудить на форуме

Создание больших web-проектов



Создание больших web-проектов

У любого успешного web-проекта рано или поздно возникает проблема роста. Существующие программно-аппаратные ресурсы перестают справляться с растущей нагрузкой. Универсальных рецептов, к сожалению не существует. В каждом проекте хороший программист будет программировать по-разному. Тем не менее, в этой статье я попробую дать несколько типичных рекомендаций по созданию больших web-проектов. Такие проекты в процессе создания и развития сталкиваются, как правило, с двумя почти противоположными по способам решения проблемами - большими скоростями и большими объемами данных.

Большие скорости

В качестве идеального примера сайта, для которого жизненно важна скорость, можно взять баннерную сеть. Итак, несколько приемов для ускорения работы баннерных сетей и других серверов, критичных к скорости работы.

Создание модулей

Смысл этого приема - вкомпилировать наиболее важные функции в сервер. Идея очень проста. Если мы посмотрим на соотношение времени, которое тратится на различные стадии выполнения запроса, то увидим интересную картину. Например, при выполнении простейшего perl-скрипта последовательно происходит следующее: 

1) сервер Apache определяет perl-скрипт для запуска, подготавливает и запускает его;
2) запуск скрипта фактически начинается с запуска perl-интерпретатора (это файл, размером около полумегабайта). Perl-интерпретатор, запустившись, размещается на 2-х мегабайтах в памяти машины, и только после этого приступает к работе с пользовательским скриптом;
3) эта работа начинается с компиляции программы. Компиляция программы - это, как правило, один из самых длительных этапов обработки программы;
4) только после предварительной компиляции (в байткод) скрипт начнет выполняться.

Статистика удручает: время, которое тратится на запуск perl-интерпретатора и компиляцию скрипта, как правило, на порядок больше времени, за которое он выполняется. 
На каждом сайте существуют узкие места - программы, которые вызываются очень часто. Например, баннерный движок. Как правило, на один просмотр страницы приходится два-три баннера, а значит и вызова программы. Понятно, что если избавиться от накладных расходов (пункты 2 и 3), работа сервера значительно ускорится. Это можно сделать двумя похожими способами.
Первый - написать модуль к Apache и вкомпилировать его в сервер. Именно так в баннерной сети Фламинго-2 (http://www.f2.ru), в создании которой я принимал участие, была реализована часть системы, которая раздавала баннеры пользователям. Это был модуль, написанный на языке C, который функционировал как часть сервера Apache и поэтому работал очень быстро.
Второй способ - использовать технологии предкомпиляции программ. Таких технологий достаточно много. Например, для perl-скриптов это могут быть FastCGI и mod_perl. Расскажу подробней о mod_perl. Это вкомпилированный (опять же в виде модуля) в Apache perl-компилятор. Во-первых, даже для простых скриптов (при надлежащей настройке) это исключает вторую стадию выполнения. Но кроме этого mod_perl дает возможность писать хэндлеры - обработчики определенных стадий выполнения запроса. Это очень мощная технология, поэтому рассмотрим ее подробнее.
Можно, например, написать хэндлер, который будет вызываться при запросе определенного URL. Делается это так. В файл httpd.conf вы прописываете следующие строки:

<Perl>

unshift(@INC, 'Путь к Вашему модулю');

@PerlModule = qw(MyHandler);

%Location = (
'/myhandler' => {
'PerlHandler' => 'MyHandler::view',
'SetHandler' => 'perl-script',
'PerlSendHeader' => 'on'
},
);

</Perl>

Тем самым вы указываете Apache и модулю mod_perl, что если пользователь запросит URL /myhandler, то для его обработки должен запуститься модуль MyHandler, а в нем процедура view. После изменения httpd.conf надо перезагрузить Apache. Кстати, все указанные в конфигурационном модуле файлы будут компилироваться при загрузке сервера, а не при первом запросе. Это в несколько раз увеличит скорость работы сервера.
Модуль MyHandler.pm может выглядеть, например, так:

package MyHandler;
use strict;

# Процедура view
sub view {
print "<HTML>n<BODY>nУра! Это отработал наш хэндлер!</BODY>n</HTML>n";
}

1;

Механизм хэндлеров обладает мощными возможностями. Фактически вы можете заменить любую стадию обработки запросов. Рассмотрим для примера создание собственного механизма проверки пароля:

package MyAuthorization;
use strict;

# Обработчик, запрашивающий пароль
sub handler {
my $r = shift;

return AUTH_REQUIRED unless $r;

my (undef, $password) = $r->get_basic_auth_pw;
my ($login) = $r->connection->user;

return AUTH_REQUIRED unless $password;

# Проверяем, все ли в порядке
# Проверка может быть любой
# Можно свериться с базой данных, а мы будем считать, что пароль должен быть
# равен логину, прочитанному задом наперед.

my $rev_login = reverse($login);

# Проверка пароля
if ($rev_login ne $passwd_sent)
{
return AUTH_REQUIRED;
} else {
return OK;
}

};

1;

В файле настроек сервера httpd.conf необходимо указать, что авторизовать пользователя мы будем сами:

%Location = (
'/myhandler' => {
'PerlHandler' => 'MyHandler::view',
'SetHandler' => 'perl-script',
'PerlSendHeader' => 'on'
'require' => 'valid-user',
'Limit' => {
'METHODS' => 'GET POST'
},
'AuthType' => 'Basic',
'AuthName' => 'PersonaUser',
'PerlAuthenHandler' => 'MyAuthorization ->handler()'
},
);

Теперь доступ к /myhandler защищен - браузер выведет пользователю стандартное окно для ввода пароля. 
Более подробно с технологией mod_perl можно познакомиться на сайте http://perl.apache.org/

Использование конвейеров

Старайтесь не производить обработку данных в интерактивных скриптах. Записывайте их в лог-файлы, а затем агрегируйте и обрабатывайте уже отдельным процессом. Например, ответ пользователя в интерактивном голосовании может вызывать у вас изменения в десятке различных параметров статистики (распределение ответов, активность пользователей, общее число проголосовавших и так далее). Не проводите их сразу. Вместо этого разбейте процедуру на две части. Первая - непосредствен- но голосование, запись результата и вывод ответной страницы пользователю. Вторая - обработка голосования, изменение статистики и т.д. 
Вообще надо стараться минимизировать количество интерактивных операций. В идеальном случае скрипт для учета голосования вообще ничего не делает, кроме записи информации в лог-файл. А для обработки данных из лог-файла можно запускать отдельный процесс-демон.
Для примера рассмотрим механизм обработки статистики в баннерной сети Фламинго-2. В ней был реализован 4-х ступенчатый конвейер:
1) Информация о каждом запросе записывалась в полный лог. Это была очень подробная информация и записывалась она без всякого сжатия, на которое потратилось бы много времени. Размер этого лога очень велик - одна запись в нем занимала 250 байт. Данные в этом логе не хранились дольше нескольких часов.
2) С периодичностью раз в 10 минут запускалась программа, которая обрабатывала полный лог и в компактном виде писала информацию в таблицы базы данных. На этой же стадии учитывались показы, изменялись временные таблицы, используемые для выдачи баннеров пользователю и для работы следующих стадий.
3) Часовой демон, который строил почасовую статистику, производил сложные географические расчеты и многое другое, запускался в конвейере один раз в час. Он уже не имел доступа к полному логу и использовал информацию исключительно из второй стадии.
4) В задачи последней стадии входила дневная ротация файлов, статистика, подведение балансов и рассылка почтовых предупреждений. Эта стадия работала каждые сутки поздно ночью, когда нагрузка на сервер была минимальной.
Как видите, механизм достаточно сложный, и наладить его корректную работу было нелегко. Чем больше стадий, тем больше проблем при их сопряжении друг с другом. Тем не менее, такая система позволяла достаточно эффективно распределять нагрузку и шустро работала на простом IDE-диске (расчетная пропускная способность была около 2-3 миллионов обращений в день при пиковой нагрузке 200 обращений в секунду). При этом система вела большое количество статистики.
Итак, резюмируем: для увеличения скорости работы программ, взаимодействующих с пользователем, разбиваем их работу на части, причем интерактивная часть должна содержать минимум расчетов и операций записи. Все необходимые расчеты можно произвести позднее, в более благоприятное с точки зрения нагрузки время и более эффективно.

Базы данных

Используйте хорошую базу данных. Какую выбрать? Единого рецепта нет. Все зависит от решаемой задачи. Если она достаточно простая и вам не требуется выполнять сложные SQL-запросы (например, вложенные), то наилучшим решением будет, пожалуй, база данных MySQL.
MySQL - один из самых простых серверов БД. Но даже в этой простой базе есть свои способы оптимизации для ускорения запросов. Например, не секрет, что INSERT - одна из самых длительных операций (вычисление физического адреса для вставки, вставка, решение проблемы фрагментации, изменение индексов и служебных таблиц). Хороший прием для ускорения работы скрипта, который вставляет данные в БД - замена операции INSERT операцией INSERT DELAYED (отложенная вставка). Обновление данных будет выполнено только тогда, когда это не приведет к замедлению работы сервера.
Другой пример: если внимательно почитать документацию MySQL, можно найти упоминание о таблицах, расположенных в памяти (HEAP tables). Очевидно, что операции с такими таблицами совершаются значительно быстрее. Heap-таблицы можно использовать для решения некоторых задач.
Существует большое количество параметров запуска сервера БД, оптимизирующих буферы сортировки, вычислений, количество детей и другие параметры. Как правило, вам заранее известно, что вы будете делать с базой, и для повышения быстродействия можно задать соответствующие параметры. Например, возьмем вполне реальную задачу: построение какого-нибудь каталога. Ясно, что это будет одна большая таблица с большим количеством индексов. Вы знаете, что будете использовать представления. Работа с этой таблицей будет заключаться в запросах по индексу без использования сортировки. Посмотрим, как можно настроить сервер БД на выполнение такой задачи (пример из MySQL 3.23.25):

  • join_buffer_size - буфер для создания представлений, по умолчанию равен 131072 байта;

  • key_buffer_size - буфер для работы с ключами и индексами. Размер по умолчанию - 1048540;

  • sort_buffer - буфер для сортировки. По умолчанию - 2097116 байт.

Скорее всего, при увеличении какого-то буфера, скорость выполнения связанной с ним задачи увеличится. Исходя из нашей задачи, мы увеличим буфер для работы с ключами (скорость выборки значений из таблицы увеличится), уменьшим буфер сортировки (уменьшится скорость сортировки) и буфер представлений (уменьшится скорость работы с представлениями).
Строка запуска демона MySQL будет выглядеть примерно так (конкретные значения зависят от количества памяти в системе):

shell>safe_mysqld -O key_buffer=8M -O sort_buffer=1M -O join_buffer=16K

Резюмируем. При использовании базы данных работу скрипта можно значительно ускорить правильной настройкой сервера БД. В руководстве базы данных MySQL есть специальный раздел, посвященный оптимизации. За более подробной информацией можно обратиться на сайты:
Разработчики MySQL - http://www.mysql.com
Разработчики PostgreSQL - http://www.PostgreSQL.org/
Оптимизация MySQL - http://www.mysql.cz/information/presentations/presentation-oscon2000-20000719/index.html и http://support.ultrahost.ru/mysql_opt.php

Большие объемы

Еще одна проблема больших сайтов - большой объем информации. Если не применять никаких ухищрений, то поддержка простого html-сайта в какой-то момент потребует слишком много времени.

Объектно-ориентированное программирование

О пользе объектно-ориентированного подхода я уже рассказывал . Повторю вкратце. Каждый, кто хоть раз пробовал создавать динамические сайты, знает, что во многом это - очень однообразная задача. Гостевая книга, конференция, форма для отправления комментариев, подписка, регистрация. Как правило, эти скрипты слабо интегрированы и, в лучшем случае, используют общую библиотеку с константами и общими процедурами.

Однако если перечислить сущности, с которыми имеют дело вышеперечисленные скрипты, мы получим очень интересные результаты:

  • Сущность "пользователь". Имеет свое имя, фамилию, ник, пароль, электронный адрес: Используется практически во всех скриптах в разных ипостасях.

  • Сущность "сообщение". Вы можете возразить, что сообщения везде разные. Ничего подобного! Различаются формы представления сообщений, а данные, структура полей и методы обработки - одни. Автор, заголовок, тело - и так во всех проектах.

Вот фактически и все сущности, с которыми оперирует большинство скриптов на сайте. Гостевая книга (она, кстати, сама может быть объектом в более сложных проектах) представляет собой цепочку объектов класса "сообщение". Форум или конференция - те же сообщения, организованные иерархически. Отправка письма владельцу сайта - сообщение. Рассылка анонсов - перебор объектов класса "пользователь" и отправка каждому объекта класса "сообщение".
Было бы эффективно описать все эти объекты в одном месте, а потом строить из них, как из кирпичиков, программы и скрипты, просто вставляя вызовы объектов в код. К тому же, единое пространство сообщений, пользователей и других объектов значительно расширяет поле для творчества.
В этом и есть сущность объектного подхода. Вы создаете множество объектов - кирпичиков будущих программ - и из них строите свои сайты. Кроме того, вы можете использовать такие мощные методы ООП как наследование и полиформизм, без которых уже немыслимо построение крупных проектов.

Шаблонирование

Об этом я тоже расскажу вкратце; возможно этому будет посвящена статья в одном из следующих номеров "Программиста". Вернемся к системе Фламинго. Как был организован интерфейс этой баннерной сети? 400 видов статистики соответствуют 400 страницам? Нет. Один скрипт-шаблонизатор, которому передаются параметры - номер статистики и другие данные: даты, ограничения и т.д.
По уникальному номеру статистики скрипт считывал описание, которое состояло из имени файла с псевдо-html и имен файлов с SQL-запросами. Файл с описанием выглядел так:

2:data/html/2.htx,data/queries/info.sql
9:data/html/9.htx,data/queries/ban-list-one.sql,data/queries/get-banners-list.sql
12:data/html/12.htx,data/queries/ban-getinfo.sql
38:data/html/38.htx,data/queries/acc-hosts-hits.sql 
44:data/html/44.htx,data/queries/acc-getsites-today.sql

Общая схема очень проста - выполнить все SQL-запросы и вставить результаты в псевдо-html, получив таким образом полноценную страничку, и выдать ее пользователю. Например, для вывода статистики с номером 2 (информация об аккаунте), требовалось выполнить SQL-запрос data/queries/info.sql, результаты вставить в data/html/2.htx. Результат вывести на экран.
А вот как обстояло дело подробнее. Первая задача - формирование SQL-запроса. В него нужно вставить идентификатор пользователя и другие параметры, которые переданы скрипту. Типичный пример SQL-запроса (data/queries/info.sql):

select
AccountName,
OwnerName,
OwnerEmail,
MainSite,
SiteName
from
Accounts
where
AccountId = <--AccountId-->

При разборе такого запроса значение параметра вставлялось на место строки <--ИмяПараметра-->. Существовали и специальные параметры, например - <--UserName--> - имя пользователя и <--AccountId--> - вычисленный по имени идентификатор аккаунта.
Результат выполнения полученного запроса заносился в html следующим образом. Каждое полученное из базы данных значение получало "имя", с помощью которого обозначалось его местоположение в html-шаблоне. Имя было составным. Первая часть - порядковый номер SQL-запроса, вторая часть - индекс значения в массиве результатов.
Допустим, выполнялся SQL-запрос с порядковым номером 1 (для примера рассмотрим запрос data/queries/info.sql). Запрос возвращал массив значений. Соответственно, значение AccountName, возвращенное базой данных, имело порядковый номер 0 в этом массиве. В html-шаблоне место, куда необходимо было вставить AccountName обозначалось как <--1.1-->. 

Кусочек HTML-шаблона data/html/2.htx из нашего примера:

<TABLE BORDER=0 WIDTH=460>
<TR>
<TD WIDTH="50%">
<FONT SIZE="-1">
Имя, фамилия ответственного:
</FONT>
</TD><TD>
<INPUT type="text" name="OwnerName" size=33 value="<--1.1-->">
</TD>
</TR>

<TR>
<TD>
<FONT SIZE="-1">
Электронный адрес:
</TD><TD>
<INPUT type="text" name="OwnerEmail" size=33 value="<--1.2-->">
</TD>
</TR>

Несмотря на кажущуюся сложность схемы, она имеет ряд преимуществ. С ее помощью мы смогли за короткое время построить систему с более чем 400 видами различных статистик. Впоследствии для добавления новой статистики надо было только написать SQL-запросы, нарисовать HTML-шаблон и изменить конфигурацию скрипта-шаблонизатора. Новая страница статистики появлялась в системе автоматически.

Заключение

Я хотел бы еще раз повторить: нет решений на все случаи жизни. Каждый раз, в каждом проекте вам придется придумывать собственные методы оптимизации быстродействия и удобства работы. Я надеюсь, что приемы, о которых я рассказал, пригодятся вам. Если у вас возникнут какие-нибудь вопросы или уточнения, я готов обсудить их с вами - vbob@aha.ru

Автор: Олег Бунин




Рубрика: Perl




Вышел MySQL 5.1.30, первый стабильный рели....

MySQL

После публикации 29 тестовых версий анонсирован первый стабильный релиз MySQL 5.1, пригодный для промышленной эксплуатации и обеспечивающий увеличение производительности для "тяжелых" SQL запросов, по сравнению с MySQL 5.0, примерно на 15-20%. Главные новшества появившиеся в MySQL 5.1:


Подробнее... | Рубрика: MySQL | Добавлено: 28.11.2008

Тестирование параллельных программ.

Тестирование

Тестирование параллельного программного обеспечения представляет собой более сложную задачу по сравнению с тестированием последовательной программы. Программист должен знать о подводных камнях при тестировании параллельного кода, имеющихся методологиях и инструментарии.


Подробнее... | Рубрика: Тестирование | Добавлено: 28.11.2008

Архитектура AMD64 (EM64T).

Архитектура AMD

Аннотация. В статье кратко рассматривается архитектура AMD64 компании AMD и ее реализация EM64T компании Intel. Описаны особенности архитектуры, ее возможности, достоинства и недостатки.


Подробнее... | Рубрика: Архитектура AMD | Добавлено: 27.11.2008

Остальные статьи:

Платформа 2009. Определяя будущее
Windows Vista Bridge Sample Library - упра...
Оптимизация 64-битных программ
Подгрузка через AJAX HTML-кода, содержащег...
Обзор нового релиза самой мощной Ajax библ...
Firebug 1.3 и 1.4 alpha — что нового и инт...
Релиз Microsoft Silverlight 2.0. Что новог...
XML документация в C#
Курсоры в MySQL 5
Microsoft опубликовала подробности о сесси...
Microsoft делится подробностями о том, что...
Тестируем новый javascript от нового брауз...
MySQL Query Cache
Использование провайдеров компиляции в As...
Чего мы ждем от C# 4.0
Delphi 2009 и C++Builder 2009
Джоэл Спольски и Джеф Этвуд запустили новы...
Поиск кода Google /* что нового? */
10 jQuery скриптов для улучшения интерфейс...
Генераторы отчетов FastReport 4 и QuickRep...


Цитата дня (все,добавить):

Портал фрилансеров

работа на дому


    Рубрикатор

Программирование

C/С++
Обучение
Windows API
XAML
Моделирование
Паттерны
Visual Basic 7 .NET
WxWidgets
Функции WinApi
Функции С++
Разработка под Mac OS
Eiffel
Visual Studio 2008
UI дизайн
Алгоритмы
Конкурсные статьи
Turbo Pascal
Visual Studio
CASE-средства
Visual Studio 2005
Без VCL
Delphi
Тех. документация
Тестирование
Software Testing
ООП
TCP/IP
Google Android
Windows Installer
.NET Framework
Драйвера
C# C Sharp
Справка
Проектирование
Информ. системы
Visual Basic
Assembler
Оптимизация кода
Gtk+
Компоненты
Реинжиниринг
Управление проектами
Extreeme programming
Lotus Notes
Алгебраическое проектирование


Интернет технологии

PHP
Perl
ASP
WAP
Cookies
SSI
CGI
Web Servers
VB Script
DNS
CSS
XML
Html
Java Script
Java2ME
Firewall
Flash
.htaccess
Apache
VRML
Протоколы
Поисковые системы
Технология JAVA
Учебник по PHP
Учебник по JavaScript
Учебник по XML
Java Q&A
AJAX
DHTML
XHTML
Dreamweaver
Web 2.0
Python
Вебмастеру
Cisco
Ruby on Rails
Silverlight

Базы данных

Access
InterBase
MySQL
Oracle
ADO .NET
Основы SQL
Учебник по Access 2002
MS
Microsoft FoxPro
Доступ к данным
XML в MS SQL Server 2000
ODBC и MyODBC
Обучение
Caché
DB2
PostgresSQL
Sybase
Теория
Хранилища данных
Безопасность
Реляционные данные
MySQL и mSQL

Остальное:

Разное
Обзоры книг
Безопасность
Графика и дизайн
Юмор
Linux
Фракталы
Microsoft Axapta
Многоядерность
Сети
Microsoft Office
Работа
MS-DOS
Криптография
Графика и игроделание
Новости SDK
Системы защиты
Учебник по AutoCad
CVS
Windows XP
Windows Server 2003
Windows Vista
Windows 7
Мероприятия