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 是否也有该问题呢???

相关文章
相关标签/搜索