Нестандартный способ использования брокера сообщений Apache Kafka
10 февраля 2023 г.Иногда разработчикам приходится использовать технологии в своей работе для других целей. Причин тому может быть несколько: начиная с ограниченного бюджета, отсутствия опыта у разработчиков, либо из-за ограниченности инфраструктуры компании, либо даже прямого запрета со стороны руководства компании. Для этого случая ниже вы можете увидеть один нестандартный способ использования брокера сообщений Apache Kafka.
Работу многих сервисов нужно настраивать для управления логикой работы приложения. И речь идет не о настройке серверных портов или учетных данных базы данных — это метаинформация, используемая в управлении системой, также известная как «бизнес-конфигурация». Одним из наиболее распространенных сценариев такой конфигурации является состояние переключателя функций, переменные коэффициенты для бизнес-формул, ветвление AB-теста и так далее. Другими словами, то, что должно оставаться неизменным между выпусками, но при необходимости изменяться в любой момент времени.
Если от службы требуется высокая доступность и низкая задержка, то эта конфигурация не может извлекаться из базы данных при каждом запросе. Если система включает большое количество микросервисов и требует горизонтального масштабирования, то для управления бизнес-конфигурацией обычно используется отдельный выделенный микросервис. Такой услугой может быть панель администратора с аутентификацией и авторизацией.
Системные функции
Описанное ниже решение создано на кластере из десятков серверов с высокой пропускной способностью, которые направляют сообщения с http на kafka или с kafka на kafka. Логика маршрутизации менялась без перезапуска серверов, поэтому правила маршрутизации можно рассматривать как бизнес-конфигурацию. Правило содержало SQL-подобный предикат, который сопоставлялся с полезной нагрузкой входящего сообщения. Поэтому правила должны обновляться онлайн.
Служба управления конфигурацией
Редактирование правил реализовано на выделенном сервере - панели администратора, доступ к которой регулировался ролями и предоставлялся только пользователям. Лучшим выбором для административной панели является база данных SQL, обеспечивающая быстрый доступ и ACID-транзакции, что идеально подходит для создания основных данных.
Часто подход Shared Database используется для админ-панелей, но в нашем случае это было исключено из соображений безопасности. Сервисы маршрутизатора располагались в разных подсетях, а между внутренней сетью были физические шлюзы безопасности, что затрудняло использование таких решений, как Hazelcast, Redis, Consul и так далее, а весь доступный арсенал ограничивался Postgres, Kafka и HTTP. -запросы.
Почему стоит выбрать Кафку?
Первая реализация была основана на REST API. Роутер-сервис при запуске пришел для настройки на сервер админки и начал работать после ее получения. Далее сервис запрашивал обновления с определенной периодичностью.
После появления внешних потребителей, для которых http доступ в нашу сеть был закрыт. Поэтому у нас возникла идея использовать темы Kafka для раздачи конфигов, так как это одно из самых простых и надежных доступных решений.
Каждый сервис при запуске считывает весь топик с самого начала, таким образом получая все обновления и применяя их к системе. Kafka гарантирует FIFO в пределах 1 раздела, поэтому изменения могут применяться постепенно — в том же порядке, что и в основных данных, а также Kafka позволяет настроить хранение сообщений, чтобы мы могли хранить сообщения вечно.
Так как была проблема наличия шлюзов безопасности между сетями, было решено обойти ее через реплики следующим образом:
- Кафка доступная для записи лежит во внутренней сети вместе с админкой;
- В других сетях есть реплики, доступные только для чтения, поскольку маршрутизаторы читают темы с самого начала, и мы даже не сохраняем смещения;
- Для репликации используются стандартные механизмы Kafka.
Возможная согласованность была приемлемым компромиссом. Отставание потребителей конфигурации не критично, достаточно подобрать схему сообщений так, чтобы они не были связаны друг с другом и имели консистентное состояние
Особенности реализации раздачи конфига через Kafka
Формат сообщения
- Kafka имеет некоторые ограничения в отношении размера сообщения, поэтому было решено записывать каждую обновленную строку как новое сообщение.
- Вы не можете удалять сообщения из Kafka, но можете отправить сообщение о надгробии, но в текущей ситуации это неуместно. Потребители хранят состояние конфигураций, и нам нужно, чтобы они реагировали на удаление объекта, поэтому мы добавляем в сообщение флаг удаления.
- Некоторые настройки могут часто меняться, поэтому мы решили использовать темы, сжатые журналом. Эти темы содержат только самые последние сообщения, а старые дубликаты удаляются. Идентификатор правила используется в качестве ключа сообщения для Kafka, а также обеспечивает попадание обновлений в один раздел.
Согласованность данных между Postgres и Kafka
Невозможно сделать гарантированную запись в двух разнородных источниках, в базе свои транзакции, в кафке свои. Есть несколько распространенных решений:
- внедрить исходящие транзакции;
- использовать собственные транзакции Kafka;
- используя раствор CDC, например, дебезиум.
Транзакционный исходящий ящик — это распространенный шаблон, состоящий из транзакционного создания задач в виде записи в дополнительной таблице SQL, которая является исходящим ящиком, и последующего асинхронного перелистывания этих задач.
Транзакции Kafka позволяют записывать то, что недоступно клиентам с определенными настройками. Это будет продолжаться до тех пор, пока не будет отправлен сигнал о завершении транзакции. Также можно синхронизировать запись и фиксацию с транзакцией реляционной базы данных, но это все же не гарантированный способ синхронизации, поскольку фиксации выполняются одна за другой.
CDC (ChangeDataCapture) — решение, которое фиксирует обновления из журналов базы данных, публикуя все внешнему потребителю, которым может быть Kafka. Но есть у этого решения один недостаток - громоздкость, а также необходимость использовать отдельный компонент и вводить дополнительную точку отказа.
Создано решение, похожее на почтовый ящик транзакций и гарантирующее последовательность отправки. Каждое правило в базе данных имеет статус отправлено
. Таким образом, после каждого обновления в одной и той же транзакции оно помечалось как ложное, после чего мы отправляли сообщение в kafka, а затем обновляли статус до истинного. Если что-то пойдет не так при отправке, мы повторим попытку отправки в задании отработки отказа. Чтобы избежать проблем с параллелизмом, мы также добавили версию в строку, чтобы клиенты могли игнорировать устаревшие версии.
Заключение
Такое решение может быть раскритиковано другими разработчиками, особенно если они присоединились к команде после того, как вы ее покинули. Но нет ничего плохого в том, чтобы заставить все работать в нужное время с помощью доступных ресурсов.
Оригинал