Как я уже писал в предыдущих постах, несколько месяцев назад я выбирал фреймворк для работы. Главную роль для меня играли простота его использования, стабильность и производительность.
За неимением в Интернете конкретной развернутой информации о сравнении скорости фреймворков, (я нашел только одно достаточно голое тестирование: Оно ограничивалось тремя фреймворками RubyOnRails, Django, Symfony и не содержало деталей), я провел детальный анализ для определения самого оптимального из шести ведущих по этим параметрам.

Update 04.Feb.2007: Pylons, RoR 1.2.1, CakePHP + eAccelerator, Zend, Turbogears with Cheetah, Jinja, Genshi

Итак, цель тестирования была - определение скорости работы самих фреймворков и сравнения их друг с другом по скорости генерирования страниц и максимальному количеству запросов на данной конфигурации.
Я выбрал тестовую модель, при которой контроллер рендерил определенный шаблон и генерировал ответ. В итоге получался HTML-файл c "Hello World!" (ниже есть код для каждого фреймворка). База данных в тесте не используется, так как она сама накладывает сильные ограничения на скорость.

Я не пытался сравнить функциональность фреймворков, коммьюнити, работу с базой данных. Мне важно было определить скорость работы именно движка MVC фреймворка, по возможности уменьшив влияние внешних факторов.
Поэтому я использовал связку Nginx + FCGI через IP:Port.

Были протестированы следующие фреймворки:
Тестирование проводил на следующем железе и софте:
CPU: AMD OpteronT Processor 146 (2 GHz)
Memory: 2 GB
OS: Debian 3.1 (Linux 2.6.14)
Web-Server: nginx/0.5.5
Версии фреймворков и языков программирования:
  • CodeIgniter 1.5.1
  • Catalyst 5.7006 Rev.5996
  • Django Rev.4254 (28Dec.2006)
  • RoR 1.1.6
  • RoR 1.2.1
  • Symfony 1.0beta2 SVN-Rev 3122
  • Turbogears 1.0b3 Rev.2323
  • Python 2.4.4
  • Python Psyco 1.5.2
  • Flup Rev.2303
  • Ruby 1.8.5-p12
  • mongrel 0.3.13.4
  • PHP 5.2.0 (cgi-fcgi)
  • perl, v5.8.4
  • CPAN ver 1.8802
Программы для тестирования:
Siege 2.65 http://www.joedog.org/JoeDog/Siege
Http_load 12.03.2006 http://www.acme.com/software/http_load/
ab 2.0.41-dev Rev: 1.141
Методика тестирования:
  • Измерение памяти (ps aux: VSZ "virtual set size" и RSS "resident set size").
  • Тестирование ApacheBenchmark (2 раза подряд)
  • ab -c 5 -n 1000 http://project.com/
  • Измерение памяти и израсходованного процессорного времени (ps aux: VSZ, RSS, %CPU, %MEM)
  • Перезапуск фреймворка
  • Тестирование ApacheBenchmark (2 раза подряд)
  • ab -c 100 -n 10000 http://project.com/
  • Измерение памяти и израсходованного процессорного времени.
  • Перезапуск фреймворка
  • Измерение http_load
  • http_load -rate 10 -seconds 5 project.com
  • Измерение памяти и израсходованного процессорного времени.
  • Перезапуск фреймворка
  • Тест Siege c 50 одновременными пользователями в течении одной минуты.
  • siege -d1 -t1M -c50 project.com
  • Тест Siege c 200 одновременными пользователями в течении одной минуты.
  • siege -d1 -t1M -c200 project.com
  • Тест Siege c 300 одновременными пользователями в течении одной минуты.
  • siege -d1 -t1M -c300 project.com
  • Измерение памяти и израсходованного процессорного времени.
Комментарии к методике:

Для начала я прогнал один Nginx с простейшим конфигом, при котором на любой запрос выдается точечный прозрачный gif-файл размером 43 байта, генерируемый самим сервером.
Этим тестом была определена примерная максимальная пропускная способность самого сервера. Забегая вперед скажу, что запас его мощности в 10 раз больше пропускной способности самого быстрого фреймворка.
Все фреймворки запускались как FastCGI 127.0.0.1:PORT. Если фреймворком предусматриваются development и production режимы, то я работал с production.
В nginx использован одинаковый для всех конфиг.
Перезапуск фреймворка я проводил, чтобы очистить статистику между тестами разными программами.

