SocketInputStream.socketRead0()中CPU占用率高的原因

在分析本土networking应用程序的时候,我发现下面非常奇怪(至less对我来说)是观察的。

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

还有一些观察:

  • 在采样模式下的VisualVM显示,方法SocketInputStream.socketRead0()正在消耗高达95%的时间(挂钟时间 CPU时间);
  • mpstat (我们使用Linux作为操作系统)显示约90%的用户时间和约1-3%的系统时间(其余为空闲时间);
  • 应用程序部署在专用服务器上;
  • 远程服务也是HTTP Web应用程序。 平均响应时间约为100ms。 平均响应大小约为2Kb。
  • 我的应用程序使用spring RestTemplate与远程服务交互,而不是直接与SocketInputStream交互。

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

你怎么看? 有没有其他的原因呢?

Solutions Collecting From Web of "SocketInputStream.socketRead0()中CPU占用率高的原因"

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

我相信你应该配置VisualVM不深入深入,而是计数这个方法调用作为你的代码(或春天)的方法的一部分。

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

我面临同样的问题。 我的应用程序有一个非常高的qps和每个请求会让我发送多个节俭调用,这使用这个本地api: socketRead0

所以我决定做一个实验。 在返回之前,我使用一个api睡眠模拟服务器,客户端调用这个api。 我的目的是测试网络io发生时的线程状态。 根据我的线程转储,线程状态是RUNNABLE

这解释了两件事情:

  1. 高qps阻塞io的应用将面临高cpu负载值

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

这些都会让你的CPU很忙。

在实验中我注意到,系统空间的cpu利用率很低。 我认为这与jvm和os之间的线程调度策略差异有关。 我们知道热点线程模型是1:1,意思是一个线程到一个线程。 当发生阻塞IO时,如socketRead0 ,内核线程将设置为状态S ,不会阻塞CPU,但用户空间线程正在阻塞(等待)。 发生这种情况时,我认为我们需要重新思考应用程序中的基本I / O模型。