GetInfo.Ru – Компьютерная библиотека
Последние поступления
Как выбрать систему управления базы данных
Базы данных03/09/14
Этапы загрузки UNIX (в схеме)
Unix27/03/12
Gatewall Antispam: тотальный контроль электронной почты
Спам21/04/11
Мастер-класс: создаем Интернет-магазин (Часть 1)
Обзоры ПО20/04/11
CorelDRAW Graphics Suite X5: Что нового?
Обзоры ПО20/07/10
Добавить статью
Самые читаемые материалы
Проверка e-mail адреса на существование(32432)
Строим календарь для сайта на Perl(11833)
Web Основы с LWP(11458)
Построение крупно-масштабного e-commerce сайта на Apache и mod_perl(11302)
Image::Magick или фотошоп для perl(9700)
Всего статей: 793Всего авторов: 364Подразделов: 47Добавлено за сутки: 0
Статьи  СТАТЬИ Форум  ФОРУМ Рейтинг  РЕЙТИНГ Поиск  ПОИСК Контакты  КОНТАКТЫ
» Главная » Perl » Построение крупно-масштабного e-commerce сайта на Apache и mod_perl

Построение крупно-масштабного e-commerce сайта на Apache и mod_perl


Данил Письменный
dapi@mail.ru

Автор: Perrin Harkins
Перевод: Danil Pismenny
Дата: 25 Декабря 2001
Версия: 1.0

Содержание:

Когда создается крупно-масштабный сайт электроной коммерции все дают советы. Разработчики будут вам говорить, что только сайт, созданный на C++ или Java (зависит от того, на чем они пишут) может справиться со столь мощным трафиком. Продавцы серверов приложений будут настаивать на том, что вам необходимо решение все-в-одном и подключ. Продавцы аппаратного обеспечения будут говорить вам, что только mega-компьютер последней модели сможет обслуживать такой большой сайт. Эта история о том, как мы создали крупный сайт электронной коммерции (в будущем e-commerce) используя в основом бесплатное программное обеспеение с открытым исходным кодом и обычное аппаратное обеспечение. Мы сделали это и вы тоже можете сделать это.

Perl долгое время был наиболее предпочитаемым языком разработки CGI скриптов. Он сочитает в себе высокую переносимость (гибкость) с быстрой разработки. Programming Perl до сих пор является одной из самых продаваемых технических книг издательства O'Reilly и число ее почитателей растет. Позже, впрочем, в некоторых кругах Perl осуждали, упирая на то, что он слишком медленен для серьезой работы и что код, написанный на Perl, тяжело поддерживать.

Apache модуль mod_perl полностью изменил картину производительности для Perl-а. Встраивание интерпретатора Perl внутрь Apache предоставляет скорость эквивалентную Java сервлетам и делает Perl отличным выбором для построения больших сайтов. Благодаря использованию объектно-ориентированных возможностей Perl-а и некоторых особых правил кодирования вы можете написать код, который будет приятно сопровождать или он будет как минимум не хуже, чем на любом другом языке.

Возможности вашего собственного сервера приложений
Когда вы комбинируете Apache, mod_perl и open-source код доступный с CPAN (Всеобъемлющий Сетевой Архив Perl) вы можете получить возможности равные возомжностям коммерческим серверам приложений:

  • Работа с сессиями
  • Балансировка загрузки
  • Постоянное соединение с базой
  • Продвинутые HTML шаблоны
  • Безопасность

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

Слушается дело: eToys.com
Когда мы впервые пришли на eToys (Один из крупнейший западных e-commerce сайтов. прим. переводчика) мы попали в ситуацию подобную тем, которые возникают во многих начинающих (startup) и растущих Internet компаниям. Система была основана на CGI скриптах, работающих с MySQL базой. И статичные файлы, и генерируемый динамический контент использовали русурсы одной и тоже машины. CGI код был в основном написан в стиле Perl4 и не был модульным, каким он могбы быть, что, впрочем, небыло сюрпризом, так как большинство из них были разработаны так быстро, насколько это было возможно, небольшой группой разработчиков.

