Обновить

Комментарии 59

А о чем нам вообще могут говорить синтетические тесты нагрузки, где тестируемый метод просто возвращает заранее заготовленную строку?
Об оверхеде, который накладывает фреймворк на любые решения. Это как планка, выше которой прыгнуть не получится :) Для каких-то проектов это не критично, но там, где по условиям техзадания вызов API должен гарантированно укладываться в 1мс, а оверхед фреймворка на обслуживание такого вызова выше, придется искать другие варианты.

Но в целом согласен с вопросом и планирую дополнить раздел тестов более-менее реальными кейсами «сходить в базу» и «отрендерить HTML шаблон». Для себя тестиовал поведение Comet с PDO и Eloquent — последний оказался в два раза медленнее на простых вставках в базу.
Поясните непонятливому: если важна каждая милисекунда, то зачем вообще нужен оверхед в виде какого-либо фреймворка? Что проще — написать своё быстрое на «чистом» php или взять «универсальное решение» и бесконечно пытаться оптимизировать окружение для его ускорения внедряя всё новые и новые «ускорялки»? Есть пример хайлоад проекта на популярном фреймворке?
Если важны миллисекунды, то php не берут.
Если есть возможность ускорить проект практически бесплатно — то почему бы и нет?
Для facebook и vk не важны, видимо? Помимо технической прагматичности есть ещё экономическая составляющая, благодаря которой php очень даже берут.
Что имеете ввиду под «бесплатно»? Перейти с одного фреймворка на другой — это не бесплатно.
Именно потому фб и напилил HHVM, а ВК KPHP, что просто php уже не подходил. Банально начали делать на том, на чем могли, а переписать уже слишком дорого. На фоне затрат на смену стека, смена фреймворка — копейки.
На «чистом» PHP будет медленнее в разы! Однозначно нужно использовать слой в виде workerman / swoole / reactphp и подобных библиотек. А с ними оверхед на код фреймворка становится совсем минимальным. Если вызов API выполняется менее чем за миллисекунду, дальнейшая «оптимизация» для многих проектов не имеет смысла.
А workerman разве не на «чистом» php написан? ;)
НЛО прилетело и опубликовало эту надпись здесь
Согласен, надо добавить в тесты Lumen — но по ожиданиям, его производительность будет где-то на уровне Symfony (судя по тестам TechEmpower Benchmarks)
использующий наработки команд SlimPHP и Workerman

По-моему, Вы используете не наработки этих команд, а их библиотеки


Как Comet поведёт себя при множестве блокирующих операций?

