(线上问题系列一)百万并发的Kafka也有效能问题?
问题现象:一核心系统在一天早上高峰期出现API时延巨大的情况,由于我们API保持每日大概2-3亿左右的请求,平均时延一般保证在0.1秒中内(物联网系统没有关联表,不用惊讶)。监控系统表现平均时延到了1.5秒,报警是响个不停,有少量使用者也投诉了。Java系统先怎么处理,你们懂的(重启!!有负载不怕),当然要保留现场(每次重启都会自动生成),留下请求日志,当时的执行绪Dump,内存Dump。如下:

重启后恢复0.1秒左右,但30分钟后,又出现同样的问题,不能再重启了。简单分析后,感觉系统有瓶颈。紧急导流到另外一个机房,我们是做了同城双活的(平时是9:1的比例),马上改为(5:5),后面一直没有出现这个问题了。
问题分析:
1、分析数据库当时的情况(正常)。
2、分析服务器IO,CPU情况(正常)。
3、快取、Nginx效能正常。
4、看看内存Dump........初看正常,如下:


就只有kafka的一个Client类占用了34M左右,看起来也不是很大(百发并发的kafka不可能有效能问题的),也没有明显FULL GC,但本着怀疑精神去执行绪栈找了一下这个类。发现有几百个执行绪都在这儿出现waiting on condition(等资源),并且都和这个类相关。

很显然,问题就在这儿了,那为什么呢?所以不是kafka问题,应该只是Client的使用问题。
问题原因:
看了一下Java源代码原来和buffer.memory引数有关:
解释:指定producer端用于快取讯息的缓冲区的大小,单位是字节,预设32M,采用异步传送讯息的架构,Java版Producer启动时会首先建立一块内存缓冲区用于储存待发送讯息,然后由另一个专属执行绪负责从缓冲区中读取讯息执行真正的传送,这部分内存空间的大小就是由buffer.memory引数指定。该引数指定的内存大小几乎可以认为是producer程式使用的内存大小,若producer程式要给很多分割槽传送讯息,那么就需要仔细设定该引数防止过小的内存缓冲区降低了producer程式整体的吞吐量。
现象快取34M>预设32M,所以就开始等待了,然后这个client又没有异步处理,就产生了阻塞,界面就明显变慢了。
解决方法:
1、扩容,简单粗暴。(临时方案)
2、API中把Producer改为多执行绪,多增加几个Producer.(推荐方案)
3、把预设32M增大,不建议,因为有可能已经处理不过来了,但如果只是高峰才有这个问题,是可以这样的。
所以kafka还是牛逼的。