Записи с тегом «performance»

Python-хостинг: издержки производства

Хостинг python приложений имеет некоторые нюансы, не всегда удобные и приятные для хостера. Мы уже больше года предоставляем python-хостинг и столкнулись с рядом особенностей. Да, не все в нашем мире идеально :-)

Вся суть в способах связки python-приложения с веб-сервером. С тех пор как php прочно вошел и закрепился в среде веб-разработчиков, его постоянно стали сравнивать с другими языками программирования, применимыми для написания веб-приложений. В том числе сравнивали и производительность. Естественно скорость работы php-парсера была высока по сравнению с perl-кодом, работающим через cgi. Да и вообще cgi стандарт себя уже изживал.

Поэтому серверные веб-технологии пошли двумя основными направлениями в плане сопряжения программной части с веб-сервером:

  1. разработка всяких mod_* — встроенных интерпретаторов в веб-сервер;
  2. переботка стандарта cgi с целью увеличения производительности (FastCGI);
Оба направления популярны и успешны по сей день, т.к. у каждого есть свои плюсы и минусы. Переходя на детали о Python, хочется сделать отдельную заметку общего плана.

В тредовой (thread) модели python есть такое понятие как Interpreter Lock. Это когда тред блокирует интерпретатор на определенное время (пока не выполнит операцию, выполнит определенное кол-во инструкций или не пройдет таймаут). В принципе этот метод разделения ресурсов вполне хорошо работает на практике. Но в случаем с хостингом есть свои нюансы...

Представте вполне реальную картину. Веб сервер (Apache) с встроенным mod_python обслуживает 50 python-приложений. Если апач работает в тредовом режиме, тогда и mod_python тоже (апач настраивается на тредовый режим через опции компиляции, а модуль уже при сборке сам определяет в каком режиме работает апач и собирается в этом же режиме). Теперь сама ситуация: 50 веб-сайтов смогут вполне создать нагрузку 1-5 запросов в секунду, а на каждый процесс апача у нас приходится, например, по 25 тредов и одному интерпретатору python. Теперь вспомним про Interpreter Lock и прикинем какие могут быть ситуации. В общем говоря в тредовом режиме mod_python работает достаточно нестабильно. Выглядеть это будет как таймауты (код будет долго ждать разблокировки интерпретатора).

При работе в fork() режиме веб-сервера, проблема блокировок снимается (т.к. на каждое соединения клиента выделяется отдельный процесс веб-сервера и следовательно отдельный интерпретатор), но возникает проблема с экономией оперативной памяти. Т.к. каждый процесс потребляет значительное кол-во памяти (от 20 до 50 Мб ориентировочно).

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

Интересно что приложение запущенное в режиме FastCGI может также работать в тредовом и fork() режимах, что соответственно влияет на потребление ресурсов. В тредовом режиме проблемы остаются те-же что и с mod_python. Только кол-во запросов к отдельному FastCGI-процессу в принципе сокращается, что дает меньшую вероятность таймаута в связи с блокировкой интерпретатора.

Подводя итог. Хочу отметить что идеального решения нет. Для каждых отдельных случаев нужно разрабатывать решения (чем мы в принципе и занимаемся). Просто имея эту информацию, Вы сможете сами представить при написании Вашего проекта в каком окружении его лучше запускать. Следовательно Вы сможете его правильно спроектировать и оптимизировать.

Желаем успехов в разработке!

И опять кеширование! - часть3

Не знаю почему, но так получается что это третья заметка за месяц на тему HTTP-кеширования. К написанию этой заметки меня побудило прочтение новости о выходе "PHPIns!de #17, Февраль 2006" на opennet.ru Получилось как всегда... прочтение пары линков, пару запросов в гугле и уже появились мысли для изложения :) Итак, набор:
  1. Статья на английском "Doing HTTP Caching Right: Introducing httplib2"
  2. Перевод на русский от xmlhack.ru "Правильное HTTP-кэширование: httplib2"
  3. И сам Httplib2.
Из интересного в этой статье: табличка с описанием разных http-заголовков (директив), объяснение самих принципов проверки валидности кешированого объекта и разъяснения стандартов. Отдельно хочу отметить 3 пункт, библиотека написана для Python. Это полноценнный http-клиент, на нём всё описанное в статье можно и опробвыать. PS: Таки Пайтон рулит? Эээх когда будет время им плотнее заняться... :)

Кеширование динамики - часть2 (PHP)

В новостях на opennet.ru попалась ссылка на интересную статью про кеширование в php. Очень толковые мысли и примеры. Скажу ещё раз что проблема производительности веб-приложения напрямую связано с кешированием, при чём не только на стороне сервера, но и на стороне клиента. Conditional get никто не отменял, он для чего-то был создан в HTTP/1.1. Что проще отдать? строку заголовка 'Not modified' или сгенерить и отдать страницу текста. Даже если страница уже готова к отправке, как минимум экономится траффик и уменьшается загрузка канала. Поэтому я не понима почему Ruby On Rails даже картинки отдаёт через скрипт и при этом не даёт нормальных заголовков для кеширования. Хотя надо ещё уточнять... В общем интересное чтиво с примерами для php-программеров. Давайте писать по стандартам не только всякие там XHTML/CSS/etc... но и заголовки.

Мониторинг хостингового сервера