Это зависит от настроек сервера Comet — количества доступных для работы воркеров. Длинные блокирующие операции выжирают пул доступных воркеров и заставляют новые запросы ждать своей очереди. Звучит не очень в теории, но на практике даже под нагрузкой Comet не проигрывает в производительности ни серверам на Go, ни проектам на NodeJS, если блокирующим фактором выступает, например, база данных.
Жаль нет в сравнении Yii2, а он вроде как по другим статьям побыстрее будет чем Symfony и Laravel в этом деле.
Хотелось бы понять так ли это и на сколько.
Должен быть быстрее — на уровне Slim, судя по этим тестам
Я правильно понимаю, что ваш фреймворк по сути состоит из двух файлов?
Если не считать composer.json — так и есть :) Пока не решил, какие части фреймворка стоит включить в базовой поставке. Думаю, расширенные версии Request / Response, миддлваре авторизации и средства миграции БД пригодятся всем пользователям.
Я такой же «фреймворк» писал для yii2 и workerman. Тоже в два файла :)
Тоже было огромное отличие в производительности, а потом заметил, что у меня op-cache не был установлен (оказалось что в centos это отдельный пакет). Установил op-cache и разница получилась всего в два раза. Возможно автор статьи тестировал с отключенным op-cache.
Насколько я знаю, opcache по умолчанию включен во всех дистрибутивах PHP7. Но проверил на всякий случай php.ini в докер-контейнере на базе Ubuntu 19.10 и PHP 7.4, в котором тестирую все фреймворки — как и ожидалось — opcache.enable=1
Да в убунте он включен по дефолту, это в центосе только почему-то решили сделать иначе.
В принципе по графикам с латенси видно, что отличие всего в два раза.
А на графиках rps такое большое отличие потому что в php-fpm было мало воркеров.
Укажите пожалуйста сколько воркеров было использовано в тесте у comet и сколько у php-fpm.
В принципе даже на TechEmpower Benchmarks
видно, что workerman быстрее чистого php не более чем в 2 раза, ну и в 5 раз по сравнению с slim.
А у вас workerman+slim получился в 7 раз быстрее чем просто slim. Т.е. во время тестов было указано недостаточное количество воркеров и php-fpm просто захлёбывался, оказавшись в неравных условиях.
К слову, в TechEmpower Benchmarks чистый пхп добился таких высоких результатов, потому что они создают около 1000 воркеров. Из-за чего конечно сильно повышается расход оперативной памяти, но многие крупные проекты так и делают. Просто увеличивают количество воркеров. Память дешевле, чем переписывать весь код.
Я использую workerman уже очень давно и он хорошо себя показывает на микросервисах без блокирующих операций, но что-то более менее серьёзное, что ходит в базу и т.д. уже не даёт почти никаких преимуществ, но сильно усложняет разработку и деплой, поэтому в проде я его использую только там, где мне максимум приходится использовать redis.
Спасибо за инсайты, настройки Nginx/FPM брал как раз на Techempower, но на результаты мог повлиять факт тестов из докер-контейнеров на платформе Windows. Надо будет прогнать их на более приближенном к реалиям окружении Linux.

Кусочек конфига, определяющий количество воркеров:

worker_processes  auto;
worker_rlimit_nofile 200000;
events {
    worker_connections 16384;
    multi_accept off;	 
}
Кусочек конфига, определяющий количество воркеров
Это воркеры nginx, а я про воркеры php-fpm:
pm.max_children = 1024
В вашем фреймворке:
$worker->count = (int) shell_exec('nproc') * 4;
т.е. в 4 раза больше чем ядер, поэтому мне было интересно сколько у вас было воркеров для пхп.
Кстати, у них в тесте сейчас количество воркеров уменьшается с 1012 до 512, если ядер два:
if [ $(nproc) = 2 ]; then sed -i «s|pm.max_children = 1024|pm.max_children = 512|g» /etc/php/7.4/fpm/php-fpm.conf; fi;
Подрихтовал все конфиги и провел тесты на Linux-машине Hetzner:

github.com/gotzmann/benchmarks

Результаты отрыва получились еще более впечатляющие :) Интересно понять, связано ли это на самом деле с конфигурированием, или все-таки workerman позволяет ускоряться до нереальных показателей.
Хм. есть же Falcon
Надо посмотреть поближе, рекомендовали Phalcon Micro. Несколько лет назад у меня с ним были проблемы (то ли не мог собрать пакет, то ли он вообще не поддерживал разработку на Windows-хостах), поэтому в этот раз я как-то прошел совсем мимо.
Сейчас он доступен на хостингах c cPanel через EasyApache, через pear, в репозиториях популярных дистрибутивов, поддерживает PHP вплоть до последнего 7.4. Реально быстрая штука с простым синтаксисом.
Я думаю, что предзагрузка должна очень сильно оптимизировать существующие фреймворки. Да и RoadRunner сейчас это очень неплохо делает.
Предзагрузка помогает, но не настолько существенно, как хотелось бы. Badoo на Хабре приводит следующие цифры: «переход c PHP 7.2 на PHP 7.4 даёт +10% к производительности на нашем endpoint’е, а preload даёт ещё 10% сверху».

В следующих версиях Comet планирую тоже поиграться с предзагрузкой и добавить более быстрые имплементации PSR-7 компонентов.

