redis--IO复用(epoll)

、select /poll 的痛点

表格

模型 缺陷
select 1. FD 最大限制 1024;2. 每次调用都把全部 FD 拷贝进内核;3. 返回后需要遍历全部 FD 找就绪的
poll 用链表去掉了 1024 上限,但依然要遍历全部 FD,FD 数量大时性能变差

二、epoll 核心结构(eventpoll)

复制代码
struct eventpoll {
    rb_root rbr;    // 红黑树:保存所有需要监听的FD
    list_head rdlist;// 就绪链表:存放已经就绪的FD
};

epoll 是 select/poll 的改进方案,提供 3 个核心 API:

  1. epoll_create(size):内核创建 eventpoll 结构体,返回 epfd 句柄
  2. epoll_ctl(epfd, op, fd, event):ADD/MOD/DEL,把 FD 加到红黑树,绑定回调;FD 就绪时内核自动把它放进就绪链表 rdlist
  3. epoll_wait(epfd, events, maxevents, timeout):检查就绪链表,把就绪 FD 拷贝到用户空间 events 数组,只返回就绪 FD,不用全量遍历

✅ epoll 解决 select/poll 问题的三点:

  1. 红黑树存监听 FD,无 1024 上限,增删改查 O (logn),性能不随 FD 数量上涨明显衰减
  2. FD 仅需要 epoll_ctl 添加一次,后续 epoll_wait 不需要重复拷贝全部 FD 到内核
  3. 内核维护就绪链表,epoll_wait 只返回就绪 FD,用户态不用遍历所有监听 fd

三、epoll 两种通知模式 LT & ET

  • LT 水平触发(默认):只要缓冲区还有可读数据,每次 epoll_wait 都会重复通知,直到数据读完。编码简单,容易出现惊群。
  • ET 边缘触发 :只有状态变化的一瞬间(新数据到达)通知一次 ,缓冲区剩余数据不会再次通知;必须搭配非阻塞 IO,一次性循环读完缓冲区所有数据,编码更复杂,能减少通知次数,避免惊群。

示例:收到 2KB 数据,只读走 1KB LT:再次 epoll_wait 还会通知,剩下 1KB 继续可读; ET:不会再通知,如果本次没读完剩下 1KB,数据会滞留缓冲区。

四、epoll 实现 Web 服务完整流程

  1. epoll_create 创建 epoll 实例
  2. 创建 serverSocket 监听 fd(ssfd)
  3. epoll_ctl,把 ssfd 加入 epoll 红黑树监听读事件
  4. 循环调用 epoll_wait 阻塞等待就绪 FD
  5. 拿到就绪 FD,判断事件:
    • 如果是服务端 listenfd 可读:代表有新连接,调用 accept 拿到客户端 fd,epoll_ctl 加入监听
    • 如果是客户端 fd 可读:读取请求数据
    • 如果是写事件:向客户端写出响应
相关推荐
乐观的Terry3 小时前
AI翻译助手-JWT与redis无状态认证
数据库·redis·缓存
我不会起名字3224 小时前
Redis 从 0 到 1(十二):先删缓存还是先更新库?4 种方案的 Go 并发实测
redis·go·并发·延迟双删·缓存一致性
牧瀬クリスだ4 小时前
Redis String深度解析:从底层到五大实战场景
数据库·redis·缓存
利威尔xu4 小时前
Go IM 源码实战(7):断线三天重连,水位算错就漏消息
redis·后端·微服务·面试·golang
独泪了无痕13 小时前
Spring Data Redis 快速上手
spring boot·redis·后端
用户529589316685018 小时前
三马代驾实战:抢单池的 Redis 锁 + RabbitMQ 异步消费怎么做
redis
代码丰19 小时前
跨系统传输大 JSON:直接压缩,还是把数据放进 Redis?
redis·后端·json
devilnumber1 天前
Redis 数据类型 + 项目落地场景(面试版,全面、实用,后端常用)
数据库·redis·面试