Нашей первоочередной задачей было улучшить эту систему, чтобы она смогла справиться с ожидаемым Рождественским потоком покупок. Игрушечный бизнес полностью сезонен и различия между пиком сезона продаж и спокойнейшим временем в году посто громадна. Сайт еле выжил предыдущее Рождество, к тому же база MySQL была уже не способна к дальнейшему росту.

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

Apache::PerlRun идет на помощь
Apache::PerlRun модуль, который предназначен для плавного перехода от простых CGI к mod_perl. Он эмулирует окружение CGI и представляет такую же (но не всю возможную) пользу в производетельности как код написанный под mod_perl. Используя этот модуль и постоянное соединение к базе через Apache::DBI мы имели возможность сделать основной переход на mod_perl и Oracle на время Рождества, а дополнив систему некоторым новым аппаратным обеспечением мы были готовы к встрече Рождества.

Пик трафика, продолжался 8 недель, большинство из которых были потрачены в бешенных исправлениях или в нервозном ожидании, что еще что-нибудь сломается. Тем не менее, мы успешно прошли через все это и за прошедшее время собрали такую статистику:

  • 60-70 000 сессий в час
  • 800 000 просмотров страниц в час
  • 7 000 заказов в час

Согласно агенству Media Metrix мы были третьим по загруженности e-commerce сайтом после eBay и Amazon.

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

Цели новой системы включали уход от оффлайновой генерации страниц. Старая система создавала HTML страницы для каждого товара или катагории товаров пакетной обработкой (batch job) и сбрасывала результаты в статичные файлы. Такой подход был эффективен, когда мы имели небольшую базу товаров и статичные файлы давали неплохую производительность, но мы недавно добавили дочерние книжные магазины на наш сайт и таким образом размер нашей базы данных заметно увеличился и стало невозможно генерировать полный набор страниц с товарами. Мы нуждались в методике, при которой нам пришлось бы создавать только те страницы которыми на самом деле интересовался покупатель и при этом мы должны попрежнему иметь высокую производительность.

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

Не все разработчики в нашей группе имели познания в объектно-ориентировнаном Perl-е, и мы привлекли Рандальфа Шварца (Randal Schwartz) и Демьяна Конвей (Damian Conway) к обучению нашей группы. Мы создали набор стандартов кодирования, набросок дизайна и построили систему.

Восхождение на Рождество 2000
В наших планах было троекратное увеличение мощности по сравнению с предыдущим пиком. Мы получили то, что и прогнозировали:

  • 200 000+ сессий в час
  • 2,5 миллионов+ страниц в час
  • 20 000+ заказов в час

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

Архитектура системы
Характер машин, на которых была запущена наша система, предельно прост: мало-бюджетные сервера базирующиеся на Intel процессорах с балансировкой нагрузки перед ними и большая железка для базы данных.

Подобно многим коммерческим пакетам, мы имеет отдельные системы для спереди стоящих веб-серверов (которых мы назваем прокси серверами) и серверами приложений, которые генерируют динамический контент. Нагрузка и на прокси сервера, и на сервера приложений сбалансирована при помощи аппаратуры от f5 Networks. Более подробные детали описаны ниже.

Мы решили использовать Linux (родную систему для mod_perl сайтов) на прокси и серверах приложений. Легкость удаленного администрирования пол линуксом делает возможным кластерный подход. К томуже линукс дает солидные возможности по обеспечению безопасности и возможность добавления новых серверов благодаря автоматическому построению. (прим. переводчика: непонятно, имеется ли в виду компиляция ПО или построение новой системы)

Сервером базы данных служит IBM NUMA-Q, на которой запущен DYNIX/ptx.

Прокси сервера
На прокси серверах запущен уменьшенный вариант Apache, без mod_perl. На нем установленно несколько стандартных Apache-модулей, в дополнении к нашей собственной, модифицированной, версии mod_session, которая назначает сессионные cookie. Так как процессы очень малы, мы можем запускать аж 400 потомков Apache на одной машине. Эти сервера сами обрабатывают все запросы изображений, а запросы страниц пропускают на сервера приложений. Они общаются с серверами приложений через обычные HTTP запросы и кешируют результирующие страницы, если для них установленны соответсвующие заголовки. Кешированные страницы хранятся на разшаренной NFS партиции файлера Network Appliance (Network Appliance filer). Страницы из кеша обслуживаются почти также быстро, как и статичные файлы, то есть очень быстро.

