ソリューションのJava NIOのepollバグや網状の道

最近の学習ネッティー、ネッティーは、バグの多くは、100%のCPU使用率の原因空のポーリングのepollはそのうちの1つは、ネイティブJava NIOの多くを解決するために主張ご覧ください。

epollを空ポーリング何である
あなたはネイティブNIOサーバー・アプリケーション・コードを記述するためにJavaを使用する場合は、通常のようなものです:

//创建、配置のServerSocketChannel
のServerSocketChannel serverChannel = ServerSocketChannel.open()。
。serverChannel.socket()バインド(新規たInetSocketAddress(9998));
(false)をserverChannel.configureBlocking。

//セレクタの作成
セレクタセレクタ= Selector.openを();

//注册
serverChannel.register(セレクタ、SelectionKey.OP_ACCEPT)。

しばらく(真の){
selector.select(); readyイベントが存在しない場合に// SELECT可能例外復帰!

Set<SelectionKey> readyKeys = selector.selectedKeys();
Iterator<SelectionKey> it = readyKeys.iterator();

while (it.hasNext()) {
    SelectionKey key = it.next();
    ...  // 处理事件
    it.remove();
}

}
Selector.select()は常にバグのため、残念ながら、readyイベントが到着するまでブロックされますが、しなければならない、(選択)は、Java NIOの実装上の中(真)で、その結果、すべての準備が整ったイベント状況なしで返すことがありますが常にありますCPUコアの使用率につながる実行は、悪名高いのJava NIOのファイルディスクリプタのバグで100%に急上昇しました。

実際には、これが原因とLinuxシステムのポール/ファイルディスクリプタのリアライズのバグですが、それは、Java NIOのバグと言うことができるので、それを完全なJava NIOの契約をしませんでした。

問題は、まず多くのバージョンが問題を解決するために主張し、6ジャワで発見されたが、実際にのみ参照するには、少なくともインターネット検索から、バグの発生頻度を減らした(スリフトは、JDKのepollバグに遭遇したとき)、問題はまだJavaの8があります。

道路ソリューションネッティー
多くのNIOフレームワークは、ネイティブのJava NIOベースでのepoll空のポーリングを解決強化追加し、紙は、網状のプラクティスについて説明します。

網状のソリューションは、2つのステップに分かれています。

epollバグ検出は、
セレクターを再構築することにより、ファイルディスクリプタバグを解決するため、
実際には、ソリューションのフレームワークのほとんどが似ている、検出モードでの唯一の違いは、基本的に検出した後、セレクタを再構築することによって解決されます。

空のポーリングファイルディスクリプタ検出
)あるいはSelector.select(網状使用NioEventLoop.select()は、ファイルディスクリプタのバグは、(論理NioEventLoop.selectで検出)ここで:

selectCnt = 0; //呼び出しファイルディスクリプタ空ポーリングシーンの数を選択
長いcurrentTimeNanos = System.nanoTimeのを(); //各絶対時間のサイクルが始まるとき

用(;;){
timeoutMillis = ... //初期化タイムアウトパラメータ

int selectedKeys = selector.select(timeoutMillis);
selectCnt++;

long time = System.nanoTime();  // 记录执行到此处的绝对时间:

// 检测逻辑
if (time - currentTimeNanos > timeoutMillis) {
    selectCnt = 1;  // 未发生 epoll 空轮询,所以把 selectCnt 重置为 1
} else if (selectCnt >= 重试次数阈值(默认 512)) {
    selector = selectRebuildSelector(selectCnt);  // 解决 epoll bug 的实际逻辑
    selectCnt = 1;  // 解决本次 epoll bug,重置 selectCnt
    break;
}

currentTimeNanos = time;  // 重置下次 for 循环开始时间

}
次の2つの条件が満たされている場合、空のポーリングが発生するファイルディスクリプタであると考えられます。

selector.select(timeoutMillis)timeoutMillisがブロックされ、未満
実行回数が>閾値(デフォルト512)を選択
遮断時間が非常に正確に行うことができないので、より特定のブロックの時間大きいか、すなわち、直ちにリセット1 selectCnt timeoutMillisに等しい512を連続必要そうであれば、時間を遮断倍selector.select(timeoutMillis)はtimeoutMillisのみ空のポーリングのepollと信じているほどです。

計算ロジックのtimeoutMillisセットは、配置することができず、閾値がio.netty.selectorAutoRebuildThresholdによって設定することができる回数は、システムを構成する、デフォルト値は512です。

空のポーリングのepollソリューション
のepollのバグを検出した後、selectRebuildSelector法による実用的なソリューション:

プライベートセレクタselectRebuildSelectorは(INT selectCnt)にIOException {スロー
セレクタが行の途中で何度も返さ//。
//問題を回避するには、セレクタを再構築します。
logger.warn( "Selector.select()は早期の行の{}回戻され、セレクタ{}を再構築する。"、selectCnt、セレクタ)。

rebuildSelector();  // 重建逻辑
Selector selector = this.selector;

// Select again to populate selectedKeys.
selector.selectNow();
return selector;

}
復興庁は復興が完了した後、すぐにselectNowイベントのために再聞き、rebuildSelector方法を与えました。

rebuildSelectorは再びrebuildSelector0に論理的な機関を再構築します。

/ **

@Override
パブリックブールinEventLoop(){
リターンinEventLoop(にThread.currentThread());
}
inEventLoop(スレッド)EventExecutorで定義されている間、論理の異なる実装が異なるクラスに実装さ、NioEventLoop.inEventLoopは、親クラスSingleThreadEventLoopで具体。

@Override
パブリックブールinEventLoop(スレッドthread){
リターンスレッド== this.thread;
}
網状では、1つのスレッド、複数のIOチャネルを扱うことができるが、チャネルはスレッドIOすることができ、イベントループスレッドセレクタに再構築されなければなりません現在のスレッドが現在のスレッドの実行セレクタ復興に直接NioEventLoopスレッドである、またはタスクを再構築することは、各NioEventLoopに提出する場合の内部は、完了です。

その理由は、rebuildSelector NioEventLoopファイルディスクリプタバグを呼び出すときの決意に加えて、追加された外部検出され、NioEventLoopGroupも呼び出します。

{公共ボイドrebuildSelectors()
(E EventExecutor:本)のために{
((NioEventLoop)E).rebuildSelector();
}
}
呼び出しにユーザのために露出され、最終rebuildSelectorはおそらく非イベントループスレッドで呼び出されるようA。

再建の最後のタスクは、rebuildSelector0に再構築手順を完了しています:

新しいセレクタを作成し、
新しいセレクタセレクタにすべての古いチャネルを登録します。
古いセレクターシャットダウン、
今、ファイルディスクリプタのバグへの完全なソリューションを。
PSは:実際には、この方法はブロックしないこのクラスの主slelectセレクタは、セレクタの構成によって解決されます

おすすめ

転載: blog.51cto.com/youling87/2480852
おすすめ