您的位置:首页 > 运维架构 > 网站架构

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

2021-02-04 22:00 609 查看

微信公众号排版或有问题,请点击查看原文获得更好体验

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

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

测试目标

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

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

  • 测试环境

broker:

3
台机器

8
core

16G

1T
SSD

Centos

6.8

kafka_2
.
12
-
0.10
.
2.0

broker jvm
参数配置:
Xms
=
8G

Xmx
=
8G

client:

8
core

16G

Centos

6.8

测试场景
集群高可靠性配置:

zookeeper.connection.timeout.ms=15000
zookeeper.session.timeout.ms=15000
default.replication.factor=3
num.partitions=6
min.insync.replicas=2
unclean.leader.election.enable=false
log.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

测试结果
不限制并发吞吐量

/kafka-producer-perf-test.sh --topic test003 --num-records 1000000 --[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.409s
user 0m14.544s
sys 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

12 分区,2.6w 吞吐量

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 的机会;同时,如果你的消息很重要,请同时写入到日志文件中。 请权衡利弊再确认使用。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: