本文介紹了SelectorImpl被阻止的處理方法,對大家解決問題具有一定的參考價值,需要的朋友們下面隨著小編來一起學習吧!
問題描述
我用很多客戶端向服務器發送一個請求,每秒大約1000個請求一個客戶端,服務器的CPU很快就上升到600%(8核),并始終保持這種狀態。當我使用jSTACK打印處理內容時,我發現SelectorImpl處于阻塞狀態。記錄如下:
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.Shutdown Gractily();
)
}
推薦答案
高CPU與此有關?
可能是。我會通過以下方式診斷這個問題(在Linux機器上):
查找占用CPU的線程
使用pidstat
我可以找出哪些線程在消耗CPU,以及以什么模式(用戶/內核)花費時間。
$ pidstat -p [java-process-pid] -tu 1 | awk '$9 > 50'
此命令顯示線程占用了至少50%的CPU時間。您可以使用jstack
、VisualVM或Java飛行記錄器檢查這些線程正在執行的操作。
如果占用大量CPU的線程和被阻止的線程相同,則CPU使用率似乎與爭用有關。
查找連接超時的原因
基本上,如果兩個操作系統無法在給定時間內完成TCP握手,您將獲得連接超時。這有幾個原因:
網絡鏈路飽和。可以使用sar -n DEV 1
進行診斷,并將rxkB/s
和txkB/s
列與您的鏈路最大吞吐量進行比較。
服務器(Netty)在給定的超時時間內未響應accept()
調用。此線程可能會被阻塞或占用CPU時間。您可以使用strace -f -e trace=accept -p [java-pid]
找出哪些線程正在調用accept()
(因此完成了tcp握手)。然后使用pidstat
/jstack
檢查可能的原因。
您還可以使用netstat -an | grep -c SYN_RECV
查找已收到的開放(但未確認)連接請求的數量
這篇關于SelectorImpl被阻止的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,