по пункту 5 значит мы решили, что всё таки как-то не ровненько, и трекать надо бы, — хорошо.
далее:
6.1) вооот. тут то вы, как раз, через досылку _только_ после удаления, и реализовали, по сути, трекание событий досыльщика, — ОК
6.2) а тут вам надо внимательно почитать про «delivery_mode=2» и «персистентность» раббита (и например еще в связи с этим и про лаг acka по 200ms) — раббит fsync делает отложенно (для буфера из многих мессаджей), то что вы потеряете — вы даже не отследите
и
далее. это всё вам надо же держать еще горячие «реплики» (и базы и очередей), вы же не будете ждать пока железо новое подвезут/введут, так что проблема восстановления после аварий и потерь (fsync а по сети тем более нету, в раббите особенно) приобретает более общие рамки. и да, мы еще не рассматривали падение и восстановлени pg.
5) вы с этого начали, но проблему в итоге так и не решили
> отдельно хранить какие из событий мы уже обработали
6) а тут я вам показываю, что вам и пачкой могут повторы прилетать:
6.1) либо когда не сработал Message acknowledgment на очереди досыльщика (и он повторно будет досылать)
6.1) либо в случае аварии раббита (kill -9 и подобное, когда он потеряет события, которые были в его очереди), когда поле восстановления всё, что пропало из очереди досыльщика (но обработалось уже на продуктовом консумере) снова дошлется
4) но вопрос мой открыт: приложение не хотели трогать совсем? такую же систему в целом можно было сделать, если просто с клиента писать еще и в раббит после записи в базу.
5) 100 рублей превращаются в 200ти всё равно, значит надо трекать всё равно повторное выполнение. значит дело не в конкретной «очереди» (pgq/rabbit/etc), а вообще так всё всегда везде.
6) вооот. опять получите повторно сообщения, так как те, которые исчезли при падении (из очереди досыльщика) и так и не успели удалится из таблицы, — все придут опять. у вас досыльщик и конечный консумер работаю же абсолютно независмо и асинхронно.
// тут еще момент: проблема с Message acknowledgment отдельно интересна для досыльщика, надо бы посмотреть, заложились ли вы на повторный приход «удаления»
вообще, решение не самое плохое, как могло показаться на первый взгляд.
замечания:
1) интересно было вспомнить про XactCallback внутри pg
2) страшно пускать древненький сишный, по цифрам бета, код pg_amqp *0.4.1* в бой, можно покрашить весь кластер начисто
3) вместо pid надо Session Id (комбинация pid и backend_start)
www.postgresql.org/docs/9.0/static/runtime-config-logging.html#GUC-LOG-LINE-PREFIX %c
4) очень не хорошо отклик базы вешать на еще один синхронный внешней сетевой вызов — потенциально это глобальный дедлок в системе, по мимо прыгающего латенси при коммите и простое центрального ресурса (коим база и является) если сеть лагает. в приведенном примере надо было тогда просто на клиенте после коммита в базу синхронно писать далее в раббит
5) проблема «повторного прихода события» не решается и в консумере rabbit а. если он упал в процессе обработки и не отметил событие как выполненное, клиент получит его еще раз (Message acknowledgment www.rabbitmq.com/tutorials/tutorial-two-python.html)
и 100 рублей превратятся в 200ти всё равно, так что трекать всё равно надо, и это не проблема pgq, а! ограничение реального мира
6) ну и большой вопрос, как быть когда раббит развалится (https://aphyr.com/posts/315-call-me-maybe-rabbitmq) и надо будет сводить концы с концами и что-то досылать в него ( тут и опять в том числе повторная доставка )
// примерно подобную штуку проектировал: pgq шный консумер перекладывал в раббит — лаг 1 секунда, но нет синхронных завязок внутри базы и страшного кода. но при этом я воспроинмал раббит уже просто как отрезок сети
www.hagander.net/talks/
Data driven cache invalidation (slightly updated), JDCon-East, New York City, NY, March 2011 and EuroPython 2011, Florence, Italy (+ scripts)
че-то правда у него пдфка не грузится, а
скрипты скачиваются
у меня на PostgreSQL 9.2.6 поведение как и описано в документации. как и должно быть. «рулы» в данном случае делают отличное от read commited поведение
далее:
6.1) вооот. тут то вы, как раз, через досылку _только_ после удаления, и реализовали, по сути, трекание событий досыльщика, — ОК
6.2) а тут вам надо внимательно почитать про «delivery_mode=2» и «персистентность» раббита (и например еще в связи с этим и про лаг acka по 200ms) — раббит fsync делает отложенно (для буфера из многих мессаджей), то что вы потеряете — вы даже не отследите
и
далее. это всё вам надо же держать еще горячие «реплики» (и базы и очередей), вы же не будете ждать пока железо новое подвезут/введут, так что проблема восстановления после аварий и потерь (fsync а по сети тем более нету, в раббите особенно) приобретает более общие рамки. и да, мы еще не рассматривали падение и восстановлени pg.
до аварии
> отдельно хранить какие из событий мы уже обработали
6) а тут я вам показываю, что вам и пачкой могут повторы прилетать:
6.1) либо когда не сработал Message acknowledgment на очереди досыльщика (и он повторно будет досылать)
6.1) либо в случае аварии раббита (kill -9 и подобное, когда он потеряет события, которые были в его очереди), когда поле восстановления всё, что пропало из очереди досыльщика (но обработалось уже на продуктовом консумере) снова дошлется
5) 100 рублей превращаются в 200ти всё равно, значит надо трекать всё равно повторное выполнение. значит дело не в конкретной «очереди» (pgq/rabbit/etc), а вообще так всё всегда везде.
6) вооот. опять получите повторно сообщения, так как те, которые исчезли при падении (из очереди досыльщика) и так и не успели удалится из таблицы, — все придут опять. у вас досыльщик и конечный консумер работаю же абсолютно независмо и асинхронно.
// тут еще момент: проблема с Message acknowledgment отдельно интересна для досыльщика, надо бы посмотреть, заложились ли вы на повторный приход «удаления»
«HornetQ» — уж лучше уж кастылить дальше)
мой вам совет итоговый — делать честного pgq-шнуго консумера с нормальным треканием обработки (там всё уже прилагется).
github.com/markokr/skytools/tree/master/sql/pgq_ext/functions
по моему, вы просто недоосвоили pgq-шные возможности.
замечания:
1) интересно было вспомнить про XactCallback внутри pg
2) страшно пускать древненький сишный, по цифрам бета, код pg_amqp *0.4.1* в бой, можно покрашить весь кластер начисто
3) вместо pid надо Session Id (комбинация pid и backend_start)
www.postgresql.org/docs/9.0/static/runtime-config-logging.html#GUC-LOG-LINE-PREFIX %c
4) очень не хорошо отклик базы вешать на еще один синхронный внешней сетевой вызов — потенциально это глобальный дедлок в системе, по мимо прыгающего латенси при коммите и простое центрального ресурса (коим база и является) если сеть лагает. в приведенном примере надо было тогда просто на клиенте после коммита в базу синхронно писать далее в раббит
5) проблема «повторного прихода события» не решается и в консумере rabbit а. если он упал в процессе обработки и не отметил событие как выполненное, клиент получит его еще раз (Message acknowledgment www.rabbitmq.com/tutorials/tutorial-two-python.html)
и 100 рублей превратятся в 200ти всё равно, так что трекать всё равно надо, и это не проблема pgq, а! ограничение реального мира
6) ну и большой вопрос, как быть когда раббит развалится (https://aphyr.com/posts/315-call-me-maybe-rabbitmq) и надо будет сводить концы с концами и что-то досылать в него ( тут и опять в том числе повторная доставка )
// примерно подобную штуку проектировал: pgq шный консумер перекладывал в раббит — лаг 1 секунда, но нет синхронных завязок внутри базы и страшного кода. но при этом я воспроинмал раббит уже просто как отрезок сети
немного истории для обобщения и введения в дальнейшее рассмотрение
можно упомянуть развитие истории «бинлога» базы данных из статьи Олега
peter.eisentraut.org/blog/2015/03/03/the-history-of-replication-in-postgresql/
wiki.postgresql.org/wiki/Foreign_data_wrappers#Tycoon_FDW
и
!!! отличный пример как всё расширяется: multicorn.org/
! londiste (из skytools) — pgfoundry.org/projects/skytools
// еще можно slony и bucardo
explain analyze
select min(item_id), max(item_id) from items
«Result (cost=0.29..0.29 rows=1 width=0) (actual time=0.045..0.046 rows=1 loops=1)»
" InitPlan 1 (returns $0)"
" -> Limit (cost=0.00..0.15 rows=1 width=8) (actual time=0.020..0.020 rows=1 loops=1)"
" -> Index Only Scan using items_item_ux1_080914 on items (cost=0.00..61820478.54 rows=422748256 width=8) (actual time=0.018..0.018 rows=1 loops=1)"
" Index Cond: (item_id IS NOT NULL)"
" Heap Fetches: 0"
" InitPlan 2 (returns $1)"
" -> Limit (cost=0.00..0.15 rows=1 width=8) (actual time=0.018..0.019 rows=1 loops=1)"
" -> Index Only Scan Backward using items_item_ux1_080914 on items (cost=0.00..61820478.54 rows=422748256 width=8) (actual time=0.016..0.016 rows=1 loops=1)"
" Index Cond: (item_id IS NOT NULL)"
" Heap Fetches: 1"
«Total runtime: 0.071 ms»
71 микросекунда
100 микросекунд — можно 10 000 раз в секунду на одно ядре делать такой min max
на пхп потребитель pgq тоже есть
там есть нормальный демон
github.com/dimitri/libphp-pgq
SystemDaemon
Фонтейн, чувак живой, всё норм
Data driven cache invalidation (slightly updated), JDCon-East, New York City, NY, March 2011 and EuroPython 2011, Florence, Italy (+ scripts)
че-то правда у него пдфка не грузится, а
скрипты скачиваются
вот еще видео
ep2013.europython.eu/conference/talks/data-driven-cache-invalidation
суть в PGQ