用心打造
VPS知识分享网站

Redis连接数突然暴涨怎么办?连接来源与泄漏排查

Redis监控里的连接数从几百快速涨到几千,应用开始出现 max number of clients reached 或连接超时,最直接的想法往往是调大 maxclients。这个动作可能暂时让新连接进入,却也会增加文件描述符、内存和事件循环压力,并让连接泄漏继续扩大。

连接数上升可能是正常流量、应用实例扩容、连接池配置变化、请求重试、订阅客户端、阻塞命令或连接没有正确关闭。排查需要保留增长趋势,再把客户端地址、名称、状态、空闲时间和应用发布记录放到同一条证据链中。

下面以Redis Open Source常见部署为例。Redis Cluster、Sentinel、代理层和云数据库对连接的统计口径、命令权限与上限不同。生产环境执行管理命令前要确认ACL,输出中包含客户端IP、端口、用户名和命令信息,必须脱敏保存。

连接数暴涨

先确认连接数、上限和真实影响

读取客户端与统计信息:

redis-cli INFO clients
redis-cli INFO stats
redis-cli CONFIG GET maxclients

重点记录 connected_clientsblocked_clientstracking_clientsmaxclientstotal_connections_receivedrejected_connections。其中 connected_clients 不包含副本连接,集群总连接和代理连接还要结合实际架构。

total_connections_received 是累计接收连接数。间隔10秒读取两次,用差值判断新建连接速率;connected_clients 是当前存量。存量持续上涨更像连接未释放,存量稳定但累计值增长极快,则可能是短连接和频繁重连。

for i in $(seq 1 12); do
  date -Is
  redis-cli --raw INFO clients | grep -E 'connected_clients|blocked_clients|maxclients'
  redis-cli --raw INFO stats | grep -E 'total_connections_received|rejected_connections'
  sleep 10
done

循环只适合短时人工采样。Redis需要密码或TLS时,应使用已配置的安全连接方式,避免把密码写进Shell历史。命令行参数中的密码可能被其他本机用户从进程列表看到,优先使用安全配置文件或环境提供的凭据机制。

连接数接近上限,同时 rejected_connections 增长且应用报错,说明已经产生业务影响。连接数上升但拒绝数为0、延迟与内存正常,先建立基线,不必仅因数字较大就紧急改参数。

用CLIENT LIST查看连接构成

CLIENT LIST 会返回当前连接的详细信息:

redis-cli CLIENT LIST

常用字段包括 addrladdrnameageidleflagsdbsubmultiqbufomemcmdage 是连接已存在时间,idle 是空闲时间;flags 可帮助识别普通、订阅、阻塞、主从等角色。

官方文档标明该命令复杂度为 O(N),N是客户端数量。连接已经达到数万时,不要每秒全量执行并把巨量结果打到终端。可先用 CLIENT LIST TYPE normal 等版本支持的过滤方式,或只在一次受控采样中保存到权限受限文件。

umask 077
redis-cli CLIENT LIST > /tmp/redis-client-list.txt

采集后及时处理和安全删除文件。不要把原始列表直接发到公开群聊,因为其中可能暴露内部地址、应用名称和账号信息。

按客户端地址和名称统计来源

先按来源IP统计,去掉端口:

redis-cli CLIENT LIST | awk '{for(i=1;i<=NF;i++) if($i ~ /^addr=/){sub(/^addr=/,"",$i); sub(/:[0-9]+$/,"",$i); print $i}}' | sort | uniq -c | sort -nr | head -n 20

IPv6地址包含多个冒号,简单删除最后端口的脚本可能误处理某些格式。遇到IPv6、Unix socket或代理地址时应保留原始数据,用更可靠的解析脚本处理。代理层可能让所有连接都显示为同一个代理IP,此时还要查代理指标和应用端连接池。

客户端设置名称后,定位会更直接:

redis-cli CLIENT LIST | awk '{for(i=1;i<=NF;i++) if($i ~ /^name=/) print $i}' | sort | uniq -c | sort -nr | head

