读kafka生产端源码,窥kafka设计之道(下)

背景

在上一篇文章《读kafka生产端源码,窥kafka设计之道(上)》 留下了kafka设计上比较优秀的一个点;内存的循环使用。本篇文章准备盘盘它。

好奇

为什么 kafka减少发送消息时向JVM频繁申请内存,就可以降低JVM GC的执行次数?

我们知道网络上传输的都是二进制数据;而在java中想通过socke网络套接字接口发送数据,底层都是用的ByteBuffer。在往网络上发送数据前,先申请块ByteBuffer的内存;然后把数据写入到此ByteBuffer内存中;调用底层socket的write接口,就OK了;大概伪代码流程

java 复制代码
   //伪代码
   //申请内存
   ByteBuffer buffer = ByteBuffer.allocate(size)
   //内存里加入数据
   buffer.put(XXX)
   //发送数据
   SocketChannel.write(ByteBuffer src)

ByteBuffer占用的内存,什么时候会被回收了?

答:在jvm进行GC时会被回收;

试想如果上面那段代码执行非常频繁,创建ByteBuffer就会很频繁;创建ByteBuffer很频繁,那么申请内存就会很频繁,申请内存越频繁,内存被占满的时间也就会越来越短,内存满了就只能靠不停的GC进行内存的回收,加以重复使用了。而现代JVM里GC的发展目标之一,就是减少GC的停顿时间。GC优化大师从PS,CMS,G1,到ZGC,都在朝这这个方向在努力。

kafka如何解决这个内存频繁申请和GC 频繁释放的问题了?

如果可以用一句简单的话来总结:那么我想应该是 对ByteBuffer的重复使用。 是的用完了不要丢,也不让jvm 给GC了。 即对进行了网络发送的ByteBuffer进行复用;如果有新的消息要发送,可以从缓存池里获取已有 ByteBuffer;然后往里面写入消息数据;当IO线程把ByteBuffer里的消息发往broker并收到对应的响应后,会把ByteBuffer放回缓存池供下一次需要发送的消息循环使用。
大概流程如下图:

核心参数和代码

有两个核心参数,可以控制缓存池BufferPool的行为

  • buffer.memory

    缓存池大小,默认32M。如果IO thread发送消息 的速率比业务线程生产消息 的速度,则会引起业务线程的阻塞,可根据实际情况和jvm大小增大此参数

  • batch.size

    控制每个缓存块ByteBuffer的大小,默认为16K。即一个 BatchRecord里可存的多条消息最大空间

  • ByteBuffer的申请

  • ByteBuffer的回收

总结

如果要编写一款网络应用程序,或者网络框架的工具,我希望能向kafka一样,能考虑到内存的复用;并且减少对上层应用的影响。

假设一个应用通过kafka发送50个G的网络数据;那么kafka的缓存池,就节约了10个G内存的申请和回收;由此减少了多少次GC和GC暂停时间了。那么假设有个50个这样的应用了?总的收益又是多少了?
不是所有的工具都能号称是为应对大数据场景而产生的;kafka做为一款中间件,能比较好的融入大数据生态,kafka的研发人员有自己的独特设计和考虑在支撑这它。

原创不易,请 点赞,关注,留言,转载 4暴击^^

相关推荐
97zz2 小时前
项目配置文件正确但是启动失败,报配置文件内容错误或中间件地址与实际不符
java·中间件·springboot
渣渣盟2 小时前
Flink从Kafka读取数据的完整指南
flink·kafka·scala
小傅哥4 小时前
【分享】拼团交易平台系统,分布式、高并发、微服务
分布式·微服务·状态模式
九河云4 小时前
电商直播流量爆发式增长,华为云分布式流量治理与算力调度服务的应用场景剖析
分布式·科技·华为云·电商·传统
归梧谣8 小时前
部署Zabbix企业级分布式监控
分布式·zabbix
wuxuanok9 小时前
八股——Kafka相关
java·笔记·后端·学习·kafka
oraen9 小时前
kraft的设计与实现
java·kafka
工藤学编程12 小时前
深入浅出 RabbitMQ:简单队列实战指南
分布式·rabbitmq·ruby
工藤学编程13 小时前
深入浅出 RabbitMQ:工作队列实战(轮训策略VS公平策略)
分布式·rabbitmq
xujinwei_gingko15 小时前
项目架构演进
分布式·微服务·架构