为了账号安全,请及时绑定邮箱和手机立即绑定

360度测试:KAFKA会丢数据么?其高可用是否满足需求?

标签:
Java

https://img1.sycdn.imooc.com//5d5cfa440001ba3e05910305.png

请仔细了解这张图,尤其注意有标志的几个关注点。我们会不止一次回到这张图上

背景

Kafka 到底能够应用在高可用的业务上?官方给出的答案是肯定的,最新版,已经支持消息队列的事务,但我们对其性能是有疑问的。
Kafka 根据配置的 ACK 级别,其性能表现将特别大,为了找到其适用场景,特做此测试,以便应用 kafka 时能够灵活应对。
测试过程还探讨了许多丢消息的场景。相对于大多数仅仅针对 kafka 集群本身的测试,本测试还介绍了丢消息的业务场景。整个方案应该是一个整体,才能够达到最高级别的高可用,不因该区别对待。

测试目标

  • 集群高可用,以及需要满足高可用时需要的最小集群大小和相关配置以及限制等

  • 消息不丢失,以及为了满足消息不丢失需要的配置和约定等

  • 测试环境

broker:

3台机器8 core 16G 1T SSD Centos 6.8kafka_2.12-0.10.2.0 broker jvm参数配置:Xms=8G Xmx=8G

client:

8 core 16G Centos 6.8

测试场景

集群高可靠性配置:

zookeeper.connection.timeout.ms=15000zookeeper.session.timeout.ms=15000default.replication.factor=3num.partitions=6 min.insync.replicas=2 unclean.leader.election.enable=falselog.flush.interval.ms=1000

ack

acks= all retries = 3 request.timeout.ms=5000

消息大小:1024byte


failover 测试

测试方法

下线一个节点,测试故障的恢复时间和故障期间的服务水平

测试过程

将 replica.lag.time.max.ms 从 10s 调整为 60s(延长时间方便观察),然后 kill Broker 0,挑选 3 个 partition,观察 ISR 变化如下:
其中,第二 / 三阶段入队成功率受损:

  • 第二阶段期间,Partition 96/97/98 均无法写入,入队成功率成功率下降至 0%。

  • 第三阶段期间,Partition 96 可继续写入,但 Partition 97/98 无法写入,因为写入要等 Broker 0 回 ack,但 Broker 0 已 kill,入队成功率下降至 33%。

而实际观察,第二 / 三阶段期间完全没吞吐,原因是压测工具不断报连接失败,停止了写入。

原因分析

Kafka Broker leader 是通过 Controller 选举出来的,ISR 列表是 leader 维护的。
前者的的租约是 Controller 定义的,后者的租约是 Broker 配置 replica.lag.time.max.ms 指定的。
所以,第二阶段持续时间较短,是 Controller 的租约时间决定的,第三阶段持续时间较长,是 replica.lag.time.max.ms 决定的。
当 Broker 0 被 kill 时,前者影响本来 Broker 0 是 leader 的 1/3 partitions 的入队成功率,后者影响 Broker 0 作为 follower 的 2/3 partitions 的入队成功率。

HA 结论

kafka 在 failover 期间,会有大约 10 秒的不可用时间,该时间由 replica.lag.time.max.ms 决定。因此应用程序需要处理此种情况下的异常信息,设置合理的重试次数和退避算法。


压力测试

测试方法

测试脚本:

./kafka-producer-perf-test.sh --topic test003 --num-records 1000000 --record-size 1024  --throughput -1 --producer.config ../config/producer.properties

测试结果

不限制并发吞吐量

