
При масштабировании инфраструктуры Kafka неизбежно встаёт вопрос репликации данных между кластерами. Будь то разделение потоков данных между командами, обеспечение резервирования между ЦОДами или даже плавная миграция на новую платформу — все эти задачи требуют надёжного инструмента для передачи сообщений.
Для организации репликации топиков между кластерами в команде автоматизации информационных систем каршеринга Ситидрайв мы используем MirrorMaker 2.0. Этот инструмент входит в стандартный стек Kafka и позволяет гибко управлять потоками данных, но при этом имеет свои нюансы и ограничения.
В этой статье я расскажу, как мы на практике внедрили MirrorMaker 2.0, с какими подводными камнями столкнулись, как настроили мониторинг и автоматизацию, а также какие альтернативные решения существуют на рынке. Гоу! 🚀
В какой-то момент команда эксплуатации получила запрос от DWH: нужно было организовать репликацию топиков из разных кластеров в отдельный новый кластер Kafka. Это позволило бы аналитикам работать в своём «пространстве» с бизнес-данными, маркетинговыми событиями, а также интегрироваться с новыми продуктами и сервисами без нагрузки на продакшен-кластеры. Задача звучала просто, но нюансов оказалось много.

Чем хорош 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 останутся актуальными.

Например, мы использовали зеркалирование для миграции целого кластера в связи переездом одного нашего отдела в новую инфраструктуру. Вместо сложных переносов и даунтайма мы просто настроили зеркалирование всего кластера и спокойно перевели сервисы на новую платформу. Настройка репликации заняла буквально несколько минут, после чего данные продолжили поступать в новый кластер без проблем.
Когда 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 способен стать ценным звеном в системе распределённой обработки данных.