直接改maxclients常无效,因redis启动时自动将其降至ulimit -n - 32(预留32个自身用),且不报错;必须同步修改limits.conf、systemd limitnofile及启用pam_limits.so,并重启redis验证。

直接改 maxclients 为什么经常没用?
因为 Redis 启动时会检查系统级文件描述符限制:ulimit -n。如果它比 maxclients 小,Redis 会自动把 maxclients 降为 ulimit -n - 32(预留 32 个给自身),且不报错、不写日志——你改了配置,重启后 CONFIG GET maxclients 看到的仍是旧值,实际生效的却是系统限制。
验证方式必须是:cat /proc/$(pidof redis-server)/limits | grep "Max open files",而不是只看 ulimit -n 或 CONFIG GET maxclients。
- 临时调高:在启动 Redis 前执行
ulimit -n 65536 - 永久生效要改三处:
/etc/security/limits.conf(加 redis 用户的 nofile)、systemdservice 文件里的LimitNOFILE、确保pam_limits.so已启用 - 改完必须重启 Redis 进程,否则新限制不会加载
redis-cli client list 怎么一眼看出连接泄漏?
执行 redis-cli client list 后,重点盯三个字段:addr、age、idle。
-
addr固定不变(比如全是10.0.1.12:54321)+age持续增长(几小时甚至几天),基本锁定是某台应用机器的连接池没关干净 -
idle > 300的连接,大概率是借出去没还,或异常中断后未清理 - 大量连接
flags=N(normal)但qbuf非零、qbuf-free很小,说明命令堆积,可能是客户端卡死或网络问题
别只数总数——要按 addr 分组统计:redis-cli client list | awk '{print }' | sort | uniq -c | sort -nr,快速定位“贡献”最多连接的客户端 IP。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
Jedis 连接池不关 close() 的真实后果
不是“偶尔连不上”,而是连接持续卡在 ESTABLISHED 状态,connected_clients 缓慢但不可逆地上升,直到撞上限。哪怕只漏一个连接/请求,QPS 上万时一天就能涨几千个。
- 错误写法:
Jedis jedis = pool.getResource(); jedis.set("k","v"); // 没 close() - 看似安全但仍有风险:
try { ... } finally { jedis.close(); }—— 如果jedis.close()抛出 IOException(如 socket 已断),可能被上层吞掉,连接仍没归还 - 正确姿势:启用连接池校验
config.setTestOnBorrow(true)和config.setTestOnReturn(true),并确保close()在 finally 中,且不忽略其异常
注意:Jedis.close() 不是关闭 socket,而是将连接归还给池子;没这一步,连接就永远“借走不还”。
主从复制也会吃掉 maxclients 名额
每个从节点至少占用 2 个连接(命令同步 + PSYNC backlog 传输),它们和业务客户端一样,全部计入 connected_clients,也受 maxclients 和 ulimit -n 双重约束。
- 主节点压力更大,
maxclients要优先调高;从节点也要同步设,否则主从握手阶段就可能失败 - 不要信“主从走内部通道”的说法——Redis 把从节点当普通 client 对待,
client list里能清楚看到addr是从节点 IP - 若用云数据库(如阿里云 Tair),还要额外检查白名单和 Sentinel 兼容性,否则错误日志可能混淆,误判为连接数问题
真正难处理的,从来不是改几个数字,而是怎么在一堆 ESTABLISHED 连接里,快速揪出那个忘了 close() 的函数调用点——它往往藏在工具类深处,调用链横跨三层以上,且只在特定分支触发。