[root@l-monitor-logstash2.pub.prod.aws.dm bin]# time ./kafka-producer-perf-test.sh --topic ack001 --num-records 1000000 --record-size 1024 --throughput -1 --producer.config ../config/producer.properties[2017-09-14 2157,543] WARN Error while fetching metadata with correlation id 1 : {ack001=LEADER_NOT_AVAILABLE} (org.apache.kafka.clients.NetworkClient)81112 records sent, 16219.2 records/sec (15.84 MB/sec), 1416.2 ms avg latency, 1779.0 max latency.92070 records sent, 18414.0 records/sec (17.98 MB/sec), 1671.7 ms avg latency, 1821.0 max latency.91860 records sent, 18368.3 records/sec (17.94 MB/sec), 1670.3 ms avg latency, 1958.0 max latency.91470 records sent, 18294.0 records/sec (17.87 MB/sec), 1672.3 ms avg latency, 2038.0 max latency.91050 records sent, 18202.7 records/sec (17.78 MB/sec), 1678.9 ms avg latency, 2158.0 max latency.92670 records sent, 18534.0 records/sec (18.10 MB/sec), 1657.6 ms avg latency, 2223.0 max latency.89040 records sent, 17808.0 records/sec (17.39 MB/sec), 1715.0 ms avg latency, 2481.0 max latency.86370 records sent, 17274.0 records/sec (16.87 MB/sec), 1767.5 ms avg latency, 2704.0 max latency.91290 records sent, 18254.3 records/sec (17.83 MB/sec), 1670.2 ms avg latency, 2553.0 max latency.92220 records sent, 18444.0 records/sec (18.01 MB/sec), 1658.1 ms avg latency, 2626.0 max latency.90240 records sent, 18048.0 records/sec (17.63 MB/sec), 1669.9 ms avg latency, 2733.0 max latency.1000000 records sent, 17671.591150 records/sec (17.26 MB/sec), 1670.61 ms avg latency, 2764.00 ms max latency, 1544 ms 50th, 2649 ms 95th, 2722 ms 99th, 2753 ms 99.9th.real 0m57.409suser 0m14.544ssys 0m2.072s

限制吞吐量 1w

[root@l-monitor-logstash2.pub.prod.aws.dm bin]# time ./kafka-producer-perf-test.sh --topic ack003 --num-records 1000000 --record-size 1024 --throughput 10000 --producer.config ../config/producer.properties[2017-09-15 1053,184] WARN Error while fetching metadata with correlation id 1 : {ack003=LEADER_NOT_AVAILABLE} (org.apache.kafka.clients.NetworkClient)[2017-09-15 1053,295] WARN Error while fetching metadata with correlation id 4 : {ack003=LEADER_NOT_AVAILABLE} (org.apache.kafka.clients.NetworkClient)49766 records sent, 9953.2 records/sec (9.72 MB/sec), 34.9 ms avg latency, 358.0 max latency.50009 records sent, 10001.8 records/sec (9.77 MB/sec), 23.9 ms avg latency, 39.0 max latency.50060 records sent, 10008.0 records/sec (9.77 MB/sec), 23.9 ms avg latency, 49.0 max latency.49967 records sent, 9991.4 records/sec (9.76 MB/sec), 23.6 ms avg latency, 38.0 max latency.50014 records sent, 10000.8 records/sec (9.77 MB/sec), 24.0 ms avg latency, 51.0 max latency.50049 records sent, 10007.8 records/sec (9.77 MB/sec), 23.5 ms avg latency, 37.0 max latency.49978 records sent, 9995.6 records/sec (9.76 MB/sec), 23.5 ms avg latency, 44.0 max latency.49803 records sent, 9958.6 records/sec (9.73 MB/sec), 23.7 ms avg latency, 47.0 max latency.50229 records sent, 10045.8 records/sec (9.81 MB/sec), 23.6 ms avg latency, 46.0 max latency.49980 records sent, 9996.0 records/sec (9.76 MB/sec), 23.5 ms avg latency, 36.0 max latency.50061 records sent, 10010.2 records/sec (9.78 MB/sec), 23.6 ms avg latency, 36.0 max latency.49983 records sent, 9996.6 records/sec (9.76 MB/sec), 23.4 ms avg latency, 37.0 max latency.49978 records sent, 9995.6 records/sec (9.76 MB/sec), 23.9 ms avg latency, 55.0 max latency.50061 records sent, 10012.2 records/sec (9.78 MB/sec), 24.3 ms avg latency, 55.0 max latency.49981 records sent, 9996.2 records/sec (9.76 MB/sec), 23.5 ms avg latency, 42.0 max latency.49979 records sent, 9991.8 records/sec (9.76 MB/sec), 23.8 ms avg latency, 39.0 max latency.50077 records sent, 10013.4 records/sec (9.78 MB/sec), 23.6 ms avg latency, 41.0 max latency.49974 records sent, 9994.8 records/sec (9.76 MB/sec), 23.4 ms avg latency, 36.0 max latency.50067 records sent, 10011.4 records/sec (9.78 MB/sec), 23.8 ms avg latency, 65.0 max latency.49963 records sent, 9992.6 records/sec (9.76 MB/sec), 23.5 ms avg latency, 54.0 max latency.1000000 records sent, 9997.300729 records/sec (9.76 MB/sec), 24.24 ms avg latency, 358.00 ms max latency, 23 ms 50th, 28 ms 95th, 39 ms 99th, 154 ms 99.9th.real 1m40.808suser 0m16.620ssys 0m1.260s更多...吞吐量5k 1000000 records sent, 4999.275105 records/sec (4.88 MB/sec), 22.94 ms avg latency, 127.00 ms max latency, 23 ms 50th, 27 ms 95th, 31 ms 99th, 41 ms 99.9th.吞吐量2w 1000000 records sent, 18990.827430 records/sec (18.55 MB/sec), 954.74 ms avg latency, 2657.00 ms max latency, 739 ms 50th, 2492 ms 95th, 2611 ms 99th, 2650 ms 99.9th.吞吐量3w 1000000 records sent, 19125.212768 records/sec (18.68 MB/sec), 1527.07 ms avg latency, 3020.00 ms max latency, 1582 ms 50th, 2815 ms 95th, 2979 ms 99th, 3011 ms 99.9th.

