При масштабировании инфраструктуры Kafka неизбежно встаёт вопрос репликации данных между кластерами. Будь то разделение потоков данных между командами, обеспечение резервирования между ЦОДами или даже плавная миграция на новую платформу — все эти задачи требуют надёжного инструмента для передачи сообщений.

Для организации репликации топиков между кластерами в команде автоматизации информационных систем каршеринга Ситидрайв мы используем MirrorMaker 2.0. Этот инструмент входит в стандартный стек Kafka и позволяет гибко управлять потоками данных, но при этом имеет свои нюансы и ограничения.

В этой статье я расскажу, как мы на практике внедрили MirrorMaker 2.0, с какими подводными камнями столкнулись, как настроили мониторинг и автоматизацию, а также какие альтернативные решения существуют на рынке. Гоу! 🚀


В какой-то момент команда эксплуатации получила запрос от DWH: нужно было организовать репликацию топиков из разных кластеров в отдельный новый кластер Kafka. Это позволило бы аналитикам работать в своём «пространстве» с бизнес-данными, маркетинговыми событиями, а также интегрироваться с новыми продуктами и сервисами без нагрузки на продакшен-кластеры. Задача звучала просто, но нюансов оказалось много.

Картинка из книги “Apache Kafka. Потоковая обработка и анализ данных. 2-е изд. Гвен Шапира, Тодд Палино, Раджини Сиварам, Крит Петти
Картинка из книги “Apache Kafka. Потоковая обработка и анализ данных. 2-е изд. Гвен Шапира, Тодд Палино, Раджини Сиварам, Крит Петти

Чем хорош MirrorMaker 2.0?

Kafka предлагает немало встроенных CLI-утилит:

  • kafka-topics.sh — управляет топиками;

  • kafka-console-producer.sh — отправляет сообщения;

  • kafka-console-consumer.sh — читает их и т. д.

А для репликации между кластерами есть MirrorMaker. В первой версии он работал по принципу «консьюмер + продюсер»: сообщения забирались из одного кластера и публиковались в другой. Однако MirrorMaker 1.0 был далеко не идеальным: слабая отказоустойчивость, отсутствие поддержки ACL, не самые удобные механизмы мониторинга.

Во второй версии MirrorMaker 2.0 появилась поддержка Kafka Connect, улучшенная отказоустойчивость, автоматическая синхронизация топиков и механизм checkpoint-репликации. В общем, выглядит уже как продвинутый инструмент, который можно смело использовать в продакшене.

Как мы настроили MirrorMaker 2.0 в продакшене

Разберёмся, как это работает на практике. Допустим, у нас есть два кластера Kafka: A и B, и нам нужно настроить репликацию топиков между ними.

1. Базовая конфигурация

Чтобы запустить MirrorMaker 2.0, достаточно подготовить конфигурационный файл connect-mirror-maker.properties. Вот его базовая структура:

# Определяем алиасы для кластеров
clusters = A, B

# Указываем список брокеров
A.bootstrap.servers = A_host1:9092, A_host2:9092, A_host3:9092
B.bootstrap.servers = B_host1:9092, B_host2:9092, B_host3:9092

# Настраиваем репликацию: откуда, куда и какие топики копировать
A->B.enabled: "true"
A->B.topics: "test_topic.*"
B->A.enabled: "false"

В этом примере мы реплицируем все топики из A в B, если их названия соответствуют регулярному выражению test_topic.*.

2. Оптимизация параллельной обработки

MirrorMaker 2.0 работает на основе Kafka Connect, поэтому у него есть стандартный параметр tasks.max, который регулирует количество задач на обработку данных. По умолчанию tasks.max = 1, но для продакшена это не всегда оптимально. Лучше задать хотя бы 2, чтобы обеспечить параллельную обработку. Если у вас много партиций и высокая нагрузка, можно увеличить значение, например: tasks.max=4

В сети можно найти кейсы, где инженеры выставляли до 36 потоков, но всё зависит от инфраструктуры. Чем больше потоков — тем выше нагрузка на CPU и RAM, так что перед изменением параметров стоит провести нагрузочное тестирование.