Установка обратных прокси это обычно рекомендуемый подход при работе с mod_perl, так как этот подход использует облегченные прокси процессы для передачи контента клиенту (который может иметь медленное соединение) и этим самым осовобождают ресурсоемкие mod_perl процессы для следующих запросов. За большей информацией, почему такая конфигурация полезна смотре в справочник разработчкика mod_perl - http://perl.apache.org/guide/.

Сервера Приложений
Сервера приложений используют mod_perl и еще кое-что. Они имеют локальный кеш для объектов Perl, использующий Berkeley DB. На них запускаются веб приложения, разделяющие такие ресурсы как HTML шаблоны, подмонтированные через NFS из филера NetApp. Такая конфигурация является более тяжелой, поэтому эти машины и более мощные, с двумя процессорами и 1-м гигабайтом памяти.

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

Программным обеспечением предназначеным для поиска на этих серверах служит много-потоковый демон, который мы разработали на C++. Сервера приложения общаются с поисковыми серверами через перловый модуль. Поисковый демон принимает запрос и возвращает отсортированный список ID продукции, которая удовлетворяет этому запросу. Затем сервера приложений сами берут данные из базы данных, чтобы показать эту продукцию. Поисковые сервера ничего незнают о HTML или Web интерфейсе.

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

Для поиска демон использует стандартный подход обратного списка слов. Индекс переодически строится по соответсвующим данным в Oracle. Если вы предпочитаете полсностью перловое решение, тогда вы можете использовать модули, которые решают эту задачу, из CPAN включая Search::InvertIndex и DBIx::FullTextSearch. Мы решили создать свое собственное решение потому что производительность на этом участке была особо низкая и еще потому что мы имели необычно сложный набор правил сортировки для возвращаемых ID.

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

Сервера приложений используют "липкую" балансировку нагрузки. Это означает, что если пользователь однажды зайдет на один сервер, все последующие запросы в рамках этой сессии пудут попадать на тотже сервер. Это выполняется благодаря аппаратуре f5 используя браузеровские cookie.

Балансировщики нагрузки переодически выполняют проверку каждого сервера и удаляют отказавших из очереди. Когда сервер "падает", все пользователи, которые "сидели" на этой машине перемещаются на другую.

Для гарантии того, что данные не потеряются если сервер приложений умирает, все изменения пишутся в базу. В результате, пользовательские данные, навроде содержимого корзины, сохраняются даже в случае катострафической аварии в аппаратуре сервера. Это важно для крупных e-commerce сайтов.

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

Структура кода
Код структурирован в соответствии с классическим паттерном проектирования Модель-Вид-Контроллер (Model-View-Controller) ("Приемы объектно-ориентированного проектирования. Паттерны проектирования.".прим.переводчика.). Произошедший из SmallTalk он теперь часто используется в веб приложениях. Паттерн MVC это путь разделения ответственности приложения на три различных подсистемы (слоя, layers).

Классы в подсистеме Модель представляют концепцию бизнес логики и данных, навроде продукции и пользователей. Они имеют API, но не интерфейс с конечным пользователем. Эти классы ничего не знают о HTTP или HTML и могут использоваться в не Web приложениях, например в задачах планировщика. Они обращаются к базе данных или другим источникам данных, а результаты обрабатывают по своему желанию.

Классы подсистемы Контроллер переводят Web запросы в соответствующие действия в подсистеме Модель. Контроллер разбирает и проверяет входящие параметры, привлекает соответствующие объекты подсистемы Модель и вызывает необходимые методы в них. Затем он использует соответсующий Вид, а получившийся HTML передает пользователю.

