Конфигурация репликации Kafka: обеспечение долговечности и доступности данных

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

Конфигурация репликации Kafka: обеспечение долговечности и доступности данных

Конфигурация репликации Kafka — это то, что превращает кластер из кучи брокеров в систему, которой можно доверять при сбоях. Настройки сами по себе не сложны: коэффициент репликации, синхронизированные реплики, подтверждения продюсера, выбор лидера и размещение по стойкам. Сложность в том, что они работают только вместе.

Тема с тремя репликами все еще может потерять подтвержденные данные, если продюсеры используют слабые подтверждения. Продюсер, использующий acks=all, все еще может не выполнить запись, если min.insync.replicas слишком строг для текущего количества живых брокеров. Кластер, распределенный по зонам доступности, все еще может столкнуться с проблемами, если все реплики горячей партиции окажутся в одной зоне отказа. Репликация — это не один флажок.

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

Тема Kafka разделена на партиции. Каждая партиция имеет одну лидер-реплику и ноль или более реплик-последователей. Продюсеры пишут в лидера. Потребители обычно читают из лидера. Последователи получают записи от лидера и синхронизируют свои локальные журналы. Если брокер лидера выходит из строя, Kafka выбирает нового лидера из реплик, которые считаются безопасными кандидатами.

Этот список безопасных кандидатов — ISR (in-sync replicas). Реплика находится в ISR, если она достаточно близко следует за лидером в соответствии с правилами задержки репликации Kafka. Если последователь перестает получать данные, отстает слишком долго или брокер исчезает, Kafka удаляет его из ISR. Когда он догоняет, он может вернуться.

Эта деталь важна, потому что ISR делает долговечность Kafka более чем просто желанием. С acks=all лидер не подтверждает запрос на запись, пока запись не будет реплицирована на требуемые синхронизированные реплики. Точное требование контролируется min.insync.replicas. Если тема имеет replication.factor=3 и min.insync.replicas=2, Kafka требует как минимум две синхронизированные реплики, прежде чем запись с acks=all может быть успешной.

Эта комбинация распространена в продакшене, потому что дает практический баланс. Один брокер может выйти из строя, и тема все еще может принимать строго подтвержденные записи. Если второй брокер выходит из строя до возвращения первого, продюсеры, использующие acks=all, должны начать видеть ошибки, такие как NotEnoughReplicas или NotEnoughReplicasAfterAppend. Это раздражает во время инцидента, но обычно это правильное поведение. Kafka отказывается делать вид, что запись долговечна, когда нет достаточного количества безопасных копий.

Вот типичный продакшен-базовый уровень для обычного кластера из трех или более брокеров:

default.replication.factor=3
min.insync.replicas=2
unclean.leader.election.enable=false

Эти значения не делают каждую рабочую нагрузку автоматически безопасной, но дают разумную отправную точку. default.replication.factor=3 означает, что новые темы получают три копии, если команда создания темы не указывает иное. min.insync.replicas=2 означает, что как минимум две реплики должны быть синхронизированы для строгих записей. unclean.leader.election.enable=false говорит Kafka не выбирать устаревшую реплику в качестве лидера только для того, чтобы партиция оставалась доступной для записи.

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

Сторона продюсера должна соответствовать стороне темы. Для важных данных используйте acks=all. Также включите идемпотентность, если у вас нет конкретной причины не делать этого. В современных клиентах Kafka идемпотентные продюсеры являются обычным выбором для уменьшения дубликатов, вызванных повторными попытками.

acks=all
enable.idempotence=true
retries=2147483647
max.in.flight.requests.per.connection=5

Не копируйте значение retries слепо в каждый клиент, не понимая версию вашего клиента и требования к доставке. Важная идея в том, что долговечная продакшен-среда Kafka обычно требует повторных попыток, идемпотентности и acks=all вместе. Если вы установите acks=1, лидер может подтвердить запись до того, как последователи скопируют ее. Если этот лидер выйдет из строя в неподходящий момент, подтвержденная запись может исчезнуть. Это приемлемо для некоторых потоков телеметрии. Это неприемлемо для платежей, аудиторских следов, перемещений инвентаря или любых данных, которые downstream-команда рассматривает как источник истины.

При создании темы сознательно выбирайте параметры репликации, а не полагайтесь на то, какие настройки по умолчанию присутствуют у брокера:

kafka-topics.sh --create   --bootstrap-server broker1:9092   --topic orders.v1   --partitions 12   --replication-factor 3   --config min.insync.replicas=2

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

Для существующих тем изменение min.insync.replicas просто:

kafka-configs.sh --alter   --bootstrap-server broker1:9092   --entity-type topics   --entity-name orders.v1   --add-config min.insync.replicas=2

Изменение коэффициента репликации для существующей темы зависит от версии Kafka и инструментов. Новые версии Kafka поддерживают kafka-reassign-partitions.sh и, в некоторых случаях, рабочие процессы изменения темы, которые упрощают увеличение. В старых кластерах увеличение репликации обычно означает генерацию и выполнение плана перераспределения партиций. Уменьшение репликации более чувствительно, потому что вы удаляете копии. Относитесь к этому как к плановой операции, а не как к случайной команде, введенной во время шумного инцидента.

Перераспределение должно быть ограничено по скорости, если тема большая или кластер уже загружен. Репликация догоняет, читая старые данные из существующих реплик и записывая их в новые. Это может отнимать ресурсы диска и сети у живых продюсеров и потребителей. Безопасный runbook обычно включает окно обслуживания, вывод --describe до и после, ограничения перераспределения и план отката.

Вы можете проверить тему следующим образом:

kafka-topics.sh --describe   --bootstrap-server broker1:9092   --topic orders.v1