3. Запуск и мониторинг

Когда конфигурация готова, можно запустить MirrorMaker 2.0 командой:/opt/kafka/bin/connect-mirror-maker.sh connect-mirror-maker.properties

На деле вы должны увидеть, что в кластере B появились топики, названия которых начинается с test_topic. Также должны быть и сообщения в топиках, а при создании нового топика, название которого начинается test_topic и/или поступлении новых сообщений в кластер A, сообщение должно появиться в кластере B. 

В нашей инфраструктуре мы все параметры connect-mirror-maker.properties регулируем через ansible. Наше зеркалирование работает как systemd-служба, которую мы мониторим. Такой подход позволяет гибко изменять конфигурацию, автоматизировать деплой и отслеживать состояние репликации.

Где и как мы используем MirrorMaker 2.0

Как я уже упоминал, основная зона применения MirrorMaker 2.0 в нашей инфраструктуре — это задачи DWH. На этих топиках не завязан критически важный функционал, поэтому небольшие задержки при репликации для нас некритичны.

Но в��зможности MirrorMaker не ограничиваются аналитикой. Если у вас несколько ЦОДов, с его помощью можно настроить репликацию данных между ними, выбрав подходящую топологию:

  • «Звезда» — один центральный кластер принимает данные из нескольких источников,

  • «Активный — резервный» — один кластер в режиме standby на случай отказа основного,

  • «Активный — активный» — оба кластера работают параллельно и синхронизируются.

Если в продакшене критична отказоустойчивость, важно убедиться, что при сбое ЦОДа A данные в ЦОДе B останутся актуальными.

Схема из книги “Apache Kafka. Потоковая обработка и анализ данных. 2-е изд. Гвен Шапира, Тодд Палино, Раджини Сиварам, Крит Петти
Схема из книги “Apache Kafka. Потоковая обработка и анализ данных. 2-е изд. Гвен Шапира, Тодд Палино, Раджини Сиварам, Крит Петти

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

Когда MirrorMaker 2.0 — не лучший выбор

MirrorMaker 2.0 может показаться универсальным решением для репликации, но у него есть ��граничения. В некоторых сценариях его использование может привести к потере данных, проблемам с задержками и другим неприятным сюрпризам. Давайте разберём ключевые нюансы, которые стоит учитывать.

1. Проблема задержек

Представим ситуацию:

  • У вас есть два кластера A и B;

  • Топик test_topic зеркалируется из A в B;

  • В test_topic поступает 1 миллион сообщений в секунду;

  • MirrorMaker 2.0 работает с задержкой 5 мс.

На первый взгляд кажется, что 5 мс — это немного. Но за это время накопится 5000 сообщений, которые отстанут от основного потока. Если в этот момент случится аварийное переключение на кластер B, то эти 5000 сообщений просто потеряются.

2. MirrorMaker 2.0 может упасть

MirrorMaker — это не магия, а обычный Kafka Connect-коннектор, который может в какой-то момент просто крашнуться. Если критический бизнес-процесс завязан на зеркалируемый топик, система может просто перестать работать. 

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

3. Репликация ≠ перенос топиков в новый кластер

Допустим, вы решили перенести топик в новый кластер и использовать для этого MirrorMaker. Есть три основных стратегии, каждая со своими проблемами:

Вариант №1: Для консьюмер группы указать самый ранний оффсет и перечитать топик с самого начала. Однако здесь приложение должно уметь находить дубликаты сообщений в топике и как-то работать с ними.

Вариант №2: Указать самый последний оффсет для консьюмер группы и смириться с потерей части сообщений.

Вариант №3: Сделать reset offset на параметр timestamp. Минус — мы повторно прочитаем некоторые сообщения, которые уже были прочитаны.