Тоже странно, почему нет RR в сравнении. Используем его в проде уже более полу-года (все php-приложения перевели на работу с ним, забыв про nginx+fpm) — полёт нормальный. Кстати, он довольно легко интегрируется с тем же Laravel, для чего написал и поддерживаю пакет avto-dev/roadrunner-laravel. По нашим тестам буст производительности (очень многое зависит от самих приложений) составил от 20 до 80 процентов.

Ну Spiral работает на RR раз в 5-7 быстрее Symfony, и это на точках с ORM (согласно тому же бенчмарку). Сравнивать микро сборки с фулл стеком достаточно ненадежное занятие.

В тестах использовал обрезанный Symfony без Doctrine и прочих бандлов — только роутинг и контроллеры.

Привет Антон :) Именно поэтому и было интересно посмотреть на бенчи указанного в посте решения под соусом RR. Кстати, дополню про "20 до 80 процентов" — это именно на "тяжелых" endpoints, условно-статичные (ping, static view) просто уходят в космос по сравнению с традиционным nginx+fpm.
В сторону Spiral пока лишь присматриваюсь, но и этот проект кажется очень интересным, обязательно что-нибудь на его основе сделаем.

А есть у Spiral какие-то микросборки для тестирования? Не смог собрать для него урезанную версию без ORM и прочих плюшек, а хотелось бы для сравнения github.com/gotzmann/benchmarks
Приложение на Comet я запускаю прямо из командной строки Windows/ Linux и для его работы не требуется ни RR, ни Nginx или FPM — считаю, это огромное преимущество. Зачем RR, если нативное приложение на PHP работает быстрее без обвязки?

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

gotz, Классный троллинг ;) Назвать демку к slim фрейворком.
Спасибо :) Это не демка Slim, просто Comet «магически» отправляет все не определенные в классе вызовы внутреннему инстансу приложения Slim — поэтому код базовых примеров выглядит один в один.

Как сказано в описании проекта на GitHub, Comet — это гибрид Slim и Workerman, приправленный собственной магией, которой будет больше в следующих релизах :)
Два года я писал микросервисы на Go
… Однако, как всё хорошо начиналось :). Что подвергло REST-ы писать на РНР?
Для Go был мощный корпоративный фреймворк для генерации 90% бойлерплейта по сваггер-спеке. Аналогичного по возможностям в опен-сорс не нашлось, а писать вручную типичный код на го для валидации и перекладки данных между JSON и базой данных — такое себе удовольствие. PHP более краткий и мощный. Для Python есть Connexion от Zalando — но увы, это не мой язык :)
«Не упоминай имя REST всуе.»

Не увидел в вашем примере ничего такого, что позволяло бы проще писать приложения с архитектурой REST. Хотя правильнее сказать — ничего такого, что заставляло бы писать этом стиле. Т.е. накладывало бы какие-то ограничения на программиста, которые исходят из ограничений описанных в REST.
У вас просто минималистичный web-фреймворк, который ни к чему не обязывает.
Остальные части фреймворка пока не готовы к публичному показу и концептуально не проработаны. Замечание справедливое :)
Замечательный фреймворк для вывода фразы «Hello world» на экран. Если я когда-нибудь захочу написать приложение, выводящее фразу «Hello world» — обязательно им воспользуюсь! (на самом деле нет)
Ну для реальной работы у меня в приложении помимо Comet подключен Eloquent, Monolog и миграция базы на Phinx. Тащить все это в сам фреймворк не вижу смысла :) У других разработчиков могут быть собственные предпочтения по выбору библиотек.

Мне кажется речь не совсем о том, что присутствует или не присутствует в вашем фреймворке(все понимают, через composer можно прикрутить что угодно), а речь о том, что тесты надо было демонстрировать хотя бы с загрузкой сервис-провайдеров/бандлов, с чтением конфигурации, заполнением контейнера зависимостей или сервис-локатора минимально необходимыми компонентами — сделать тот же "hello world", но включая минимальный набор того, что действительно понадобится во время разработки. Я почему-то уверен, что вы взяли тот же laravel и не выпиливали из него сервис-провайдеры, которые не будут использоваться(бродкасты, авторизация, вьюхи, сессии, очереди, dbal и.т.п), не отключали искоробочные глобальные middleware и прочее. Я не говорю, что оно сразу в одном вырастет, а в другом резко просядет, однако результаты будут немного справедливее, чем наблюдается сейчас… Отсюда и такие поспешные выводы про фрэймворк для "hello world".

Я старался провести максимально честное сравнение и выпилил из Laravel / Symfony все бандлы, которые вообще можно было выпилить. Буду рад, если посмотрите и подскажете, как их еще можно ускорить, я выложил бенчмарки в репозиторий:

github.com/gotzmann/benchmarks

Провел сравнительные тесты на машине Hetzner и разница между Comet и остальными фреймворками получилась еще более внушительной.

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

я не понимаю, зачем все эти реакты, воркманы и т.д. если есть swoole с корутинами.
Для того, чтобы не ломать привычный поток разработки на PHP :) Не нужно изучать новые подходы и разруливать целый класс новых проблем и нюансов асинхронного кода — ведь все летает и без этого. Но если хочется бОльшего именно в рамках PHP — да, Swoole интересный вариант. Но я программировал в такой парадигме на Go / Node.js и мне не очень понравилось.
Так что там не так с отваливающимся контроллером в примере?

gotz прошу прощения, но какой смысл сравнивать проекты, которые работают по разным принципам? Если Вы воспользовались workerman в новом "фреймворке" получается, что это детище тоже работает асинхронно. Вы показали бэнчмарки сравнивая синхронные фреймворки с асинхронными. Может для справедливости к остальным фреймворка прикрутить Swool или что-то подобное и потом уже меряться, что скажете?

Так Comet — это и есть попытка использовать Slim в гиперускоренном варианте. Ну и дополнительные плюшки, заточенные именно под REST. Сейчас добавляю HTTP-клиент, сравниваю тот же привычный Guzzle / новый легковесный Buzz и собственную реализацию поверх стримов PHP (file_get_contents).
Не хотите ломать, не используйте корутины. В чём workman лучше? сообщество меньше, библиотек меньше, использование в больших проектах — меньше. В чем смысл?
Swoole я тоже планирую попробовать в качестве «ускорителя» в будущем, но Workerman прямо сейчас лучше тем, что поддерживает разработку на Windows-хостах. При этом не требуется ничего компилировать или подключать сторонние расширения — все работает просто из коробки. Для меня это было важно, по умолчанию сейчас корпоративный ноутбук Dell / Windows 10 :)
windows, тогда понятно. Обязательно попробуйте, приятно удивитесь. Кстати, корутины на swolle, даже немного быстрее чем на Го.
Но windows для разработки, это конечно печаль.
Зашёл на github посмотрел пример контроллера в описании и…
он всегда будет возвращать 500 ошибку…
public function setCounter(Request $request, Response $response, $args)    
    {        
        $body = (string) $request->getBody();
        $json = json_decode($json);
        if (!$json) {
            return $response->withStatus(500);
        }  
        self::$counter = $json->counter;
        return $response;        
    }

Когда такие косяки прямо в примерах в описании, сразу теряется доверие к автору, и пропадает желание использовать.
он всегда будет возвращать 500 ошибку…

Я конечно не xDebug, но как вы пришли к такому выводу?
$body = (string) $request->getBody();
$json = json_decode($json);


надо всё-таки
$json = json_decode($body);
Да, дошло. Спасибо
Пример с контроллерами был оформлен по ходу подготовки документации прямо из головы, спасибо за наводку :) Исправил ошибки в примере, проверил на локалхосте работу и обновил README на GitHub.
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

Минуточку внимания