1. 介绍

最近kafka集群要换机房了。为了确保新环境正常,我们来做一些压力测试。这次压力测试重点会关注一些异常情况下,kafka收发消息的状况。

2. 基本信息

3台broker,使用kafka0.10.1版本,每台broker使用6T硬盘,内存100G。broker配置按照官方文档推荐的生产配置来配置。

3. broker挂掉的情况

3.1 整个broker集群挂掉

这个同事做过测试,所以这里直接放结论了:
即使设置了acks=all,但是如果整个集群都连接不上了,也是不能避免消息丢失的(重发次数到了设定的值,或者发送请求超时了都会导致生产者丢弃该条消息,发送下一条消息)。重试次数增多、发送请求超时设定长点可以减少“丢失”(丢失只是相对于消费者角度来说的,实际上是生产者由于超时或者重发次数限制丢弃了一些消息)的消息数。重试次数增多,发送请求超时增加都意味着对发送失败的消息进行更长时间的重发。因此相对来说,被生产者丢弃的消息数会少些。

3.2 部分broker节点挂了

例如集群有N份replication,那么一般来说,挂掉n-1 个节点都是没关系的。挂掉的broker对原来的消息收发几乎不产生任何影响。该部分的实验可以看kafka容错对消费者影响分析中的第四章。

4. 磁盘故障的情况

磁盘空间满了、磁盘故障都可以归结到“磁盘故障”的情形。之前和同事做过相关的实验,这里直接放结论:

当某个broker上的磁盘发生故障时,分区leader在该broker上的分区都无法进行访问,broker server进程被阻塞。如果磁盘上的数据能及时恢复,并且磁盘重新进行工作的话,出现磁盘故障的broker就能够重新恢复服务。而在磁盘故障没修复之前,其实整个kafka集群是不可用的。 因此对可用性要求比较高的场景下,如果某个broker由于磁盘故障而不能服务,可以考虑尽快下线该broker,触发分区复制,确保整个集群可用。

磁盘故障恢复方法: 首先第一件事还是下线出问题的broker,确保整个集群可用。然后尽快修复磁盘上的数据,然后重启broker。如果磁盘上的数据没法恢复,也没有关系。可以尽快替换健康的磁盘,然后重启broker,这样数据还是可以通过复制恢复过来的。

5. 流量压测

模拟大量的生产消费,看看在突发的大量数据的收发压力下,生产和消费是否会受影响。

生产者发送数据使用命令:kafka-producer-perf-test.sh ,命令具体为:

sh kafka-producer-perf-test.sh --topic admin.benchmark --num-records 100000000 --record-size 1024   --throughput 5000000 --producer-props bootstrap.servers=10.8.30.31:9092,10.8.30.32:9092,10.8.30.33:9092 acks=all retries=2 linger.ms=1 

消费者接受数据使用命令:kafka-consumer-perf-test.sh

# 默认就是从earliest来访问的,每个消费者访问1亿条记录
sh kafka-consumer-perf-test.sh --topic admin.benchmark --batch-size 10000  --num-fetch-threads 2 --threads 10 --show-detailed-stats --group kafka.benchmark --messages 100000000 --broker-list 10.8.30.31:9092,10.8.30.32:9092,10.8.30.33:9092

实验步骤:

  1. 首先在我们测试用的admin.benchmark这个topic上生成1亿条记录,作为历史消息。
# 放入1亿条记录之后的统计信息
100000000 records sent, 264310.427311 records/sec (258.12 MB/sec), 109.91 ms avg latency, 1195.00 ms max latency, 52 ms 50th, 375 ms 95th, 737 ms 99th, 1008 ms 99.9th.
  1. 准备3个生产者和9个消费者同时对admin.benchmark生产和消费消息,每个生产者发送1亿条数据,每个消费者消费admin.benchmark这个topic中的1亿条记录。这些生产者和消费者均匀分散在3个broker上。

  2. 3个生产者持续发送大量数据,9个消费者各自开始消费1亿条记录,并发执行。

实验结果:

  1. 消息收发吞吐情况如下所示:当收发稳定之后,平均每台broker上消息流入速率为10GB/秒,流出速率为5GB/s,消息收发正常无报错

broker1:

broker2:

broker3:

  1. broker GC情况如下图所示:在流量比较大的时候,势必也造成YGC次数和时间均增多。可见流量大的时候,某些broker的峰值YGC耗时可能超过500ms。如果应用对响应时间要求比较高,在kafka调优时可以考虑别给集群施加太大压力。不过值得注意的是,即使在我们这种大流量压测下,也没有发生FULL GC。

broker1:

broker2:

