Comments 53
На всякий случай сделал обработку поведения по Mysql gone away: просто переподключаемся и работаем дальше. На тестах работает, в живую вроде бы не пригождалось.
Тут скорее всего то же самое поведение будет, демон он и есть демон.
За памятью разве что надо следить, а PHP для этого не совсем подходит, впрочем, все решаемо.
Нужно не забывать закрывать коннекты после обработки запроса, либо если используете пул коннектов то учитывать состояние. Чтобы не получилось так что в при обработке запроса вы открыли транзакцию и зафейлили запрос после чего бд с открытой транзакцией ушла обратно в пул.
В целом годная штука, но облать применения довольно узка так как оно не ложится на мышление современных php программистов и на сторонние библиотеки этими программистами написанные.
Так всё же, в целом, насколько велики отличия классического php подхода к разработке и тем, что предлагает RoadRunner? Если представить некое абстрактное, типичное PHP приложение-сайт, то при переносе его на эту технологию, в каких узлах ожидать проблемы, что вероятно потребует изменений? Хочется понять уровень этих проблем и изменений, это уровень глобальный, архитектурный или всё таки локальный, вроде того что вы описали насчет работы с БД.
с одной стороны вы вроде говорите, что состояние получается изолированным для каждого отдельного запроса и иного подхода потребуют, вроде как, только вполне конкретные места, типа взаимодействие с БД
Где? Вроде не говорил такого.
Типичное PHP приложение-сайт будет легче переписать с нуля чем натянуть на эту технологию. Проблем стоит ожидать везде где речь идёт о глобальном состоянии (синглтоны, статические свойства классов и тд) — а современный php код (как ваш так и сторонних библиотек) пишется без оглядки на это состояние.
Также следует ожидать утечечек памяти, но я так понимаю этот вопрос фиксится просто переодическим перезапуском воркеров.
Если ваше приложение использует request — response абстракции (например построено на основе symfony) и написано в академично-интерпрайз манере то ваши шансы на переход конечно возрастают, однако с ходу всё равно не заведется — нужны будут правки.
<?php
use Spiral\Goridge\StreamRelay;
use Spiral\RoadRunner\Worker;
use Spiral\RoadRunner\PSR7Client;
use Symfony\Bridge\PsrHttpMessage\Factory\DiactorosFactory;
use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory;
use Illuminate\Http\Request;
require_once(__DIR__ . '/../vendor/autoload.php');
$relay = new StreamRelay(STDIN, STDOUT);
$psr7 = new PSR7Client(new Worker($relay));
$requester = new HttpFoundationFactory();
$responder = new DiactorosFactory();
$app = require_once(__DIR__ . '/../bootstrap/app.php');
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
while ($psr7Request = $psr7->acceptRequest()) {
try {
$request = Request::createFromBase(
$requester->createRequest($psr7Request)
);
$response = $kernel->handle($request);
$kernel->terminate($request, $response);
$psr7Response = $responder->createResponse($response);
$psr7->respond($psr7Response);
} catch (\Throwable $e) {
$psr7->getWorker()->error((string) $e);
}
}
При таком подходе, постоянно есть ссылка только на инстанс $app и $kernel. Все остальное, что находится вне этих инстансов, сборщик мусора затирает (ибо он затирает все, на что ссылок больше не осталось), в том числе и подключения к БД (если они созданы вне контейнера $app), сокеты и прочие ресурсы.
В теории, если внести создание $app и $kernel внутрь цикла, то сборщик мусора при каждом новом запросе будет чистить абсолютно все.
Может тогда уж просто вернёмся к умиранию?)
А по существу, то даже так прирост производительности будет, ибо нет создания процесса, подключения файлов и компиляции кода/загрузка из опкэша)
При использовании php-fpm уже давным-давно как нету создания процесса.
Дополню соседний ответ:
в 7.4 планируется подгрузка библиотек при первом запросе и подключение во всех последующих, что убирает ещё 1 пункт из вашего сообщения.
Все коннекты гарантированно упадут в какой-то момент если их не закрывать, больше нюансов расписано вот тут: https://github.com/spiral/roadrunner/wiki/Production-Usage
Все же непонятно, зачем было так изголяться. Взяли бы java, kotlin или nodejs (с typescript), и не пришлось бы женить ежа с ужом
Угу, уволить давно подобранные команды и начать с нуля или начать переучивать хороших спецов php на совсем другой стек технологий.
Цена? Смысл?
Мне очень странно от инженеров слышать что-то вроде "возьмем язых Х и это решит все наши задачи". Не решит. Решит какую-то часть лучше, какую-то хуже. Мы инженер, а не пустомели все же, и должны идти от задачи, а не нашей хотелки. Иначе мы просто играем в клевую разработку, но не создаем решение.
Про велосипеды, можно примеры, лучше с коллапсом?
Но заметьте, в статье ровно об этом речь: для части задач php плохо подходил, взяли go, решили задачу лучше.
Я знаю примеры эволюции компании от php к go+php, затем к java, и сейчас к java+go. Но это не значит, что именно связка java+go работает идеально или что ее нужно было брать сразу. Каждый набор инструментов решал свои задачи в свое время, и имел определенную цену, которая или оправдана или нет.
В поиске этих компромиссов, оценке разной стоимости и затем обосновании решения и состоит наше с вами дело. Но, согласитесь, странно заявлять "c#! kotlin! Golang! Java!"
Работал на огромном портале недвижимости, весь написан на пыхе. Очень много работы с географией, кучей парсеров на миллионы записей и прочих прелестей. Сам портал увешан в итоге стал и редисом, и мемкешем, и риаком для хранения изображений, и кучей каких-то демонов, которые проверяют процессы распарсивания данных, пару разных очередей zeroMq и кролик. Плюс еще стоял эластик для поиска и еще куча всего. Времени исполнения некоторых скриптов не хватало, стали запускать в терминале с бесконечным таймингом. Потом стали писать под это свои веб обертки. В итоге пришли к тому, что в один поток работать — это лютый треш. Стали придумывать костыли. Прикрутили какую-то стороннюю сырую либу для пыхи, которая делала вид, что работает с тредами. Потом занимались херней, распараллеливая запросы прямо с веб морды, через сокеты (не нужно ждать ответа от сокета, что позволяет выполнять код в цикле, открывая новые сокеты с задачами). После всего этого зоопарка пришло понимание, что все это обслуживать, а тем более ловить баги — это очень суровая задача. Стали бить на микросервисы. Уперлись в монолитную БД, которую пришлось дробить и организовывать свой SOAP сервис, чтобы весь это зоопарк связать вместе (плюс еще 1С была подключена и своя CRM). Естественно, никто не писал никакой документации, комментариев в коде, так как всем все нужно на вчера. В итоге, через год команда на столько зае… алась со всем этим, что три четверти уволились в течении одной недели. Набрали новых, реально опытных людей. Они туда глянули, поколупались пару недель и тоже свалили. Так как возиться с этой кучей навоза на хрен никому не нужно ни за какие деньги.
Отсюда мораль. Не стоит делать на неподходящей технологии сложные вещи только по тому, что ты хорошо знаешь эту технологию, но не знаешь другую, которая больше всего подходит для конкретной задачи. И вместо того, чтобы реализовывать бизнес логику и развивать БИЗНЕС, все дружно пытаются на… бать ЯП, чтобы он делал то, для чего не предназначен.
Решать конечно каждый должен сам, что ему делать и как он считает правильным. Но лично я с пыхи вообще свалил на фиг, потому что знаю не по наслышке, что такое суровые проекты на пыхе.
И да, мне не показалось, что вы предлагаете померяться? Можем, но тогда избавьте окружающих от этого зрелища и переходите в личку. Но если коротко, то проблемы в языке у вас не особо было, максимум, выделили бы эти самые критичные куски и вынесли в отдельные микросервисы, где сможете любой подходящий набор технологий использовать.
И да, однопоточный php отлично себя чувствует в highload, если всеми любимая архитектура была под это поправлена. Многопоточность-то тут причем? Да и «пришло понимание, что» — это какая-то задача не решалась или просто нового захотелось?
Про php, есть опыт работы в e-commerce на 6 стран. Была изначально php 5.4, и большие проблемы в рампродажи, когда нагрузка уходила за 20k rps на checkout. Стали рефакторить этот кусок, чтобы его выкусить в микросервис, затем тоже для импорта товаров, и затем для рассчета акций и скидок. Отрефпкторенный php переносили в гошные микросервисы, переключались на них с php, оставляя ту же БД и постепенно перекрывая доступы к отдельным ее табличкам со стороны php.
В итоге решение заработало, php осталось, весь проект не переписывали, фичи бизнес получал non-stop, поскольку часть ресурсов оставалась на php и кодила дальше. Как подоспела 7я версия, то мигрировали на нее и нагрузка стала переноситься и еще с большим запасом.
Вопрос, зачем бегать кругами и орать, что весь язык плохой? Тем более сгенерировать html php часто умеет вровень или шустрее java, python, go.
Не решалась очень определенная задача «checkout не выдерживает в дни распродаж», ее и решили. Зачем все переписывать? Или зачем страдать об отсутствии (условно) многопоточности в php, когда пишешь генерацию html странички по закэшированным данным?
Очень странно — это взять не рунтайм язык и заниматься годами построением костылей, чтобы он стал рунтайм.Современный PHP — вполне может работать рантайм, я его напрмер использую для telegram бота как systemd сервис для обработки long polling запросов, вот пруф (картинку лучше открыть в отдельной вкладке):
Жалко этот сервер в начала декабря перегружал, до этого там несколько месяцев рантайма было.
Плюс взять ЯП, который не умеет создавать треды и обвешивать его другими сервисами и технологиями, чтобы сделать хоть какое-то подобие многопоточности. Да, у меня есть примеры крупных проектов и коллапсов. Если что, то отписал на пыхе, почти 15 лет.Предполагаю, что вы проработали 15 лет и ушли до PHP 5.3 т.к. начиная с этой версии PHP вполне себе умеет потоки.
pthread вполне рабочая штука, не требующая особой магии, полностью согласен.
еще было третье решение, но забыл…Наверно про это github.com/php-pm/php-pm
Затем, что проект размера Badoo, большая часть которого написана на пхп, двумя пальцами на жаве не перепишешь. Это слишком дорогой. Кроме того, зачем ломать то, что работает? Ещё и штат новый набирать? А со старыми что делать?
В статье речь не про Badoo. А про студию веб дизайна
JS это хайп и мода, хаять его — значит плыть против течения. К этому наше сообщество не склонно. С PHP ситуация аналогичная, но со знаком минус. К сожалению, люди забывают, что говнокод создается в конечном итоге ими же, а не инструментом, и говнокода на том же JS тонны. PHP сейчас хорошо развивается и будет сохранять свою нишу еще долгое время. Вспомните, был хайп ruby/ror, но где это щас все? Потихоньку и эта волна спадет, а PHP впитает в себя лучшее и будет спокойно жить дальше.
Мы знали, что сможем написать веб-сервер на чистом PHP (PHP-PM) или с использованием С-расширения (Swoole). И хотя у каждого способа есть свои достоинства, оба варианта нас не устраивали — хотелось чего-то большего.
Слабоватые аргументы. Чем не устраивали? Вы же наверно что-то смотрели, с чем-то сравнивали. Можно об этом подробнее?
Например, есть такое решение github.com/amphp/http-server, есть тот же PPM.
Что-то можете сказать об этом?
Завести Swoole в режиме "поставил и забыл", мы не смогли. Пробовали несколько раз в течении 4 последних лет.
Нагружая PPM мы упирались в сам балансировщик. Насчет AMP не скажу, еще не гоняли его.
Вообще изначально RR был нужен не для HTTP, а для AWS SWF воркеров. В итоге это не HTTP сервер, а app server (любой фронтенд). Например https://github.com/spiral/php-grpc
grpc & grpc-gateway?
Но мне лично Go не взошел
Очень уж специфичным показался
Но это только на мой взгляд!
Если их действительно можно будет объединить во что-то общее… Думаю, должна получиться как минимум Ракета_)
Очевидное отличие разработки под RoadRunner от классической схемы сохранил_скрипт — перезагрузи_страничку состоит в том, что теперь это выглядит сохранил_скрипт — перезагрузи_демона — перезагрузи_страничку. Руками это делать скучно, но умные люди уже всё придумали. Для автоматизации понадобится modd.
Мой modd.conf выглядит вот так:
**/*.php {
daemon +sigterm: ~/bin/roadrunner/1.2.6/rr serve -d -v -c /home/foo/src/boo/rr.json
}
Кстати, вопрос к Lachezis: почему-то у меня не получилось использовать rr http:reset — php код сервера не обновляется. Команда rr http:reset -d -v -c /home/foo/src/boo/rr.json отрабатывает — в логе появляется сообщение new worker pool, но код не перегружается. Или это так и задумано и http:reset нужен для чего-то другого? Возможно, есть еще какой-то более правильный способ обновления кода на сервере, пожалуйста поделитесь.
и rr.json
{
"http": {
"address": "0.0.0.0:8880", <-- биндинг на ваше усмотрение
"workers": {
"command": "/usr/bin/php /home/foo/src/boo/main.php",
"pool": {
"numWorkers": 4 <-- число ядер CPU
}
}
}
}
Заходим в /home/foo/src/boo и запускаем modd, теперь при изменении в php файлах, находящихся в директории /home/foo/src/boo, rr процесс автоматически перезагрузится и вы сможете увидеть сделанные изменения. Рекомендую использовать tmux, если дело происходит в терминале ssh
Еще можно maxJobs использоват для разработки. Должен перезагружаться (есть тесты), http:reset и задуман для безопасной перезагрузки пула. Если стабильно воспроизводится то кидайте нам багу на гитхаб (желательно со способом воспроизвести).
Теперь возник вопрос, а насколько дорого перезапускать весь сервер целиком по сравнению с оперцией http:reset?
Поясню суть проблемы, если вызвать rr http:reset при выключенном сервере, то в ответ получаем Error: dial tcp 127.0.0.1:6001: connect: connection refused, что в принципе логично. Можно ли сделать так чтобы в этом случае rr всё-таки запускался? Иными словами, http:reset_or_start
При использовании modd c директивой daemon +sigterm достаточно запустить только modd и он автоматически запустит новый rr и будет за ним следить, при этом rr будет выводить свои сообщения в этом же самом окне. Если же использовать конструкцию в modd.conf вида prep: rr http:reset, то сначала в одном окне нужно запустить rr serve, а в другом окне modd, мелочь, конечно…
Или посоветуете использовать для разработки daemon +sigterm и «не придумывать себе», а http:reset оставить только для продакшена?
В проде перезагружать сервер будет очень дорого, может отвалится хелсчек и система начнет скейлится. Для локальной разработки можно использовать то что работает, но я все же рекомендую http:reset
.
http:reset
написан с учетом того что сервер может и не перезапустится (например случайно залили кривой код), в таком случае старый пул останется работать.
Хотя разработчики стараются, клепают версию за версией. Но догнать передовые языки, как мне кажется, уже не смогут.
Скажите можно ли использовать путь к конфигу отличительный от .rr.json?
RoadRunner: PHP не создан, чтобы умирать, или Golang спешит на помощь