前两天,突然收到了QA的反馈,我跑程序的storm集群(20多台)所有机器CPU居高不下。这就让我非常莫名其妙了,我的程序在最近一次上线以后,已经连续运行了3天了,怎么会突然就有问题了呢?
这时,我还是感觉程序不会有问题的,要不然怎么会正常运行了3天呢。。。因此我就对程序进行rebalance(为什么要这么做呢?我也不知道,就好像电脑有问题了重启就行了。。。)以及重启操作,但是都无济于事,程序在跑一会以后,就出现了CPU利用率很高的情况。
我找QA老大亮哥说明了程序跑了3天,程序应该没有问题,应该是环境的问题,但是他却告诉我,应该是有死循环导致的这种情况,而我却对他的说法抱怀疑的态度,,,然后就去看各种storm的log没有发现异常的东西,然后就看了我近几次的代码提交,也没有发现while(true) 这样的死循环。
然后,又查看了机器的详细监控,发现了在CPU升高的那一刻,网络IO、连接数、内存全部都降了,我逐渐感觉亮哥的推测是正确的。然后就开始了对进程分析的过程。
好了,废话不说了,直接上过程。
Step1: jstack
首先使用top命令查看占用CPU高的进程的id,发现有很多,果然是storm的,随意选一个pid;使用jstack命令查看线程状态,保存数据到stack.log中,返回结果如下:
"BrokenConnectionDestroyer-33-1464012569600" daemon prio=10 tid=0x00007fe174040800 nid=0x9432 waiting on condition [0x00007fdfa6ae9000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x000000076175b998> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:158)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1987)
at java.util.concurrent.ArrayBlockingQueue.take(ArrayBlockingQueue.java:317)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:947)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)
at java.lang.Thread.run(Thread.java:662)
Locked ownable synchronizers:
- None
打出来的有3000多行,翻了一遍,没有看出来什么不正常的。。。
Step2:ps
ps -eL -o pid,%cpu,lwp|grep -i $pid
使用如上命令打出该pid中所有线程所占cpu的情况,打出结果如下(只贴出来关键的几行):
23323 0.0 25085
23323 0.0 27025
23323 52.3 27057
23323 0.0 28285
23323 48.9 28287
23323 0.0 28946
23323 53.2 28949
23323 0.0 29492
23323 51.8 29497
23323 0.0 29828
23323 0.0 29829
23323 5.5 29921
23323 0.0 29925
23323 0.0 29952
23323 0.0 30008
23323 0.0 30011
现在结果很明了了,可一眼看出来这几个线程特别忙,其他的都是那么清闲,那么罪魁祸首找到了。。
Step3:printf
printf 0x%x $27057
以Step2中的27057为例,将子线程id转为16进制,输出结果如下:0x1b91
Step4
在jstack.log中,搜索0x1b91这个线程号,果然有收获(由于当时保存的文件有问题,并不是真的这个线程号,但是结果一致),结果如下:
"Thread-13-UserInfoRecordConsumerBolt" prio=10 tid=0x00007fe2bcb0d000 nid=0x7339 runnable [0x00007fe244a56000]
java.lang.Thread.State: RUNNABLE
at com.jd.ad.user.jimDao.BaseJimUtilDao.addUserCartSkuKeyData(BaseJimUtilDao.java:280)
at com.jd.ad.user.jimDao.BaseJimUtilDao.addUserCartSkuKeyData(BaseJimUtilDao.java:128)
at com.jd.ad.user.dao.jim.impl.UserCartSkuInfoJimDaoImpl.addUserCartSkuInfoData(UserCartSkuInfoJimDaoImpl.java:13)
at com.jd.ad.user.service.impl.UserCartSkuInfoServiceImpl.addUserCartSkuInfoData(UserCartSkuInfoServiceImpl.java:28)
at com.jd.ad.user.service.impl.AdUserServiceImpl.addUserInfoRecordTask(AdUserServiceImpl.java:231)
at com.jd.ad.user.job.storm.UserInfoRecordConsumerBolt.execute(UserInfoRecordConsumerBolt.java:48)
at backtype.storm.daemon.executor$fn__3498$tuple_action_fn__3500.invoke(executor.clj:615)
at backtype.storm.daemon.executor$mk_task_receiver$fn__3421.invoke(executor.clj:383)
at backtype.storm.disruptor$clojure_handler$reify__2962.onEvent(disruptor.clj:43)
at backtype.storm.utils.DisruptorQueue.consumeBatchToCursor(DisruptorQueue.java:82)
at backtype.storm.utils.DisruptorQueue.consumeBatchWhenAvailable(DisruptorQueue.java:61)
at backtype.storm.disruptor$consume_batch_when_available.invoke(disruptor.clj:62)
at backtype.storm.daemon.executor$fn__3498$fn__3510$fn__3557.invoke(executor.clj:730)
at backtype.storm.util$async_loop$fn__444.invoke(util.clj:403)
at clojure.lang.AFn.run(AFn.java:24)
at java.lang.Thread.run(Thread.java:662)
Locked ownable synchronizers:
- None
显而易见,这里已经定位到了程序中的位置了,那么就应该去查看程序了,结构如下:
List<UserCartSkuItemInfo> oldSkuItemList = userCartSkuInfosBuilder.build().getSkuInfosList();
for (int i = 0; oldSkuItemList != null && i < oldSkuItemList.size();) {
UserCartSkuItemInfo item = oldSkuItemList.get(i);
if (item.getId() == userCartSkuInfoRecord.getSkuId()) {
userCartSkuInfosBuilder.removeSkuInfos(i);
break;
}
}
OMG,现在已经看出来结果了。。。。
i 变量一直是0 ...........................
目前为止,问题已经找到了。
现在再回头想一下,确实现象是跟这个吻合的:
为什么刚开始会正常运行了3天呢?
答曰:这个数据还没有正式接入,只有一些少量的测试数据,那么代码运行到这里的几率很小,所以没影响。而这一天恰好开始接入数据了,造成了这个问题的出现。而且,刚开始一个用户的数据也就只有一条,那么恰好两个id相等,跳出了循环。。可是数据积累以后,那么当i=0的时候,数据不想相等了,就进入死循环了。
还有一点,确实不能够按照以前运行的状态来判断,因为具体问题,具体分析。老鸟的很大优势,就是碰到的坑比较多,有经验了,,,所以,QA大哥刚开始就判定它为“dead loop”
分享到:
相关推荐
【Storm集群搭建】是关于构建分布式实时计算系统Storm的集群过程。Storm是一个开源的、用于处理实时数据流的计算框架,常被用于大数据处理、实时分析等场景。在Storm集群中,主要有两种类型的节点——主控节点...
Storm集群的部署和配置是构建实时大数据处理系统的关键步骤,本文将详细讲解这一过程。Storm是一个分布式实时计算系统,能够处理大规模数据流,确保每个事件都得到正确的处理。以下是搭建Storm集群的详细步骤: 1. ...
Storm集群环境搭建 Storm集群环境搭建是指在多台服务器上安装和配置Storm集群,实现高可用和负载均衡。Storm是一个分布式实时计算系统,能够对大量数据进行实时处理和分析。本文将详细介绍Storm集群环境搭建的步骤...
Storm集群安装部署步骤,一步一步记录了作者亲自实践部署的过程,包括遇到的错误解决办法
storm集群安装与运维.doc
今天接上文,来实现一个Storm数据流处理综合案例的第二部分,Storm集群向Kafka集群源源不断读取数据,通过MyBatis写入到MySQL数据库,并部署为远程模式 准备工作 参考上文准备工作 代码编写 思路:Storm集群从...
停止storm集群的过程相对简单,基本顺序与启动相反: 1. **停止UI**:如果已启动,先通过`storm kill ui`关闭Web界面。 2. **停止Supervisor**:在所有worker节点上执行`storm stop supervisor`命令,关闭...
### Storm集群部署知识点 #### 一、Storm集群简介 Apache Storm 是一款开源的分布式实时计算系统,它提供了简单而强大的API来处理无限的数据流。Storm的设计使其能够支持各种类型的流处理应用,包括实时分析、在线...
整个过程分为三个主要部分:Java环境(JDK)的安装、Zookeeper集群的配置以及Storm集群的具体安装。 #### 二、安装前准备 在开始任何安装之前,请确保已经做好以下准备工作: - **硬件准备**:至少三台物理或虚拟机...
在搭建Storm集群的过程中,我们需要以下步骤: 1. **环境准备**:确保安装了Java JRE和JDK,因为Storm是用Java编写的。同时,需要在所有参与集群的服务器上安装并配置好Zookeeper,它作为协调服务,管理Storm集群的...
### 从零开始搭建Storm集群 #### 一、概述 Apache Storm 是一款开源的大规模实时计算系统,类似于Hadoop处理批量数据,Storm处理的是实时数据流。它支持各种编程语言,能够实现高吞吐量、低延迟的数据处理,并且...
storm集群环境搭建文档
今天来实现一个Storm数据流处理综合案例的第一部分,Storm集群向Kafka集群源源不断写入数据,并部署为远程模式 准备工作 搭建三台Kafka集群服务器 参考文档:Linux部署Kafka集群 搭建三台Storm集群服务器 参考...
在本压缩包“storm集群搭建Java客户端测试代码.zip”中,包含了有关Apache Storm集群的搭建教程以及使用Java客户端进行测试的代码示例。Apache Storm是一个分布式实时计算系统,它允许开发者处理无界数据流,常用于...
02_流式计算基础_第1天 (Storm集群部署、单词计数、Stream Grouping).docx
### storm集群部署手册知识点梳理 #### 一、安装虚拟机 **知识点1:虚拟机软件与操作系统准备** - **软件需求:** - VMware Workstation 12:虚拟机管理软件。 - CentOS-6.5-x86_64-bin-DVD1.iso:64位操作系统...
Storm集群部署详细手册.docxStorm集群部署详细手册.docx
总之,Storm部署是一个涉及多个组件和配置的过程,理解其工作原理和依赖关系至关重要。通过以上步骤,可以成功搭建一个运行Storm应用的集群。在实际操作中,务必仔细检查每个环节,确保所有服务正常运行,从而实现...
storm的集群安装笔记,在我的虚拟机上安装的整个过程,所有注意点都写了。绝对好用