【发布时间】:2015-08-01 13:21:26
【问题描述】:
我们有一个客户端服务器应用程序,1 个服务器,大约 10 个客户端。它们使用自定义查询通过 tcp 套接字进行通信。
系统已经平稳运行了好几个月,但是在某个时间点,在每天约 50 秒的预定服务器 FULL GC 之后,我们计算出客户端发送查询之间的时间从服务器收到的响应很大,> 10-20 秒。大约 3 小时后,系统恢复正常,一切正常。
在调查该问题时,我们发现:
- 客户端和服务器都没有垃圾回收问题
- 服务器上的查询处理时间很短。
- 服务器负载很高。
- 网络带宽未饱和。
- 在 FULL GC 期间未重置连接(在此之前,每日 FULL GC 是正常事件)
- 机器和操作系统最近从 Centos 6(内核 2.6.32)更改为 Centos 7(内核 3.10.0),但新配置经过了广泛的测试。 Oracle JDK 版本也从 1.7.65 更改为 1.7.75。
我们在服务器上进行了线程转储:
java.lang.Thread.State: RUNNABLE
at java.io.FilterInputStream.read(FilterInputStream.java:83)
at util.network.BytesBasedSocketConnection$ReadConnectionRunnable.run(BytesBasedSocketConnection.java:293)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:178)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:292)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
FilterInputStream.read() 如下:
public int read() throws IOException {
return in.read();
}
我们代码中的in 是BufferedInputStream。
问题是:为什么在 Full GC 暂停后大多数连接变慢了?为什么堆栈跟踪以FilterInputStream.read() 结尾?它不应该在BufferedInputStream 或套接字输入流中的某处结束吗?这种读取会导致服务器负载过高吗?
我们用来阅读的代码:
int constructLength = _socketDIS.readInt();
ByteArrayOutputStream constructBOAS = new ByteArrayOutputStream(constructLength);
for (int i = 0; i != constructLength; i++)
constructBOAS.write(_socketDIS.read());
constructBOAS.close();
byte[] bytes = constructBOAS.toByteArray();
地点:
_socketDIS = new DataInputStream(new BufferedInputStream(_socket.getInputStream()));
这是来自运行良好的客户端连接的堆栈跟踪:
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:152)
at java.net.SocketInputStream.read(SocketInputStream.java:122)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:235)
at java.io.BufferedInputStream.read(BufferedInputStream.java:254)
- locked <0x00007f522cbebca8> (a java.io.BufferedInputStream)
at java.io.DataInputStream.readInt(DataInputStream.java:387)
at util.network.BytesBasedSocketConnection$ReadConnectionRunnable.run(BytesBasedSocketConnection.java:287)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:178)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:292)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
更新:
关于 EJP 答案:
没有涉及 EOS,连接已建立,但速度很慢
即使有 EOS,我也看不出代码如何在 EOS 上旋转,
for受constructLength值的限制。但是,建议的改进仍然有效。有问题的堆栈跟踪以对继承自
FilterInputStream.read()的DataInputStream((_socketDIS.read()) 的读取结束,请参见上面的代码。DataInputStream,而不是BufferedInputStream缺少read()。 在FilterInputStream.read()中有一个in.read()调用BufferedInputStream,这个有自己的read()方法定义。但是堆栈跟踪在中间停止,没有到达BufferedInputStream.read()。为什么?
【问题讨论】:
标签: java sockets networking inputstream high-load