Посмотрите на три поля в выводе: Leader, Replicas и Isr. Replicas — это назначенный набор. Isr — это набор, который в настоящее время синхронизирован. Если Replicas равно 1,2,3, но Isr равно 1,2, брокер 3 отстает или недоступен для этой партиции. Если многие партиции показывают отсутствующий брокер в ISR, проверьте диск, сеть, состояние процесса и журналы этого брокера. Если затронуты только несколько горячих партиций, лидер может быть перегружен, или партиция может иметь необычно высокий трафик.

Нечистые выборы лидера требуют особого внимания. Если все синхронизированные реплики для партиции исчезли, у Kafka есть два варианта. Она может оставить партицию недоступной до возвращения безопасной реплики, или она может выбрать несинхронизированную реплику и рисковать потерей записей, которые были подтверждены на старом лидере. unclean.leader.election.enable=false выбирает безопасность. true выбирает доступность с риском потери данных.

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

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

broker.rack=zone-a

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

Мониторьте репликацию непрерывно. Наиболее полезные ранние предупреждающие признаки — это недополученные партиции, офлайн-партиции, события уменьшения ISR и ошибки записи, связанные с недостаточным количеством реплик. В настройках на основе Prometheus команды обычно отслеживают метрики брокера Kafka для недополученных и офлайн-партиций, а затем связывают эти оповещения с метриками диска, сети и JVM брокера.

Хороший вопрос при инциденте: уменьшился ли ISR из-за того, что брокер умер, из-за того, что репликация не успевает, или из-за ненадежной сети? Решение различается. Мертвый брокер требует восстановления сервиса. Медленный брокер может потребовать замены диска, исследования ввода-вывода или уменьшения количества лидеров партиций. Проблема с сетью может проявляться в виде повторяющихся отключений и задержки фетчера, даже когда ЦП и диск выглядят нормально.

Роллинг-перезапуски брокеров — еще одно место, где настройки репликации показывают свою ценность. Перезапускайте по одному брокеру за раз. Ждите, пока партиции восстановят здоровый ISR, прежде чем перезапускать следующего брокера. Если вы перезапускаете брокеров слишком быстро с min.insync.replicas=2, продюсеры могут начать выдавать ошибки, потому что слишком мало реплик синхронизировано. Этот сбой ожидаем, но вы можете избежать его с помощью терпения и мониторинга.

Практический чеклист короток. Используйте коэффициент репликации три для большинства продакшен-тем. Используйте min.insync.replicas=2 с продюсером acks=all для важных данных. Держите нечистые выборы лидера отключенными, если данные явно не одноразовые. Распределяйте реплики по зонам отказа с помощью осведомленности о стойках. Следите за здоровьем ISR, а не только за временем работы брокера. И проверяйте свои предположения, перезапуская брокера в контролируемом окне до того, как реальный сбой сделает это за вас.

Одна деталь, которая помогает при ревью, — это разделение долговечности и доступности простыми словами. Долговечность спрашивает: «После того, как Kafka сказала, что запись успешна, сколько сбоев может произойти, прежде чем эта подтвержденная запись окажется под угрозой?» Доступность спрашивает: «Могут ли продюсеры и потребители использовать партицию прямо сейчас?» Строгие настройки иногда снижают доступность, потому что Kafka будет отклонять записи, а не принимать слабо реплицированные данные. Это не сбой Kafka. Это Kafka соблюдает контракт, который вы настроили.

Например, представьте тему с коэффициентом репликации три, min.insync.replicas=2 и продюсерами, использующими acks=all. Брокер 1 — лидер, брокеры 2 и 3 — последователи. Если брокер 3 выходит из строя, ISR становится 1,2. Записи все еще успешны, потому что две реплики синхронизированы. Если затем брокер 2 выходит из строя до возвращения брокера 3, ISR становится только 1. Записи не удаются. Некоторые команды впервые видят это в продакшене и спрашивают, почему Kafka не работает, когда лидер все еще жив. Ответ в том, что тема все еще доступна для некоторых чтений, но не безопасна для строго подтвержденных записей.

Вам также следует подумать о восстановлении потребителей. Репликация защищает копии записей на стороне брокера. Она не защищает автоматически смещения потребителей от каждой ошибки рабочего процесса. Смещения потребителей также хранятся в Kafka, обычно в __consumer_offsets, поэтому эта внутренняя тема также нуждается в здоровой репликации. Если пользовательские темы тщательно настроены, но внутренние темы были созданы с слабой репликацией в ранней сборке кластера, поведение при отказе все равно может быть хуже, чем ожидалось. Проверьте репликацию внутренних тем в рамках ревью готовности к продакшену.

В мультитенантных кластерах не каждая тема заслуживает одинаковой конфигурации. Одноразовая тема метрик с высоким объемом и низкой бизнес-ценностью может использовать более короткое хранение и терпеть более слабые гарантии. Тема биллинга — нет. Ошибка в том, чтобы позволить случайным настройкам по умолчанию решать это различие. Запишите классы тем: критические потоки событий, воспроизводимая телеметрия, компактные темы состояний, временные разработческие темы. Затем сопоставьте каждый класс с настройками репликации, ISR, хранения и продюсера.

Во время инцидентов избегайте изменения настроек долговечности только для того, чтобы заглушить ошибки, если все не понимают компромисс. Снижение min.insync.replicas с 2 до 1 может заставить продюсеров работать, но это также означает, что подтвержденные записи могут жить на одном брокере. Включение нечистых выборов лидера может восстановить доступность партиции, но устаревшие реплики могут потерять записи. Иногда бизнес может выбрать этот компромисс. Это должно быть сознательное решение при инциденте, а не скрытый ярлык оператора.