木名

https://lwn.net/Articles/726917/

网络大部分时候都是性能敏感的,受数据拷贝操作的影响比较大,网络数据包的zero-copy一直在不断改进。通过sendfile()系统调用,文件内容可以不用拷贝到用户态就直接发送出去;但是这个只能用于发送文件数据,类似对数据排序后的输出这种的没法使用zero-copy的sendfile()。 来自google的MSG_ZEROCOPY系列就是为了解决上述问题。首先需要在socket建立之后调用setsockopt()设置新的SOCK_ZEROCOPY选项;然后可以用如下方式实现一个zero-copy的发送:

status = send(socket, buffer, length, MSG_ZEROCOPY);

都成功的情况下,给定的buffer将会锁定在内存里面。在send返回之前,由于zero-copy,注意需要保护好buffer不被修改。 zero-copy机制实现里面会将通知消息发送到和socket绑定的error queue里面,这样可以获知到数据发送完和buffer何时可以被重新使用。通知消息通过如下方式读取:

status = recvmsg(socket, &message, MSG_ERRORQUEUE);

使用zero-copy传输需要将页锁定到内存,对数据量很小的传输这个锁定内存操作开销比较大,因此并不推荐对小数据量的传输使用该方式。实际上即便设置了MSG_ZEROCOPY,内核里面也有可能对小操作使用拷贝的方式,但在这种情况,会有额外的状态数据包的开销。 有些情况zero-copy是不可能的,比如:网络设备不支持生成checksum,这个时候内核需要自己计算,也就不可避免的要拷贝数据;另外类似需要对数据进行加密发送,这种情况也是无法实现zero-copy。

benchmark(netperf)测试的结果显示zero-copy有39%的性能提升,当然在实际环境并无法达到这么好效果,一个线上负载测试的结果显示有5-8%的性能提升。 参考论文