12 分区,2.6w 吞吐量

[root@l-monitor-logstash2.pub.prod.aws.dm bin]# time ./kafka-producer-perf-test.sh --topic ack001 --num-records 1000000 --record-size 1024 --throughput 26000 --producer.config ../config/producer.properties129256 records sent, 25840.9 records/sec (25.24 MB/sec), 31.9 ms avg latency, 123.0 max latency.129794 records sent, 25953.6 records/sec (25.35 MB/sec), 28.6 ms avg latency, 73.0 max latency.130152 records sent, 26025.2 records/sec (25.42 MB/sec), 28.3 ms avg latency, 64.0 max latency.130278 records sent, 26045.2 records/sec (25.43 MB/sec), 28.1 ms avg latency, 55.0 max latency.130106 records sent, 26010.8 records/sec (25.40 MB/sec), 27.9 ms avg latency, 45.0 max latency.130080 records sent, 26005.6 records/sec (25.40 MB/sec), 27.7 ms avg latency, 41.0 max latency.130093 records sent, 26013.4 records/sec (25.40 MB/sec), 74.5 ms avg latency, 343.0 max latency.1000000 records sent, 25904.051394 records/sec (25.30 MB/sec), 38.33 ms avg latency, 343.00 ms max latency, 28 ms 50th, 122 ms 95th, 242 ms 99th, 321 ms 99.9th.real 0m39.395suser 0m12.204ssys 0m1.616s

cpu 与内存无任何变化。网络 rx/tx :170Mbps/120Mbps,磁盘 IoUtil: 6%。1 百万数据能在 2 分钟内完成。

压测结论

影响提交效率的原因主要有:partition 数量 + 超时时长 + 消息大小 + 吞吐量

  • 不做限制:ack=all 的模式,不限制吞吐量,TPS 能够保持在 2w 左右,平均耗时在 1600ms 左右,99.9% 的记录能够两秒左右正常提交反馈,最大耗时有记录超过 5 秒。

  • 超时时长:当将超时时常设置为 5 秒以上时,提交全部成功(ack)。将超时逐步降低到 3 秒左右,陆续会有大量超时出现。官方的默认值为 30 秒,考虑到网络环境的复杂性,建议将此参数设置成 10 秒,如还有超时,需要客户端捕获异常进行特殊处理。

  • 消息大小:当将消息大小设置为 512byte,提交的 TPS 能够打到 3w/秒;当增加到 2k 左右,TPS 降低到 9k/s,消息大小与 TPS 成线性关系。

  • 流量:当限制吞吐量为 1.3w 左右,减少竞争,效果最佳。平均耗时降低到 24 毫秒,最大延迟仅 300 多毫秒,服务水平相当高。

  • 分区数量:增加分区数能显著提高处理能力,但分区数会影响故障恢复时间。本测试用例仅针对 6 分区的情况,测试证明,当分区数增加到 12,处理能力几乎增加一倍,但继续增加,性能不会再有显著提升。

最终结论:假定网络状态良好,在 ack=all 模式、超时 10 秒、重试 3 次、分区为 6 的情况下,能够承受 1.3w/s 的消息请求,其写入平均耗时不超过 30ms,最大耗时不超过 500ms。想要增加 TPS,可以增加 partition 到 12,能够达到 2.6w/s 的高效写入。

堆积测试

