网络框架netpoll中的SO_ZEROCOPY

2024-06-11 18:28
文章标签 框架 网络 netpoll zerocopy

本文主要是介绍网络框架netpoll中的SO_ZEROCOPY,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

背景了解

https://www.163.com/dy/article/FS6AS7SS0518R7MO.html
https://docs.kernel.org/networking/msg_zerocopy.html

send() with MSG_ZEROCOPY

kernel v4.14 版本接受了来自 Google 工程师 Willem de Bruijn 在 TCP 网络报文的通用发送接口 send() 中实现的 zero-copy 功能
用户进程就能够把用户缓冲区的数据通过零拷贝的方式经过内核空间发送到网络套接字中去

因为前面几种零拷贝技术都是要求用户进程不能处理加工数据而是直接转发到目标文件描述符中去
Willem de Bruijn 在他的论文里给出的压测数据:
采用 netperf 大包发送测试,性能提升 39%,而线上环境的数据发送性能则提升了 5%~8%
官方文档陈述说这个特性通常只在发送 10KB 左右大包的场景下才会有显著的性能提升
一开始这个特性只支持 TCP,到内核 v5.0 版本之后才支持 UDP

这个功能的使用模式如下:
if (setsockopt(socket_fd, SOL_SOCKET, SO_ZEROCOPY, &one, sizeof(one)))
error(1, errno, “setsockopt zerocopy”);
ret = send(socket_fd, buffer, sizeof(buffer), MSG_ZEROCOPY);
// https://docs.kernel.org/networking/msg_zerocopy.html

第一步,先给要发送数据的 socket 设置一个 SOCK_ZEROCOPY option
第二步,在调用 send() 发送数据时再设置一个 MSG_ZEROCOPY option
其实理论上来说只需要调用 setsockopt() 或者 send() 时传递这个 zero-copy 的 option 即可
两者选其一,但是这里却要设置同一个 option 两次
官方的说法是为了兼容 send() API 以前的设计上的一个错误:send() 以前的实现会忽略掉未知的 option
为了兼容那些可能已经不小心设置了 MSG_ZEROCOPY option 的程序,设计成两步设置

猜测其他可能:
给使用者提供更灵活的使用模式,因为这个新功能只在大包场景下才可能会有显著的性能提升
现实场景很复杂:不仅仅是全部大包或者全部小包的场景,有可能是大包小包混合的场景
因此使用者可以先调用 setsockopt() 设置 SOCK_ZEROCOPY option
然后再根据实际业务场景中的网络包尺寸选择是否要在调用 send() 时使用 MSG_ZEROCOPY 进行 zero-copy 传输

注意:
send() 可能是异步发送数据,因此使用 MSG_ZEROCOPY 时,调用 send() 之后不能立刻重用或释放 buffer
因为 buffer 中的数据不一定已经被内核读走了,所以还需要从 socket 关联的队列里读取一下通知消息
看看 buffer 中的数据是否已经被内核读走

底层原理
这个技术是基于 redhat 红帽在 2010 年给 Linux 内核提交的 virtio-net zero-copy 技术之上实现的
通过 send() 把数据在用户缓冲区中的分段指针发送到 socket 中去
利用 page pinning <页锁定机制>锁住用户缓冲区的内存页
然后利用 DMA 直接在用户缓冲区通过内存地址指针进行数据读取,实现零拷贝
具体的细节可以通过阅读 Willem de Bruijn 的论文 (PDF)

主要缺陷:
(1) 只适用于大文件 (10KB 左右) 的场景,小文件场景因为 page pinning 页锁定和等待缓冲区释放的通知消息这些机制
甚至可能比直接 CPU 拷贝更耗时
(2) 因为可能异步发送数据,需要额外调用 poll() 和 recvmsg() 系统调用等待 buffer 被释放的通知消息,增加代码复杂度
以及会导致多次用户态和内核态的上下文切换;
(3) MSG_ZEROCOPY 目前只支持发送端,接收端暂不支持

绕过内核的直接 I/O
前面种种的 zero-copy 的方法,都是在想方设法地优化减少或者去掉用户态和内核态之间以及内核态和内核态之间的数据拷贝
为了实现避免这些拷贝可谓是八仙过海,各显神通,采用了各种各样的手段
那如果换个思路:这么费劲地去消除这些拷贝不就是因为有内核在掺和吗?

netpoll中的实现

初始化时的fd option设置

