SelectorImpl is BLOCKED



我使用了很多客户端向服务器发送请求,每秒大约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.shutdownRacefully();}

}

高CPU与此有关?

可能是这样。我会按照以下方式(在Linux盒子上)诊断这个问题:

查找正在消耗CPU的线程

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

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

此命令显示线程占用至少50%的CPU时间。您可以使用jstack、VisualVM或Java飞行记录器来检查这些线程正在做什么。

如果CPU占用线程和BLOCKED线程是相同的,那么CPU的使用似乎与争用有关。

查找连接超时的原因

基本上,如果两个操作系统不能在给定的时间内完成TCP握手,就会导致连接超时。原因如下:

  • 网络链路饱和。可以使用sar -n DEV 1进行诊断,并将rxkB/stxkB/s列与您的链路最大吞吐量进行比较
  • 服务器(Netty)在给定超时内未响应accept()调用。此线程可能被阻塞或CPU时间不足。您可以找到哪些线程正在使用strace -f -e trace=accept -p [java-pid]调用accept()(从而完成TCP握手)。然后使用pidstat/jstack检查可能的原因

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

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

调用close()或close(ChannelPromise)以在使用完Channel后释放所有资源是很重要的。这确保了所有资源都以正确的方式释放,即文件句柄

如果你正在关闭通道,那么问题可能是它自己运行到无限循环或类似的逻辑——这可能能够解释高CPU。

相关内容

最新更新