kafka 生产和消费理论上不受消息堆积影响,消息堆积只是占用磁盘空间,这里的消息堆积是指 topic 中的消息数,和消息是否消费无关


结论

kafka 采用基于时间的 SLA(服务水平保证),重要消息保存 3 天。

性能

基本配置:消息 1k 大小,ack=all,即所有副本都同步的情况。为确保消息可靠,全部采用 3 个副本。

  • 3 副本,1 个 partition 的情况:6k-8k

  • 3 副本,6 个 partition 的情况:1.3w-1.6w

  • 3 副本,12 个 partion 的情况:2.6w-2.8w

注意:生产端,考虑一种场景,单条发送,然后调用 future.get() 确认,TPS 会急剧降低到 2k 以下,请确认确实需要这么做,否则,使用异步提交,callback 调用的方式。相对于 ACK 模式 1.6w 的 TPS,普通模式提交,能够达到 13w(主要是网络和 IO 瓶颈,带宽占满)。当吞吐量限制在 1w 左右并且开启 ACK(非常符合我们的业务特征),kafka 是高效且高可用的,平均耗时仅 24 毫秒,生产者的最佳实践是将超时设置成 10 秒,重试 3 次。消费者同样是高效的,6 个 partition、ack 模式,平均耗时在 20 毫秒左右,具体处理耗时取决于消费端的处理能力。

kafka 消息可靠性

  • 写 3 个副本,开启 ack=all 模式,每 1 秒刷一次磁盘。一条消息要经历 Client --> Leader →Replica 这个过程。leader 等待所有的 replica 的 ack 应答,然后 ack 给 Client 端,整个过程多次确认;ack 失败的消息,会再次重试,此模式能保证数据不丢失。要想达到此种消息级别,请务必按照架构组提供的最佳实践进行配置(kafka 不同版本间参数相差很多)。

  • 消息传递有三种模式,kafka 同步发送是 At least one 模式(0.10 版)。消费端,要做幂等处理。可能产生重复消息的场景为:生产端发送了消息到 leader 节点,leader 节点同步到所有 follower 节点并得到确认,此时 leader 节点当机,未将 ack 返回给生产端,生产端此时会尝试重发消息。然后 follower 节点中某台机器提升为 leader,重复的数据由此产生。

扩容,故障的影响

  • 单节点当机,短暂影响生产消费,故障恢复时间与 leader 选举时间与 partition 数量有关(约 10 秒 isr 探测时间)。使用 ACK 模式,配合重试,能够保证故障期间数据不丢失。上图的 2 位置。

  • 扩容,等同于节点上线,不影响使用方。但节点到达可用状态,与整体落后数据量相关(简单的网络拷贝过程)。根据经验,部分消息拉取时间会变长,但影响不大。压测过程无明显抖动。建议消费端设置较长的超时来进行处理(包括异步处理情况)。上图的 3 位置。

  • >=2 节点当机(机房断电等),服务不可用。故障恢复需要两个节点达到同步状态,与整体数据量相关。磁盘每秒 fsync,极端情况(全部当机),最多会丢失 1 秒数据。


什么时候会丢数据

  • 使用 batch 模式发送,缓冲区有数据时没有优雅关闭,此时缓冲区中数据会丢失。上图 1 位置。

  • 使用 batch 模式消费,拉取消息后,异步使用线程池处理,如果线程池没有优雅关闭,此时消费数据会丢失。上图 4 位置。


风险

  • 压测 TPS 仅作参考,实际运行中受网络延迟,坏盘、高低峰流量等影响,服务会有抖动。生产和消费端务必将所有处理失败的消息进行记录,以便极端情况下进行数据回放。

  • 消息中请勿传递大块不必要数据,消息大小对服务质量有直接线性影响。(请保持消息 <2kb)

  • 消费端消费,除考虑幂等,不正确的异步线程池使用(比如使用了无界队列),经常造成消费端故障,请谨慎消费。

  • 如分配了 6 个 partition,如果你有 7 台消费机器,其中有一台会是空闲的。设计时请考虑 kafka 的限制。

  • 默认 kafka 生产端开启了 batch 提交模式,也就是说,如果此时你的生产者当了,buffer 中的消息会丢。请确保:生产者使用 "kill -15" 杀进程以给服务 flush 的机会;同时,如果你的消息很重要,请同时写入到日志文件中。 请权衡利弊再确认使用。


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
JAVA开发工程师
手记
粉丝
4555
获赞与收藏
3234

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消