Освоение конфигурации топиков Kafka: полное руководство

Практическое руководство по разделам Kafka, репликации, хранению, компакции и безопасным изменениям конфигурации.

Освоение конфигурации топиков Kafka: полное руководство

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

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

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

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

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

Создайте топик с явными настройками:

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

Имя топика также должно нести некоторую смысловую нагрузку. Имена вроде events или data становятся бесполезными, когда кластер растет. user-events.v1, billing-invoices.v1 или inventory-adjustments.v1 сообщают будущим операторам, что представляет собой поток, и дают возможность для последующего изменения схемы с нарушением обратной совместимости.

Коэффициент репликации определяет, сколько копий Kafka хранит для каждого раздела. В производственной среде 3 является распространенным значением по умолчанию, поскольку позволяет одному брокеру выйти из строя, оставляя еще одну доступную реплику. Это не означает, что вы можете игнорировать настройки производителя. Если производители используют acks=1, Kafka может подтверждать записи до того, как подписчики их скопируют. Для важных топиков сочетайте коэффициент репликации три с min.insync.replicas=2 на уровне топика и acks=all у производителя.

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

Настройки хранения определяют, когда Kafka может удалять старые сегменты журнала. Хранение на основе времени контролируется параметром retention.ms на уровне топика. Хранение на основе размера контролируется параметром retention.bytes. Более старые имена на уровне брокера, такие как log.retention.ms, являются значениями по умолчанию для брокера; конфигурация топика обычно использует retention.ms.

Например, чтобы хранить топик в течение семи дней:

kafka-configs.sh --alter   --bootstrap-server broker1:9092   --entity-type topics   --entity-name user-events.v1   --add-config retention.ms=604800000

Чтобы ограничить хранилище на раздел, используйте retention.bytes:

kafka-configs.sh --alter   --bootstrap-server broker1:9092   --entity-type topics   --entity-name user-events.v1   --add-config retention.bytes=10737418240

Помните, что retention.bytes обычно указывается на раздел, а не на общий размер топика. Топик с двенадцатью разделами и retention.bytes=10GB может использовать примерно 120 ГБ до репликации и примерно 360 ГБ с коэффициентом репликации три. Это та деталь, которая вызывает неожиданные оповещения о заполнении диска.

Kafka удаляет данные по сегментам журнала, а не по записям. Если вы установите короткий срок хранения, но большие сегменты, удаление может не произойти в ту минуту, которую вы ожидаете. Настройки сегментов, такие как segment.bytes и segment.ms, влияют на то, когда Kafka переключается на новый сегмент, и только закрытые сегменты могут быть удалены или сжаты. Меньшие сегменты могут сделать очистку более быстрой, но они добавляют накладные расходы.

cleanup.policy определяет, что Kafka делает со старыми данными. По умолчанию используется delete, который удаляет старые сегменты на основе срока хранения. compact сохраняет последнюю запись для каждого ключа и со временем удаляет более старые записи с тем же ключом. Вы также можете использовать delete,compact для топиков, которым требуется компакция плюс окно хранения.

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

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

Сжатие может быть установлено производителями, и топик может определить compression.type для управления поведением брокера. Распространенные значения включают producer, gzip, snappy, lz4 и zstd, в зависимости от версии Kafka. Многие команды оставляют топик на producer и стандартизируют сжатие производителя. lz4 и zstd являются распространенными вариантами, но правильный ответ зависит от бюджета ЦП, формы сообщения и сетевой нагрузки.

Вы можете просмотреть конфигурацию топика следующим образом:

kafka-configs.sh --describe   --bootstrap-server broker1:9092   --entity-type topics   --entity-name user-events.v1

И просмотреть размещение разделов следующим образом:

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

Используйте обе команды. Конфигурации топиков сообщают вам о хранении, компакции и правилах ISR. Описание топика сообщает вам о лидерах, репликах и состоянии ISR. Топик может иметь идеальную конфигурацию и все равно быть нездоровым, потому что реплики не синхронизированы.

Некоторые изменения просты. Политика хранения, компакции, min.insync.replicas и несколько других конфигураций топиков могут быть изменены динамически. Некоторые изменения требуют большей осторожности. Вы можете увеличить количество разделов, но вы не можете безопасно уменьшить его с помощью простой команды. Увеличение количества разделов также изменяет распределение ключей для будущих записей, потому что расчет разбиения имеет больше целевых разделов. Существующие записи остаются на своих местах; новые записи для того же ключа могут попасть в другой раздел после увеличения, в зависимости от разделителя. Если важна строгая упорядоченность по ключу при изменении, планируйте тщательно.

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

Для обычного производственного топика событий практическая отправная точка может выглядеть так:

kafka-topics.sh --create   --bootstrap-server broker1:9092   --topic payments-authorized.v1   --partitions 24   --replication-factor 3   --config min.insync.replicas=2   --config retention.ms=1209600000   --config cleanup.policy=delete

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

Для топика состояния форма другая:

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

Этот топик должен быть ключом по идентификатору пользователя. Потребители, восстанавливающие состояние, могут читать сжатый журнал и со временем увидеть последнее значение для каждого пользователя. Они не должны ожидать, что каждое историческое изменение предпочтений останется навсегда.

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

Полезная привычка при проверке — записать историю потребителя перед выбором настроек топика. Кто читает этот топик? Нужно ли им воспроизводить с начала? Сколько времени займет полное восстановление? Может ли исходная система переиздать старые данные? Если потребитель не работает в течение трех дней, должны ли в Kafka все еще быть пропущенные записи? Эти ответы определяют хранение более честно, чем настройка по умолчанию в семь дней.

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

Размер сообщения также относится к обсуждению топика. Kafka может обрабатывать большие записи, если они настроены, но большие сообщения влияют на производителей, брокеров, потребителей, репликацию и память выборки. Если команды начинают помещать многомегабайтные JSON-блоб или закодированные файлы в топик, не просто повышайте max.message.bytes и двигайтесь дальше. Спросите, не принадлежит ли полезная нагрузка объектному хранилищу со ссылкой в Kafka. Kafka обычно лучше всего подходит для перемещения событий, а не для работы в качестве хранилища блобов.

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

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

Последняя проверка перед публикацией топика — проиграть сценарий отказа. Если один брокер исчезает, могут ли производители все еще писать? Если группа потребителей не работает в течение выходных, покроет ли хранение пробел? Если производитель отправляет плохие данные, могут ли потребители безопасно пропустить, поместить в карантин или воспроизвести? Если топик растет вдвое быстрее, чем ожидалось, какой предел защищает кластер: время хранения, байты хранения, квоты или оповещение?

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

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