В прошлом уроке мы разрезали топик на партиции, и консьюмеры поделили работу. Но у этого есть цена. Отто открыл табло и увидел заказ, который сначала доставили, а потом создали. Курьер не путешествовал во времени: просто статусы одного заказа попали в разные партиции. Разберёмся, как это предотвратить.
Почтовые ящики по фамилиям
В большом доме почту раскладывают по ящикам с буквами: А-Ж, З-О, П-Я. Все письма Иванову ложатся в ящик З-О в том порядке, в каком их принёс почтальон. Сколько бы писем ни пришло, Иванов прочтёт их по порядку: они в одном ящике.
Письма Иванову и Петрову лежат в разных ящиках. Какое из них пришло раньше, по ящикам уже не понять, но обычно это и не нужно.
А теперь в доме повесили четвёртый ящик и переделили алфавит. Иванов теперь получает почту в другой ящик. Старые письма лежат в старом, новые в новом, и если сначала открыть новый ящик, вчерашнее письмо прочтётся после сегодняшнего.
В Kafka ящики это партиции, а фамилия это ключ.
Порядок есть только внутри партиции
Kafka обещает одно: записи одной партиции читаются в том порядке, в каком их записали. Между разными партициями порядка нет. Консьюмер читает их параллельно или по очереди, как ему удобно, и запись из партиции 1 может обработаться раньше записи из партиции 0, хотя её отправили позже.
Чтобы события одного заказа шли по порядку, они должны лежать в одной партиции. Решает это ключ.
Ключ решает, куда ляжет запись
У каждого сообщения может быть ключ. Продюсер считает от ключа хеш и берёт остаток от деления на число партиций:
партиция = хеш(ключ) mod число_партиций
Эту работу делает партиционер продюсера. Одинаковый ключ даёт одинаковый хеш, значит, одну и ту же партицию. Ключом статусов заказа берут номер заказа: все статусы order-7 попадут в одну партицию и прочтутся по порядку.
А если ключа нет? Тогда партиционер раскладывает записи сам. С Kafka 2.4 он «липкий», а с 3.3 ещё и равномерный: копит записи без ключа в одной партиции, пока не наберёт пачку размером batch.size, а потом переходит к другой. Поэтому в маленькой песочнице записи без ключа часто оказываются в одной партиции. Это совпадение, а не обещание: на настоящем потоке соседние события одного заказа разъедутся по разным партициям.
урок из курса
Урок из курса «Data Engineering». Курс покупается один раз и остаётся навсегда: 500 ₽.
Оплата пока не подключена: премиум и курсы открываются промокодом.