【Free Style】kafka 解密:破除单机topic数多性能下降魔咒(下)

步步清风 发表于 2017/11/24 18:18:22 2017/11/24
【摘要】 kakfa大规模集群能力在前面已给大家分享过,kafka作为消息总线,在支撑云千万tps上千节点的集群能力非常出色,本文继续对业界关于单机多topic的性能瓶颈点问题,国内某云使用RocketMQ,性能对比唱衰kafka 64分区时出现性能拐点,为此我们表示不服,从理论到实测数据,一步步揭开所谓单机性能拐点的秘密及解决之道。

3.2.4    客户端分析

3.2.4.1 Consumer客户端

Consumer客户端,使用的是Scala的客户端。

多硬盘,单分区下,JProfile如下:

image.png

400分区如下:

image.png

3000分区如下:

image.png

 

3000分区的时候,可以看到,97.8cpu时间被用来执行了parseFull这个函数,这个函数是创建Streams的时候,对从zk获取的json文件进行解析,每次只执行一次。

但是由于分区越多,这个文件越大越复杂,导致执行时间非常长,影响了ConsumerTPS

由于这个函数只执行一次,不会大量被执行,所以当Consumer运行时间越长,那么影响会越小。

3.2.4.2 Producer Scala客户端

最开始使用Scala客户端的测试,发现多分区下,大量的时间被消耗在日志打印参数的format函数上:

25分区:

image.png

这里的代码,会在分个消息发送的时候,对分区的MAP循环执行如下的函数,这个代码里面会多次拼接字符串很耗时。

通过屏蔽日志打印函数,避免执行format,可以大大提升TPS

    partitionMetadata.map { m =>

      m.leader match {

        case Some(leader) =>

          //debug("Partition [%s,%d] has leader %d".format(topic, m.partitionId, leader.id))

          new PartitionAndLeader(topicm.partitionIdSome(leader.id))

        case None =>

          //debug("Partition [%s,%d] does not have a leader yet".format(topic, m.partitionId))

          new PartitionAndLeader(topicm.partitionIdNone)

      }

    }.sortWith((st) => s.partitionId < t.partitionId)

那两句debug信息打印注释掉,能大大的提升TPS

估计还有其他的瓶颈点,之后我们将测试客户端切换到了java客户端。

3.2.4.3 Producer Java客户端

多硬盘一分区下,客户端的情况(ACK=1):

 image.png

多硬盘5000分区下,Producer客户端(ACK=1):

image.png

多硬盘5000分区下,Producer客户端(ACK=0

image.png

我们可以看到,分区数量越大,send函数耗时越长,5000分区下,耗时大半。

ACK=0的时候,客户端是不需要等待server的响应的,可以说基本上客户端的TPS和服务器端没有关系,但是,TPS照样降低,send照样消耗大量的时间。

所以,我们判断,多硬盘下,当分区达到5000以上的时候,瓶颈在客户端代码上,可以通过优化客户端代码来提升性能。

4     分析结论

4.1   结论

一、单Broker的分区,主要受以下几个方面的瓶颈限制:

1、 OS限制:Kafka代码中没有对分区做限制,但是分区数量受到OS的文件句柄的数量限制。可以用ulimit –a查看。需要调整该数目到一个较大的值。

2、 文件系统(磁盘刷盘):单硬盘下,磁盘IOutil会随着分区数目增大而增大,导致Kafka的性能会下降。

主要原因:

刷盘是一个很昂贵的操作,虽然OS提供了Group Commit和排序等优化机制,但是当分区数量太多之后,无法完全消除影响。每个分区写入是磁盘顺序写,但是多个分区同时顺序写入在操作系统层面变为了随机写入。

另外,当Pagecachedirty数据达到一定限制之后,刷盘操作会阻塞应用的write操作,也会带来影响。

3、 客户端瓶颈:

通过追加硬盘可以解决单硬盘下的文件系统瓶颈。但是当达到5000以上,客户端会成为瓶颈。

这个是由于发送消息的时候需要获取Topic下的分区信息而产生的。

实际生产中,这个限制的影响应该不大,因为不会在1Topic下划分太多的分区,而是会有多个Topic,每个Topic下有一些分区。测试的时候为了测试方便,采取了一种比较极端的测试方法(单个Topic下挂上数千的分区)。

当有需要的时候,也可以考虑优化。

建议分区数量:

1、单台服务器单硬盘下,推荐值1000,最好不超过2000

2、单台服务器多硬盘下(7个),推荐值3000,最好不要超过5000。(当分区被分散到多个Topic的时候,这个值会更高,预计至少可以达到7000以上)。


二、集群(多节点)的分区限制:

理论上是随着节点增加而线性增加。但是实际还是受到Zookeeper的影响。节点最大支持数量估计在1wzookeeper的限制)左右,那么整个集群分区的支持估计在百万左右(但是实际上受网络速度的影响,分区越大,存放在zookeeper的数据量越多等各种因素影响肯定会有个折扣)。

