Golang 网络库 evio 一些问题/bug和思考

本文探讨了Golang网络库evio在eventfd使用、listen fd注册、loopWrite处理及潜在数据丢失问题上的不足,并分析了其背后的原理。作者指出,evio并未刻意减少epoll唤醒次数,可能导致性能损失,且存在内存拷贝问题。同时,evio的某些设计可能引起数据丢失。最后,推荐了替代库gev。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

新博客链接:https://note.mogutou.xyz/articles/2019/08/15/1565876205121.html

Fast event-loop networking for Go

最近翻了 evio 的源码,发现一些问题,主要集中在 linux 平台 epoll 上和读写的处理。

  • 用来唤醒 epoll 的 eventfd 写入数据没有读出
  • listen 的 fd 注册到所有事件循环,epoll 的惊群问题
  • loopWrite 在内核缓冲区满,无法一次写入时,出现写入数据丢失

eventfd 的使用问题

在 internal/internal_linux.go 中封装了 epoll 的使用 API 。

// Poll ...
type Poll struct {
   
	fd    int // epoll fd
	wfd   int // wake fd
	notes noteQueue
}

在 OpenPoll 时,会创建一个 eventfd 并将 fd 赋值给 Poll 的 wfd 成员, 并且注册到 epoll 监听可读事件。

当需要唤醒当前 epoll 时,提供了 Trigger 方法

// Trigger ...
func (p *Poll) Trigger(note interface{
   }) error {
   
	p.notes.Add(note)
	_, err := syscall.Write(p.wfd, []byte{
   0, 0, 0, 0, 0, 0, 0, 1})
	return err
}

这是往刚刚提到的 eventfd 中写入八字节数据,此时 epol l会被唤醒 epoll_wait 函数返回。 但是,evio 并没有去把 8 个字节的数据读取出来,内核缓冲区会不断积压,并且 evio 使用的是 epoll 的LT模式(默认模式),只要缓冲区中有数据,epoll 就会不断唤醒。这应该算是一个 bug 吧。

listen 的 fd 注册到所有事件循环,epoll 的惊群问题

evio 可以指定启动多个事件循环。evio 将 listen fd 注册到每一个事件循环中(epoll)监听可读事件,所以当一个连接到来时,所有的事件循环都会唤醒。

// create loops locally and bind the listeners.
	for i := 0; i < numLoops; i++ {
   
		l := &loop{
   
			idx:     i,
			poll:    internal.OpenPoll(),
			packet:  make([]byte, 0xFFFF),
			fdconns: make(map[int
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值