Комментарии 13
сборщик мусора для чистки ссылок
Вот тут по подробнее, зачем? Во первых просто для ссылок php и так почистит тогда когда надо, в прочем как и для циклических ссылок. Раскройте цель подобных манипуляций со сборщиком подробнее. Есть мнение что это как-то связано с
постоянно копить в нем ссылки и держать соединение с бд — это плохо.
как я уже говорил — php сам удалит ссылки. Более того вызов gc_collect_cycle
вообще ничего не сделает особо.
Зато другая проблема появляется — reset менеджера при исключениях. И вот там вполне коннекшен умирает и его надо передернуть. А закрывать коннекшен между задачами в очереди — крайне неразумно. Скажем для postgresql реконнект штука относительно дорогая, да и зачем нам этот оверхэд по времени обработки сообщений..
Вот тут я уже не знаю точно, но насколько я помню менеджер памяти не просто так не высвобождает запрошенные у системы блоки, а потому что планирует реюзать их далее. То есть если приложению вдруг понадобилось 200 метров, то почему бы ему еще раз не понадобилось?
Ну то есть я к тому что часто ее вызывать наверное тоже не стоит как минимум потому что иначе это будет вынуждать пых чаще просить систему выделять память. Но периодически, скажем раз в 100 сообщений или в зависимости от потребления памяти — пожалуй стоит.
Разве rabbitmq:consumer работает в режиме демона? Мне казалось, что обычное CLI приложение.
О некоторых багах phpamqp-lib. Баг репорты есть на гитхабе, до сих пор нету решения.
1. Consumer: допустим запустили мы consumer и активировали heartbeat. От тихо ожидает новых сообщений в этой точке github.com/php-amqplib/RabbitMqBundle/blob/master/RabbitMq/BaseConsumer.php#L53. Бесконечно долго, т.к. timeout = 0. Допустим, падает сетевое соединение на какое-то время, затем оно восстанавливается. Консьюмер по прежднему ждёт сообщения в той точке, а RabbitMQ уже закрыл соединение. Всё, консьюмер будет висеть в памяти до тех пор, пока его не прибьют сигналом каким-нибудь. Соответсвенно, если в консьюмере есть таймер для «самоубийства», то он не сработает.
2. Без heartbeat могут быть проблемы с незакрытыми соединениями на стороне RabbitMQ. Возможно тут ещё всему виной HAProxy, который в нашем случае стоит перед кластером RabbitMQ.
Из-за этих казалось бы незначительных проблем, код надёжного консьюмера выглядит как бесконечный try/catch и while loops, чтобы консьюмер мог реагировать на разрыв соединения и переподключаться. Такого функционала нету ни в какой высокоуровневой библиотеке (см. Enqueue, например, или бандл, описанный в данной статье)
Далее, есть очень хорошая инициатива — github.com/queue-interop/queue-interop — при помощи данных интерфейсов можно быть независимым от конкретной библиотеки, которая реализует AMQP протокол (phpamqp-lib, php extension, bunny lib). Интерфейсы позаимстованны из мира Java. Но они тоже на начальном этапе своего существования.
Например, в нашем проекты мы решили стать менее зависимыми от конкретной AMQP библиотеки. Посему перевели всех наших consumer/producer на github.com/php-enqueue/enqueue-dev. Проект не на Symfony, поэтому используем только имплементацию Queue Interop интерфейсов с использованием phpamqp-lib, чтобы в ближайшем будущем попробовать имплементацию от bunny lib.
Но тут ждало разочарование: такая фича, как Publisher Confirms, которая есть только в RabbitMQ, отсутсвует out-of-the-box в самих интерфейсах от Queue Interop (тикет на гитхабе есть). Пришлось делать костыли, очень нехорошие костыли. В проекте у нас договорённость о at-least-once delivery, потому и нужен Publisher Confirms.
Если всё подытожить, то вот мои рекомендации:
1. Подумайте 10 раз, нужин ли вам Message Broker вообще. Если можно, используйте MySQL/файлы/что угодно, что уже есть в вашем проекте. Тех поддержка самого RabbitMQ в продакшене — тот ещё геморой для Operations Team.
2. Если всё же решились на Message Broker, то ответьте на вопрос, можете ли вы потерять пару сообщений? Если можете — то используйте любые бандлы/библиотеки. В противном случае крайне рекомендую сначала написать пару consumer/producer на низком уровне (к примеру, используя phpamqp-lib без обёрток) и хорошенько пройдитесь отладчиком, разрывая соединение/физически отключая/аварийно выключая RabbitMQ. Вы удивитесь, как легко можно потерять сообщения. А уже потом подбирайте конкретные высокоуровневые бандлы под свои нужды.
Но тут ждало разочарование: такая фича, как Publisher Confirms, которая есть только в RabbitMQ, отсутсвует out-of-the-box в самих интерфейсах от Queue Interop (тикет на гитхабе есть). Пришлось делать костыли, очень нехорошие костыли. В проекте у нас договорённость о at-least-once delivery, потому и нужен Publisher Confirms.
Я думаю что Publisher Confirms не про at-least-once delivery. Это расширение дает возможность отправителю получать уведомления когда его сообщения обработаны получателем.
В документации ничего не сказано про случай когда соединение с получателем обрывается (по причине исключения например) и брокер возвращает сообщение в очередь с пометкой redelivered. Есть шанс обработать сообщение больше чем один раз. Уверен есть и другие ситуации.
Если бы мне нужно было «at-least-once delivery» я бы делал это на стороне получателя + хранилище для проверки на повтор.
От отправителя требуется проставить уникальный идентификатор сообщению.
Практически все что вы описываете, в Enqueue уже реализовано из коробки: например, такие веши как, переподключение к базе данных, чистка entity manager, повторы с задержкой, RPC.
EnqueueBundle умеет это делать из коробки.
коммуникацию между компонентами через AMQP, как красиво делать RPC, то я сам чего-то подобного очень давно жду на хабре…
Вот Message bus to every PHP application
Пользуюсь бернардом уже год, новые проекты переводим на enqueue. Он удобнее и больше полезных фич из коробки.
У меня бернард на 3 проектах, когда выбирал что ставить то больше внимания обратил на количество звезд на гитхабе. Но в будущем попробую enqueue. Спасибо.
Symfony + RabbitMQ Быстрый старт для молодых