Search
Write a publication
Pull to refresh
11
0
svaor @svaor

Архитектор

Send message

Не голой критики ради, но всё же... Хотелось бы, чтобы во второй части поста была раскрыта тема, обозначенная в затравке: "какие у нас были проблемы и как мы их решали". Проблемы как-то были описаны, хотя лично мне было сложно понять, почему они такие и в чём именно они состоят. Возможно, требуется знание предметной области. А возможно, формулировки нечёткие. Например, сначала говорится о 14ти методах, а потом в следующем же предложении - о единственном. Или сначала речь о принципах SOLID, а потом начинаются размышления о том, чтобы сделать not-null поле nullable. Это не нарушение принципа Open-Closed? Такие вещи лично меня путают и усложняют понимание текста.

Короче, в итоге описание решений могло бы пояснить, о чём именно речь. Но намёков на решение в тексте не увидел совсем. Надеюсь на скорую публикацию второй части :)

В комментариях выше, я считаю, справедливо замечено, что смена брокера на СУБД не решает проблему недоступности хранилища по сети, какое бы оно не использовалось. Наоборот, правильно развёрнутый и настроенный брокер должен быть по идее более выживаем, чем просто СУБД. Это раз.

Во-вторых, при использовании СУБД у Вас по идее появляется новое звено, обеспечивающее связку СУБД и брокера. А именно, Вам приходится (или придётся рано или поздно) развернуть сервис, который опрашивает табличку Outbox на регулярной основе выше некоторой ватерлинии на предмет наличия новых записей для создания/переноса соответствующих сообщений уже в Kafka. В качестве ватерлинии обычно используется монотонно возрастающий первичный ключ. По сути Вам придётся реализовать или использовать что-то аналогичное JDBC Connector от Confluent.

И только тогда у Вас должны появиться строгие гарантии того, что сообщения не будут потеряны... раз уж у Вас именно эта проблема вынесена в топик.

Простите, не раскрутки ради, оставлю ссылку на свою статью, где, сугубо имхо, как раз эта проблема очень подробно разжёвана.

Да, это у меня тоже описано :)

Сразу нужно оговориться, что есть третий, самый приоритетный с точки зрения Kafka вариант, – это использование её в качестве источника событий или реализация принципа CQRS. При таком подходе типичная транзакция затрагивает только топики Kafka и выглядит так...

var consumedMessage = consumer.consume();

Ещё раз. Я говорю о CDC и очереди в БД в сценарии, когда нет никакого входящего сообщения из Kafka. Например, пользователь жмёт на сайте на кнопку "Отправить сообщение", далее средний слой обрабатывает http запрос, пишет что-то в БД и возвращает пользователю ответ "Отправлено". А уже потом должна появиться Kafka, очереди, обработка этого сохранённого в БД сообщения и пр.

Вы описали как раз первый сценарий: приём сообщений из Kafka. У меня в тексте это описано так:

...на основании данных из обрабатываемого сообщения мы получаем или однозначно вычисляем значение, которое сохраняем вместе с теми изменениями, которые производим на стороне БД. Таким образом, если мы видим, что такое значение ключа идемпотентности уже ассоциировано с изменяемым объектом в БД, то это изменение уже было выполнено. Это указывает на то, что сообщение обрабатывается не первый раз, а предыдущий раз по какой-то причине его обработка была прервана. То есть её можно пропустить в штатном режиме и перейти к следующем сообщению.

Вы просто предложили использовать в качестве ключа идемпотентности идентификатор сообщения. В комментариях выше и статье на medium, на которую ссылался автор, также шла речь о таком же подходе. Только в качестве ключа там предлагалось использовать не только идентификатор сообщения, но и наименование топика. Вариант вполне допустимый на мой взгляд.

Навскидку, что тут может пойти не так: например, идентификатор сообщения может измениться:

in case of error, commit offset, but enqueue the message again at the end of your Kafka Topic (maybe store how many times this operation was tried)

Это не проблема, но должно учитываться.

Теперь касательно CDC. Во втором случае говорится об отправке сообщения в Kafka. Это другой кейс. Он никак не связан с первым:

Существует также обратная ситуация, когда открывается транзакция в СУБД, во время которой требуется отправить сообщение в Kafka.

Ключи идемпотентности, используемые в предыдущем случае, не сильно помогают, если вложенная транзакция – в Kafka, так как мы не можем искать в очереди старое сообщение и анализировать его ключ. Очередь постоянно изменяется, сообщения могут из неё вытесняться. Кроме того, действие, вызвавшее транзакцию в СУБД, может быть пользовательским и не повториться в конечном счёте.
Если отправлять сообщение без учёта того, как оно будет обрабатываться при получении, в том числе потенциальных дублей, то будут возникать проблемы. Или принимающая сторона должна учитывать возможность дублей.

Альтернативы просты: либо принимающая сторона должна учитывать возможность появления дублей сообщений, либо нужно строить очередь в БД. Это построение очереди в моём тексте и описывается.

Мне кажется, какая-то путаница возникла.

Ключи идемпотентности нужны при взаимодействии Kafka->DB. Смещение в этом кейсе – это и есть ключ.
Poller нужен при взаимодействии DB->Kafka.
У Вас же всё смешалось в кучу...

Прочитал по диагонали. Насколько я вижу, речь идёт о получении сообщений из Kafka и отражении полученной информации в Postgres. В моём тексте это первый кейс, покрываемый за счёт ключей идемпотентности. На medium, если я правильно понимаю, в качестве ключа идемпотентности используется смещение и топик. Вполне допустимо в общем случае, как мне кажется.

Poller же требуется для кейса выгрузки данных из PostgreSQL в Kafka, то есть в обратную сторону.

Я сходу не понял, что нам даёт значение смещения в Kafka... Можно поподробнее описать Ваш вариант?

Увеличенный размер страницы позволяет сразу относительно недорого (без дополнительного запроса) определить, имеется ли следующая (предыдущая) страница или пользователь долистал все записи до последней страницы.

Наверное, имелся в виду этот момент?
Нужно учитывать вводные. Речь в большей части идёт об оперативных хранилищах. Это раз. Во-вторых, селективный фильтрующий предикат жизненно необходим, иначе окно с рабочими данными будет со временем только расширяться, и система обречена.
Под фразой «как правило, пользователю они не нужны» я подразумеваю, что с требованиями бизнеса нужно работать и объяснять стоимость этих требований. Альтернативы просты: куча денег на железо и обречённость системы в перспективе или работа с пользователями, обучение, ограничения в интерфейсе и решения, принуждающие пользователя использовать фильтрацию вместо сортировок, где это возможно, и становиться умным и шарящим. Наверное, правильнее бы звучало «как правило, пользователю они на самом деле не нужны».

Information

Rating
Does not participate
Location
Ростов-на-Дону, Ростовская обл., Россия
Date of birth
Registered
Activity