NIO中幾個非常重要的技術點

來源:互聯網
上載者:User

這些都是在實踐中踩過雷的,今天某應用再次踩雷,把遇到的幾個雷都收集一下,給後來者參考。

1.即使是accept事件,沒有真正的read和write,Channel也要關閉,否則unix domain socket會被泄漏(WINDOWS更可怕),因為NIO的每個

Channel上都有兩個FD用來監聽事件(接收和發送走不同的FD)。

2.cancel事件導致CPU佔用100%,http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6403933 

其原因就是調用key.cancel()時底層在下一次seelect前並沒有真正的取消。導致等待select事件返回卻又沒有返回我們註冊的key.這個事件不斷地

迴圈觸發,CPU一直處理返回 key為0的select()調用。解決方案有兩種,一是在key.cancel()後立即selectNow();但是如果是多線程並行作業,有

可能這兩行語句中間線程被切換,使得key.cancel()後沒有立即執行 selectNow().這在多Selector情況下是可能的。另一種就是jetty處理方式,如果

select()返回0且連續幾次出現這樣的情況(有事件觸發返回,卻不是返回我們註冊的KEY),就將有效key重新註冊到一個新的selector上。其實

glassfish在處理多次次次次write返回為0的情況時也是這種策略。

範例程式碼:(真實的項目中)

            int selectTimeout = connectionConfig.getSelectTimeout();            int allProcessMaxTime = connectionConfig.getAllProcessMaxTime();            //selector在實現時有bug,epool底層可能會發送一個錯誤的訊號導致select方法提前返回,但沒有            //返回註冊的事件,而且不斷迴圈造成CPU100%            int slelectZeroCount = 0;            int maxZeroCount = 20;            int fixed = 0;            while (selector.isOpen() && selector.keys().size() != 0 && allProcessMaxTime > 0) {                long start = System.currentTimeMillis();                // 查詢看是否有已經準備好的通道,指定逾時時間                int count = selector.select(selectTimeout);                if (count == 0) {                    slelectZeroCount++;                } else {                    slelectZeroCount = 0;                    //保證是連續的count==0時才將slelectZeroCount++,如果其中有一次返回註冊事件測已經正常                }                if (slelectZeroCount > maxZeroCount && fixed == 0) {                    //沒有嘗試修複動作,則先進行修複幹預                    for (SelectionKey key : selector.keys()) {                        if (key.isValid() && key.interestOps() == 0) {                            key.cancel();                        }                    }                    fixed = 1;                } else if (slelectZeroCount > maxZeroCount && fixed == 1) {                    //如果已經幹預過仍然連續返回0,注意如果不返回0的話slelectZeroCount就被置0.                    //重新擷取一個selector,將當前事件重新註冊到新的selector上。並銷毀當前selector                    Selector newSelector = this.getSelector();                    this.changeSelector(selector, newSelector);                    selector = newSelector;                }                //對channel進行正常處理          } 

重新註冊的代碼:

private synchronized void changeSelector(Selector oldSelector, Selector newSelector) {        for (SelectionKey key : oldSelector.keys()) {            if (!key.isValid() || key.interestOps() == 0) {                continue;            }            Object att = key.attachment();            try {                if (att == null) {                    key.channel().register(newSelector, key.interestOps());                } else {                    key.channel().register(newSelector, key.interestOps(), att);                }            } catch (ClosedChannelException e) {                SocketChannel sc = (SocketChannel) key.channel();                sc.close();            }        }        try {            oldSelector.close();        } catch (IOException e) {            logger.error(e.getMessage());        }    }

同樣對於網路狀態不好時,連續寫操作返回0的處理:

    private void flushData(Selector selector, SocketChannel socketChannel, ByteBuffer byteBuffer)            throws IOException {        int count = 0;        int maxCount = 20;        while (byteBuffer.hasRemaining()) {            int len = socketChannel.write(byteBuffer);            if (len < 0) {                throw new EOFException("write channel is closed.");            }            // 如果不對len==0(即當前網路不可用)的情況處理,則while(byteBuffer.hasRemaining())可能一直            // 迴圈下去而消耗大量的CPU.            if (len == 0) {                count++;            } else {                count = 0;            }            if (count > maxCount) {                throw new IOException("can't connect to target.");            }        }    }

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.