8 个进程共享同一个 listen fd,新连接到达时 8 个进程同时从 epoll_wait 返回,7 个 accept 报 EAGAIN,CPU 空转 30%。第一次遇到会往复杂处想,其实漏掉的多是个小前提。
epoll_ctl(epfd, EPOLL_CTL_ADD, lfd,
EPOLLIN | EPOLLEXCLUSIVE)
多个进程等同一个 fd 的可读事件,内核把他们都唤醒,只有一个能拿到连接。accept 返回 EAGAIN 后如果不重新挂回,还会漏掉后续事件。这一点先确认清楚,后面就不用反复试。
「epoll 惊群」这类改动最怕改一半,回滚脚本先准备好,再动生产。把这次用到的命令存进笔记,比记住结论有用,换个环境还能照着走。
改完隔一天再看一次,当场正常不代表能稳住。测试环境和线上的差别,往往就在版本号和那几行被忽略的配置上。
线上出问题先对时间点,跟发布、备份、任务执行的时刻排一排,能省掉一半功夫。日志级别临时调高可以,记得改回去,长期开着既占磁盘又掩盖真问题。
具体做法是,注册事件时加 EPOLLEXCLUSIVE;或者用 SO_REUSEPORT 每进程独立监听;accept 循环到 EAGAIN 为止;统计空唤醒次数验证效果。
改完照着核一遍,加 EPOLLEXCLUSIVE 后空唤醒从每秒 5000 次降到 30 次以内,CPU 空转消失。
