Ответ
Да, в 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 распределение между партициями. - Изменение количества партиций топика нарушит соответствие ключ→партиция.
- Для абсолютного порядка в масштабе всего топика используйте топик с одной партицией.