Мои субъективные дополнения по каждому фреймворку при инсталляции и запуске:
  1. CodeIgniter
    Легко ставится и быстро настраивается. Никаких проблем с ним не возникло. Для запуска использовал spawn-php.sh с пятью процессами.
    Довольно шустрый для PHP фреймворк.
  2. Catalyst
    Для начала надо установить CPAN и парочку модулей для FCGI. Установка выглядела несколько запутанно.
    Запуск также не простой. Для начала нужно запустить фреймворк
    ./CatInABox/start.sh
    Потом сам проект
    ./script/world_fastcgi.pl -l 127.0.0.1:9500 -n 5
    Код не так прост, но разобраться можно.
  3. Django
    Легко ставится из репозитария. Также легко создаются пректы. Запускал двумя методами prefork и threaded. Хотя питон не очень хорошо работает с тредами.
    python manage.py runfcgi method=threaded host=127.0.0.1 port=8801
    python manage.py runfcgi method=prefork host=127.0.0.1 port=8801
    Также проверил фреймворк с модулем ускорения psyco. В manage.py вставил:
    from django.core.management import execute_manager
    import psyco
    psyco.full()
  4. RubyOnRails
    Его легко поставить следуя инструкции с сайта, но оказалось сложно запустить. Хотя в интернете видел разные конфигурации для связки Nginx + FastCGI, мне не удалось запустить его вместе с nginx.
    С lighttpd + FCGI же все запустилось нормально. Поэтому я воспользовался "официальной" рекомендацией запускать через сервер mongrel.
    Благодаря Алексею Ковырину можно прикинуть коэффициент умножения.
    Nginx+FastCGI быстрее примерно в 1.29 раз чем Nginx+Mongrel.
    Запускал 5 серверов mongrel:
    mongrel_rails start -d -e production --port 8501 --pid /tmp/rb1.pid
    mongrel_rails start -d -e production --port 8502 --pid /tmp/rb2.pid
    mongrel_rails start -d -e production --port 8503 --pid /tmp/rb3.pid
    mongrel_rails start -d -e production --port 8504 --pid /tmp/rb4.pid
    mongrel_rails start -d -e production --port 8505 --pid /tmp/rb5.pid
    
    Через пару дней после проведения тестов вышла новая версия RoR 1.2.1
    Я, конечно, проверил и ее со всеми параметрами, обновил только фреймворк. Результаты несколько шокировали: падение производительности в 2 раза на всех тестах.
  5. Symfony
    Поставить было не сложно, но зато потом намучался с самим проектом. Довольно запутанно.
    Для запуска использовал так же spawn-php.sh с пятью процессами.
  6. TurboGears
    При установке возникли небольшие проблемы, которые, немного повозившись, все же решил.
    Для запуска в threaded режиме использовал скрипт отсюда, где изменил
    from fcgi import WSGIServer
    	на
    from flup.server.fcgi  import WSGIServer
    
    WSGIServer(application=wsgiApp).run()                                                                                                                                                               
    	на
    WSGIServer(application=wsgiApp, bindAddress=
    ('127.0.0.1', 8900)).run()

Конфигурационные файлы web-сервера: Коды проектов каждого фреймворка: Скрипт запуска PHP-FCGI: Результаты web-сервера для сравнения: Результаты по каждому фреймворку в отдельности: Результаты:
  1. Тест ApacheBenchmark
    • Таблица с скоростью обработки запросов
      Таблица с скоростью обработки запросов

      * 1) во второй раз фреймворк завис и не отвечал
      * 2) коэффициент умножения по Ковырину =1.29. Для перевода скорости работы из mongrel в fastcgi
    • Диаграмма со скоростью обработки запросов. Тест „ab c 5 n 1000“
      Диаграмма со скоростью обработки запросов
    • Диаграмма со скоростью обработки запросов. Тест „ab c 100 n 10000“
      Диаграмма со скоростью обработки запросов
    • Расход памяти до и после тестов
      Расход памяти до и после тестов
      * 3) Питон устроен так, что при сильной нагрузке в режиме prefork он перестартует свои процессы. Поэтому невозможно определить реальную загрузку процесора и максимальное потребление памяти.
    • VSZ "virtual set size"
      VSZ
    • RSS "resident set size"
      RSS
    • Загрузка процессора
      Загрузка процессора
  2. Тест http_load
    • Таблица с результатами
      Таблица с результатами
    • Диаграмма с временем соединения на коннект
      Диаграмма с временем соединения на коннект
    • Диаграмма с временем отклика первого соединения
      Диаграмма с временем отклика первого соединения
  3. Siege тест
    • Общая таблица с результатами
      Общая таблица с результатами
    • Диаграмма транзакций
      Диаграмма транзакций
    • Время отклика
      Время отклика
    • Наибольшее время транзакции
      Наибольшее время транзакции
    • Расход памяти после тестов
      Расход памяти после тестов
    • Загрузка процессора
      Загрузка процессора

Выводы:

