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

时间:2012-09-19 05:50:03

标签: java linux performance jvm cpu-usage

在对自行开发的网络应用程序进行分析时,我发现了非常奇怪的(至少对我来说)观察。

几乎所有时间都用在socketRead0()课程的SocketInputStream方法中。这并不奇怪,因为我的应用程序在每个请求上都使用远程服务进行联网。奇怪的是,此方法不仅挂钟时间使用率很高, CPU时钟时间也非常高。我无法理解为什么CPU时间很长,因为如果我的应用程序等待远程服务回复(实际上并不是那么快),那么应用程序本身就没有什么可做的了。所以CPU时间应该很低。

更多观察:

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

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

你怎么看?还有其他原因吗?

2 个答案:

答案 0 :(得分:0)

VisualVM显示加载不是绝对值而是相对值,因此它只是意味着您的应用程序没有任何耗费CPU的点。

我相信您应该将VisualVM配置为不深入钻取,而是将此方法调用计为代码(或弹簧)中方法的一部分。

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

答案 1 :(得分:0)

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

所以我决定做一个实验。我在返回之前制作一个带有api睡眠30s的模拟服务器,并且客户端调用此api。我的目的是在net io发生时测试线程状态。根据我的线程转储,线程状态为RUNNABLE

这解释了两件事:

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

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

  3. 这两个都会让你的cpu忙。

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