const (SO_ZEROCOPY       = 60SO_ZEROBLOCKTIMEO = 69MSG_ZEROCOPY      = 0x4000000
)func setZeroCopy(fd int) error {return syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, SO_ZEROCOPY, 1)
}func setBlockZeroCopySend(fd int, sec, usec int64) error {return syscall.SetsockoptTimeval(fd, syscall.SOL_SOCKET, SO_ZEROBLOCKTIMEO, &syscall.Timeval{Sec:  sec,Usec: usec,})
}func (c *connection) init(conn Conn, opts *options) (err error) {... ...if setZeroCopy(c.fd) == nil && setBlockZeroCopySend(c.fd, defaultZeroCopyTimeoutSec, 0) == nil {c.supportZeroCopy = true}... ...
}

poll wait中的使用

仅关注 triggerWrite

// Wait implements Poll.
func (p 

这篇关于网络框架netpoll中的SO_ZEROCOPY的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1051944

相关文章

SpringBoot基础框架详解

《SpringBoot基础框架详解》SpringBoot开发目的是为了简化Spring应用的创建、运行、调试和部署等,使用SpringBoot可以不用或者只需要很少的Spring配置就可以让企业项目快... 目录SpringBoot基础 – 框架介绍1.SpringBoot介绍1.1 概述1.2 核心功能2

python如何下载网络文件到本地指定文件夹

《python如何下载网络文件到本地指定文件夹》这篇文章主要为大家详细介绍了python如何实现下载网络文件到本地指定文件夹,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下...  在python中下载文件到本地指定文件夹可以通过以下步骤实现,使用requests库处理HTTP请求,并结合o

Linux高并发场景下的网络参数调优实战指南

《Linux高并发场景下的网络参数调优实战指南》在高并发网络服务场景中,Linux内核的默认网络参数往往无法满足需求,导致性能瓶颈、连接超时甚至服务崩溃,本文基于真实案例分析,从参数解读、问题诊断到优... 目录一、问题背景:当并发连接遇上性能瓶颈1.1 案例环境1.2 初始参数分析二、深度诊断:连接状态与

Spring框架中@Lazy延迟加载原理和使用详解

《Spring框架中@Lazy延迟加载原理和使用详解》:本文主要介绍Spring框架中@Lazy延迟加载原理和使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录一、@Lazy延迟加载原理1.延迟加载原理1.1 @Lazy三种配置方法1.2 @Component

Qt实现网络数据解析的方法总结

《Qt实现网络数据解析的方法总结》在Qt中解析网络数据通常涉及接收原始字节流,并将其转换为有意义的应用层数据,这篇文章为大家介绍了详细步骤和示例,感兴趣的小伙伴可以了解下... 目录1. 网络数据接收2. 缓冲区管理(处理粘包/拆包)3. 常见数据格式解析3.1 jsON解析3.2 XML解析3.3 自定义

Linux系统配置NAT网络模式的详细步骤(附图文)

《Linux系统配置NAT网络模式的详细步骤(附图文)》本文详细指导如何在VMware环境下配置NAT网络模式,包括设置主机和虚拟机的IP地址、网关,以及针对Linux和Windows系统的具体步骤,... 目录一、配置NAT网络模式二、设置虚拟机交换机网关2.1 打开虚拟机2.2 管理员授权2.3 设置子

揭秘Python Socket网络编程的7种硬核用法

《揭秘PythonSocket网络编程的7种硬核用法》Socket不仅能做聊天室,还能干一大堆硬核操作,这篇文章就带大家看看Python网络编程的7种超实用玩法,感兴趣的小伙伴可以跟随小编一起... 目录1.端口扫描器:探测开放端口2.简易 HTTP 服务器:10 秒搭个网页3.局域网游戏:多人联机对战4.

Python Dash框架在数据可视化仪表板中的应用与实践记录

《PythonDash框架在数据可视化仪表板中的应用与实践记录》Python的PlotlyDash库提供了一种简便且强大的方式来构建和展示互动式数据仪表板,本篇文章将深入探讨如何使用Dash设计一... 目录python Dash框架在数据可视化仪表板中的应用与实践1. 什么是Plotly Dash?1.1

基于Flask框架添加多个AI模型的API并进行交互

《基于Flask框架添加多个AI模型的API并进行交互》:本文主要介绍如何基于Flask框架开发AI模型API管理系统,允许用户添加、删除不同AI模型的API密钥,感兴趣的可以了解下... 目录1. 概述2. 后端代码说明2.1 依赖库导入2.2 应用初始化2.3 API 存储字典2.4 路由函数2.5 应

Python GUI框架中的PyQt详解

《PythonGUI框架中的PyQt详解》PyQt是Python语言中最强大且广泛应用的GUI框架之一,基于Qt库的Python绑定实现,本文将深入解析PyQt的核心模块,并通过代码示例展示其应用场... 目录一、PyQt核心模块概览二、核心模块详解与示例1. QtCore - 核心基础模块2. QtWid