应用可以在连接建立后执行 CLIENT SETNAME,名称中放服务名、环境和实例角色,不要放用户数据或密钥。没有命名的连接只能依靠IP、端口、命令和部署记录交叉判断,排查成本更高。

某个新发布的应用IP占绝大多数,优先回看该服务的连接池初始化、并发实例和错误日志;来源均匀增长则可能是整体流量上升、平台扩容或代理配置变化。

区分长连接堆积与短连接风暴

连接泄漏常表现为 connected_clients 随时间单向增长,列表中出现大量age较大、idle也很大的普通连接。短连接风暴则更常看到 total_connections_received 快速增加,但当前连接数上下波动。

对列表中的age和idle做分桶前,先保存原始快照。简单观察可筛选空闲超过一小时的连接:

redis-cli CLIENT LIST | awk '{idle=0; for(i=1;i<=NF;i++) if($i ~ /^idle=/){split($i,a,"="); idle=a[2]} if(idle>3600) print}' | sed -n '1,80p'

空闲很久不一定就是泄漏。连接池会保留一定数量的空闲连接,订阅、Sentinel和监控客户端也可能长期存在。判断要回到预期池大小、应用实例数和客户端flag。

假设每个实例的最大池为100,应用扩到50个实例,理论上就可能建立5000条连接。应计算所有服务池上限之和,并给Redis管理、复制和监控连接保留余量,而不是只看单个应用配置。

检查连接池生命周期

应用应复用进程级连接池,避免每个请求重新创建客户端。常见问题包括客户端对象在请求函数内初始化、异常路径没有归还连接、池没有空闲回收、健康检查每次建连,以及进程重启后旧连接未及时消失。

回看故障前的发布与扩容记录:

  • 应用实例数是否突然增加
  • 连接池最大值、最小空闲数和等待超时是否调整
  • SDK版本是否变更
  • TLS、认证或DNS错误是否触发高频重试
  • 容器健康检查是否频繁重启进程

连接池不是越大越好。池过大让每个实例长期占用大量连接,池过小又会造成等待和反复建连。应按并发请求、单次Redis操作时间、实例数量和Redis容量计算,并设置获取连接超时,避免请求无限堆积。

错误重试要有限次、带退避和随机抖动。认证错误、ACL拒绝和配置错误通常不应毫秒级无限重连,否则多个实例会形成连接风暴。

识别阻塞、订阅和事务连接

blocked_clients 增长时,检查是否大量使用BLPOP、BRPOP、XREAD BLOCK或其他阻塞操作。阻塞连接并不一定异常,它可能是队列消费者的正常工作方式,但数量应与消费者实例匹配。

CLIENT LIST中的flag和 cmd 能帮助区分订阅、阻塞、事务与监控连接。Pub/Sub客户端通常长期占用连接,不能把它们当作普通请求池随意关闭。事务处于multi状态、输出缓冲持续增大或查询缓冲异常,则需要继续查慢消费者和客户端行为。

redis-cli CLIENT LIST TYPE pubsub
redis-cli CLIENT LIST TYPE normal

TYPE过滤是否可用取决于Redis版本。云数据库也可能限制CLIENT子命令。没有权限时,应使用控制台连接监控、代理指标和应用侧池统计,不要为了排查临时授予应用账号完整管理员权限。

检查慢客户端与缓冲区压力

连接数不是唯一风险。少量慢客户端也可能占用大量输出缓冲内存。读取:

redis-cli INFO memory
redis-cli MEMORY STATS

结合CLIENT LIST中的 qbufoblollomem 查找输入或输出缓冲异常的连接。订阅客户端消费太慢、大结果返回和网络拥塞都可能让输出缓冲增长。

client-output-buffer-limit 用于限制不同客户端类别的输出缓冲,但直接调大可能把断开问题变成内存问题,调小又可能误伤正常订阅。调整前应确认客户端类型、消息速率、消费能力和当前内存余量。

Redis事件循环还可能被慢命令、fork、磁盘持久化或系统调度影响。连接增长与延迟同时发生时,结合:

redis-cli SLOWLOG GET 20
redis-cli LATENCY DOCTOR
redis-cli INFO persistence

