Как Kafka гарантирует порядок доставки сообщений

Ответ

Kafka гарантирует строгий порядок сообщений только в пределах одной партиции (partition).

Каждое сообщение в партиции получает уникальный, монотонно возрастающий порядковый номер — offset. Консьюмеры читают сообщения из партиции последовательно в соответствии с этим offset.

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

Пример на Python (kafka-python):

from kafka import KafkaProducer

producer = KafkaProducer(bootstrap_servers='localhost:9092')

# Сообщения с одинаковым ключом попадут в одну и ту же партицию,
# их порядок будет сохранен.
producer.send('my-topic', key=b'user-123', value=b'event-1')
producer.send('my-topic', key=b'user-123', value=b'event-2')

# Сообщения с разными ключами могут попасть в разные партиции,
# порядок между ними не гарантирован.
producer.send('my-topic', key=b'order-abc', value=b'created')
producer.send('my-topic', key=b'order-xyz', value=b'shipped')

producer.flush()

Как обеспечить строгий порядок?

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

Ответ 18+ 🔞

Ага, слушай, щас объясню про порядок в Кафке, как есть, без прикрас. Представь себе, что партиция — это такая очередь, как в совковом магазине за колбасой, блядь. Внутри одной очереди — всё чётко: кто встал первым, тот первый и получит свою докторскую, и номерок ему дадут, этот самый offset. Монотонно возрастающий, ёпта! То есть второй за первым, третий за вторым — идиллия, пиздец.

А теперь смотри сюда, умник. Ты же не один магазин, ты сеть, сука, «Колбасы №1», «Колбасы №2» и так далее. Это и есть разные партиции. И вот в первой очереди мужик уже сало получил, а во второй бабка ещё только справку на скидку ищет. Порядка МЕЖДУ очередями — НИХУЯ! Кто быстрее кассиршу обработает, тот и молодец. Это и есть тот самый фундаментальный компромисс, на котором всё и держится: скорость и масштабируемость в обмен на глобальный порядок. Хочешь быстро всех обслужит — делай много касс, но тогда не возмущайся, что кто-то с десятой кассы ушёл раньше, чем ты со второй.

Вот, глянь на код, тут всё наглядно:

from kafka import KafkaProducer

producer = KafkaProducer(bootstrap_servers='localhost:9092')

# Вот эти два сообщения — как два чела с одним ключом 'user-123'.
# Они оба пойдут в одну и ту же очередь-партицию, и event-2 всегда будет после event-1.
# Порядок гарантирован, как моё слово, блядь.
producer.send('my-topic', key=b'user-123', value=b'event-1')
producer.send('my-topic', key=b'user-123', value=b'event-2')

# А вот эти — с разными ключами. Их швырнёт в разные партиции, как охуевших.
# Может, 'created' улетит в партицию 5, а 'shipped' — в партицию 9.
# И кто из них на выходе раньше окажется — хуй его знает! Порядка нет.
producer.send('my-topic', key=b'order-abc', value=b'created')
producer.send('my-topic', key=b'order-xyz', value=b'shipped')

producer.flush()

Ну и как тогда, блядь, порядок навести?

  • Ключ — твой царь и бог. Всё, что должно идти строго друг за другом (все события по одному юзеру, по одному заказу), — пихай с одинаковым ключом. Кафка по хэшу ключа определит одну и ту же партицию, и там уж порядок будет железный. Это как если бы ты всем своим родственникам дал один номерок на всю семью — стояли бы кучкой.
  • Сделать одну партицию на весь топик. Это вариант для максималистов, блядь. Да, тогда ВСЕ сообщения будут в одной очереди, и глобальный порядок наступит. Но это же пиздец, а не производительность! Это как весь город послать в один магазин за той самой колбасой. Очередь до Луны, скорость — ноль ебать. Узкое место системы, одним словом. На такое решаются только в очень особых, извращённых случаях.

Вот так вот, ебанашка. Выбирай: либо скорость и масштаб, но без глобального порядка, либо порядок, но в одном потоке, как последний олдскульный перфекционист.