Мертвые события убивают микросервисы: Как Debezium и Outbox-паттерн спасут вашу систему от несогласованности
Ненадежная отправка сообщений — частая причина ошибок в микросервисной архитектуре. Паттерн Outbox решает эту проблему, а Debezium делает его реализацию невероятно простой.
Проблема, которую решаем
Если сначала вносить изменения в базу данных, а потом отправлять события в брокер сообщений (или наоборот), то возникает риск того, что один из шагов не выполнится и упадет с ошибкой. В итоге данные в нашей системе окажутся несогласованными.
Решение
Популярный подход для решения этой проблемы — паттерн Outbox. Приложение записывает события, которые необходимо отправить при изменении данных, в таблицу outbox в рамках транзакции, в которой осуществляются и основные операции. Далее мы, используя подход Change Data Capture (CDC), отслеживаем изменения в таблице outbox и отправляем события в брокер. На просторах сети можно найти множество реализаций CDC, готовых к промышленному применению. Одна из таких реализаций — Debezium.
Debezium
Debezium — распределенная платформа с открытым исходным кодом (лицензия Apache 2.0), реализующая CDC. Она представляет собой набор коннекторов для нескольких популярных баз данных — PostgreSQL, MySQL, MongoDB и других. Debezium слушает лог изменений в БД (WAL в Postgres, binlog в MySQL), извлекает их, преобразует в события и публикует сообщения в Kafka.
Есть несколько вариантов развертывания Debezium:
- С помощью Kafka Connect — наиболее распространенный вариант. Коннектор отслеживает изменения в соответствующих БД и/или таблицах. Потом Kafka Connect обрабатывает данные от коннекторов и передает их в Kafka.
- Отдельный сервер Debezium — это готовое приложение, которое передает изменения в БД в различные системы обмена сообщениями.
- Embedded движок — библиотека движка подключается к java-приложению, и события нужно обрабатывать непосредственно в приложении. Это наиболее гибкое и расширяемое решение, но требует дополнительных усилий со стороны разработки.
Пример настройки Debezium
Запустим Debezium Kafka Connect на локальном компьютере с помощью docker-compose. Полный пример доступен по ссылке.
Представим, что у нас есть таблица outbox, в которую записываются сообщения об изменении каких-то сущностей в нашем приложении. Вот скрипт создания:
Теперь нам нужно настроить Debezium Kafka Connect, чтобы он отслеживал изменения в таблице outbox и отправлял сообщения в Kafka. Сначала создадим свойства коннектора в которых будут указаны таблицы для подключения Debezium и топики Kafka, куда отправлять сообщения об изменениях:
Здесь database.* — настройки базы данных, table.include.list — список таблиц, которые будут отслеживаться, topic.prefix — префикс для топиков Kafka, в которые будут отправляться сообщения.
Теперь сконфигурируем docker-compose.yml, чтобы запустить всю инфраструктуру локально. Первую часть файла, которая конфигурирует Postgres и Kafka, не буду здесь приводить. Стоит только обратить внимание на конфигурацию Postgres, а именно command: ["-c", "wal_level=logical", "-c", "max_replication_slots=10", "-c", "max_wal_senders=10"] — здесь обязательно нужно включить wal_level=logical, иначе debezium не сможет работать.
Конфигурация коннектора очень проста:
Для инициализации коннектора нужно отправить запрос на http://localhost:8083/connectors с телом запроса, который мы описывали выше. В нашем случае используется отдельный контейнер, который поднимается после старта debezium и отправляет запрос на создание коннектора:
Теперь поднимем наши контейнеры:
И проверим как работает коннектор. Добавим несколько записей в таблицу outbox:
Зайдем в kafka-control-center и проверим, что сообщения появились в топике debezium.outbox.public.outbox. Если все пройдет хорошо, то можно увидеть сообщения примерно такого содержания:
Как видите, конфигурирование Debezium для запуска на локальной машине не представляет никаких трудностей. Конечно, при конфигурации в кластере будет больше шагов и больше технических нюансов, но для опытного DevOps-инженера это будет не очень трудно.
Преимущества
- Простота настройки и гибкость — Debezium не требует глубоких знаний для настройки, особенно для начала разработки. Если работали с Kafka Connect, то настройка не будет представлять ничего сложного. Есть возможность подключения к системе в различных вариантах, в том числе и без Kafka.
- Интеграция с Kafka — изначально платформа строилась вокруг экосистемы Kafka, поэтому отлично интегрирована с ней.
- Масштабируемость и надежность — Debezium обладает множеством преимуществ, которые предоставляет экосистема Kafka, среди них надежность и масштабируемость.
- Отсутствие блокировки транзакции и минимальные накладные расходы на БД — коннектор читает изменения из журнала транзакций, поэтому не создается дополнительного влияния на текущую работу БД.
- Поддержка множества баз данных — Debezium поддерживает из коробки интеграцию с множеством популярных баз данных, как реляционных, так и NoSQL.
Недостатки
Как и у любой технологии, у Debezium есть и свои недостатки, к таким можно отнести:
- Зависимость от журнала транзакций — если журнал будет поврежден или удален, то данные невозможно будет отправить.
- Необходимость настройки на стороне БД — очень часто требуется настроить БД, например уровень журнала и/или привилегии для пользователя. Это добавляет дополнительную сложность администрирования.
- Невозможность ретрансляции старых событий — нельзя повторно отправить события, произошедшие до запуска debezium.
- Задержки чтения — в любом случае есть небольшая задержка между записью в таблицу и последующей публикацией события.
- Интеграция с Kafka — для того чтобы использовать на полную, нужно поддерживать инфраструктуру Kafka, но не во всех приложениях это нужно.
Итог
Debezium — отличная реализация паттерна CDC. Для знакомых с экосистемой Kafka его настройка не составит труда. Но его применение должно учитывать особенности проекта и требования к безопасности.
Подписывайся на мой канал в telegram