关于后端:Go组件设计与实现netpoll的总结

62次阅读

共计 1712 个字符,预计需要花费 5 分钟才能阅读完成。

次要针对字节跳动的 netpoll 网络库进行总结。netpoll 网络库相比于 go 自身的 net 规范库更适宜高并发场景。

基础知识

netpoll 与 go.net 库一样应用 epoll 这种 IO 多路复用机制解决网络申请。

根本了解

咱们晓得 linux 万物皆文件,每个文件有个文件标识符 fd,咱们能够设想 linux 提供给咱们的 socket fd 就是操作系统将传输层及以下的协定进行封装抽象化的一个接口。咱们能够简略把 socket 了解成对应的一次 tcp 连贯。那么网络操作基本上也是针对网卡的 IO 操作,咱们须要 读取数据 / 写入数据 ,那么如何更加高效地解决数据呢?目前大多数网络库都应用IO 多路复用机制,在 linux 零碎中最先进的 io 多路复用就是epoll 机制。

epoll 工作形式

  • 事件告诉机制
  • epoll_ctl/epoll_wait
  • ET(边缘触发)/LT(程度触发)
事件告诉机制
  • 注册事件:epoll 须要注册一些可读的事件
  • 监听事件:监听到可读的数据
  • 触发事件:告诉数据可读

次要还是有两个零碎调用:

  • epoll_ctl
  • epoll_wait
工作模式

epoll 有两种触发工作模式:ET 和 LT

  1. ET 也叫 边缘触发,注册的事件满足条件之后,epoll 只会触发一次告诉。就算你这一次的读写事件的数据没有解决完,下一次 epoll_wait 也不会再触发告诉。
  2. LT 也叫 程度触发,注册的事件满足条件之后,不论数据是否读写实现,每一次 epoll_wait 都会告诉以后监听的 fd 事件。

BIO/NIO

  1. BIO:blocking I/O,阻塞 I /O。就是当咱们向一个 socket 发动 read 的时候,数据读取实现之前 始终是阻塞 的。
  2. NIO:nonblocking I/O,非阻塞 I /O。就是 read 数据的时候 不阻塞,立刻返回

那么咱们每次发现 socket 中有可读数据的时候,咱们就会开启一个 goroutine 读取数据。

Netpoll 的优化点

go 的 net 库是 BIO 的,节约了 更多的 goroutine 在阻塞,并且难以对连接池中的连贯进行探活。netpoll 采纳了 LT 的触发形式,这种触发形式也就导致编程思路的不同

ET

LT

netpoll 采纳 LT 的编程思路 因为 netpoll 想在 零碎调用 和 buffer 上做优化,所以采纳 LT 的模式。

优化零碎调用

syscall 这个办法其实有三步:

  1. enter_runtime
  2. raw_syscall
  3. exit_runtime

因为零碎调用是一个耗时的阻塞操作,容易造成 goroutine 阻塞,所以须要退出一些runtime 的调度流程。然而,epoll_wait 触发的事件,保障不会被阻塞,所以 netpoll 间接采纳 RawSyscall 办法做零碎调用,跳过了 runtime 的一些逻辑。

优化调度

应用 msec 动静调参和 runtime.Gosched 被动让出 P

msec 动静调参

epoll_wait 的零碎调用有个参数是,等待时间,设置成 - 1 是有限期待事件到来,0 是不期待。

这样就有事件到来的时候下次循环的 epoll_wait 采纳立刻返回,没有事件就始终阻塞,缩小重复无用的调用。

runtime.Gosched 被动让出 P

如果 msec 为 - 1 的话会立刻进入下一次循环,开启新的 epoll_wait 调用,那么调用就阻塞在这里,goroutine 阻塞工夫长了之后会被 runtime 切换掉,只能等到下一次执行这个 goroutine 才行,导致工夫节约。netpoll 调用 runtime.Gosched 办法被动将 GMP 中的 P 让出,缩小 runtime 的调度过程

优化 buffer

咱们在读取和写入数据的时候须要应用到 buffer。少数框架应用环形 buffer,能够做到流式读写。然而环形 buffer 容量是死的,须要扩容的话,须要从新 copy 数组,引入了很多的并发问题。

LinkBuffer

netpoll 应用的 buffer 实现包含:

  • 链表解决扩容 copy 问题
  • sync.Pool 复用链表节点
  • atomic 拜访 size,躲避 data race 和锁竞争

还有一些 nocopy 方面的优化,缩小了 write 和 read 的次数,从而进步了读取和发送的时候的编解码效率。

更多信息看:https://www.cloudwego.io/zh/b…

正文完
 0