Ключ партиционирования и порядок внутри партиции
Урок про то, как выбор ключа сообщения управляет и порядком, и равномерностью нагрузки.
Ключ партиционирования — поле сообщения, по хешу которого Kafka выбирает партицию; все события с одним ключом попадают в одну партицию и потому строго упорядочены между собой.
Зачем это нужно
Порядок в Kafka гарантирован только внутри партиции. Значит, чтобы события одной сущности (одного заказа, одного пользователя) шли по порядку, они должны попадать в одну партицию. Этого добиваются ключом: key = order_id — и вся история заказа лежит в одной партиции, в правильной последовательности.
Как ключ выбирает партицию
partition = hash(key) mod число_партиций key="ord-7" -> hash -> P2 key="ord-7" -> hash -> P2 (тот же ключ -- та же партиция) key="ord-9" -> hash -> P0 key=null -> по кругу (round-robin) по партициям
Одинаковый ключ всегда даёт одну и ту же партицию (пока не менялось их число). Если ключ не задан, Kafka раскидывает события равномерно по кругу — порядок между ними не гарантируется.
Порядок для связанных событий
Рассмотрим заказ с событиями created -> paid -> shipped. Если ключ = order_id, все три попадут в одну партицию и консьюмер увидит их строго в этом порядке. Без ключа они могли бы разъехаться по партициям, и shipped прочитался бы раньше paid.
{"key": "ord-7", "event": "created", "ts": "12:00:01"}
{"key": "ord-7", "event": "paid", "ts": "12:00:05"}
{"key": "ord-7", "event": "shipped", "ts": "12:10:00"}
Перекос ключей (hot partition)
Обратная сторона: если один ключ встречается чрезмерно часто, его партиция перегружается, а остальные простаивают. Классика — ключ = country, и 80% трафика из одной страны валится в одну партицию.
Перекос по ключу "country": P0 (RU): [#########################] перегружена P1 (KZ): [##] P2 (BY): [#] -> параллелизм потерян, P0 -- бутылочное горло
Как работает под капотом
Партиция вычисляется на стороне продюсера: он берёт байты ключа, считает хеш (по умолчанию murmur2), берёт остаток от деления на число партиций — и пишет в найденную партицию. Брокер не перевыбирает партицию. Поэтому при увеличении числа партиций тот же ключ может начать попадать в другую партицию: mod изменился. Это важный нюанс — менять число партиций у топика с порядком по ключу нужно осознанно, иначе «хвост» истории сущности окажется в новой партиции.
Частые ошибки
- Не задать ключ там, где нужен порядок. События сущности разъедутся по партициям и перемешаются.
- Выбрать ключ с низкой кардинальностью. Мало уникальных значений (страна, статус) -- перекос и hot partition.
- Менять число партиций, полагаясь на порядок по ключу. Раскладка ключей сместится, история сущности разорвётся.
Итоги
- Ключ определяет партицию: одинаковый ключ — одна партиция — гарантированный порядок событий.
- Без ключа события раскидываются по кругу, и порядок между ними не гарантируется.
- Ключ с низкой кардинальностью даёт перекос (hot partition) и теряет параллелизм.