Сохранение консистентности при интеграции систем

Немного информации на тему интеграции с сохранением консистентности данных на стороне потребителя.

Потоковая интеграция

Если вы используете брокер сообщений для интеграции, например Kafka, то сохранить консистентность на стороне потребителя можно, но требуется выполнить несколько условий:

  • Использовать в топиках только 1 партицию.
  • Передать во все топики финальное сообщение, сигнализирующее об окончании пакета изменений – кадра (см. пояснения ниже), даже если пакет был пустой.
    Потребителю нужно дождаться финальных сообщений во всех топиках. После этого данные можно перекладывать в предметные таблицы или завершать транзакцию, если запись была непосредственно в них.
  • Для чтения данных можно использовать только одну сессию.
  • Перед чтением необходимо открыть транзакцию с уровнем изоляции Repeatable Read.
    Это условие актуально, если чтение данных производится из нескольких предметных таблиц. Если чтение делается из логов, размеченных кадром, то это условие можно не учитывать.
  • Если переносится инкремент (CDC), то он должен быть перенесен целиком.
    Это условие актуально, если чтение данных производится из предметных таблиц.
  • При работе с брокером нужно использовать транзакцию, чтобы гарантировать целостность кадра.

Очевидно, что дизайн решения непростой и есть ограничение по производительности. Потоковая интеграция плохо подходит для строгого сохранения консистентности, но это в принципе достижимо.

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

Прямой запрос к БД

При прямом обращении к БД также можно реализовать перенос данных с сохранением консистентности, но требуется выполнить условия:

  • Использовать только 1 сессию к БД-источнику.
  • Перед чтением необходимо открыть транзакцию с уровнем изоляции Repeatable Read.
    Это условие актуально, если чтение данных производится из нескольких таблиц.
  • Если переносится инкремент (CDC), то он должен быть перенесен целиком.

Увы, но консистентность и многопоточность несовместимы. Если интеграционный адаптер остановится на длительное время, то перенос накопившегося инкремента целиком может стать проблемой.

Чтение из лога

Иногда требуется организовать перенос данных из журнала/ов, в котором записаны изменения строк. Эта информация относится к источнику данных и подготовке данных для передачи с сохранением консистентности. Лог хорошо подходит для передачи инкремента в брокер или с помощью REST API.

Для инкрементного вычитывания данных из лога необходимо отслеживать значение id (идентификатор строки, порождаемый генератором). Вычитывать данные из лога нужно в порядке возрастания id, но … так как некоторые записи (с меньшими id) могут быть еще недоступны для чтения (из-за незавершенных транзакций), то просто так отслеживать id не получится, тут требуется дополнительное действие – раскадровка журнала. Сразу оговорюсь, есть случаи, когда раскадровка может быть не нужна:

  • Если есть возможность удалять строки из лога при вычитывании.
  • Если данные пишутся в лог монопольно, т.е. всего одним процессом, и строго последовательно.
  • Если есть другой способ правильно отслеживать инкремент.

Разметка кадра выполняется примерно так …

UPDATE data_log SET frame_id = <new id> WHERE frame_id is null

Размечаем новые строки лога идентификатором кадра. Значения кадра можно брать из того же генератора, что используется для id. Если логов несколько, то разметку нужно делать единым идентификатором с уровнем изоляции транзакции Repeatable Read.

Крайне важно! Разметка должна выполняться строго в отдельной транзакции. Разметку можно выполнять по регламенту (job), например раз в 5 секунд.

Вычитывать данные из лога нужно в порядке возрастания идентификаторов (ORDER BY frame_id , id), отслеживать тоже нужно оба значения.

Кадр должен быть целиком передан потребителю и атомарно применен, это будет главное условие сохранения консистентности.

Для ускорения записи и чтения сделайте всего 1 BRIN-индекс для поля frame_id.

Так ли нужна консистентность?

  • Иногда это просто необоснованное требование со стороны заказчика.
  • Иногда нарушение консистентности будет иметь временный эффект (Eventual Consistency), целостность восстановится в следующей итерации.
  • Несогласованность ссылочной целостности можно закрыть с помощью специальной доработки – модуля восстановления ссылочной целостности (МВСЦ). МВСЦ запускается в конце каждой итерации (для реализации потребуется описание модели данных и доступ к источнику данных).
11
1 комментарий