预计10w左右的分区支持问题不大。

1)        参考LinkedInKafka集群部署规模:

http://www.slideshare.net/miguno/apache-kafka-08-basic-training-verisign

image.png

2)   在这篇文章中,提到曾经在单broker上使用了上万的分区。

http://www.confluent.io/blog/how-to-choose-the-number-of-topicspartitions-in-a-kafka-cluster/

image.png

4.2   社区意见参考

这里,kafkacommitter有很明确的答复,基本上和我们验证的结果一致:

http://www.quora.com/How-many-topics-can-be-created-in-Apache-Kafka

image.png

image.png

有几个主要观点:

1、 Kafka的分区数量两个因素的影响:文件系统和zookeeper

2、 实际应用中,分区数量不应该成为一个问题。分区的数量在实际中应该随着消费者数量扩展,不应该根据Data的特征来扩展。

4.3  解决方案

针对目前的几个瓶颈的解决方案如下:

1、 OS限制:通过调整Server的支持文件数目的句柄来解决。

2、 文件系统(磁盘刷盘):通过追加硬盘或追加Broker Node的方式来解决。

单个硬盘支持的分区数量推荐1000。多个硬盘:N*1000

3、 客户端:当一个Topic下有过多的分区的时候(>3000),客户端预计会成为瓶颈。

如果有这种需求,可以考虑优化客户端来解决这里的瓶颈。

image.png

5     备注

5.1   参考资料

5.1.1    Cloudera配置Kafka的建议

http://blog.cloudera.com/blog/2015/07/deploying-apache-kafka-a-practical-faq/

非常好的实际经验。

http://blog.cloudera.com/blog/category/kafka/

是否应当为Kafka Broker使用 固态硬盘 (SSD)

实际上使用SSD盘并不能显著地改善 Kafka 的性能,主要有两个原因:

·         Kafka写磁盘是异步的,不是同步的。就是说,除了启动、停止之外,Kafka的任何操作都不会去等待磁盘同步(sync)完成;而磁盘同步(syncs)总是在后台完成的。这就是为什么Kafka消息至少复制到三个副本是至关重要的,因为一旦单个副本崩溃,这个副本就会丢失数据无法同步写到磁盘。

·         每一个Kafka Partition被存储为一个串行的WALWrite Ahead Log)日志文件。因此,除了极少数的数据查询,Kafka中的磁盘读写都是串行的。现代的操作系统已经对串行读写做了大量的优化工作。

如何对Kafka Broker上持久化的数据进行加密 

目前,Kafka不提供任何机制对Broker上持久化的数据进行加密。用户可以自己对写入到Kafka的数据进行加密,即是,生产者(Producers)在写Kafka之前加密数据,消费者(Consumers)能解密收到的消息。这就要求生产者(Producers)把加密协议(protocols)和密钥(keys)分享给消费者(Consumers)