Какой вариант выбрать? Всё зависит от бизнес-логики, инфраструктуры и требований к консистентности данных.

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

  • uReplicator (Uber) — улучшенная версия MM2 с высокой отказоустойчивостью,

  • Brooklin (LinkedIn) — поддерживает не только Kafka, но и другие потоки данных,

  • Confluent Replicator — коммерческое решение с расширенными возможностями мониторинга.

Если погрузиться в историю этих инструментов, можно заметить, что все они основаны на той же концепции MirrorMaker (консьюмер + продюсер, связанные очередью), но адаптированы под конкретные задачи компаний.

Где запускать MirrorMaker 2.0?

MirrorMaker 2.0 не привязан к конкретному кластеру Kafka — он может работать где угодно:

  • На кластере A (источнике данных),

  • На кластере B (приёмнике данных),

  • На отдельной инфраструктуре, например, на выделенном кластере из нескольких машин, который управляет репликацией между всеми кластерами.

В Ситидрайве мы запускаем MirrorMaker в том кластере, которому он нужен. Например, репликация понадобилась аналитикам — значит, MirrorMaker запущен в их кластере. Если со временем появится необходимость вынести зеркалирование на отдельные серверы, это можно сделать без простоя и с минимальными изменениями в инфраструктуре.Главное — выбрать тот вариант, который оптимально вписывается в вашу архитектуру.

Мониторинг MirrorMaker 2.0: как не пропустить проблемы

Мы подошли к мониторингу двухуровнево:

1. Внутренний мониторинг — когда сам MirrorMaker сигнализирует о проблемах (например, частые рестарты или вообще отказ от запуска).

MirrorMaker 2.0 у нас запущен через systemd, поэтому для мониторинга мы используем node-exporter и передаём ему аргумент:

--collector.systemd.unit-include=^(kafka-mirror-maker.service)$

На основе этой метрики в Prometheus настроен алерт:

groups:
  - name: alerts.kafka
    rules:
      - alert: KafkaMirrorMakerServiceDown
      expr: node_systemd_unit_state{name="kafka-mirror-maker.service", state="active"} == 0

Если служба упала, мы сразу получаем уведомление.

2. Внешний мониторинг — когда сервис работает, но репликация на самом деле остановилась.

Бывает, что systemd считает сервис работающим, но репликация фактически остановилась. Чтобы это отслеживать, мы используем jmx-exporter и "технические топики" MirrorMaker, которые содержат heartbeats в названии. Эти топики создаются автоматически для связанных кластеров, и мы проверяем их активность:

groups:
  - name: alerts.kafka
    rules:
      - alert: KafkaMirrorMakerHeartbeatsStopped
        expr: |
          avg(
            irate(
              jmx_kafka_server_brokertopic_messagesin_total{job="kafka-jmx-exporter", topic=~".*heartbeats.*"}[5m])
            ) by (topic) == 0

За основу концепции мониторинга, конечно же: брали методы белого и чёрного ящика.

Развитие MirrorMaker 2.0: что дальше?

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

Помимо стабильности, нас интересует и глубокое понимание работы MirrorMaker. Например, в ходе тестирования Kafka 3.9.0 мы обнаружили любопытный «‎косметический» баг, связанный с его работой. Подробности можно найти в тикете: KAFKA-17232, а вот исправление: KAFKA-18021.

Этот случай дал нам не только повод отправить баг-репорт, но и ценный опыт. Мы глубже разобрались в механизмах работы MirrorMaker, выявили неочевидные нюансы, и это помогло нам оптимизировать работу репликации в нашей инфраструктуре.

Заключение

MirrorMaker — мощный инструмент, который можно быстро развернуть и настроить «‎из коробки». Однако, как и любое решение, он не лишён нюансов. На первых итерациях у нас возникали вопросы, и не всё шло гладко. Но, разобравшись в деталях, протестировав разные сценарии и изучив тонкости работы, мы сумели встроить MirrorMaker в нашу инфраструктуру и превратить его в надёжный инструмент для репликации данных. В конечном итоге, все в ваших руках: если уделить время изучению и настройке, MirrorMaker способен стать ценным звеном в системе распределённой обработки данных.