Объекты Вид на самом деле являются шаблонами HTML. Контроллер передает им параметры из объектов Модель и они генерирует соответсвующую веб-страницу. Эта часть реализована с помощью Template Toolkit, мощной шаблонной системой, написанной на Perl. Шаблоны имеют несколько базовых выражений и циклов, которых достаточно для быстрого создания форматирующей логики. Никаких средств контроля над выполнением приложений в шаблоне нет.

Кеширование
Основа производительности нашей системы это многоярусная система кеширования. На серверах приложений данные объектов кешируются в разделенной памяти (shared memory) с сохранением на локальный диск. Приложения указывают на то как долго данные объектов могут не синхронизироваться с базой и все последующие обращения в течении этого времени обслуживаются высокоскоростным кешем. Этот тип управления кешированием изместен как ''время жизни'' (time-to-live). Локальный кеш реализован с помощью базы дынных Berkeley DB. Объекты сериализуются с помощью стандартного CPAN-овского модуля Storable.

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

Объекты серверов приложений разделяют друг с другом данные о продуктах используя широковещательный IP протокол и кастомизированный демон написанный на C. Когда продукт ложится в кеш на одном сервере данные копируются в кеш и на все остальные сервера. Эта технология является удачной благодаря частому локальному доступу к этим данным. В течении сезона Рождества 2000-го года рейтинг хитов этого кеша достигал 99%, так что бо'льшая часть работы происходила без обращения к базе данных (Зачем интересно тогда они купили крутую железяку на сервер баз данных и использовали там дорогой Oracle? прим. переводчика).

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

Для возможности аварийных исправлений мы добавили новую возможность в mod_proxy. Она позволяет нам удалять кешированные копии указанных URL. Это используется когда страница должна измениться сразу после корректировки информации.

Дополнительное преимущество кеша mod_proxy в автоматическом управлении запросами If-Modified-Since. Мы не нуждались в реализации этого своими силами, так как mod_proxy уже предоставляет такую возможность.

Работа с сессиями
Пользователям назначается сессионный ID используя HTTP cookie нашей кастомизированной версией mod_session, которая стоит на прокси серверах. Эти ID устанавливаются именно на прокси для того, чтобы запрашиваемые пользователем кешированные страницы имели уже назначенный ID. Сессионный ID это просто ключ к данным хранящимся на стороне сервера. Пользовательские сессии прикрепляются к какому-либо серверу приложений, который продолжают использовать в теченее всей сессии. Такой подход называется "липкой" балансировкой нагрузки. Сессионные и другие данные модифицированные пользователем, такие как содержимое корзины с покупками, пишутся и в кеш объекта и в базу данных. Двойная запись приносит небольшое ухудшение производительности, но это позволяет быстрее читать данные при последующих запросах без обращения к базе. Если ошибка на сервере заставляет пользователя переместиться на другой сервер приложений, то эти данные просто снова берутся из базы данных.

Безопасность
Крупный e-commerce сайт является популярной целью для атак всех типов. Когда разрабатывается подобная система, вы должны учитывать, что будете атакованы и должны не забывать об этом и на уровне приложений, и на машинном уровне.

Здесь главное правило "никогда не верь клиенту!". Пользовательские данные передаваемы клиенту защищены несколькими уровнями шифрования. SSL шифрует обмен важными данными защищая их от всех покупателей. Для предотвращения "захвата сессий" (когда кто-то подменивает сессионный ID чтобы получить доступ к сессии другого пользователя) мы включили Код Подлинности Сообщения (Message Authentication Code, MAC) как часть сессионной куки. Этот код генерируется стадартным модулем Digest::SHA1 доступным на CPAN с seed phrase (что то типа пароля. прим. переводчика) известной только нашим серверам. Пропуская ID из сессионной куки через алгоритм MAC мы можем удостовериться были ли представленные данные сгенерированы нами или кем-то подставлены.

В случиях, когда мы нуждались в вывыоде некоторой статусной информации в HTML форму или URL и нехотели чтобы это было видно пользователю мы использовали CPAN-овские модули Crypt:: для кодирования и разкодирования. Модуль Crypt::CBC неплохое начало.

