Требуется ли ключ для отправки сообщений в Kafka?

102
KeyedMessage<String, byte[]> keyedMessage = new KeyedMessage<String, byte[]>(request.getRequestTopicName(), SerializationUtils.serialize(message)); 
producer.send(keyedMessage);

В настоящее время я отправляю сообщения без ключа как часть сообщений с ключом, будет ли оно работать delete.retention.ms? Нужно ли мне отправлять ключ как часть сообщения? Хорошо ли делать ключ частью сообщения?

гаурав
источник

Ответы:

184

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

В случае конечного автомата ключи могут использоваться с log.cleaner.enable для дедупликации записей с одним и тем же ключом. В этом случае Kafka предполагает, что ваше приложение заботится только о самом последнем экземпляре данного ключа, а очиститель журнала удаляет более старые дубликаты данного ключа, только если ключ не равен нулю. Эта форма сжатия журнала контролируется свойством log.cleaner.delete.retention и требует ключей.

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

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

Kuujo
источник
Я новичок в Kafka, поэтому я задаю так много вопросов: есть пара вопросов по этому поводу: первый вопрос, можем ли мы использовать сообщение на основе ключа, в настоящее время я использую сообщение от MessagAndMetadata mm. Или можно игнорировать ключ во время использования сообщения. Я использую Consumer Api высокого уровня.
gaurav
1
@kuujo Я предполагаю, что это дедупликация предназначена только для записей журнала, это не обязательно дедупликация сообщений в очереди тем?
user1658296
2
@oblivion, в котором сообщения последовательно попадают в один и тот же раздел, важен для обработки неидемпонентных обновлений, например, клиент выбирает дату доставки (одно сообщение), но меняет свое мнение позже (второе сообщение). Если сообщения должны поступать в разные разделы, то любое сообщение может обрабатываться первым / последним, например, двумя потребителями, потребляющими из каждого раздела. Если оба сообщения, относящиеся к одной и той же доставке, попадают в один и тот же раздел, они обрабатываются в порядке очереди, что дает правильную окончательную дату доставки.
Kunal
3
Гарантии порядка исходят не от ключа, а от сообщений, находящихся в одном разделе. Маршрутизация сообщений в разделы не обязательно должна основываться на ключах. Вы можете явно указать раздел при созданииProducerRecord
Malt
2
Насколько я понимаю, клиент-производитель несет ответственность за выбор раздела ( kafka.apache.org/documentation.html#design_loadbalancing ), который может или не может быть основан на ключе. Так почему вы говорите, что ключи необходимы для заказа?
lfk 06
11

В дополнение к очень полезному принятому ответу я хотел бы добавить еще несколько деталей

Разбиение

По умолчанию Kafka использует ключ сообщения для выбора раздела темы, в которую он записывает. Это делается в DefaultPartitionerВУ

kafka.common.utils.Utils.toPositive(Utils.murmur2(keyBytes)) % numPartitions;

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

В Kafka можно создать свой собственный Partitioner, расширив Partitionerкласс. Для этого вам нужно переопределить partitionметод с подписью:

int partition(String topic, 
              Object key,
              byte[] keyBytes,
              Object value,
              byte[] valueBytes,
              Cluster cluster)

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

Заказ

Как указано в данном ответе, Kafka гарантирует упорядочивание сообщений только на уровне раздела.

Допустим, вы хотите хранить финансовые транзакции для своих клиентов в теме Kafka с двумя разделами. Сообщения могут выглядеть так (ключ: значение)

null:{"customerId": 1, "changeInBankAccount": +200}
null:{"customerId": 2, "changeInBankAccount": +100}
null:{"customerId": 1, "changeInBankAccount": +200}
null:{"customerId": 1, "changeInBankAccount": -1337}
null:{"customerId": 1, "changeInBankAccount": +200}

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

// partition 0
null:{"customerId": 1, "changeInBankAccount": +200}
null:{"customerId": 1, "changeInBankAccount": +200}
null:{"customerId": 1, "changeInBankAccount": +200}

// partition 1
null:{"customerId": 2, "changeInBankAccount": +100}
null:{"customerId": 1, "changeInBankAccount": -1337}

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

С осмысленным ключом (например, с customerId) этого можно было бы избежать, поскольку разделение было бы таким:

// partition 0
1:{"customerId": 1, "changeInBankAccount": +200}
1:{"customerId": 1, "changeInBankAccount": +200}
1:{"customerId": 1, "changeInBankAccount": -1337}
1:{"customerId": 1, "changeInBankAccount": +200}

// partition 1
2:{"customerId": 2, "changeInBankAccount": +100}

Уплотнение бревен

Без ключа в составе ваших сообщений вы не сможете установить конфигурацию темы cleanup.policyна compacted. Согласно документации, «сжатие журнала гарантирует, что Kafka всегда будет сохранять по крайней мере последнее известное значение для каждого ключа сообщения в журнале данных для одного раздела темы».

Эта приятная и полезная настройка не будет доступна без ключа.

Использование ключей

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

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

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

Майк
источник
0

Ключ с сообщением в основном отправляется, чтобы получить порядок сообщений для определенного поля.

  • Если key = null, данные отправляются циклически (в другой раздел и другому брокеру в распределенной среде и, конечно, в ту же тему).
  • Если ключ отправлен, то все сообщения для этого ключа всегда будут отправляться в один и тот же раздел.

Объясните и пример

  • key может быть любой строкой или целым числом, и т. д. возьмем для примера целочисленное значение employee_id в качестве ключа.
  • Таким образом, emplyee_id 123 всегда будет переходить в раздел 0, а employee_id 345 всегда будет идти в раздел 1. Это определяется алгоритмом хеширования ключей, который зависит от количества разделов.
  • если вы не отправляете никаких ключей, сообщение может быть отправлено в любой раздел с использованием метода циклического перебора.
Прадип Сингх
источник