起源于Thread.sleep
最近在零碎调优过程中遇到一个比拟有意思的高CPU耗费的问题(过后CPU使用率曾经到90%左右),先上图感受一下。
是的,就是Thread.sleep这个办法,耗费了大略34%的CPU,而且久居不下。其实第一眼看到这玩意儿我是懵的,啥玩意儿。
心里暗骂了开发xxx遍,这nm是哪个没脑子的开发sleep的时候用的纳秒,事实证明我错了(其实也是因为本人平时撸代码比拟少,对lettuce不是很熟,因为过后并不知道是lettuce导致的),向咱们勤勤恳恳的dev赔罪,瑞思拜。
开始找“BUG”
OK,言归正传,问题还是要好好剖析的。终于在线程dump中发现了突破口,找到了这个线程:
而后通过这个线程我找到明天的配角,有请lettuce闪亮退场。
到这里,晓得是lettuce搞的鬼,但我对lettuce并不熟啊,老老实实温习英语。
lettuce官网文档(https://lettuce.io/core/5.3.7...)
在官网文档中发现了这个:
lettuce的延时监控性能默认是开启的,在内存dump中,也能够看到相干的属性为true:
简略介绍一下延时跟踪性能,具体参见官网文档:
- 依赖LatencyUtils模块
- 能够统计执行次数
- 第一次响应的提早(min, max, percentiles)
- 命令执行完的提早(min, max, percentiles)
- 命令提早统计能够1、按主机和端口或套接字门路辨别(不辨别命令),2、按命令类型(GET、SET、...)跟踪
延时监控能够通过配置进行敞开,官网文档中有示例如下:
ClientResources res = DefaultClientResources .builder() .commandLatencyCollectorOptions( DefaultCommandLatencyCollectorOptions.disabled()) .build();RedisClient client = RedisClient.create(res);
到这边根本能够给优化倡议:在非必要的状况下,间接敞开该性能。
除了这个办法,临时想不到其余解决办法。
依据之前的形容,Time.sleep()是在LatencyUtils模块下的调用到的,为了满足本人的好奇心,间接看了一下LatencyUtils相干的源码。
源码地址:https://github.com/LatencyUti...
能够看到默认sleep的工夫是1毫秒
线程sleep为什么耗费CPU
这边阐明一下,其实挂起的线程是不会耗费CPU资源的,耗费资源的是频繁的唤醒和sleep。sleep会导致线程上下文切换和额定的零碎耗费,类似的其实还有LockSupport.park()
。上面是sleep的demo(对于park的小伙伴能够本人整一个玩玩),感触下散热风扇的怒吼(线程数量越多,CPU耗费越多):
public class HighCPU { public static void main(String[] args) { int threadCount = 100; final List<Thread> list = new ArrayList<>(threadCount); for(int i =0; i<threadCount; i++){ Thread thread = new Thread(()->{ while(true){ try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } }); thread.setName("cpuThread" + i); list.add(thread); thread.start(); } }}
打完出工,留念第一篇正儿八经的博文。