1. 程式人生 > >Java nio 空輪詢bug到底是什麼

Java nio 空輪詢bug到底是什麼

編者注:Java nio 空輪詢bug也就是Java nio在Linux系統下的epoll空輪詢問題。

epoll機制是Linux下一種高效的IO複用方式,相較於select和poll機制來說。其高效的原因是將基於事件的fd放到核心中來完成,在核心中基於紅黑樹+連結串列資料結構來實現,連結串列存放有事件發生的fd集合,然後在呼叫epoll_wait時返回給應用程式,由應用程式來處理這些fd事件。

使用IO複用,Linux下一般預設就是epoll,Java NIO在Linux下預設也是epoll機制,但是JDK中epoll的實現卻是有漏洞的,其中最有名的java nio epoll bug就是即使是關注的select輪詢事件返回數量為0,NIO照樣不斷的從select本應該阻塞的Selector.select()/Selector.select(timeout)

中wake up出來,導致CPU 100%問題。如下圖所示:

那麼產生這個問題的原因是什麼的?其實在 https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6670302 上已經說明的很清楚了,比如下面是bug復現的一個場景:

A DESCRIPTION OF THE PROBLEM :
The NIO selector wakes up infinitely in this situation..
0. server waits for connection
1. client connects and write message
2. server accepts and register OP_READ
3. server reads message and remove OP_READ from interest op set
4. client close the connection
5. server write message (without any reading.. surely OP_READ is not set)
6. server's select wakes up infinitely with return value 0

上面的場景描述的問題就是連接出現了RST,因為poll和epoll對於突然中斷的連線socket會對返回的eventSet事件集合置為POLLHUP或者POLLERR,eventSet事件集合發生了變化,這就導致Selector會被喚醒,進而導致CPU 100%問題。根本原因就是JDK沒有處理好這種情況,比如SelectionKey中就沒定義有異常事件的型別。

class SelectionKey {
    public static final int OP_READ = 1 << 0;
    public static final int OP_WRITE = 1 << 2;
    public static final int OP_CONNECT = 1 << 3;
    public static final int OP_ACCEPT = 1 << 4;
}

既然nio epoll bug存在,那麼能不能規避呢?答案是有的,比如netty就很巧妙的規避了這個問題,它的處理機制就是如果發生了這種情況,並且發生次數超過了SELECTOR_AUTO_REBUILD_THRESHOLD(預設512),則呼叫rebuildSelector()進行Selecttor重建,這樣就不用管之前發生了異常情況的那個連線了。因為重建也是根據SelectionKey事件對應的連線來重新註冊的。

該問題最早在 Java 6 發現,隨後很多版本聲稱解決了該問題,但實際上只是降低了該 bug 的出現頻率,目前從網上搜索到的資料顯示,Java 8 還是存在該問題(當 Thrift 遇到 JDK Epoll Bug)。

最後一起來分析下,nio epoll bug不是linux epoll的問題,而是JDK自己實現epoll時沒有考慮這種情況,或者說因為其他系統不存在這個問題,Java為了封裝(比如SelectionKey 中的4個事件型別)的統一而沒去處理?

這裡思考下,如果想要從java nio層面上來解決這個問題,該如何做呢?

一種是nio事件型別SelectionKey新加一種"錯誤"型別,比如針對linux epoll中的epollhup和epollerr,如果出現這種事件,建議程式直接close socket,但這種方式相對來說對於目前的nio SelectionKey改動有點大,因為SelectionKey的定義目前是針對所有jdk平臺的;還有一種是針對jdk nio 對epoll的封裝中,對於epoll的epollhup和epollerr事件,epoll封裝內部直接處理,比如close socket,但是這種方案也有一點尷尬的是,可能上層應用程式碼還保留有出現問題的socket引用,這時最好是應用程式能夠感知這種情況來處理比較好。

Java nio空轉問題由來已久,一般程式中是通過新建Selector的方式來遮蔽掉了JDK5/6的這個問題,因此,對於開發者來講,還是儘量將JDK的版本更新到最新,或者使用NIO框架如Netty,Grizzly等進行研發,以免出更多的問題。

推薦閱讀

  • Netty 入門,這一篇文章就夠了
  • Netty 啟動流程解析
  • Netty 處理連線那些事
  • Java常見幾種動態代理的對比
  • 程式設計師必看| mockito原理淺析
  • Eureka 原理分析
  • MQ初窺門徑【面試必看的Kafka和RocketMQ儲存區別】
  • java lambda 深入淺出

歡迎小夥伴關注【TopCoder】閱讀更多精彩好文。

相關推薦

Java nio bug到底是什麼

編者注:Java nio 空輪詢bug也就是Java nio在Linux系統下的epoll空輪詢問題。 epoll機制是Linux下一種高效的IO複用方式,相較於select和poll機制來說。其高效的原因是將基於事件的fd放到核心中來完成,在核心中基於紅黑樹+連結串列資料結構來實現,連結串列存放有事件發

Netty的高效能及NIO的epollbug

Selector BUG出現的原因 若Selector的輪詢結果為空,也沒有wakeup或新訊息處理,則發生空輪詢,CPU使用率100%, Netty的解決辦法 對Selector的select操作週期進行統計,每完成一次空的select操作進行一次計數, 若在某個週期內連續發生N次空輪詢,則

Epollbug

開發十年,就只剩下這套架構體系了! >>>   

