Что является первичным ключом для оффсета в Apache Kafka?

Ответ

В Apache Kafka не существует единого "первичного ключа" для оффсета в классическом смысле СУБД. Оффсет однозначно идентифицируется комбинацией трех элементов:

  1. Топик (Topic)
  2. Партиция (Partition)
  3. Группа потребителей (Consumer Group)

Как это работает:

  • Каждое сообщение в партиции топика имеет монотонно возрастающий порядковый номер — это его оффсет в рамках этой партиции.
  • Потребитель (в составе группы) читает данные из одной или нескольких партиций.
  • Для каждой партиции, которую обрабатывает потребитель, группа хранит последний успешно обработанный оффсет. Это состояние (commit) сохраняется во внутреннем топике __consumer_offsets.

Ключ записи в __consumer_offsets:

[group_id, topic, partition] -> offset_metadata

Таким образом, чтобы найти позицию (оффсет) для конкретного потребителя, система использует тройку (group_id, topic, partition) в качестве составного ключа.

Пример:

  • Топик: user-events
  • Партиция: 3
  • Группа потребителей: notification-service
  • Последний коммит: offset 1452

Запись в __consumer_offsets будет иметь ключ ["notification-service", "user-events", 3] и значение 1452. Когда потребитель из группы notification-service перезапустится, он запросит по этому ключу сохраненный оффсет и продолжит чтение партиции 3 топика user-events с сообщения 1453.

Важно: Разные группы потребителей хранят свои оффсеты независимо. Группа analytics-service будет иметь свою собственную запись для той же пары [topic, partition].

Ответ 18+ 🔞

А, слушай, тут про Кафку и её оффсеты часто спрашивают, и народ реально путает, думая, что там какой-то один волшебный первичный ключ, как в базе данных. Так вот, ёпта, ничего подобного нету.

Представь себе, что оффсет — это не просто цифра, а хитрая жопа из трёх частей. Чтобы его однозначно найти, тебе нужны все три штуки:

  1. Топик (Topic) — ну, куда данные пишут, ясно.
  2. Партиция (Partition) — а вот это уже интереснее, потому что топик-то на куски разбит.
  3. Группа потребителей (Consumer Group) — и вот это, блядь, самый важный нюанс, который все забывают!

Как это всё, сука, крутится:

  • В каждой партиции сообщения идут подряд, и у каждого есть свой порядковый номер — это и есть его локальный оффсет внутри этой партиции.
  • Твой потребитель (в составе какой-то группы) читает из определённых партиций.
  • И вот тут магия: для каждой пары [партиция, топик] твоя группа потребителей хранит свой, блядь, последний обработанный оффсет. Куда? Да в свой же внутренний служебный топик __consumer_offsets. Удивление пиздец, да?

Так вот, ключ в этой самой служебной табличке __consumer_offsets выглядит так:

[group_id, topic, partition] -> offset_metadata

Вот и весь ваш "первичный ключ"! Не одна колонка, а целая тройка: (group_id, topic, partition). Без группы — нихуя не найдёшь.

Пример, чтобы вообще всё встало на свои места:

  • Топик: user-events
  • Партиция: 3
  • Группа потребителей: notification-service
  • Последний коммит: offset 1452

Значит, в __consumer_offsets будет лежать запись с ключом ["notification-service", "user-events", 3] и значением 1452. Перезапустился твой сервис нотификаций — он тыркнется с этим ключом, получит свою сохранённую позицию 1452 и продолжит читать с сообщения 1453. Красота!

И главное, что доверия ебать ноль у групп друг к другу. Другая группа, например, analytics-service, будет иметь свою, отдельную, блядь, запись для той же самой пары [user-events, 3]. Они друг про друга ничего не знают и им, в общем-то, да похуй. Каждая жрёт данные в своём темпе и со своей точки. Вот и вся философия.