Redis在百万连接下响应变慢并非epoll机制瓶颈,而是文件描述符耗尽、内存压力陡增、过期键扫描阻塞主线程或内核网络队列溢出等连锁反应所致;需协同调优tcp-backlog、timeout和hz三项配置,并强制使用连接池复用连接,避免虚假连接膨胀。

为什么 Redis 在百万连接下响应变慢,不是因为 epoll 本身
Redis 的 epoll 机制本身能轻松支撑 10 万+ 连接,但“百万级连接”下响应延迟升高,通常不是 epoll_wait() 调用效率问题,而是连接数远超合理负载边界后引发的连锁反应:文件描述符耗尽、内存压力陡增、过期键扫描阻塞主线程、或内核网络队列溢出。此时调整 epoll 相关参数只是表层操作,真正要动的是系统层与 Redis 配置协同。
必须调的三个 epoll 关联配置项
Redis 不直接暴露 epoll 接口,但通过以下三个配置间接控制其行为:
-
tcp-backlog:Linux 内核 TCP 全连接队列长度。默认值常为 511,高并发建连时易丢包。需同步调大内核参数net.core.somaxconn,否则 Redis 启动会报WARNING: The TCP backlog setting of 511 cannot be enforced -
timeout:客户端空闲连接自动断开秒数。设为 0 表示永不断开,但会导致大量僵尸连接堆积,挤占maxclients上限;设太小(如 10)又可能误杀长轮询连接。生产建议设为 300~600 -
hz:Redis 事件循环每秒执行频率,默认 10。提高到 100 可加快过期键清理、命令统计等后台任务响应,但会略微增加 CPU 占用 —— 百万连接下建议设为 50~100,避免主线程被定时任务拖慢
epoll_wait timeout 设置不当的典型表现
Redis 源码中 aeApiPoll() 调用 epoll_wait() 时传入的 timeout 值,由当前最近一个定时事件决定。如果业务中大量使用 EXPIRE 或 PEXPIRE,且过期键密度高,hz 过低会导致定时事件延迟触发,epoll_wait 等待时间拉长,表现为「偶发性 100ms+ 延迟」而非持续卡顿。
验证方式:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 监控
INFO stats中的expired_keys和evicted_keys增速 - 用
redis-cli --latency -h x.x.x.x -p 6379观察 P99 延迟毛刺是否与过期键集中到期时间吻合 - 检查
INFO commandstats中cmdstat_expire的usec_per_call是否突增
连接池 + 连接复用才是百万连接的正解
硬扛百万连接不现实 —— Redis 默认 maxclients 是 10000,即使调到 100 万,单机内存和网络带宽也撑不住。真实压测或线上场景中,所谓「百万连接」绝大多数是客户端未复用连接导致的虚假连接数膨胀。
必须做到:
- 应用侧强制使用连接池,例如 Go 的
go-redis库中PoolSize设为 100~200,MinIdleConns≥ 10,避免每次请求都新建 socket - 禁用短连接模式,关闭 HTTP 客户端的
Connection: close,确保 Redis 客户端复用底层 TCP 连接 - 用
CLIENT LIST定期采样,过滤idle> 300 的连接,配合应用日志定位未正确释放连接的代码路径
epoll 本身没有“调优上限”,但连接管理失控会让它在错误的地方拼命轮询。别在 epoll_wait 参数上反复试错,先让连接数回归真实业务量级。

















