在netty中发送两个字节缓冲区(header + body)的最佳方法

时间:2014-10-24 14:07:01

标签: netty

在netty

中发送两个字节缓冲区(header + body)的最佳方法是什么

我在我们的项目中使用netty,现在我们将以下列格式发送数据

  1. header:int(32bit),其中包含正文的长度
  2. body:byte []
  3. 我正在搜索关于标题+正文的最快发送方式 关键是我想避免数组副本,因为正文有大量数据。

    1)创建一个新的byte []并将正文复制到其中

    void sendData1(ChannelHandlerContext ctx, byte[] body) {
        byte[] newBuf = new byte[4+body.length];
    
        // header
        int len = body.length;
        newBuf[3] = (byte) (len & 0xff);
        len >>= 8;
        newBuf[2] = (byte) (len & 0xff);
        len >>= 8;
        newBuf[1] = (byte) (len & 0xff);
        len >>= 8;
        newBuf[0] = (byte) len;
    
        // body
        System.arraycopy(body, 0, newBuf, 4, body.length);
    
        final ByteBuf outBuf = Unpooled.wrappedBuffer(newBuf);
        ctx.writeAndFlush(outBuf);
    }
    

    2)直接使用netty ByteBuf的写函数

    void sendData2(ChannelHandlerContext ctx, byte[] body) {
        final ByteBuf outBuf = ctx.alloc().buffer(4+body.length);
    
        // header
        outBuf.writeInt(body.length);
        // body
        outBuf.writeBytes(body);
    
        ctx.writeAndFlush(outBuf);
    }
    

    3)设置两个netty ByteBuf并分别发送出来然后flush()

    void sendData3(ChannelHandlerContext ctx, byte[] body) {
        // header
        final ByteBuf headBuf = ctx.alloc().buffer(4);
        headBuf.writeInt(body.length);
    
        // body
        final ByteBuf bodyBuf = Unpooled.wrappedBuffer(body);
    
        ctx.write(headBuf);
        ctx.write(bodyBuf);
        ctx.flush();
    }
    

    4)使用netty的CompositeByteBuf

    void sendData4(ChannelHandlerContext ctx, byte[] body) {
        // header
        final ByteBuf headBuf = ctx.alloc().buffer(4);
        headBuf.writeInt(body.length);
    
        // body
        final ByteBuf bodyBuf = Unpooled.wrappedBuffer(body);
    
        CompositeByteBuf composite = ctx.alloc().compositeBuffer();
        composite.addComponents(headBuf, bodyBuf);
        ctx.writeAndFlush(composite);
    }
    

    选项1)和选项2)将进行阵列复制,我认为它们会有相同的性能吗? 选项3)我不确定它是否会进行数组复制,但它会调用ctx.write()两次,我认为这很昂贵; 选项4)我不确定它是否有效。但是我已经在netty5中尝试了它,似乎它只是把头发出去了。

    您正在使用哪一个或者您有什么好的选择?

    非常感谢!

1 个答案:

答案 0 :(得分:2)

首先是标准免责声明......

性能通常归结为您的用例,软件和硬件配置。对于Netty而言,软件配置的一个重要组成部分是管道的大小以及管道中的内容将对您的写入起作用。性能至少还有两个主要组成部分:运行时间,内存(并且经常需要权衡以优化一个或另一个)。为了获得最佳的用例解决方案,我建议您运行不同的场景,看看是什么让您获得最佳性能。

接下来的一些实际观察:

  1. 似乎是2的更复杂的版本。
  2. 正如您所说,您正在将数据复制到Netty的缓冲区中。
  3. ctx.write()不一定要复制。这取决于您的管道以及正在使用的分配器。无论采用哪种方法,您都必须将数据写入通道。唯一的区别是您是复制应用程序层中的数据还是让通道直接将其写出来。
  4. CompositeByteBuf - 还没有使用过这么多,但处理缓冲区集合会有一些开销。如果您可以手动分配缓冲区并使调用直接写入,那么我将无法提供使用它的理由。通过自己管理缓冲区,您可能会为每个CompositeByteBuf方法进行循环展开。
  5. 您是否考虑过PooledByteBufAllocatordirectBuffer?如果您的用例允许这些可能会提供一些性能优势。池化分配器意味着您只需支付Java一次自动调零缓冲区的费用,也可能导致GC活动减少。有关直接缓冲区ByteBuffer.allocate() vs. ByteBuffer.allocateDirect()的一般说明,请参阅此问题。