Для защиты против простых атак на перегрузку, когда кто-то использует программы для посылки крупных запросов на наши сервера надеясь сделать их недоступными для потребителей, доступ к серверам приложений контролируется ругелирующей (throttling) программой. Код основан на модуле Stonehenge::Throttle Рандальфа Шварца (Randal Schwartz). Заходы каждого пользователя компактно записываются в журнал на NFS партиции. Программа ограничнивает число запросов от одного пользователя в течении определенного периода времени.

Для большей информации о web безопасности, включая использование MAC, шифрования и предупреждения перегрузки, мы рекомендуем взглянуть на книги CGI Programming with Perl, 2nd Edition и Writing Apache Modules with Perl and C, обе издательства O'Reilly.

Обработка исключений
Когда мы планировали эту систему мы обсуждали использование Java для ее реализации. Хотя мы всё-таки решили перейти на Perl, нам нехватало замечательных возможностей Java по обработке исключений. К счастью модуль Error Грахама Барри (Graham Barr) из CPAN предоставляет подобные возможности для Perl.

Perl уже имеет поддержку отображения ошибок исполнения и отлов объектов исключения, но модуль Error добавляет немного приятного синтаксиса. Следующий код показывает, как мы обычно использовали этот модуль:

try {
  do_some_stuff();
    } catch My::Exception with {
  my $E = shift;
  handle_exception($E);
    };

Модуль разрешает создавать ваши собственные классы исключений и ловить исключения заданных типов.

Дополнительная выгода от этого в том, что таким образом можно работать с DBI. Если вы включили DBI-ный RaiseError и используете блоки try в месте, где такое исключение может возникнуть, модуль Error переворачивает ошибки DBI в простой объект Error.

try {
  $sth->execute();
    } catch Error with {
  # откатиться назад и восстановить
  $dbh->rollback();
  # и т.д.
    };

Этот код показывает как в случае возникновения ошибки мы должны отменить (сделать rollback) транзакцию. На практике, большинство ошибок DBI показывают что с базой данной случилось что-то неожиданное и текущее действие не может быть продолжено. Эти исключения могут распространяться на верхний уровень блока try{}, который окружает весь запрос. Когда ошибки впойманы, мы журналируем стек вызовов (stacktrace) и шлем дружественную страницу с сообщением об ошибке пользователю.

Шаблоны
И HTML код и форматирующая логика, предназначенная для вставки данных из приложения в этот код, сливаясь вместе хранятся в шаблонах. Шаблоны реализуются при помощи CPAN-овского модуля Template Toolkit, который предоставляет простой, но мощный синтакс для доступа к Perl-овым структурам данных, передаваемых приложением. В дополнение к таким базисам как циклы и условные выражения, эта шаблонная система предоставляет широкую поддержку модульности, позволяющую использовать включения (includes) и макросы для упрощения обслуживания шаблонов и избегания излишиств.

Template Toolkit был для нас в этом проекте неоценимым инструментом. Наши HTML кодеры быстро его освоили и могли делать всю работу с шаблонами без вмешательства Perl-программистов. Мы снабдили их документацией о том какие данные будут поступать в каждый темплейт и они оставили нас в покое. Если вы никогда не имели удовольствия сказать менеджеру проекта, что HTML группа может справляться со своими проблемами без всякой помощи от вас, вы что-то серьезно упустили. (Вот только где они нашли таких сообразительных HTML кодеров? :) прим. переводчика)

Template Toolkit компилирует темплейты в перловый байткод и кеширует их в памяти для увеличения производительности. Когда файл с шаблоном меняется на диске он его читает и перекомпилирует. Также работают и другие mod_perl системы, такие как Mason и Apache::Registry

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

Это простой пример основного цикла в Template Toolkit:

[% FOREACH item = cart.items %]
    name: [% item.name %]
    price: [% item.price %]
[% END %]

Пример контроллера
Давайте теперь взглянем на простой "Hello World" пример, который показывает как в коде используется паттерн Model-View-Controller. Начнем с самого Контроллера.

