乐趣区

关于java:高CPU消耗这次又是lettuce的锅

起源于 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();}

    }
}

打完出工,留念第一篇正儿八经的博文。

退出移动版