Java nio的一個嚴重BUG

  這個BUG會在linux上導致cpu 100%,使得nio server/client不可用,具體的詳情可以看這裡。令人失望的是這個BUG直到jdk 6u4才解決,sun的拖沓讓人難以相信。這個BUG在server端容易出現,因為server端有頻繁地接入斷開連線。使

Java nio的一個嚴重BUG,導致cpu 100%

這個BUG會在Linux上導致cpu 100%,使得nio server/client不可用,具體的詳情可以看這裡http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6403933  。令人失望的是這個BUG直到jdk 6u4才解決,sun的拖沓讓人難以

java學習歷程:NIO為什麼SelectionKey在被後需要remove()

學習NIO的過程中,對selector選擇器的知識產生了興趣,尤其是關於SelectionKey的輪詢後remove()的問題,博主嘗試簡單地解釋一下NIO如何實現非阻塞的。 首先是客戶端的程式碼: public void testNonBlockingNIOClient

JAVANIO中為什麼之後需要刪除SelectionKey

1.在呼叫Seletor的select()方法的時候,其中呼叫了各個OS實現的posix介面中的poll函式。(posix介面中的select函式和poll函式類似:都是返回就緒描述符的數目,如超時則為0,若出錯則為-1)。 2.當poll返回時,其後會執行updatese

java多執行緒中顯式鎖的檢測策略

顯式鎖簡介 java5.0之前,在協調對共享物件的訪問時可以使用的機制只有synchronized和volatile,java5.0增加了一種新的機制:ReentrantLock。 鎖像synchronized同步塊一樣,是一種執行緒同步機制,與synchronized不同的是ReentrantLock提

java LDAP 使用 DirSyncControl 對windows AD進行變更

import com.sun.jndi.ldap.ctl.DirSyncControl; import com.sun.jndi.ldap.ctl.DirSyncResponseControl; import org.slf4j.Logger; import org.slf

Java之路--js中定時任務之

最近在專案裡做了非常簡單的審批流程,根據領導要求 需要定時檢查 登入使用者是否 有表單需要去審批 ,一開始以為用spring  task定時任務排程可能更易於實現,一上手發現,task定時後臺任務,比如清理快取,清理日誌等更為方便好用,而前臺頁面的定時任務,用js的定時器se

權重排程演算法 java版本

權重輪詢排程演算法(Weighted Round-Robin Scheduling)--java版本 由於每臺伺服器的配置、安裝的業務應用等不同,其處理能力會不一樣。所以,我們根據伺服器的不同處理能力,給每個伺服器分配不同的權值,使其能夠接受相應權值數的服務請求。 2個ja

java 執行多執行緒時,外部停止

1,先建一個Map/** * 建立一個Map用於存放執行緒id物件集合,主要是用於到達崗亭之後掃碼付費,如果人工收費就需要關閉執行緒,key是停車記錄Id, */ public static Map<String, String> MAPTH

Dubbo加權負載均衡的原始碼和Bug,瞭解一下?

      本文是對於Dubbo負載均衡策略之一的加權隨機演算法的詳細分析。從2.6.4版本聊起,該版本在某些情況下存在著比較嚴重的效能問題。由問題入手,層層深入,瞭解該演算法在Dubbo中的演變過程,讀懂它的前世今生。   之前也寫了Dubbo的負載均衡策略: 《

十四.nginx,web,反向代理,調用加權算法,nfs服務

文件夾 是否 觀察 查看 方式 har sys 重新啟動 chm 一.部署nginx反向代理web服務,調度算法使用加權輪詢: 1.首先配置一個nginx服務端,三個web客戶端。用vmware 新建虛擬機完成,並用xshell連接 2.在服務端和3個web客戶端都下載e

2017-5-5 QQ面板 (用戶控件、timer控件,實現聊天功能)

賬號 reat foreach friend ext 分享 label nec back using System; using System.Collections.Generic; using System.ComponentModel; using System.

java NIO 學習

之間 理解 poll 利用 .com 根據 handler react 階段 一、了解Unix網絡編程5種I/O模型 1.1、阻塞式I/O模型 阻塞I/O(blocking I/O)模型,進程調用recvfrom,其系統調用直到數據報到達且被拷貝到應用進程的緩沖區中或者發

Java NIO:淺析I/O模型

問題 區別 ror borde ket .cn dex selector 以及 學習Java的同學註意了!!! 學習過程中遇到什麽問題或者想獲取學習資源的話,歡迎加入Java學習交流群:618528494 我們一起學Java!   也許很多朋友在學習NIO的時候都會

Java NIO筆記(一):NIO介紹

事件 .net 數據報 數據類型 單線程 long 處理 哪些 選擇 Java NIO即Java Non-blocking IO(Java非堵塞I/O),由於是在Jdk1.4之後添加的一套新的操作I/O工具包,所以通常會被叫做Java New IO。NI

reactor模式與java nio

time handlers write syn linu pipe accept 事件處理 schmidt ?? Reactor是由Schmidt, Douglas C提出的一種模式,在高並發server實現中廣泛採用。改模式採用事件驅動方式,當事件出現時,後調用對應的

java nio--采用Selector實現Socket通信

lock finish taf 取數 block static isempty inpu col server: 1 /** 2 * 選擇器服務端 3 * Created by ascend on 2017/6/9 9:30. 4 */ 5 pu