如果真的要回忆关于印象深刻的bug,可能就要追溯到我刚实习的时候。而之所以那么深刻,可能是源自初入社会那份求知的信,亦或者是那时候遇到的人,对我如今选择的这条路影响深远。
故事
2017年,实习,大数据组。
对于二三线城市来说,很多公司的计算机实习岗位,约等于无门槛免费劳动力。当然,我也不例外,在大数据实习的前两个月,除了整理工作文档,就是自己悄摸摸的学习。后来在机缘巧合之下,以运维的角色接触到了一个数据接入的项目。
程序主要分为三个部分:TCP数据接入、数据解析、写kafka。当时的问题就是程序启动之后,运行一段时间就内存溢出,进而造成的结果就是TCP阻塞以及数据量核对不上。当时怀疑是解析这部分的代码性能效率不高,因为解析这一块比较复杂,每条数据平局100个字段,每个字段都要根据规范中的字节长度和数据类型,将二进制转换成明文数据。
所以当时看他们就是铆足了劲,如何去优化解码逻辑。后来就来了一位大佬,就用jvisualvm定位出了问题所在:因为当时平台都是集中化建设,Hadoop还是1.x版本,所以kakfa也是0.8版本,正因为kafka版本太低,写入效率太慢,虽然整个程序占用cpu过高,但实际上二进制数一直阻塞在程序的queue中,最后导致内存溢出。
后来找到问题之后,在Hadoop2.x建设阶段,将kafka升级到了0.10版本,就解决了这个问题。当时自己空有jvm的理论知识,后来在这次经历中也算是将理论映进了现实,所以到至今都印象深刻,现在也特别推崇通过jvm来分析程序性能的方式。所以,本篇文章就主要大概复现上述问题,看看如何使用jvisualvm来分析程序性能问题。
问题复现
为了复现上面的问题,原来程序的TCP数据接入、数据解析、写kafka三个部分,我分别进行了简单的代码替换。首先我们定义数据接入的模块,这里主要模拟数据写入queue的一个过程。
private static final ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();
public static void dataReceive() {
String data = "data";
for (; ; ) {
// 生产数据并放入队列
queue.add