package ESF::Control::Hello;
    use strict;
    use ESF::Control;
    @ESF::Control::Hello::ISA = qw(ESF::Control);
    use ESF::Util;
    sub handler {
  ### Делаем некоторую установку
  my $class = shift;
  my $apr = ESF::Util->get_request();

  ### текущая модель
  my $name = $apr->param('name');

  # создаем новый объект модели Model::Hello.
  my $hello = ESF::Model::Hello->new(NAME => $name);

  ### получить вид
  my $view_data{'hello'} = $hello->view();

  # метод process_template() наследоват из
  # базового класса ESF::Control
  $class->process_template(
    TEMPLATE => 'hello.html',
    DATA     => \%view_data);
    }

В дополнение к тому, что вы видите здесь, есть еще несколько интересных деталей о базовом классе ESF::Control. Все запросы отправляются сначала в метод ESF::Control->run(), в котором соответсвующий вызов handler() окружен блоком try{}. Тоже самое предоставляет из себя метод process_template(), который запускает Template Toolkit и передает ему результаты с соответсвующим HTTP заголовком. Контроллер может указывать заголовок, включающий аттрибуты Last-Modified и Expires для контроля кеширования страниц прокси серверами.

А вот как выглядит код соответсвющей Модели.

package ESF::Model::Hello;
    use strict;
    sub new {
  my $class = shift;
  my %args = @_;
  my $self = bless {}, $class;
  $self{'name'} = $args{'NAME'} || 'World';
  return $self;
    }

    sub view {
  # объект сам будет служить Видом
  return shift;
    }

Это простой объект Модель. Большинство объектов Модели будут иметь некоторые взаимодействия с базой и кешом. Они будут включать метод load(), который принимает ID и загружает соответвующий статус объекта из базы данных. Объекты Модели, которые могут быть изменены приложением также включают метод save().

Благодаря гибкому стилю ООП в Perl нет необходимости вызывать new() когда объект загружается из базы. Методы load() и new() оба могут быть конструкторами и оба метода возвращают связанные (blessed) ссылки.

Метод load() обычно управляет как кешированием, так и доступом к базе. Здесь представлен некоторый псевдо-код, показывающий типичный метод load():

sub load {
  my $class = shift;
  my %args = @_;
  my $id = $args{'ID'};
  $self = _fetch_from_cache($id) ||
    _fetch_from_database($id);
  return $self;
    }

Метод save() будет использовать такой-же подход, только в другом порядке, сначала сохраняя в кеш, а затем в базу данных.

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

В заключении нашего примера, мы должны показать шаблон, который генерирует соответствующий вид. Например:

<HTML>
<TITLE>Hello, My Oyster</TITLE>
<BODY>
[% PROCESS header.html %]
  Hello [% hello.name %]!
  [% PROCESS footer.html %]
    </BODY>
</HTML>

Настройка производительности
Так как перловый код достаточно быстро исполняется из-под mod_perl, узким местом в производительности обычно является база данных. Мы исполнили все докуметированные тонкости настройки производительности DBD::Oracle. Мы использовали связанные (bind) переменные, prepare_cached(), Apache::DBI и регулировку размера буфера через RowCache.

Огромный выйгрыш в производительности достигается в первую очередь, конечно, избеганием работы с базой данных. Кеширование, которое мы сделали, дало огромный толчек в производительности. Выборка данных о товарах из кеша Berkeley DB осуществлялась в 10 раз быстрее чем из базы данных. Обслуживание страниц продукции из кеша прокси серверов в 10 раз быстрее, чем генерация их из кешированных данных на сервере приложений. Ясно, что сайт без кеширования под сильной нагрузкой никогда бы не выжил

Разделение данных объектов стало еще одной большой победой. Мы определили несколько различных наборов товарных даных, которые могли быть загружены и кешированы по отдельности. Когда приложению нужны товарые данные оно может установить какой набор ему небходим и не загружать ненужные данные из базы данных.

Другой стандартной техникой улучшения производительности, которой мы воспользовались, было уклонение от ненужного создания объекта. Объект Шаблон, созданный в первый момент его использования, кешируется на всю оставшуюся жизнь процесса Apache. Соединение к поисковым серверам кешируется подобно тому, как Apache::DBI делает это с соединениеми с базой. Ресурсы, которые часто используются в большей части запроса, такие как хэндлы к базам данных и сессионные объекты, были кешированы mod_perl-овым $r->pnotes() до самого конца запроса.