另外一种选择,就是使用软件提供的文件系统级别的加密,例如Cloudera Navigator EncryptCloudera Navigator EncryptCloudera企业版(Cloudera Enterprise)的一部分,在应用程序和文件系统之间提供了一个透明的加密层。

Apache Zookeeper正成为Kafka集群的一个痛点(pain point),真的吗?

Kafka高级消费者(high-level consumer)的早期版本(0.8.1或更早)使用Zookeeper来维护读的偏移量(offsets,主要是Topic的每个Partition的读偏移量)。如果有大量生产者(consumers)同时从Kafka中读数据,对Kafka的读写负载可能就会超出它的容量,Zookeeper就变成一个瓶颈(bottleneck)。当然,这仅仅出现在一些很极端的案例中(extreme cases),即有成百上千个消费者(consumers)在使用同一个Zookeeper集群来管理偏移量(offset)

不过,这个问题已经在Kafka当前的版本(0.8.2)中解决。从版本0.8.2开始,高级消费者(high-level consumer)能够使用Kafka自己来管理偏移量(offsets)。本质上讲,它使用一个单独的Kafka Topic来管理最近的读偏移量(read offsets),因此偏移量管理(offset management)不再要求Zookeeper必须存在。然后,用户将不得不面临选择是用Kafka还是Zookeeper来管理偏移量(offsets),由消费者(consumer)配置参数 offsets.storage 决定。

Cloudera强烈推荐使用Kafka来存储偏移量。当然,为了保证向后兼容性,你可以继续选择使用Zookeeper存储偏移量。(例如,你可能有一个监控平台需要从Zookeeper中读取偏移量信息。假如你不得不使用Zookeeper进行偏移量(offset)管理,我们推荐你为Kafka集群使用一个专用的Zookeeper集群。假如一个专用的Zookeeper集群仍然有性能瓶颈,你依然可以通过在Zookeeper节点上使用固态硬盘(SSD)来解决问题。

Kafka是否支持跨数据中心的可用性

Kafka跨数据中心可用性的推荐解决方案是使用MirrorMaker。在你的每一个数据中心都搭建一个Kafka集群,在Kafka集群之间使用MirrorMaker来完成近实时的数据复制。

使用MirrorMaker的架构模式是为每一个逻辑topic在每一个数据中心创建一个topic:例如,在逻辑上你有一个”clicks”topic,那么你实际上有”DC1.clicks”“DC2.clicks”两个topic(DC1DC2指得是你的数据中心)DC1DC1.clicks中写数据,DC2DC2.clicks中写数据。MirrorMaker将复制所有的DC1 topicsDC2,并且复制所有的DC2 topicsDC1。现在每个DC上的应用程序都能够访问写入到两个DC的事件。这个应用程序能够合并信息和处理相应的冲突。

另一种更复杂的模式是在每一个DC都搭建本地和聚合Kafka集群。这个模式已经被Linkedin使用,Linkedin Kafka运维团队已经在 这篇Blog 中有详细的描述(参见“Tiers and Aggregation”)

5.1.2    大数据领域的架构图

http://www.blogbus.com/navigating-logs/272257444.html

5.1.3    源代码High level分析

http://ju.outofmemory.cn/entry/124628

5.1.4    Kafka的配置推荐

http://bbs.chinacloud.cn/archiver/showtopic-29836.aspx

http://liyonghui160com.iteye.com/blog/2163899

5.1.5    Zookeeper的讨论

http://bbs.chinacloud.cn/archiver/showtopic-29836.aspx

 重要的记录: 

5.1.6    Kafka跨集群同步方案

http://jingyan.baidu.com/article/8065f87fea4d3a233124989f.html

http://tangzhaohui.net/post/524

5.1.7    实践部署与使用apache kafka

http://blog.csdn.net/zhongwen7710/article/details/41252649

5.1.8    Apache Kafka 重温文件高效读写

http://calvin1978.blogcn.com/articles/kafkaio.html

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区),文章链接,文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:cloudbbs@huaweicloud.com进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。