Можно ли явно распределять сообщения по партициям в Kafka?

«Можно ли явно распределять сообщения по партициям в Kafka?» — вопрос из категории Брокеры сообщений, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

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

Основные механизмы:

1. Указание ключа сообщения (Message Key)

  • Сообщения с одинаковым ключом всегда попадают в одну и ту же партицию (на основе хэширования).
  • Гарантирует порядок обработки для записей в пределах одного ключа.
using Confluent.Kafka;

var config = new ProducerConfig { BootstrapServers = "localhost:9092" };
using var producer = new ProducerBuilder<string, string>(config).Build();

// Сообщения с одинаковым 'userId' попадут в одну партицию
var message1 = new Message<string, string> 
{ 
    Key = "user123", 
    Value = "User logged in" 
};
var message2 = new Message<string, string> 
{ 
    Key = "user123", 
    Value = "User made a purchase" 
};

await producer.ProduceAsync("user-events", message1);
await producer.ProduceAsync("user-events", message2);

2. Прямое указание номера партиции

  • Можно явно отправить сообщение в конкретную партицию, минуя стандартный партиционер.
// Отправка строго в партицию 2
var tp = new TopicPartition("my-topic", new Partition(2));
await producer.ProduceAsync(tp, new Message<Null, string> { Value = "Direct message" });

3. Кастомный партиционер

  • Можно реализовать интерфейс ICustomPartitioner или IProducer для сложной логики распределения.
public class CustomPartitioner : Partitioner
{
    public override int Partition(string topic, int partitionCount, ReadOnlySpan<byte> keyData, bool keyIsNull)
    {
        // Ваша логика: например, по первому байту ключа
        return keyIsNull ? 0 : keyData[0] % partitionCount;
    }
}

Важные замечания:

  • Если ключ null, используется round-robin распределение между партициями.
  • Изменение количества партиций топика нарушит соответствие ключ→партиция.
  • Для абсолютного порядка в масштабе всего топика используйте топик с одной партицией.