Ловушка: Вложенные исключения
Когда пробуешь новую технологию, подобную модую Error, попадаются некоторые вещи, которых ты сразу не замечаешь. Мы нашли определенную структуру кода, которая вызывает утечку памяти каждый раз, когда она запущена. она включает в себя вложенные блоки try{} и выглядит так:

my $foo;
    try {
  # какието штуки...
  try {
$foo++;
# еще больше всяких вещей...
  } catch Error with {
# обработка ошибки
  };

    } catch Error with {
  # обработкав другой ошибки
    };

И это не ошибка Грахама Барра (Graham Barr. Создатель модуля Error. прим. переводчика.) вызывающая утечку, это просто результат того, что операторы try и catch реализуются с использованием анонимных процедур. Следующий код, эквивалентен предыдущему:

my $foo;
    $subref1 = sub {
  $subref2 = sub {
$foo++;
  };
    };

Эти вложенные процедуры создают преграду для $foo и будут создавать новую копию переменной каждый раз, когда они запущены. Эту ситуацию легко избежать, когда вы уже знаете о существовании такой проблемы.

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

Модуль DB_File часть стандартной поставки Perl. Правда этот модуль поддерживает только интерфейс к Berkeley DB версии 1.85 и не включает интересных возможностей поздних версий. Чтобы получить эти возможности надо скачать модуль BerkeleyDB.pm с CPAN-а. Этот модуль сложно откомпилировать, но об этом есть исчерпывающие инструкции.

Новые версии Berkeley DB предоставляют множество возможностей, которые помогают увеличить быстродействие в окружении mod_perl. Начнем с того, что файлы баз данных, вместо того, чтобы постоянно открываться и закрываться, могут быть открыты однажды при старте программы и оставаться открытыми на протяжении всего запроса. Berkeley DB будет использовать буффер в разделяемой памяти для повышения скорости доступа к данным для всех процессов, использующих ее. Параллельный доступ с управляемой вами блокировкой напрямую поддерживается базой данных. Большой выйгрыш дает DB_File, который требует от вас делать блокировку самим. Блокировка может осуществляться на уровне базы данных или на уровне страницы памяти, чтобы разрешать множественную одновременную запись. Еще доступны транзакции с возможностью отката.

Все это звучит слишком хорошо чтобы быть правдой и тут есть отрицательные моменты. Документация это что-то ужасное и вам возможно прийдется обращаться к C-ному API, если вы захотите понять как там все устроено.

Более серьезная проблема с повреждением базы данных. Когда процесс Apache, использующий Berkeley DB, умирает от сигнала kill или происходит segfault, он может повредить базу данных. Поврежденная база данных иногда может быть причиной зависания. Согласно тому, что нам сказали люди из Sleepycat Software (которые предоставляют коммерческую поддержку Berkeley DB), это может случиться даже в режиме транзакций. Они работают над решением этой проблемы. В нашем случае, никакие данные, сохраненные в кеше не были существенными для какой-либо операции, так что мы всегда могли просто очистить кеш когда перезапускали сервер.

Другая вещь, на которую стоит обратить внимание, это тупиковые ситуации (deadlocks). Если вы используете страничный уровень блокировки, то вы можете управлять дедлоками. Есть демон, включенный в дистрибутив, который будет следить и исправлять такие ситуации или вы можете управлять ими сами используя C API.

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

Если в вашей группе есть хороший программист на C, вы можете попытаться использовать альтернативный подход, который мы в конце концов и реализовали. Вы можете написать собственный демон поверх Berkeley DB и использовать его в клиент/серверной манере через Unix сокеты. Это позволяет вам отлавливать сигналы и обеспечивать безопасную остановку. Еще вы можете подобным способом написать ваш собственный код обработки тупиковых ситуаций .

