Kafka 消费者滞后的锯齿模式是如何出现的?
How does a sawtooth pattern of Kafka consumer lag emerge?
我的一些 Kafka 消费者(但不是全部)表现出一种有趣的滞后模式。
下图显示了两个很好的例子:
深蓝色:
- 主题中每秒约 200 条消息
- 32个分区
- 组中有 1 个消费者(Python 客户端,运行 在 Kubernetes 上)
浅蓝(与深蓝同题):
- 因此主题中每秒也有大约 200 条消息
- 所以也是 32 个分区
- 组中有 1 个消费者(也是 Python 客户端,在 Kubernetes 上 运行)
棕色:
- 主题中每秒约 1500 条消息
- 40 个分区
- 组中有 2 个消费者(Java/Spring 客户端,运行 在 Kubernetes 上)
两个 sawtoothy 客户端都可以处理比这大得多的吞吐量(通过暂停、恢复和让它们赶上进行测试),因此它们没有达到极限。
重新平衡有时确实会发生(根据日志),但比图表中的跳跃要少得多,而且少数事件也不与跳跃及时相关。
消息也不是分批来的。以下是受影响主题之一的附加信息:
这个图案起源于哪里?
刚发现低频锯齿波不是真的。而且解释很有趣。 ;)
当我使用命令行 (kafka-consumer-groups --bootstrap-server=[...] --group [...] --describe
) 检查消费者滞后时,我发现总消费者滞后(每个分区的滞后总和)波动非常快。某一时刻大约是 6000,2 秒后大约是 1000,再过 2 秒可能是 9000。
然而,显示的图表似乎是基于以较低频率采集的样本,这违反了 Nyquist–Shannon sampling theorem. So the averaging does not work, and we see a Moiré pattern。
结论:锯齿图案只是一种错觉。
为了完整起见,这里是一个描述效果的模拟:
#!/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()
我的一些 Kafka 消费者(但不是全部)表现出一种有趣的滞后模式。
下图显示了两个很好的例子:
深蓝色:
- 主题中每秒约 200 条消息
- 32个分区
- 组中有 1 个消费者(Python 客户端,运行 在 Kubernetes 上)
浅蓝(与深蓝同题):
- 因此主题中每秒也有大约 200 条消息
- 所以也是 32 个分区
- 组中有 1 个消费者(也是 Python 客户端,在 Kubernetes 上 运行)
棕色:
- 主题中每秒约 1500 条消息
- 40 个分区
- 组中有 2 个消费者(Java/Spring 客户端,运行 在 Kubernetes 上)
两个 sawtoothy 客户端都可以处理比这大得多的吞吐量(通过暂停、恢复和让它们赶上进行测试),因此它们没有达到极限。
重新平衡有时确实会发生(根据日志),但比图表中的跳跃要少得多,而且少数事件也不与跳跃及时相关。
消息也不是分批来的。以下是受影响主题之一的附加信息:
这个图案起源于哪里?
刚发现低频锯齿波不是真的。而且解释很有趣。 ;)
当我使用命令行 (kafka-consumer-groups --bootstrap-server=[...] --group [...] --describe
) 检查消费者滞后时,我发现总消费者滞后(每个分区的滞后总和)波动非常快。某一时刻大约是 6000,2 秒后大约是 1000,再过 2 秒可能是 9000。
然而,显示的图表似乎是基于以较低频率采集的样本,这违反了 Nyquist–Shannon sampling theorem. So the averaging does not work, and we see a Moiré pattern。
结论:锯齿图案只是一种错觉。
为了完整起见,这里是一个描述效果的模拟:
#!/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()