一次线程池有关的性能调优之旅
来源:互联网 发布:怎么给淘宝刷好评赚钱 编辑:程序博客网 时间:2024/05/18 03:56
最近在做的项目,在调试时打开了top,发现CPU一直是90%以上的,这让我们感觉奇怪。一般来说写得好的程序,CPU不应该满负载运行。大家决定查找原因。
1、总共有3个大模块,每个模块都是由Quartz定时器触发。所以每次只开放一个,屏蔽掉其他两个。结果发现,本人和大师写的模块单独运行时CPU都很高
2、刚好那晚是周五,其他人都满怀激动的心情迎接周末,我们一直搞到9点半,排查问题。这个过程也是挺曲折的。首先想了一下程序中哪些地方会耗资源。db连接?db写入?
Socket通讯?线程池?当晚没有找出问题。
3、时间来到了周末,继续在宿舍中探索此问题。我的模块共有3个主要的job,从这里入手。
<ref bean="loadMessageJobTrigger" /> a
<ref bean="updataMongoJobTrigger" /> b
<ref bean="threadPoolJobTrigger" /> c
先只开了a,这是个从MongoDB读取数据到队列的job,一次1w条。运行时cpu稳定在20%,不是这里的问题;
只开b,这是个批量写入MongoDB的job,一次最多也就写1k,也不是这里的问题;
开了a和c,一下子就90%了,看来是c的问题。这是一个用job来启动线程池,定义了一个pool,在while(true)中,判断有空闲thread就添加任务。这里大师在群里说他已经找到是死循环的问题。若非我的也是了。
while (true) { if (normalFutures.size() == poolSize) { tmpFutureList = new ArrayList<Future<ConsumeMessageThread>>(); for (int i = 0; i < poolSize; i++) { // 1 future = normalFutures.get(i); if(! future.isDone()) { tmpFutureList.add(future); } } normalFutures = tmpFutureList; }else { // 2 ConsumeMessageThread msgThread = (ConsumeMessageThread) BeanHoldFactory .getApplicationContext() .getBean("consumeMessageThread"); map = MessageContainer.waitForPushQueue.poll(); ...... msgThread.initMap(map, newSerialId); future = (Future<ConsumeMessageThread>) exService.submit(msgThread); normalFutures.add(future); }while(true)中大致如上。如果task总数已经等于线程池中thread数量,就进入1中判断是否有没做完的task,有就放到临时的list中。如果task不满,get一个bean,带上数据,提交到pool中。我先把所有代码都注释,空跑while(true),发现cpu不高。想到可能是task处理中耗资源。我的ConsumeMessagThread中包含了httpClient的代码。便把这几段注掉
client = HttpClients.createDefault();post = new HttpPost(url);post.setHeader("Content-Type", "text/html;charset=UTF-8");ByteArrayEntity e = new ByteArrayEntity(json.getBytes("UTF-8"));post.setEntity(e);response = client.execute(post);
再跑,cpu正常。就是这几段的问题了吧。由于这是一个关于消息推送的项目,数据量会很大,必须要快速地把数据推送给三方接口,所以在一个dead loop中不停使用httpclient。client和post要频繁创建并且excute,这是消耗资源的。于是在外层用了一个int变量来记,当循环1000次,就sleep(100)。发现在sleep期间cpu下降了,但是做1000次的期间,cpu照样100%,呈锯齿状波动。看来一次性执行太多httpclient还是不行。把1000改小,波动则小一些。没意思,无论cpu再高,也要成为一条平稳的线才好。那只能dead loop的最后加sleep,不要凑够1000了。这样子就是每个task都会sleep,而不再是任由瞬间的执行,发送速度上也做了妥协。比如说加了sleep(5),理论上的最快速度也只能是200个/s,但是cpu平稳,在i7 4720HQ上平均十几而已。不加sleep,可能是好几百,但是cpu满载。后期这种速度应该是达不到要求了。到时再考虑集群什么的来buff了。集群的话,从数据源做好入口控制,保证不同server发送不同的数据即可。
(注:有个误区就是之前以为空跑while(true)时cpu很低,以为不是死循环的问题。其实是错误的。如果一点代码都不写,几乎不占资源的,但是如果只写一行system.out.print,也是100%)
- 一次线程池有关的性能调优之旅
- 一次性能峰值提升10W的DB调优之旅
- JVM 性能调优实战之:一次系统性能瓶颈的寻找过程
- JVM 性能调优实战之:一次系统性能瓶颈的寻找过程
- JVM 性能调优实战之:一次系统性能瓶颈的寻找过程
- JVM 性能调优实战之:一次系统性能瓶颈的寻找过程
- JVM 性能调优实战之:一次系统性能瓶颈的寻找过程
- JVM 性能调优实战之:一次系统性能瓶颈的寻找过程二
- 一次性能调优的实战
- 一次性能调优的实战
- 一次性能调优的实战
- 一次性能调优的实战
- 一次性能调优的实战
- 有关性能调优的博客
- SQL性能调优之Insert语句干扰了正确的执行计划的一次记录
- Lock锁,一次唤醒所有线程低性能的问题
- 一次MYSQL 服务器性能优化之旅
- 关于多线程编程您不知道的 5 件事 有关高性能线程处理的微妙之处
- python GUI编程(Tkinter)
- CDH5.5自行编译支持sparkSQL,sparkR
- 手机网站打电话链接等
- VS2013编写嵌入网页的ATL控件1-新建和配置
- “段错误”定位及调试的一点经验
- 一次线程池有关的性能调优之旅
- iOS - 程序调试模拟器能通真机则不行
- JAVA反射机制
- Android常见知识点
- 图像处理之错切变换
- iOS—UIFont设置字体
- Ⅰ.19 如何实现自动化批量测试
- ios 键盘用多种方式都无法收起的问题
- 关于API接口