在netty中发送两字节缓冲区(头和正文)的最佳方式

在netty中发送两字节缓冲区(头和正文)的最佳方式,netty,Netty,在netty中发送两字节缓冲区(头+体)的最佳方式是什么 我在我们的项目中使用netty,现在我们将以以下格式发送数据 标题:int(32位),包含正文的长度 正文:字节[] 我正在寻找最好的方式,这是最快的发送头+身体 关键是我想避免数组拷贝,因为主体有大量数据 1) 创建一个新字节[],并将正文复制到其中 void sendData1(ChannelHandlerContext ctx, byte[] body) { byte[] newBuf = new byte[4+body.l

在netty中发送两字节缓冲区(头+体)的最佳方式是什么

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

  • 标题:int(32位),包含正文的长度
  • 正文:字节[]
  • 我正在寻找最好的方式,这是最快的发送头+身体 关键是我想避免数组拷贝,因为主体有大量数据

    1) 创建一个新字节[],并将正文复制到其中

    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,分别发送,然后刷新()

    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中试过,似乎它只会让人头痛

    你用的是哪一种?你有什么好的选择吗


    非常感谢

    首先是标准免责声明… 性能通常归结为您的用例、软件和硬件配置。对于Netty来说,软件配置的一个重要组成部分是您的管道有多大,以及管道中的内容将对您的写操作产生影响。性能至少有两个主要组成部分:运行时、内存(通常可以进行权衡以优化其中一个)。为了为您的用例获得最佳的解决方案,我建议运行不同的场景,看看什么能给您带来最好的性能

    下面是一些实际观察:

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

    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);
    }