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

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

背景

Kafka 到底能够应用在高可用的业务上?官方给出的答案是肯定的,最新版,已经支持消息队列的事务,但我们对其性能是有疑问的。

Kafka 根据配置的 ACK 级别,其性能表现将特别大,为了找到其适用场景,特做此测试,以便应用 kafka 时能够灵活应对。

测试过程还探讨了许多丢消息的场景。相对于大多数仅仅针对 kafka 集群本身的测试,本测试还介绍了丢消息的业务场景。整个方案应该是一个整体,才能够达到最高级别的高可用,不因该区别对待。

测试目标

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

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

测试环境

broker:

client:

测试场景

集群高可靠性配置:

ack

消息大小:1024byte

failover 测试

测试方法

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

测试过程

第二阶段期间,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 结论

压力测试

测试方法

测试脚本:

测试结果

不限制并发吞吐量

限制吞吐量 1w

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

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

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

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

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

订阅微信公众号,小姐姐,教你玩架构~

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180629G0AHG200?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券