Comments 58
Ещё Swoole потеряли
Преимущество у Go перед PHP ровно одно — это скорость. А какие ещё, раз уж вы говорите об "уйме"? По-мне, так наоборот.
- Это преимущество высосано из пальца, будем чествными.
- Это не преимущество, под пых их на несколько порядков больше.
- Зависит от реализации, конечно же, но в целом да, вы повторили мой пункт о скорости.
- Тот же самый пункт о скорости.
В целом, кроме повтора тезиса "он быстрее" я не услышал никаких реальных оправданий его использования. Ну разве, только "он мне нравится", лично для меня это был самый убедительный аргумент. Т.к. язык, на котором нравится писать будет на порядок профитнее в умелых руках. Но это уже сугубо личное для каждого.
Если постараться оценивать объективно, то пых и мощнее как язык, и экосистема в "веб-сфере" у него на порядок взрослее, и при базе на том же swoole, есть подозрения, что будет побыстрее большинства реализаций на Go, но это вообще не точно =)
вот правильная — https://github.com/amphp/websocket
Да Amp вообще довольно дикая штука и написана большей половиной в хипстерском функциональном стиле. Лично у меня, как и любого php-шника, пережившего "эпоху DLE" (ну т.е. докомпозеровские времена) развилась фобия подобных штук. Не, ну хоть бы в класс закатали, да статики наружу прокинули бы...
Так что учитывая всё это, я отдаю свой голос за React-based штукенции и даже не по причине йилдов, а просто код кажется более опрятным и читаемым, нежели пачка хелпер-функций ядра.
Да Amp вообще довольно дикая штука и написана большей половиной в хипстерском функциональном стиле
а можно пример? бегло пробежался по репозиториям — вроде все норм
Прям самое сердце этой либы: https://github.com/amphp/amp/blob/master/lib/functions.php Сейчас уже поопрятнее стало, с год назад вообще жуть творилась в этом файлике. Тысяча строк функций и процедурок.
Сейчас — обычная либа для асинхронности. Ни вижу ничего особо страшного, всего-то сделали аналог async/await через генераторы. Обычное дело для языков, где еще нет async/await, но уже есть генераторы. Через это прошли Python, C# и Javascript. Теперь вот очередь PHP.
Вот год назад, согласен — был кошмар. Только не надо называть таку свалку из функций "функциональным стилем" — в ФП любят чистые функции, а там первая же функция — с сайд-эффектом.
"функциональный стиль" я для красного словца упомянул с некоторой толикой иронии над JS. Нынче просто они любят подобную шляпу разводить и считают это нормой. Правда, в защиту можно сказать, что почти всегда она не уезжает за пределы модуля, но не суть. Надеюсь перерастут, как PHP в своё время, исходники какого-нибудь Ангулара почти что вменяемые, даже. Далеко не уровня Symfony или Laravel, но некоторый прогресс есть.
Ну и смотрели\использовали эту либу в продакшене как раз год назад примерно, вот и запомнился этот файлик и любовь мейнтейнеров к километровй кучке функций. Потом забили болт и переехали на Газзл, т.к. на тот момент она (библиотека Amp, а точнее сборка Artax) все логи спамила ошибками (которые гасятся через собаку, что не отменяет наличие самих сообщений об ошибках). Сейчас, к слову, они тоже остались, но не в таком количестве, конечно.
А вообще мы используем Ratchet. А схема работы в тяжелых случаях такая. Сам WS-сервер работает как шина, тоесть только передает сообщения. Ну и вот когда, например, приходит rpc-вызов на тяжелый таск, то это сообщение отправляется в очередь. Собственно это – элемент масштабирования. Можно поднять сколько надо воркеров, да еще и на разных серверах, если не будет хватать «сработки» при текущем количестве консумеров.
Для нас было самым большим открытием – это как вернуть ответ. Сначала консумер сообщался с ws-сервером по ws же протоколу. Но так мы имеем мега оверхэд по вермени затрачиваемому на само соединение. Особенно это заметно когда передается очень много сообщений на ws. Надо было как-то упростить схему. После продолжительных поисков был найден React Child Process Component. Он решил все проблемы с производительностью. И ответ теперь возвращается так: В loop react'а добавляется дочерний процесс, который поднимает ratchet же tcp-сервер. Тоесть консумер передает ответ через небольшую обертку над fsockopen на tcp сервер, который является процессом петли ws сервера и ему (дочернему процессу) остается только выдать сообщение в stdout и он попадет в onData обработчик дочернего процесса. А тут уже можно выбрать соединение и отправить ответ.
Тут остается только не забывать передавать sigterm на дочерние процессы-серверы-слушатели ответов, когда гасите сервер. Да, тут еще подоспела новая возможность PHP – pcntl_async_signals(). Специально для ratchet'а наверно писали, для диспатчинга в нем сигналов :)
Собственно поэтому и используем Ratchet, ибо подходит хорошо по производительности и степени удобства при конструировании сервера.
А через очередь ответ не передать никак?
Ну, должен же тут быть какой-то способ. Вряд ли вы — первый кому захотелось обрабатывать ws и amqp в одном цикле.
А еще, это дает свободу творчества :) Можно в этом дочернем процессе что угодно сделать. Хоть еще дочерних процессов напихать, каждый из которых сам сокет сервер. Кароче, как я и говорил, понятное и производительное решение.
Э… а что сложного в подходе вида "вот ws-сокет, вот amqp-сокет, вот мы их слушаем в цикле"?
В том же цикле что и сокеты? Вы понимаете, что stdout процесса сильнее отличается от сокета чем amqp от ws?
— Это дополнительные либы
— Дополнительная теория
А что, если (тфутфуконечно) начнется усложение, увеличение нагрузки?
Надо знать как пользоваться \React\Promise\all, \Bunny\Async\Client, React\ZMQ\Context…
Не проще ли как-то так?
Как мне кажется, это более универсально. Я имею в виду добавление получения данных откуда-то в сокет.
Надо сказать, что минусы применимы и к вашему методу :)
- Дополнительная теория (реализация очень близка к моей)
- Надо знать как пользоваться
React\ChildProcess\Process
— Теория/абстракции несравнимо проще (либо промисы/контексты/корутины/елды/ватева, либо in/out/err выхлоп процесса)
— Универсальность: можно подключить программу на любом языке, которая являться может чем угодно
Мне кажется или мы про Яблоки vs. Апельсины? :)
Видите ли — дочерний процесс, он не из воздуха берется. Его тоже еще надо написать.
Если вам дочерний процесс достался от другого разработчика — то, конечно же, проще запустить его как вы показали. Но если стоит задача переслать запрос от ws-клиента в amqp-очередь, а потом вернуть клиенту ответ — то проще обойтись без дочернего процесса: будет на 1 требующий изучения слой меньше.
Нет, вам надо один раз разобраться как передавать асинхронные события в вашу петлю, после чего использовать этот способ где угодно. Базовых абстракций всего две — колбеки и корутины, обе сводятся к месту, где вы можете написать какой пожелаете код.
PS надоело читать ругательства вместо аргументов. Ловите минус в карму за "елду".
Мне кажется или мы про Яблоки vs. Апельсины? :)
Весьма вероятно :)
Ваша универсальность тоже имеет свои границы.
Во-первых, не понятно как быть если процесс отвалился с ошибкой? Во-вторых, придется как-то парсить stdout, т.к. он все-таки предназначен для чтения пользователем, а не машиной.
На счет ошибок: еще есть stderr.
На счет выпадения скрипта полностью. Есть возможность сделать так:
$process->on('exit', function($exitCode, $termSignal) use ($process) {
$process->start($server->loop);
// или через фабрику
});
А в целом конечно лучше через обертку запускать (хотя это тоже под большим вопросом), которая сама будет там ответственна за перезапуск отвалившихся частей.
Полагаю, лучше всё это на практике потестить.
Вебсокет сервер при методе, который я описываю, продолжает выполнять 1 роль – быть тупой шиной и перегонять данные от бэкенда к клиентам.
«парсингом вывода»
Это делают процессы, которые он запускает
«и перезапуском упавших процессов»
По этой де логике можно сказать, что, да, мы нарушаем принцип единой ответственности ибо сервер реагирует не только на ondata, но и на onopen, onclose, onerror, вызывает методы контроллеров при событиях…
Либо мы не понимаем друг-друга, либо вы – знатные тролли, господа :)
Но коментарий не камень в огород, а благодарность за работу — либка хорошо написана и было удобно использовать!
После знакомства с https://github.com/centrifugal/centrifugo я для себя этот вопрос закрыл раз и навсегда
Спасибо fzambia
Аналогично, уже 2 проекта с ним делаем, до этого писали свои поделки на socket-io. Был один проект на Ratchet года 2 назад и как-то что-то не рекомендую больше никому так делать.
Был один проект на Ratchet года 2 назад и как-то что-то не рекомендую больше никому так делать.
А не поделитесь какие именно проблемы? В разработке и (или) эксплуатации?
В разработке он не так удобен как связка из php + nodejs + socket-io через zeromq какой. На тот момент были какие-то проблемы с реализацией протокола, всех нюансов уже не упомню. Ну и отдельная проблема — найти библиотеки с учетом event loop и т.д. практически невозможно, потому по итогу вышло всеравно так что от основного приложения мы отделили это все через zeromq. А если так — то на кой черт websockts на php непонятно.
В итоге получился проект CppComet
Рекомендую https://github.com/centrifugal/centrifugo
Для возможности использовать таймеры необходим доступ к EventLoop. Насколько я понял взглянув на код, EventLoop нужно создать самому и передать в конструктор Ratchet\App, иначе доступа к нему не будет. Пример:
$loop = \React\EventLoop\Factory::create();
$app = new Ratchet\App('localhost', 8080, '127.0.0.1', $loop);
// ...
$loop->addPeriodicTimer(1, function() {
echo "Timer fired!" . PHP_EOL;
});
$app->run();
github.com/arthurkushman/php-wss
как альтернативу легковесной либыСоздание процессов — не очень легковесно, а stream_select — тоже не очень оптимальный вариант по ресурсам, к тому же ограничен одной тысячью процессов.
Лучше использовать библиотеки libevent/event. Например, workerman использует и не подвержен описанным выше проблемам и ограничениям. Также есть swoole, который тоже без таких проблем.
Именно благодаря существованию workerman и swoole я отказался от развития и поддержки своего велосипеда github.com/morozovsk/websocket
Существующие решения меня более чем устраивают, имеют большое комьюнити и т.д. Отказываться от них я планирую, только когда поддержка вебсокетов будет из коробки, ориентировочно с выходом PHP 8.
Ссылку на вашу библиотеку + описание можете отправить автору php-дайжеста, с просьбой включить её в следующий дайджест. Дайджест читает очень много людей, это поможет найти единомышленников, которые захотят её использовать / поддерживать.
Вебсокеты на php. Выбираем вебсокет-сервер