7

我使用很多客户端向服务器发送一个请求,一个客户端每秒大约1000个请求,服务器的CPU很快就上升到600%(8核),并且一直保持这个状态。当我使用 jstack 打印进程内容时,我发现 SelectorImpl 处于 BLOCKED 状态。记录如下:

nioEventLoopGroup-4-1 prio=10 tid=0x00007fef28001800 nid=0x1dbf waiting for monitor entry [0x00007fef9eec7000]
java.lang.Thread.State: BLOCKED (on object monitor)
at sun.nio.ch.EPollSelectorImpl.doSelect(Unknown Source)
- waiting to lock <0x00000000c01f1af8> (a java.lang.Object)
    at sun.nio.ch.SelectorImpl.lockAndDoSelect(Unknown Source)
    - locked <0x00000000c01d9420> (a io.netty.channel.nio.SelectedSelectionKeySet)
    - locked <0x00000000c01f1948> (a java.util.Collections$UnmodifiableSet)
    - locked <0x00000000c01d92c0> (a sun.nio.ch.EPollSelectorImpl)
    at sun.nio.ch.SelectorImpl.select(Unknown Source)
    at io.netty.channel.nio.NioEventLoop.select(NioEventLoop.java:635)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:319)
    at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:101)
    at java.lang.Thread.run(Unknown Source)

CPU高跟这个有关系吗?还有一个问题是我连接很多客户端的时候,发现有的客户端会连接,报错如下:

"nioEventLoopGroup-4-1" prio=10 tid=0x00007fef28001800 nid=0x1dbf waiting for monitor entry [0x00007fef9eec7000]
java.lang.Thread.State: BLOCKED (on object monitor)
at sun.nio.ch.EPollSelectorImpl.doSelect(Unknown Source)
- waiting to lock <0x00000000c01f1af8> (a java.lang.Object)
at sun.nio.ch.SelectorImpl.lockAndDoSelect(Unknown Source)
- locked <0x00000000c01d9420> (a io.netty.channel.nio.SelectedSelectionKeySet)
- locked <0x00000000c01f1948> (a java.util.Collections$UnmodifiableSet)
- locked <0x00000000c01d92c0> (a sun.nio.ch.EPollSelectorImpl)
at sun.nio.ch.SelectorImpl.select(Unknown Source)
at io.netty.channel.nio.NioEventLoop.select(NioEventLoop.java:635)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:319)
at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:101)
at java.lang.Thread.run(Unknown Source)

生成客户端是通过使用线程池来完成的,并且已经设置了连接超时,但是为什么频繁的连接超时呢?是为了服务事业的诉讼吗?

    public void run() {

    System.out.println(tnum + " connecting...");
    try {
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(group)
        .channel(NioSocketChannel.class)
        .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 30000)
        .handler(loadClientInitializer);

        // Start the connection attempt.
        ChannelFuture future = bootstrap.connect(host, port);
        future.channel().attr(AttrNum).set(tnum);
        future.sync();
        if (future.isSuccess()) {
            System.out.println(tnum + " login success.");
            goSend(tnum, future.channel());
        } else {
            System.out.println(tnum + " login failed.");
        }
    } catch (Exception e) {
        XLog.error(e);
    } finally {

// group.shutdownGracefully(); }

}
4

2 回答 2

1

CPU高跟这个有关系吗?

有可能。我会按照以下方式诊断这个问题(在 Linux 机器上):

查找占用 CPU 的线程

使用pidstat我会发现哪些线程正在占用 CPU 以及在什么模式下(用户/内核)花费了时间。

$ pidstat -p [java-process-pid] -tu 1 | awk '$9 > 50'

此命令显示线程占用了至少 50% 的 CPU 时间。jstack您可以使用VisualVM 或 Java Flight Recorder检查这些线程在做什么。

如果 CPU-hungry 线程和 BLOCKED 线程相同,则 CPU 使用率似乎与争用有关。

查找连接超时的原因

基本上,如果两个操作系统无法在给定时间内完成 TCP 握手,您将获得连接超时。造成这种情况的几个原因:

  • 网络链路饱和。可以使用和比较列来诊断您sar -n DEV 1的链接最大吞吐量。rxkB/stxkB/s
  • 服务器(Netty)在给定的超时时间内没有响应accept()调用。该线程可能会被阻塞或缺乏 CPU 时间。您可以accept()使用strace -f -e trace=accept -p [java-pid]. 然后使用pidstat/检查可能的原因jstack

您还可以找到收到的连接打开请求数(但未确认)netstat -an | grep -c SYN_RECV

于 2016-05-26T08:32:38.753 回答
0

如果您可以详细说明您的 Netty 正在做什么,它可能会有所帮助。无论如何 - 请确保您正在关闭频道。来自Channel javadoc的通知:

完成 Channel 后,调用 close() 或 close(ChannelPromise) 以释放所有资源非常重要。这确保所有资源都以适当的方式释放,即文件句柄

如果您正在关闭通道,那么问题可能出在它自身的逻辑上 - 陷入无限循环或类似情况 - 这可能可以解释高 CPU。

于 2014-12-14T11:49:27.697 回答