某些命令或延迟监控可能未启用,结果为空不代表一定没有问题。云平台提供的命令审计和延迟指标也应纳入同一时间窗口。

核对操作系统文件描述符上限

Redis的实际客户端上限还受到进程文件描述符限制:

redis-cli CONFIG GET maxclients
pid=$(pidof redis-server)
sudo cat /proc/$pid/limits | grep -i 'open files'
systemctl show redis-server -p LimitNOFILE

服务名和PID获取方式因发行版、容器与多实例部署而不同。进程限制低于预期时,即使配置了更大的 maxclients 也无法真正承载。提高文件描述符会增加资源需求,不能代替连接池修复。

还要检查宿主机内存、CPU、网络和连接跟踪:

free -h
vmstat 1 10
ss -s

连接数增加会占用客户端结构、缓冲区和TCP资源。决定提升上限前,先在测试环境测量单连接内存与实际命令负载,而不是只按理论最大值配置。

不要直接批量关闭所有客户端

Redis支持 CLIENT KILL,但它会中断正在执行的请求、订阅与业务连接。先通过ADDR、ID、TYPE、USER或SKIPME等版本支持的过滤条件精确选择,并确认应用能够安全重连。

生产环境不应运行不带过滤的批量关闭,也不要先执行 FLUSHALL、重启Redis或清空数据。连接问题与数据内容无关,这些操作会扩大故障。

当单一故障应用持续创建连接并影响其他业务时,更安全的止血方式通常是先在应用入口停止该版本、缩减错误重试或隔离流量,再精确关闭已确认的异常客户端。写入业务还要评估请求中断与重复执行风险。

调大maxclients前要计算完整容量

确认证明业务正常增长且连接池合理后,才评估上限。需要统计应用实例数、每实例最大池、订阅和阻塞连接、监控、管理、复制及集群连接,并保留安全余量。

修改方式取决于部署。临时 CONFIG SET maxclients 可能在重启后丢失,配置文件、容器参数或云平台参数组才是持久入口。Redis启动时若无法把文件描述符提高到目标值,还会把实际上限降低并记录警告。

现有实例已接近上限,又不适合直接在生产环境压测时,可以在 萤光云 建立同版本Redis与脱敏应用连接池,或在按小时计费的 LightNode 上模拟实例扩容后的连接数量。测试时设置硬性连接上限和数据隔离,不能用真实生产密码连接测试程序。

修复后怎样验收

修复连接池或重试后,至少覆盖一个业务高峰,持续观察:

redis-cli INFO clients
redis-cli INFO stats
redis-cli INFO memory

核心标准不是把当前连接数立即降到最低,而是新建连接速率恢复合理、连接存量与实例数匹配、拒绝数不再增加、延迟与内存稳定。应用侧还应观察池内活跃、空闲、等待和创建失败指标。

重启一个应用实例并再次观察,确认连接能够正常释放和重建;Redis重启或故障转移后,也要验证客户端不会进入无限重连。将CLIENT SETNAME、连接池指标和发布记录纳入长期监控,下次可以更快定位来源。

最终结论应能说明连接由哪些客户端创建、为什么增长、是否达到真实容量限制,以及修复后连接速率、拒绝数和业务延迟发生了什么变化。

常见问题

Redis默认可以连接多少客户端?

常见默认上限为10000,但实际值受配置、文件描述符、平台产品和集群架构影响,应读取当前实例的 maxclients 与服务限制。

空闲连接很多,可以全部断开吗?

不建议。连接池、订阅、阻塞消费者和监控都可能长期空闲。先按来源、名称、类型和预期池大小分类,再精确处理异常连接。

调大连接数会明显增加内存吗?

每个连接都有基础结构和缓冲区,实际占用取决于客户端状态、输入输出缓冲和命令行为。连接数增加前应结合MEMORY STATS与压测评估,而不是只看空闲连接理论值。

赞(0)
未经允许不得转载;国外VPS测评网 » Redis连接数突然暴涨怎么办?连接来源与泄漏排查
分享到