Как возникает пилообразный паттерн потребительского отставания Kafka?

Некоторые из моих потребителей Kafka (но не все) демонстрируют интересную закономерность в отношении их отставания.

На следующем изображении показаны два хороших примера:

введите здесь описание изображения

введите здесь описание изображения

темно-синий:

  • около 200 сообщений в секунду в теме
  • 32 раздела
  • 1 потребитель в группе (клиент Python, работающий на Kubernetes)

светло-синий (та же тема, что и темно-синий):

  • так еще и около 200 сообщений в секунду в теме
  • так еще и 32 раздела
  • 1 потребитель в группе (также клиент Python, работающий на Kubernetes)

коричневый:

  • около 1500 сообщений в секунду в теме
  • 40 разделов
  • 2 потребителя в группе (клиент Java/Spring, работающий на Kubernetes)

Оба пилообразных клиента могут обрабатывать гораздо большую пропускную способность, чем это (проверено путем приостановки, возобновления и разрешения им наверстать упущенное), поэтому они не работают на своих ограничениях.

Ребалансировка иногда бывает (по логам), но гораздо реже, чем скачки на диаграмме, и немногочисленные события тоже не коррелируют по времени со скачками.

Сообщения также не приходят пакетами. Вот дополнительная информация по одной из затронутых тем:

введите здесь описание изображения

введите здесь описание изображения

введите здесь описание изображения

Откуда может взяться этот узор?


person Tobias Hermann    schedule 25.09.2018    source источник
comment
Что ж, клиентам нужно циклически перебирать все разделы, блокируя, пока они потребляют из них. Если вы добавите в группу больше потребителей, вы увидите то же самое?   -  person OneCricketeer    schedule 25.09.2018
comment
@cricket_007 Хорошая идея! Но я просто посмотрел на других потребителей и нашел клиента, который является противоположным примером. Я добавил это к вопросу.   -  person Tobias Hermann    schedule 25.09.2018
comment
На первый взгляд похоже, что группа потребителей перебалансируется (возможно, потоки потребителей периодически умирают и перезапускаются). Но в остальном, если вы не отправляете сразу пачками по 3k записей, то эта коричневая линия выглядит странно.   -  person OneCricketeer    schedule 25.09.2018
comment
@cricket_007 В Sentry есть ребалансные записи, но они гораздо реже, чем скачки на диаграмме, и даже те немногие, что не коррелируют по времени со скачками. Также сообщения не приходят пачками. Я только что добавил необходимые графики, поэтому покажите это на мой вопрос.   -  person Tobias Hermann    schedule 27.09.2018
comment
@cricket_007 Я нашел объяснение. Спасибо за помощь в расследовании. :)   -  person Tobias Hermann    schedule 27.09.2018


Ответы (1)


Только что выяснил, что низкочастотный пилообразный рисунок не настоящий. И объяснение довольно интересное. ;)

Когда я проверяю задержку потребителя с помощью командной строки (kafka-consumer-groups --bootstrap-server=[...] --group [...] --describe), я вижу, что общая задержка потребителя (сумма задержек на раздел) колеблется очень быстро. В какой-то момент это около 6000, через 2 секунды около 1000, еще через 2 секунды может быть 9000.

Однако показанный график, похоже, основан на выборках, взятых с более низкой частотой, что нарушает Теорема Найквиста–Шеннона о выборке. Таким образом, усреднение не работает, и мы видим муаровый узор.

Вывод: пилообразный паттерн — всего лишь иллюзия.


Для полноты, вот симуляция, изображающая эффект:

#!/usr/bin/env python3
"""Simulate moire effect of Kafka-consumer-lag graph.
"""

import random

import matplotlib.pyplot as plt


def x_noise_sampling() -> int:
    return 31 + random.randint(-6, 6)


def main() -> None:
    max_x = 7000
    sample_rate = 97
    xs = list(range(max_x))
    ys = [x % 100 for x in xs]
    xs2 = [x + x_noise_sampling() for x in range(0, max_x - 100, sample_rate)]
    ys2 = [ys[x2] for x2 in xs2]

    plt.figure(figsize=(16, 9))
    plt.xlabel('Time')
    plt.xticks([])
    plt.yticks([])
    plt.ylabel('Consumer lag')
    signal, = plt.plot(xs, ys, '-')
    samples, = plt.plot(xs2, ys2, 'bo')
    interpolated, = plt.plot(xs2, ys2, '-')
    plt.legend([signal, samples, interpolated], ['Signal', 'Samples', 'Interpolated samples'])
    plt.savefig('sawtooth_moire.png', dpi=100)
    plt.show()


if __name__ == '__main__':
    main()

введите здесь описание изображения

person Tobias Hermann    schedule 27.09.2018
comment
Любопытно, что привело вас на этот путь расследования? А какую библиотеку вы использовали для мониторинга? Между прочим, недавно я наткнулся на этот github.com/zalando-incubator/remora. - person OneCricketeer; 28.09.2018
comment
@cricket_007 Это была буквально душная мысль, так что в основном удача. ;) Инструмент Прометей. - person Tobias Hermann; 28.09.2018