Результаты видны по таблицам и графикам.
Некоторые дополнения:
Меньше всего потребление процессора у django.
Удивил Catalyst, который при чрезмерной нагрузке резко начинает грузить процессор. Хотя потерь запросов не наблюдалось.
RoR 1.2.1 под большой нагрузкой также сильно грузит процессор.
Интересно было у TurboGears, который показал низкое потребление времени CPU в тесте "ab", но зато в siege-тесте имел самый худший результат.
Потребление памяти самым большим оказалось у Catalyst, у RoR оно скорее обусловлено запуском через mongrel.
PHP-фреймворки даже в спокойном состоянии занимают много ресурсов CPU.

Среднее время коннекта для всех примерна равно. Время первого отклика сильно отличается, отличился django, имея наименьшее среднее время и самое высокое максимальное время коннекта. Фреймворки на питоне показали себя с хорошей стороны, а вот руби разочаровал.

Во время siege-теста наблюдались потери при большом количестве "concurrent users" у CodeIgniter, Symfony, RoR 1.2.1 & 1.1.6
Руби быстр при небольшой нагрузке, но резко теряет производительность при большом количестве пользователей.

Psyco модуль ускоряет django на 15-30%, но за это приходится расплачиваться возросшим потреблением памяти VSZ на 80% в prefork-режиме и на 400% (!!!) в threaded-режиме. RSS потребление увеличивается в 2-2.5 раза.
Prefork-режим забирает больше памяти, но за это получается система, стабильно работающая на больших загрузках, и меньшее потребление ресурсов процессора.
В threaded-режиме django зависал под большой нагрузкой и не отвечал на запросы.
Это же происходило и с TurboGears. Связано это с плохой работой питона в threaded-режиме.

Комментарии от Ивана Сагалаева:

"- FastCGI сервер запущен в threaded-режиме. Известно, что Питон в тредах работает существенно медленно из-за GIL (Global Interpreter Lock), из-за которого все треды очень часто просто ждут друг-друга, потому что интерпретатором может владеть только кто-то один. Поэтому в юниксах, если есть возможность, серверы с питоновским кодом стоит запускать в prefork-режиме - будет быстрее. Кстати, под Windows ситуация обратная, потому что там создание процесса существенно медленней, чем в юниксах, и там на тредах Питон тормозит, насколько я знаю, все же меньше. - Насчет Psyco. Джанговские девелоперы тестировали его, и нашли интересную штуку. На 32-битных системах он действительно дает прирост в производительности. А вот на 64-битных - наоборот, производительность падает. Происходит так из-за того, что под Psyco процессор переключается в 32-битный режим и не использует всех прелестей своей архитектуры. Если все это так, то тот факт, что под Psyco Django таки работал быстрее означает, вероятно, что Linux и Python скомпилены не в 64 битах (несмотря на то, что работает это все на Opteron'е). Это так?"

Да, система 32 битная.

Распределение мест по данному тесту:
  1. Минимум с трехкратным превосходством над ближайшими конкурентами победил django.
  2. Второе и третье места поделили TurboGears и RoR 1.1.6, так как они одинаково быстры, но ведут себя по разному при разных нагрузках, обгоняя друг друга.
  3. .
  4. Catalyst. Честно говоря, от фреймворка на перле я ожидал большего.
  5. CodeIgniter. Фреймворки на PHP, как и ожидалось, оказались самыми медленными. Но CodeIgniter можно посоветовать тем, кто хочет программировать только на PHP, и в тоже время иметь удобную и относительно быструю систему.
  6. Результаты RoR 1.2.1 сильно шокировали: падение производительности в 2-4 раза по сравнению с 1.1.6 версией.
    Время первого отклика в http_load также больше в 2 раза, чрезмерно высокое потребление процессорного времени при высокой нагрузке, все это скорее говорит о какой-то ошибке в новой версии.
  7. Symfony досталось последнее место. Очень сложный и медленный фреймворк. Разница с django - до 35(!!!) раз.


P.S. По многочисленным просьбам (так как я использовал для django ускоритель Psyco) сделал сокращенный тест для фреймворка на PHP с ускорителем eAccelerator-0.9.5.
Использовал команды, запущенные два раза подряд:
ab -c 5 -n 1000 http://ci.test.com/
ab -c 100 -n 10000 http://ci.test.com/
В результате CodeIgniter заработал в 6,5 раз быстрее, выдавая до 600 запросов/сек.
В сравнении с django разница сократилась до двух раз.
Здесь эти результаты
153 Votes | Average: 4.5 out of 5153 Votes | Average: 4.5 out of 5153 Votes | Average: 4.5 out of 5153 Votes | Average: 4.5 out of 5153 Votes | Average: 4.5 out of 5 (153 votes, average: 4.5 out of 5)
Loading ... Loading ...

Top Posts: