dubbo中的那些「坑"(3)-netty4-rpc網絡接口中的高併發的bug

在幾個月前改造dubbo時,netty4已經穩定好久了,一時手癢,按照netty3-rpc的源碼克隆了一套netty4,在修正了大量的包、類型不一樣以後,基本保持了netty3的風格,併發量小或者數據包很小時,一切都很ok, 在進行大併發測試時,結果和netty3徹底不一樣,基本用慘不忍睹來形容。因爲當時急於開發php客戶端,就把netty4-rpc當作一個失敗的組件存檔起來, 前幾天php-dubbo開發基本完成以後,返回過來思考netty4-rpc的問題,通過仔細分析數據包的解析過程,單步跟蹤源碼php

NettyCodecAdapter, TelnetCodec, ExchangeCoedec,發現ByteBuf的緩衝區爲1024,當數據超過1024時,會調用屢次Decoder.messageReceived函數,第一次分析dubbo的協議頭時,是正確的,第二次以後數據就錯誤了,而後dubbo內部緩衝區的數據愈來愈長,可是仍然分析不到一個完整的dubbo數據包網絡

所以去看netty4的源碼,發現AbstractNioByteChannel中有網絡數據接收的代碼時這麼處理ByteBuf的
併發

  ByteBuf byteBuf = null;
            int messages = 0;
            boolean close = false;
            try {
                int totalReadAmount = 0;
                boolean readPendingReset = false;
                do {
                    byteBuf = allocHandle.allocate(allocator);
                    int writable = byteBuf.writableBytes();
                    int localReadAmount = doReadBytes(byteBuf);
                    if (localReadAmount <= 0) {
                        // not was read release the buffer
                        byteBuf.release();
                        close = localReadAmount < 0;
                        break;
                    }
                    if (!readPendingReset) {
                        readPendingReset = true;
                        setReadPending(false);
                    }
                    pipeline.fireChannelRead(byteBuf);
                    byteBuf = null;app

看見沒,內核是須要ByteBuf.release的,繼續經過byteBuf的一個實現PooledByteBuf分析源碼,原來是實現了一個基於簡單計數應用計數的循環使用的緩衝區,一旦計數變爲1,該緩衝區被歸還到netty4內核,被後面的數據讀取線程從新使用函數

而咱們InternalDecoder的代碼爲高併發

      message = com.alibaba.dubbo.remoting.buffer.ChannelBuffers.wrappedBuffer(
                    input.toByteBuffer());測試

直接引用了ByteBuf.toByteBuffer,繼續查看源碼UnpooledHeapByteBuf, 其toByteBuffer實際是對內部數據的spa

一個nio封裝而已,所以,使用上述函數時,致使dubbo的decode保存了一個某一個ByteBuffer的內部數據,可是雖有該線程

buffer被歸還到netty4緩衝區中被循環引用,下一次可能被其餘讀寫線程從新改寫數據,所以,高併發下當緩衝區被重複使用時,bytebuf將因爲計數問題不斷被使用,而解碼器中缺傻傻等待。netty

解決方案

1.經過byteBuf的retain和release函數保證計數的有效性,經過程序例外或者緩衝區被使用完成時候歸還ByteBuf到netty4內核

2.拷貝數據到dubbo的緩衝區中

思考:

netty3 是否也有該問題呢???

相關文章
相關標籤/搜索