broker3:

  1. 网卡流量情况如下图所示:使用的万兆网卡基本被压满。输入输出合起来在每个broker上平均约有7G/s的流量。因此前面的输入输出吞吐量合计的平均值为12G左右也是可以理解的了。 broker1:

broker2:

broker3:

  1. 生产者的延迟情况 这个实验结果,可以作为第6节实验的基准参考值。
# broker1
100000000 records sent, 123782.598147 records/sec (120.88 MB/sec), 240.49 ms avg latency, 26623.00 ms max latency, 115 ms 50th, 913 ms 95th, 1248 ms 99th, 18743 ms 99.9th.
# broker2
100000000 records sent, 123094.951753 records/sec (120.21 MB/sec), 243.42 ms avg latency, 21447.00 ms max latency, 138 ms 50th, 962 ms 95th, 1336 ms 99th, 13403 ms 99.9th.
# broker3
100000000 records sent, 122244.307694 records/sec (119.38 MB/sec), 243.64 ms avg latency, 24602.00 ms max latency, 90 ms 50th, 930 ms 95th, 1316 ms 99th, 17396 ms 99.9th.

重点可以发现,平均延迟在250ms左右。

6. 恢复能力测试

这个测试主要测试kafka进行数据恢复的能力。当kafka集群上有大量历史数据时,如果其中一个broker挂了,需要多少时间来完成恢复,同时对生产和消费会产生神马影响,是我们主要关心的内容。由于我们采用3个节点,并且admin.benchmark这个topic只有2份副本,也就是意味着只能容忍1个broker故障。如果超过1个broker故障,就会影响消息收发,需要尽快恢复broker。

实验过程:

  1. 按照第5节的方法进行大量消息的收发(先在上面保留2亿条记录,然后按照原来3个生产者9个消费者的方式启动整个收发流程)
  2. 在收发过程中下线broker1,观察对消息收发的影响(延迟变化、是否发生错误或者异常)
  3. 过几小时后重新启动broker1,查看恢复的时长和对生产消费的影响。
  4. 再次关掉broker1并且清除broker1上面所有的日志记录,查看集群需要多久时间恢复约10亿条记录。

PS: 我们下线broker1的时间为14:48分,这个对照图来分析的时候请留意。

实验结果:

  1. 下线broker1之后,消费者没有报错,生产者开始刷出大量报错,约1分钟之后,所有生产者均开始重新恢复发送。在下线broker1之后,该broker上面的leader分区无法访问。这时候需要重新选取分区,然后到新的broker上去获取分区数据。而且还要触发复制。整个异常过程中,只有kafka集群的生产者会受影响,并且在较短的时间内自动恢复。

  2. 下线broker1之后,broker1的网卡仍然占用着比较大的网络带宽,主要是复制分区数据导致

  1. 下线broker1之后,生产者的发送吞吐量降低、平均延迟增加、峰值时的延迟也增加
#broker1:
100000000 records sent, 78886.812413 records/sec (77.04 MB/sec), 379.62 ms avg latency, 58904.00 ms max latency, 277 ms 50th, 652 ms 95th, 8745 ms 99th, 16687 ms 99.9th.
#broker2:
100000000 records sent, 79778.916666 records/sec (77.91 MB/sec), 375.03 ms avg latency, 59444.00 ms max latency, 265 ms 50th, 632 ms 95th, 5703 ms 99th, 17713 ms 99.9th.
#broker3:
100000000 records sent, 78588.673172 records/sec (76.75 MB/sec), 381.02 ms avg latency, 72196.00 ms max latency, 289 ms 50th, 657 ms 95th, 6811 ms 99th, 19581 ms 99.9th.
  1. 下线broker1之后的10分钟的时间内,消费者的消费速率会有显著下降,应该是要等待分区选举leader吧。不过总体上,消费者受影响仍然较小,总体上仍然是以比较正常的速率进行消费(平均有3W+条消息每秒的消费速率)。下图是broker2的一个消费者的消费统计信息,可供参考:

  1. broker1下线后整个集群仍然正常提供服务。过几小时后重新恢复broker1,由于其节点上原来的数据仍然是保留的,所以整个集群马上可以恢复。

  2. broker1如果下线后删除上面10亿条记录再上线,发现数据恢复需要耗时:

7. 总结

kafka作为分布式的消息系统,在集群可用性上还是做得比较完善的。在副本数充足的情况下发生节点故障,只会对生产和消费的速率产生一些影响,总体系统仍然是可用的。

而针对突发的大量消息收发,kafka集群能非常稳定的工作。从实验结果我们也可以看到,即使使用万兆网卡,我们的生产和消费都快要跑满整块网卡的带宽。一般来说,只要网络带宽给力,kafka的吞吐性能绝对是够用了(前提是生产者、发送者本身不是性能瓶颈)。