原因在SocketInputStream.socketRead0高CPU使用率()(Reasons

2019-07-31 16:27发布

虽然剖析自主开发的网络应用程序,我碰到下面很奇怪(至少对我来说)观察。

几乎所有的时间都花在socketRead0()一个方法SocketInputStream类。 因为我的应用程序做一个网络上每个请求远程服务,这并不奇怪。 什么奇怪的是,不仅挂钟时间使用率很高这种方法,CPU时钟时间也非常高。 我不明白为什么CPU时间很长,因为如果我的申请等待远程服务回复(这实际上不是那么快),没有什么做的留给应用程序本身。 所以CPU时间应该是明显偏低。

一些更多的观察:

  • VisualVM的在采样模式示出了方法SocketInputStream.socketRead0()是吃高达95%的时间(两个壁时钟时间 CPU时间);
  • mpstat (我们使用Linux作为操作系统)示出左右〜90%的用户时间和〜1-3%的系统时间(其余为空闲时间);
  • 应用程序部署在专用服务器上;
  • 远程服务是HTTP web的应用也。 平均响应时间是100ms左右。 平均响应大小约为2K位。
  • 我的应用程序使用Spring RestTemplate与远程服务,而不是互动SocketInputStream直接。

现在我只有一个想法-也许这就是调用JVM的本地方法的开销( SocketInputStream.socketRead0()是天然的)?

你怎么看? 是否有其他原因呢?

Answer 1:

VisualVM的显示负载不是绝对值,而是相对值,所以它只是意味着你的应用程序没有任何更多的CPU消耗点。

我相信你应该配置的VisualVM不钻在内心深处,和而算上调用此方法,因为这是在你的代码(或弹簧的)的方法的一部分。

我已经经历过这样的行为,但它并没有看起来就像是不需要任何优化。 Web应用程序只需简单地读取套接字数据(即HTTP请求,数据库,内部网络服务...)并没有帮助它。



Answer 2:

我面临着同样的问题。 我的应用程序有一个非常高的QPS并且每个请求都会让我发送多个节俭调用,使用原生API: socketRead0

所以,我决定做一个实验。 我就与一个API睡眠30多岁的模拟服务器返回之前和客户端调用此API。 我的目的是测试线程状态时的净IO发生。 根据我的线程转储,该线程状态为RUNNABLE

这说明两点:

  1. 应用具有高QPS阻塞IO将面临较高的CPU负荷值

  2. 你的java线程仍然在JVM上运行,因为线程状态是RUNNABLE这将有助于提高用户空间cpu利用率

这两个都会让你的CPU忙。

我注意到,在实验过程中,系统空间的CPU利用率很低。 我觉得这个东西涉及JVM和操作系统之间的线程调度策略的差异。 我们知道热点的线程模型是1:1,这意味着一个JVM线程一个操作系统线程。 当阻塞IO发生,如socketRead0内核线程将设置为状态S并且不会阻塞CPU,但用户空间线程被阻塞(等待)。 当发生这种情况,我认为我们需要重新思考的基本I / O模型在我们的应用程序。



文章来源: Reasons for high CPU usage in SocketInputStream.socketRead0()