Полезный инструментарий
Если вы планируете заниматься серьезными разработками на Perl, то вы действительно должны уделить время на ознакомление с некоторыми из доступных инструментов разработки. Дебаггер хорошо сохраняет время и он работает под mod_perl. Существует профайлер, называющийся Devel::DProf, который также работает с mod_perl. Это точно та вещь, с которой надо начинать улучшение производительности вашего приложения.

Мы нашли очень полезную возможность полностью запускать нашу систему на индивидуальной рабочей станции. Каждый мог заниматься разработкой на его собтвенной машине и координировать свои изменения используя систему контроля версий CVS.

Для моделирования и дизайна объектов мы использовали свободную программу Dia и Rational Rose. Обе поддерживают работу с UML и замечательно подходят для создания хорошеньких диаграм классов для обивки ваших стен.

С тех пор, как мы начали работать над этим проектом, было выпущено несколько разработческих каркасов (frameworks), которые предоставляют подобный тип архитекруры. У нас нет опыта использования их, но они имеют схожий с нашим дизайн и долюны быть удобными для вас, если вы захотите использовать MVC подход в вашей системе.

Apache::PageKit - mod_perl модуль, доступный на CPAN, который предоставляет основы MVC структуры для веб приложений. Он использует модуль HTML::Template для построения отображения.

OpenInteract это недавно созданный каркас для веб приложений (Web application framework) на Perl, который работает вместе с постоянным слоем (percistency layer) SPOPS. Оба доступны с CPAN

Application Toolkit от Extropia это понятный набор Perl-овых классов для построения web приложений. Он отлично документирован и имеет хорошее преимущество перед модулями из CPAN. Вы можете найти его здесь http://www.extropia.com/.

Если вы хотите готовый к использованию кеш модуль, то обратите внимение на Perl-овый кеш проект на http://sourceforge.net/. Это следующее поколение популярного модуля File::Cache.

Мир Java также имеет множество решений. Каркас Struts, часть проекта Jakarta, это хороший open-source выбор. Существует также множество коммерческих продуктов от различных производителей, которые используют дизайн такого типа. Одними из лучших решений являются ATG Dynamo, BEA WebLogic, и IBM WebSphere.

Счастливая история Open-Source
Мы создали на свободном программном обеспечении Web сайт высшего разряда применив при этом минимум усилий и затрат. Система, которую мы создали, легко расширяема для увеличения способности обрабатывать приходящий трафик. Она работает в основном на широко распространенной аппаратуре, делая таким образом, при необходимости, легким увеличение мощности. Возможно самое замечательное в этом то, что этот опыт предоставил нам возможность обучения наших разработчкиков и сделал нас частью еще большего сообщества разработчиков.

Благодаря нашей работе мы представили патчи обратно различным open-source проектам (прим.переводчика: имеется в виду, что они пользуясь различным свободным ПО находили и исправляли в нем ошибки, а исправления отослали обратно создателям этого ПО, чем оказали не оценимую помощь open-source сообществу.) и оказывали помощь в майл-листах. Мы рады случаю выразить официальную благодарность разработчикам свободного ПО, которые учавствовали в проектах, упомянутых здесь. Без них это небыло бы возможным. Мы также благодарим работящих Web девелоперов фирмы eToys. Магазин может быть закрыт, но таланты, которые он создал будут жить.

Если вы имеете вопросы касающиеся этого материала, вы можете спросить у нас по следующим email адресам:
Bill Hilf - bill@hilfworks.com
Perrin Harkins - perrin@elem.com

Уважаемые господа!
Я не большой специалист в английском и поэтому прошу всех, кто имеет такую возможность и желание, проверить правильность и коррестность моего перевода.
Заранее всем спасибо!

Замечания, критику, слова благодарности, а также вопросы, которые вы не смогли задать на прямую Перрину, жду по адресу:
dapi@mail.ru, Данил Письменный.


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

 
27.12.2003
Версия для печати Версия для печати Запомнить ссылку Запомнить ссылку
Ваша оценка:  1   2   3   4   5     

 О проектеПерепечаткаАвторамПартнерыО нас пишут
Наверх
©2003—2007. GETINFO.RU. ВСЕ ПРАВА ЗАЩИЩЕНЫ.