Решил поделиться опытом по этой теме. Значит у меня задача звучала примерно так: "не сложный клиент-серверный монитор загрузки сервера с веб-интерфейсом". Если конкретезировать то попросту рисовалка графиков и желательно сделанная на rrdtool. Начал как всегда с гугления и freshmeat.net. В итоге остановился на двух интересных софтинах. Первая cacti (кактус типа). Сделана на rrdtool + php + cactid (написанный на Си даемон-poller, который опрашивает хосты). Использование cactid - опционально. Для хранения конфигурации используется MySQL. Софтина позиционируется автором как комлексное средство монитроинга для сетей локального и глобального масшатаба с размахом до тысячи хостов. Мои запросы оказались поскромнее, поэтому пришлось отказаться от неё. Но в принципе очень стоящая вещь: гибкость на высоком уровне, мониторить может почти всё что угодно (не только стандартные заготовки по параметрам, которые кстати позволяют и так чуть ли не всё мониторить, есть framework для написания своих скриптов). Для сбора статистики по сети с хостов пришлось бы поднимать ещё snmpd - тоже минус. Вторая софтина - symon. На порядок проще. Рисует тоже через rrdtool и веб-интерфейс работает на php. Но своей простотой она меня и привлекла. В комлекте получается три компоненты: symon - локальный даемон для сбора статистики на хосте, symux - серверный даемон для сбора статистики с хостов и syweb - веб-интерфейс. Всё в принципе очень быстро поднялось. Вся конфигурация в текстовых файлах, взаимодействие symon и symux по tcp. Думаю что этот вариант подойдёт и для больших сетей хостов в 100. Главный минус этого варианта - мониторинг только unix-серверов, с устройствами (например switches, cisco routers) он не заработает, SNMP не умеет. Тут как раз выигрывает cacti. Но на данный момент нам как раз и нужно мониторинг только unix-серверов. В итоге мы получили мониторинг загрузки I/O на дисках, процессора, памяти, сетевых интерфейсов, системных буферов (mbuf), кол-ва и состояния процессов Apache, файервола (OpenBSD PF в нашем случае).

Кеширование динамики

Вопрос вообще достаточно насущный, особенно для сайтов с высокой посещаемостью. Для меня одно главное преимущество (для кого-то недостаток) MovableType перед Wordpress это возможность экспорта в статику контента (html). Сейчас поставил wp-cache плагин - тестирую.

Самое главное что меня поражает, почему разработчики не могут сделать нормальную обработку If-Modified-Since HTTP-заголовка во многих динамических програмных продуктах. Ведь это значительно снизит и траффик и нагрузку на сервер. Я вполне понимаю что объективным такое значение может быть довольно относительно, но можно поставить небольшое время экспайринга... Вообщем я пока ищу ответ на этот вопрос и заодно пытаюсь разобраться как научить Wordpress понимать такие элементарные вещи.

Тестирование производительности Apache2 (часть 1)

Первый интересующий меня вопрос при тестировании был "какое количество соединений сможет отработать корректно апач на статическом контенте". Начнём с того что отличительная фича работы apahce2 с запросами это возможность использования тредов. Напомню, что в 1-ой версии апач на каждое соединение делал fork процесса, во 2-ой ветке есть возможность собрать его со старой схемой обработки, но было бы глупо на продакшене не воспользоваться тредовой сборкой. Кому интересно можно почитать в официальной документации апача про многопоточность и мультипроцессные модули. В моём варианте апач был собран с многопоточным модулем worker. Вопрос тюнинга немного не в топик, обсудим его позже подробно. Ещё одно примечание - количество соединений, которое может отработать апач во многом ещё зависит от тюнинга ОС (в нашем случае это FreeBSD) об этом тоже отдельно. Утилита, которой я тестировал называется siege, она позиционриуется автором как стресс-тестер для веб-сервера, что как раз нам и надо. Скажу от себя что утилита вполне справляется со своим предназначением и была выбрана мной из-за простоты использования, гибкости и подробных отчётов. Теперь о процессе тестирования. Для начала я заготовил файлы разного размера на веб-сервере (размер почти произвольный), я брал вариации маленьких файлов до пол-мегабайта и один больше 8 мегабайт (кеш на винте был 8 мегабайт); потом сгенерировал текстовый файл с ссылками. Прочитав мануал по siege настроил конфиг (командой siege.config можно создать темплейт конфига - .siegerc в домашней директории, откуда он и будет читаться). Мои рекомендации по конфигу:
  1. переключить connection в режим close (keep-alive был по умолчанию) - как ни печально, но у меня siege не захотел нормально отработать keep-alive, с этим я ещё поразбераюсь и может что-то отдельно напишу;
  2. установить адекватный concurrent - это количество воображаемых пользователей "гуляющих" по ссылкам, которые генерирует siege;
  3. установить путь к файлу содержащему ссылки (если вы работаете больше чем с одним url) - директива file;
  4. установить время тестирования директивой time;
  5. рекомендую использовать директиву internet для рандомного перебора url-ами из списка (симуляция реальных запросов);
  6. timeout выбирайте на свой вкус, желательно чтоб он был согласован с таймаутом апача и был приближен к таймаутам браузеров.
Все опции можно задавать через ключи в командной строке, но чтоб не запутаться лечге прописать умолчания в конфиге. В результате можно получить следующую интересную статистику:
  • среднее время ответа сервера на запрос;
  • среднее кол-во транзакций в секунду (отработанных запросов);
  • пиковое кол-во одновременных запросов в секунду, после которого производительность апача начинает уменьшаться;
  • процентное отношение корректно обработанных запросов к общему кол-ву запросов;
  • кол-во необработанных запросов (не завершённых).
Публиковать свои результаты думаю не стоит, т.к. аппаратная и программная часть всё-равно у всех будет значительно отличаться. Может будут примеры к статьям о тюнинге самого апача и FreeBSD. Вообщем первая часть на этом заканчивается. To be continued... :-)