Да, часть кода писалась в nodepad++, а там ставится таб, а не пробел. Потому вперемешку. Исправил
По поводу var_export() — app.php это пример использования библиотеке, для самой простой интеграции — webhook. У нас в живом проекте phpcs-stash подключается с помощью composer и работает внутри очереди
спасибо, опечатку и ошибку в стиле исправил
Как такой стиль кода не задан, но я по привычке пишу в symfony code style http://symfony.com/doc/current/contributing/code/standards.html
1) Пользоваться не так удобно как с web интерфейсе. Хук можно отключить и забыть об этом. В качестве быстрой проверки используются стандартный проверщик phpstorm (там тоже phpcs под капотом)
2) Задумывались, но отказались, так как ка хотели терять авторов последних строк
LISTEN+NOTIFY ненадежен (пока слушающий демон отключен — он не будет получать сообщения). Следовательно использовать можно (для ускорения получения сообщений) но поллинг он не отменяет (так как надежность в любом случае нужна)
Есть 3 варианта жить:
1) Узкая специализация страны. Когда мы производим что-то одно (например, нефть), а все остальное покупаем. Путь заведомо в никуда
2) Пытаться самим освоить производство всего. Как пробовали делать в СССР, но даже тогда не хватало на все ресурсов.
3) Приглашать (заставлять?) иностранные компании локализировать производства в России (в данном случае услуги — дата центры). Как по мне — оптимальный путь, что и будет делаться в рамках этого закона
И да, какое-то время пользователям придется потерпеть. В том числе и мне придется переносить сервера БД из Германии
И да, сервера в России будут стоить дороже. Но это создает рабочие места для инженеров, администраторов и т.д.
6.1) Пометка ack делается только после успешного удаления/досылки. Досылка подразумевает удаление досылаемой строки из БД. При повторном получении пакета строки в БД уже не будет и досыльщик ничего не будет досылать
6.2) У rabbitmq есть режим, когда он сохраняет события на диске (delivery_mode=2). И в случае аварии они никуда не деваются. Соответственно заново не дошлются
4) В принципе да, можно было запрос к rabbitmq делать на уровне приложения, но таблицу message и досыльщик все равно должен остаться
5) я уже сказал :) одно место где дублируются пакеты — не повод создавать ещё одно место и создавать ещё больше дублей
6) не понял вас, поясните. Что значит сообщения исчезли из очереди? Я не рассматриваю ситуацию когда мы в раббит успешно закомитили, а сам ребит и где-то потерял. Пакеты могли потеряться только в дороге, при неуспешном комите в rabbit. Досыльщик досылает только то, что гарантированно не пришло в rabbitmq
По поводу недоосвоения pgq не комментирую :) тема статьи в механике перехода, а не в причинах, побудивших это сделать
первое: спасибо, очень содержательный комментарий. По некоторым пунктам пришлось очень крепко задуматься и даже советоваться в нашими ДБА
А теперь по пунктам
1)
2) Там всего 600 строк кода, то есть по размеру как средняя задача. Его можно отревьювить и допилить. Или даже переписать под себя
3) да, верно. pid — зациклен, нужно добавить backend_start. Спасибо!
4) Дедлок — это 2 процесса ждут друг-друга. А у нас только pg ждет amqp. То есть дедлок невозможен, просто будут запросы в БД тормозить и упремся в количество соединений. Или я не прав?
5) Да, не решается. Но баг в одном месте системы — не повод допускать ещё один баг в другом месте :) То есть нам бы этого лучше по возможности избежать
6) Когда rabbitmq развалится мы будем просто наружу кидать exception и ролбечить, и пусть родительское сообщение разбирается что делать (например, ролбек транзакци и 500 ошибка пользователю). Сообщения теряются именно тогда, когда у нас на момент начала транзакции rabbitmq был доступен, а к концу транзакции пропал
Вариант с перекладывателем я обдумывал, но он сам по себе не транзакционен и не надежен. Будет или дубли порождать, или сообщения терять. Если нет груза существующего кода, тогда уж лучше использовать HornetQ и реализовать честные распределеные транзакции, как предложил kefirfromperm
Вообще задача была — максимально безболезненный переход с PgQ на amqp. А использование честного менеджера транзакций (для двухфазного комита) потребовало бы существенного переписывания основного приложения (так как события в очередь будут отправляться уже не изнутри PostgreSQL, а из приложения).
Лаг получается около 10-30мс. При одном потоке досыльщика, написанном на пхп пропускная способность получается ~1000 пакетов в секунду. Сейчас перепишу досыльщик на что-то более серьезное и выложу его на гитхаб
1) А вы уверены что у вас просто крон-скрипт на две минуты не «зависал»? Или что будет, если вы часы в системе на 2 минуты переставите?
2) Например, может упасть сеть между базой и вашим скриптом. Или вы банально можете захотеть перезагрузить базу данных/сервер
1) Что значит «простроченное»? Секунда, 10 секунд, минута? Мы никак не можем прогнозировать время доставки сообщения. И дослать сообщение нужно максимально быстро, не дожидаясь некоторого времени «прострочки»
2) Как вы можете гарантировать что скриптик, который досылает, не сгенерирует дубли сообщений? Например, если упадет после отправки в ZeroMQ и перед пометкой о отправке в базе?
3) Крон подразумевает опять таки полинг базы, от которого хотелось избавиться. Время доставки сообщений у вас, очевидно, не realtime
Нет, я ничего такого не нашел
Плюс есть ограничение на минимальное исправление логики основного приложения (у нас же переход с PgQ на amqp, а не просто обеспечение целостности PgQ+amqp). Следовательно переход должен осуществляться просто подменой хранимки в PostgreSQL или ещё чем-то простым
На общую производительность это конечно не сильно влияет и на боевой системе не играет никакой роли. Но когда хотим создать отдельный контур для тестирования конкретной задачи это вырождается в дополнительные процессоры на каждую задачу
По поводу var_export() — app.php это пример использования библиотеке, для самой простой интеграции — webhook. У нас в живом проекте phpcs-stash подключается с помощью composer и работает внутри очереди
Как такой стиль кода не задан, но я по привычке пишу в symfony code style http://symfony.com/doc/current/contributing/code/standards.html
2) Задумывались, но отказались, так как ка хотели терять авторов последних строк
1) Узкая специализация страны. Когда мы производим что-то одно (например, нефть), а все остальное покупаем. Путь заведомо в никуда
2) Пытаться самим освоить производство всего. Как пробовали делать в СССР, но даже тогда не хватало на все ресурсов.
3) Приглашать (заставлять?) иностранные компании локализировать производства в России (в данном случае услуги — дата центры). Как по мне — оптимальный путь, что и будет делаться в рамках этого закона
И да, какое-то время пользователям придется потерпеть. В том числе и мне придется переносить сервера БД из Германии
И да, сервера в России будут стоить дороже. Но это создает рабочие места для инженеров, администраторов и т.д.
6.2) У rabbitmq есть режим, когда он сохраняет события на диске (delivery_mode=2). И в случае аварии они никуда не деваются. Соответственно заново не дошлются
5) я уже сказал :) одно место где дублируются пакеты — не повод создавать ещё одно место и создавать ещё больше дублей
6) не понял вас, поясните. Что значит сообщения исчезли из очереди? Я не рассматриваю ситуацию когда мы в раббит успешно закомитили, а сам ребит и где-то потерял. Пакеты могли потеряться только в дороге, при неуспешном комите в rabbit. Досыльщик досылает только то, что гарантированно не пришло в rabbitmq
По поводу недоосвоения pgq не комментирую :) тема статьи в механике перехода, а не в причинах, побудивших это сделать
А теперь по пунктам
1)
2) Там всего 600 строк кода, то есть по размеру как средняя задача. Его можно отревьювить и допилить. Или даже переписать под себя
3) да, верно. pid — зациклен, нужно добавить backend_start. Спасибо!
4) Дедлок — это 2 процесса ждут друг-друга. А у нас только pg ждет amqp. То есть дедлок невозможен, просто будут запросы в БД тормозить и упремся в количество соединений. Или я не прав?
5) Да, не решается. Но баг в одном месте системы — не повод допускать ещё один баг в другом месте :) То есть нам бы этого лучше по возможности избежать
6) Когда rabbitmq развалится мы будем просто наружу кидать exception и ролбечить, и пусть родительское сообщение разбирается что делать (например, ролбек транзакци и 500 ошибка пользователю). Сообщения теряются именно тогда, когда у нас на момент начала транзакции rabbitmq был доступен, а к концу транзакции пропал
Вариант с перекладывателем я обдумывал, но он сам по себе не транзакционен и не надежен. Будет или дубли порождать, или сообщения терять. Если нет груза существующего кода, тогда уж лучше использовать HornetQ и реализовать честные распределеные транзакции, как предложил kefirfromperm
Кстати ActiveMQ не поддерживает двухфазный комит, а только некий аналог, который может продуцировать дубли сообщений — activemq.apache.org/should-i-use-xa.html
2) Например, может упасть сеть между базой и вашим скриптом. Или вы банально можете захотеть перезагрузить базу данных/сервер
2) Как вы можете гарантировать что скриптик, который досылает, не сгенерирует дубли сообщений? Например, если упадет после отправки в ZeroMQ и перед пометкой о отправке в базе?
3) Крон подразумевает опять таки полинг базы, от которого хотелось избавиться. Время доставки сообщений у вас, очевидно, не realtime
Плюс есть ограничение на минимальное исправление логики основного приложения (у нас же переход с PgQ на amqp, а не просто обеспечение целостности PgQ+amqp). Следовательно переход должен осуществляться просто подменой хранимки в PostgreSQL или ещё чем-то простым