大厂redis链接超限处理思路

下面按事前预防、事中处置、事后复盘治理三个阶段给你一套可以直接落地的方案。
这里的报错 ERR max number of clients reached 在互联网生产中最常见于 Redis 连接数达到 maxclients 上限,也可能出现在 Redis Proxy、云 Redis、缓存集群代理层,但本质都是:服务端可接受的客户端连接数已经耗尽,新连接被拒绝


一、问题本质

1. 报错含义

Redis 返回:

ERR max number of clients reached

表示当前 Redis 实例的客户端连接数已经达到上限:

connected_clients >= maxclients

常见表现:

  • 应用访问 Redis 报错;
  • 缓存读写失败;
  • 登录、鉴权、会话、验证码、库存、限流等依赖 Redis 的功能异常;
  • 大量线程阻塞在获取 Redis 连接;
  • 应用连接池耗尽;
  • 请求 RT 飙升;
  • 错误率升高;
  • 如果降级不充分,可能进一步压垮数据库或下游服务。

2. 典型根因

线上出现该问题,一般不是单点原因,而是以下一种或多种叠加:

2.1 应用侧连接泄漏

例如:

  • 每次请求都创建 Redis 客户端;
  • Redis 连接没有关闭或归还连接池;
  • 异常路径没有释放连接;
  • 协程、线程、Future 超时后连接未释放;
  • pipeline、transaction、pub/sub 连接没有关闭;
  • 应用热部署后老连接未释放。

2.2 连接池配置不合理

例如 Java Jedis、Lettuce、Redisson、Go Redis、Node Redis 等客户端配置不当:

  • 每个应用实例连接池过大;
  • 最大连接数无限制;
  • 空闲连接不回收;
  • borrow 等待时间过长;
  • 没有连接获取超时;
  • HPA 扩容后实例数翻倍,Redis 总连接数随之翻倍;
  • 每个业务模块都创建一个独立 Redis 客户端,连接数成倍增加。

2.3 HPA、弹性扩容、发布导致连接风暴

例如:

  • 大促流量上来后应用自动扩容;
  • 每个 Pod 启动时建立大量连接;
  • 一次性滚动发布大量实例;
  • 启动探针、预热逻辑大量访问 Redis;
  • 服务短时间重启,旧连接未及时释放,新连接又打上来。

2.4 Redis 服务端配置不足

例如:

maxclients 10000

但实际业务总连接预算已经超过 10000。

同时 Redis 的 maxclients 还受操作系统文件描述符限制影响:

ulimit -n

Redis 启动时如果 OS 文件描述符太小,实际可用 maxclients 会被限制。

2.5 慢命令、阻塞命令导致连接堆积

如果 Redis 执行慢:

  • KEYS
  • 大 Key 操作
  • 大批量 MGET
  • 大 Lua 脚本
  • SORT
  • SMEMBERS 大集合
  • LRANGE 大列表
  • HGETALL 大 Hash
  • 阻塞命令,如 BLPOPBRPOP

则客户端请求处理慢,连接长时间占用,最终连接数上升。

2.6 网络异常导致连接残留

例如:

  • 应用到 Redis 网络抖动;
  • NAT Gateway 连接异常;
  • SLB、Proxy 半连接残留;
  • 客户端未感知连接断开;
  • TCP keepalive 配置不合理;
  • Kubernetes 网络组件异常。

2.7 Pub/Sub、Stream 消费者连接膨胀

Pub/Sub 和阻塞消费通常会长期占用连接:

  • 消费者数量无限增长;
  • 每个订阅主题一个连接;
  • 没有统一连接复用;
  • 消费者异常退出后连接残留。

2.8 多租户或多业务混用 Redis

一个 Redis 被多个业务共用:

  • A 业务突增连接;
  • B 业务被连带影响;
  • 没有按照业务重要性隔离;
  • 没有连接数预算和配额。

二、事前:预防体系建设

事前目标是:即使业务增长、发布、扩容、异常流量、代码缺陷出现,也不会让 Redis 连接数耗尽,或者能够在耗尽前自动发现、自动限流、自动降级。


1. 架构设计阶段

1.1 Redis 不能无限共享,要做业务隔离

互联网大厂生产中不建议所有业务共用一个 Redis。

应该按照以下维度拆分:

维度建议
核心链路登录、支付、交易、库存、风控单独隔离
非核心链路推荐、埋点、活动、排行榜可独立集群
读写压力高 QPS 读缓存和写密集型业务拆开
数据模型普通 KV、计数器、队列、Session、分布式锁分开
故障影响面一个业务连接异常不能拖垮其他业务

最低要求:

  • 核心业务 Redis 独立集群;
  • 高风险业务 Redis 独立集群;
  • 测试、预发、生产完全隔离;
  • 不同业务有独立账号、ACL、监控、配额。

1.2 建立 Redis 连接数容量模型

所有接入 Redis 的系统必须做连接数预算。

公式:

Redis 总连接数 =
Σ(服务实例数 × 每实例 Redis 最大连接数 × Redis 客户端数量)
+ 运维连接
+ 监控连接
+ Proxy 连接
+ Sentinel/Cluster 连接
+ Pub/Sub/Stream 长连接
+ 预留 Buffer

例如:

一个业务有 5 个服务:

服务实例数每实例连接池最大连接数Redis client 数最大连接数
order-service1002012000
user-service802011600
activity-service503023000
risk-service60101600
job-service205011000

业务最大连接数:

2000 + 1600 + 3000 + 600 + 1000 = 8200

再加:

监控/运维/复制/哨兵/Proxy/预留 buffer

如果按 30% 预留:

8200 × 1.3 = 10660

那么 Redis maxclients 至少要大于 10660,并且要评估 CPU、内存、网络是否支撑。


1.3 为每个 Redis 实例设置连接数红线

建议分三级:

指标阈值动作
提醒60% maxclients观察趋势
警告70% maxclients通知业务负责人
严重80% maxclients触发限流/排查
紧急90% maxclients自动降级/禁止扩容/人工介入
故障100%新连接失败

不要等到 100% 才报警。


1.4 Redis 服务端参数要纳入基线

必须统一基线化 Redis 配置。

重点参数:

maxclients 30000
timeout 300
tcp-keepalive 300

说明:

maxclients

控制 Redis 最大客户端连接数。

查看:

CONFIG GET maxclients
INFO clients

修改:

CONFIG SET maxclients 30000

持久化:

CONFIG REWRITE

注意:

如果系统文件描述符限制不够,Redis 无法真正支撑这么多连接。


timeout

关闭空闲连接。

timeout 300

表示普通客户端空闲 300 秒后断开。

注意:

  • 不建议设成过小,否则长时间空闲但合法的连接可能被频繁断开;
  • Pub/Sub、阻塞命令、复制等场景要谨慎;
  • 应结合客户端连接池的 idle 配置。

tcp-keepalive

用于探测死连接。

tcp-keepalive 300

一般建议生产开启,避免网络异常后连接长期残留。


1.5 操作系统文件描述符必须匹配

Redis 的每个客户端连接都需要文件描述符。

检查:

ulimit -n

检查 Redis 进程限制:

cat /proc/$(pidof redis-server)/limits

systemd 配置:

[Service]
LimitNOFILE=100000

Redis 启动时如果文件描述符限制不足,日志中通常会有类似提示:

You requested maxclients of 30000 requiring at least 30032 max file descriptors.
Server can't set maximum open files to 30032 because of OS error.

生产要求:

LimitNOFILE >= maxclients + Redis内部文件描述符 + 安全余量

一般建议 Redis 进程文件描述符至少:

maxclients + 10000

1.6 不能盲目调大 maxclients

调大 maxclients 前必须评估:

资源风险
内存每个连接有客户端结构、输入缓冲、输出缓冲
CPU连接数增加会增加事件循环负担
网络大量客户端并发会打满网卡
fd文件描述符耗尽
延迟Redis 单线程处理命令,连接多不等于吞吐高
输出缓冲慢客户端可能导致内存暴涨

要避免:

把 maxclients 从 10000 直接调到 100000,却不治理应用连接池

这只会把问题从连接数耗尽变成 Redis 延迟飙升或 OOM。


2. 应用开发阶段

2.1 所有 Redis 客户端必须统一封装

大厂生产中不允许业务代码随意创建 Redis Client。

必须通过统一 SDK 或基础组件访问 Redis:

  • 统一连接池配置;
  • 统一超时配置;
  • 统一重试策略;
  • 统一埋点;
  • 统一降级;
  • 统一 client name;
  • 统一接入治理平台。

禁止:

// 错误示例:每次请求创建客户端
Jedis jedis = new Jedis("redis-host", 6379);
jedis.get("key");

正确方式:

// 应使用全局单例连接池
JedisPool jedisPool = new JedisPool(config, host, port);
try (Jedis jedis = jedisPool.getResource()) {
    return jedis.get(key);
}

2.2 Redis Client 必须是单例或受控连接池

每个应用进程内:

  • Redis Client 不要重复创建;
  • 每个 Redis 集群最多一个主 Client;
  • 不同 Redis 集群使用不同 Client;
  • 不同用途可以分池,但必须登记连接预算。

禁止:

  • 每个 DAO 一个 RedisClient;
  • 每个请求 new RedisClient;
  • 每个租户 new RedisClient;
  • 每个线程 new RedisClient;
  • 每个任务 new RedisClient。

2.3 连接池必须有上限

以 Java Jedis 为例:

redis.pool.maxTotal=20
redis.pool.maxIdle=10
redis.pool.minIdle=2
redis.pool.maxWaitMillis=50
redis.timeout=100
redis.soTimeout=100

关键点:

参数要求
maxTotal必须设置,不能无限
maxIdle不能过大
minIdle不要盲目设置太高
maxWaitMillis必须设置,不能无限等待
command timeout必须设置
socket timeout必须设置
connect timeout必须设置

如果连接池拿不到连接,应该快速失败或降级,而不是一直阻塞。


2.4 每个服务必须有连接池预算

例如:

order-service:
  Redis maxTotal: 20
  最大实例数: 100
  最大连接预算: 2000

这个预算必须进入服务元数据:

service: order-service
redis:
  cluster: cache-order-prod
  max_pool_size_per_instance: 20
  max_instance_count: 100
  max_connection_budget: 2000

发布、扩容、HPA 前必须校验连接预算是否超限。


2.5 HPA 扩容必须受 Redis 连接预算约束

例如:

当前 Redis 可用连接预算:

maxclients = 30000
当前连接数 = 18000
剩余安全连接数 = 30000 × 0.8 - 18000 = 6000

如果某服务每个 Pod 最大连接数 30:

最多还能新增 Pod = 6000 / 30 = 200

HPA 最大副本数不能超过这个限制。

必须避免:

流量上升 -> HPA 扩容 -> Redis 连接数飙升 -> Redis 拒绝连接 -> 应用错误率升高 -> HPA 继续扩容

这是典型的正反馈雪崩。


2.6 应用必须设置 Redis clientName

每个连接要能从 Redis 侧识别来源。

Redis 支持客户端设置名称:

CLIENT SETNAME order-service@pod-xxx

客户端接入层要统一设置:

服务名 + 环境 + 实例ID + 机房 + 版本

例如:

order-service|prod|az-a|pod-123|v20240501

这样事中排查可以通过:

CLIENT LIST

看到是谁占用了连接。


2.7 所有 Redis 调用必须设置超时

必须包括:

超时建议
connect timeout50ms ~ 200ms
read timeout50ms ~ 300ms
command timeout根据业务 SLA
pool borrow timeout10ms ~ 100ms

不要无限等待。

错误示例:

Redis 命令卡住 -> 业务线程卡住 -> 连接不释放 -> 连接池耗尽 -> 实例继续创建连接 -> Redis maxclients 达到上限

2.8 Redis 调用必须有熔断和降级

不是所有 Redis 失败都应该拖垮业务。

按业务类型处理:

类型Redis 失败处理
普通缓存回源 DB,但要加限流和防击穿
非核心推荐返回默认值
排行榜返回旧数据
风控进入保守策略
分布式锁失败则不执行关键操作
限流器进入本地限流兜底
Session核心链路需要多活或备用方案

一定要避免:

Redis 不可用 -> 所有请求直接打 DB -> DB 被打崩

所以 Redis 降级必须和 DB 保护一起设计。


2.9 禁止高风险 Redis 命令

线上业务禁止或严格审批:

KEYS *
FLUSHALL
FLUSHDB
MONITOR
CLIENT KILL 无限制执行
HGETALL 大 Hash
SMEMBERS 大 Set
LRANGE 超大范围
ZRANGE 超大范围
复杂 Lua 脚本

推荐替代:

禁止/慎用替代
KEYSSCAN
HGETALL 大 Hash分页 HSCAN
SMEMBERS 大 SetSSCAN
LRANGE 0 -1分页
大 Key拆分 Key
大 Lua拆小或异步化

慢命令会导致连接占用时间变长,间接推高 connected_clients


3. 测试阶段

3.1 单元测试必须覆盖连接释放

重点测试:

  • 正常路径连接释放;
  • 异常路径连接释放;
  • 超时路径连接释放;
  • 取消任务时连接释放;
  • pipeline 执行异常后释放;
  • Lua 异常后连接释放;
  • pub/sub 取消订阅后释放。

Java 中必须检查:

try-with-resources
finally

Go 中检查:

defer close
context timeout

Node.js 中检查:

client.quit()
client.disconnect()

3.2 集成测试检查连接池行为

测试场景:

场景验证
并发请求连接数不超过 maxTotal
Redis 宕机不无限创建连接
Redis 慢响应连接池不被永久占满
请求超时连接能释放
应用重启老连接能断开
发布滚动连接数平滑变化

必须在测试中观察 Redis:

INFO clients
CLIENT LIST

3.3 压测必须包含连接数指标

压测不能只看 QPS 和 RT,必须看:

指标说明
connected_clients当前连接数
rejected_connections被拒绝连接数
blocked_clients阻塞客户端
total_connections_received累计连接数
Redis CPUCPU 使用率
Redis 内存包括 client buffer
网络流量入/出流量
命令耗时slowlog、latency

压测通过标准必须包含:

峰值流量 × 1.5 或 2 倍下,
connected_clients < maxclients × 70%
rejected_connections = 0
Redis P99 延迟满足 SLA

3.4 长稳测试必须做

很多连接泄漏短压测看不出来。

至少做:

12 小时、24 小时、72 小时长稳测试

重点观察:

connected_clients 是否持续单调递增
total_connections_received 是否异常增长
应用连接池 active 是否不释放

如果连接数持续上涨但流量稳定,基本可以判断存在连接泄漏或连接未复用。


3.5 故障演练必须包含 Redis 连接耗尽

演练场景:

  1. Redis maxclients 调小模拟连接耗尽;
  2. 应用连接池耗尽;
  3. Redis 慢命令导致连接堆积;
  4. 大量 Pod 同时启动;
  5. 网络抖动导致连接残留;
  6. Proxy 层连接耗尽;
  7. HPA 扩容导致 Redis 连接暴涨。

验证:

  • 告警是否及时;
  • 自动降级是否触发;
  • SRE 是否能定位来源服务;
  • 是否能通过 CLIENT LIST 找到异常连接;
  • 是否能快速恢复;
  • 是否会压垮 DB。

4. 发布阶段

4.1 发布前必须做 Redis 连接预算校验

每次发布前检查:

服务当前实例数
发布后最大实例数
每实例 Redis 最大连接池
Redis 当前连接数
Redis maxclients
剩余安全容量

例如:

当前 connected_clients = 15000
maxclients = 30000
安全阈值 = 80% = 24000
剩余安全连接数 = 9000
本次发布服务最大新增连接数 = 4000
允许发布

如果:

本次发布服务最大新增连接数 > 剩余安全连接数

必须阻断发布。


4.2 灰度发布必须观察连接数

灰度阶段看:

  • 新版本每实例连接数是否高于老版本;
  • 是否存在连接持续增长;
  • total connections 是否异常增长;
  • Redis rejected_connections 是否出现;
  • 应用连接池 active 是否异常;
  • 客户端错误率是否升高。

灰度门禁:

新版本单实例 Redis 连接数不超过基线 20%
rejected_connections = 0
connected_clients 无持续上升趋势

4.3 滚动发布要限制并发批次

不要一次重启大量实例。

建议:

maxUnavailable <= 5%
maxSurge <= 5% ~ 10%

并且根据 Redis 连接容量调整。

避免:

1000 个 Pod 同时启动,每个 Pod 建 20 个连接,瞬间新增 20000 个连接

4.4 应用启动要做连接预热限速

启动时不要瞬间把连接池打满。

建议:

  • 懒加载连接;
  • 连接池按需增长;
  • 预热有速率限制;
  • 启动后延迟接流量;
  • readiness probe 通过前不要接收业务流量;
  • 控制同时启动实例数量。

5. 运维监控阶段

5.1 Redis 侧必须监控的指标

通过:

INFO clients
INFO stats
INFO commandstats
INFO memory
SLOWLOG GET
LATENCY DOCTOR

核心指标:

指标含义告警建议
connected_clients当前连接数> 70%、80%、90% 分级
maxclients最大连接数配置基线
rejected_connections拒绝连接累计数增量 > 0 立即告警
blocked_clients阻塞客户端数> 0 持续告警
total_connections_received累计连接数斜率异常告警
client_recent_max_input_buffer客户端输入缓冲峰值异常增大告警
client_recent_max_output_buffer客户端输出缓冲峰值异常增大告警
used_memory内存使用常规监控
used_memory_rssRSS常规监控
instantaneous_ops_per_secQPS趋势判断
latest_fork_usecfork耗时RDB/AOF 风险
slowlog len慢日志增长告警

重点:

rejected_connections 只要出现增量,就说明已经出过连接拒绝

这应该是严重告警。


5.2 应用侧必须监控连接池指标

每个服务必须上报:

指标含义
redis_pool_active活跃连接数
redis_pool_idle空闲连接数
redis_pool_waiters等待连接线程数
redis_pool_borrow_time获取连接耗时
redis_pool_create_count新建连接数
redis_pool_destroy_count销毁连接数
redis_cmd_timeout_countRedis 命令超时数
redis_cmd_error_countRedis 错误数
redis_cmd_rt_p95/p99Redis 命令耗时
redis_cmd_qpsRedis 命令 QPS

必须能按以下维度聚合:

  • 服务名;
  • 实例;
  • 机房;
  • Redis 集群;
  • 命令类型;
  • 版本号。

5.3 必须能从 Redis 反查来源服务

要求所有客户端设置 CLIENT SETNAME

排查命令:

CLIENT LIST

示例字段:

id=123 addr=10.1.2.3:45678 name=order-service|prod|pod-xxx age=3600 idle=0 db=0 cmd=get

通过 nameaddr 可以定位:

  • 哪个服务;
  • 哪个 Pod;
  • 哪个版本;
  • 哪个机房;
  • 是否异常连接。

5.4 建立 Redis 连接数看板

至少包含:

  1. Redis 集群总连接数;
  2. 各 Redis 节点连接数;
  3. maxclients;
  4. 使用率;
  5. rejected_connections 增量;
  6. top client name;
  7. top client addr;
  8. 应用连接池 active;
  9. 应用实例数;
  10. HPA 副本数;
  11. 版本发布时间线;
  12. Redis 慢命令;
  13. Redis CPU、内存、网络。

看板必须能回答:

哪个服务在什么时候把连接数打上去了?
是发布导致,扩容导致,还是流量导致?
连接数上涨后有没有释放?

三、事中:线上故障应急处理

事中目标是:先止血恢复业务,再定位根因,避免扩大影响。


1. 故障识别

出现以下任一情况,进入 Redis 连接耗尽应急流程:

  • 应用日志出现:
ERR max number of clients reached
  • Redis 指标:
connected_clients >= maxclients × 90%
  • rejected_connections 出现增量;
  • 应用 Redis 连接池等待线程数飙升;
  • 大面积 Redis timeout;
  • 业务错误率升高。

2. 立即拉起应急角色

互联网大厂建议明确分工:

角色职责
Incident Commander整体指挥、决策
Redis SRERedis 侧排查和操作
应用 owner应用侧降级、回滚、限流
业务负责人业务影响判断
DBA防止 DB 被打爆
网关负责人流量控制
发布负责人暂停发布或回滚

3. 第一优先级:止血

3.1 暂停相关发布、扩容、批任务

立即执行:

  • 暂停当前发布;
  • 暂停自动扩容;
  • 暂停大批量任务;
  • 暂停离线任务访问 Redis;
  • 暂停非核心消费者;
  • 暂停压测或活动流量;
  • 冻结配置变更。

尤其要防止:

HPA 持续扩容导致连接数继续上涨

3.2 启动业务降级

按业务优先级降级:

业务动作
推荐、排行榜、非核心缓存返回默认值或旧值
活动页降级静态页
批处理任务暂停
低优先级查询限流
登录/支付/交易保留最小 Redis 能力
DB 回源必须加限流

注意:

Redis 故障时不能无脑走 DB,否则会造成二次事故。


3.3 网关或服务层限流

如果已经影响核心链路,需要限流保护。

可以按:

  • 接口;
  • 用户等级;
  • 来源渠道;
  • 地域;
  • 业务优先级;
  • 非核心服务;
  • 爬虫和异常流量。

优先限:

非核心、高 QPS、低价值、可重试、批量类接口

4. 第二优先级:确认 Redis 状态

如果还能连上 Redis,执行:

INFO clients
CONFIG GET maxclients
INFO stats
INFO memory
INFO commandstats
SLOWLOG GET 20
CLIENT LIST

重点查看:

connected_clients
blocked_clients
maxclients
rejected_connections
total_connections_received

示例:

redis-cli INFO clients

输出可能类似:

connected_clients:9999
client_recent_max_input_buffer:20480
client_recent_max_output_buffer:1048576
blocked_clients:0

查看上限:

redis-cli CONFIG GET maxclients

4.1 如果 Redis 已经无法新建连接怎么办?

因为连接已经满了,新的 redis-cli 也可能连不上。

可选手段:

  1. 使用已有的运维连接或监控连接执行命令;
  2. 登录 Redis 所在机器本地尝试连接;
  3. 如果有 Proxy 管理面,使用管理面;
  4. 通过云厂商控制台查看指标和调整参数;
  5. 如果之前预留了管理通道,使用管理通道;
  6. 必要时先从应用侧切断异常来源,等待连接回落。

事前建议长期保持一个低频、受控的运维管理连接,但不要依赖它作为唯一手段。


5. 第三优先级:定位谁占用了连接

5.1 按客户端名称统计

执行:

CLIENT LIST

拿到连接列表后按 nameaddrcmd 聚合。

如果客户端都设置了名称,可以统计:

order-service  2000
activity-service 12000
risk-service 500
unknown 3000

如果没有设置 client name,则只能按 IP 聚合:

10.1.2.3  300
10.1.2.4  500
10.1.2.5  2000

这会显著增加排查成本,所以事前必须强制设置 clientName。


5.2 看连接是否空闲

CLIENT LIST 中关注:

字段含义
age连接存在时间
idle空闲时间
cmd最后执行命令
db使用的库
name客户端名
addr客户端地址
obl/oll/omem输出缓冲相关
qbuf/qbuf-free输入缓冲相关

如果大量连接:

idle 很大
cmd=get/set

说明可能是空闲连接池过大或连接泄漏。

如果大量连接:

cmd=blpop/brpop/xread

说明可能是阻塞消费连接多。

如果大量连接:

cmd=subscribe

说明可能是 Pub/Sub 连接膨胀。

如果大量连接:

omem 很大

说明可能有慢客户端或大响应导致输出缓冲堆积。


6. 第四优先级:释放连接

6.1 优先从应用侧回收或缩容

如果定位到某服务连接异常,优先做:

  • 回滚最近版本;
  • 降低连接池上限;
  • 缩容异常服务;
  • 停止异常任务;
  • 关闭非核心功能;
  • 重启异常实例释放连接。

注意:

缩容、重启要分批进行,避免重启后又瞬间建更多连接。


6.2 Redis 侧谨慎 kill 连接

如果需要 Redis 侧释放连接,可以使用:

CLIENT KILL

例如按地址:

CLIENT KILL ADDR 10.1.2.3:45678

按客户端名称需要根据 Redis 版本能力决定,常见方式是先 CLIENT LIST 找到 id,再 kill:

CLIENT KILL ID 12345

杀普通客户端:

CLIENT KILL TYPE normal

注意:

不要误杀:

  • replicas;
  • sentinel;
  • cluster bus;
  • 正在执行核心业务的连接;
  • 运维连接;
  • Proxy 关键连接。

实操建议:

  1. 先 kill 明确异常来源;
  2. 先 kill 长时间 idle 的连接;
  3. 分批 kill;
  4. 每批后观察业务错误率和连接数;
  5. 不要一次性无差别 kill。

6.3 临时设置 timeout 回收空闲连接

如果大量连接空闲,可以临时调整:

CONFIG SET timeout 60

这会让普通空闲客户端在 60 秒后断开。

风险:

  • 可能影响合法长空闲连接;
  • 对 Pub/Sub、阻塞连接不一定适用;
  • 要与应用连接池 idle 策略配合;
  • 故障恢复后应恢复到标准值。

6.4 临时调大 maxclients

如果 Redis 资源充足,这是快速止血手段之一。

步骤:

第一步:查看当前

CONFIG GET maxclients
INFO clients

第二步:查看 OS fd 限制

cat /proc/$(pidof redis-server)/limits

第三步:评估资源

确认:

  • Redis CPU 未打满;
  • Redis 内存有余量;
  • 网络未打满;
  • fd 足够;
  • 没有严重慢命令;
  • 连接数上涨是短期峰值而不是持续泄漏。

第四步:临时调整

CONFIG SET maxclients 30000

第五步:确认生效

CONFIG GET maxclients
INFO clients

第六步:决定是否持久化

如果确认长期需要:

CONFIG REWRITE

如果只是临时止血,不要随意持久化,事后走容量评审。


6.5 如果 OS fd 不足

如果 LimitNOFILE 太小,单纯 CONFIG SET maxclients 不一定生效。

需要修改 systemd:

[Service]
LimitNOFILE=100000

然后重启 Redis 才能彻底生效。

但是线上故障中重启 Redis 风险很高,必须评估:

  • 是否有主从;
  • 是否有哨兵;
  • 是否有 Redis Cluster;
  • 是否可 failover;
  • 是否允许短暂不可用;
  • 数据是否有持久化;
  • 当前业务是否能承受。

不建议故障中盲目重启 Redis。


7. 第五优先级:确认是否有慢命令导致连接堆积

查看慢日志:

SLOWLOG GET 20

查看延迟:

LATENCY LATEST
LATENCY DOCTOR

查看命令统计:

INFO commandstats

如果发现:

  • 大量 keys
  • 大量大范围 zrange/lrange
  • 大量 hgetall/smembers
  • Lua 执行时间长;
  • 网络输出很大;

需要立即:

  • 禁用相关接口;
  • 降级相关功能;
  • 回滚发布;
  • kill 执行异常命令的客户端;
  • 后续做数据结构治理。

8. 第六优先级:恢复验证

恢复不能只看错误率下降,还要确认:

connected_clients 降到安全阈值以下
rejected_connections 不再增长
blocked_clients 正常
Redis P99 延迟正常
应用 Redis 连接池 active/idle 正常
业务错误率恢复
DB 未被回源打爆
HPA 没有继续异常扩容

建议恢复标准:

connected_clients < maxclients × 70%
rejected_connections 10 分钟无新增
业务错误率回到基线
Redis P99 延迟回到基线

四、事后:复盘、修复、治理

事后目标:找到真实根因,修代码、修机制、修监控、修流程,确保同类问题不会再次发生。


1. 复盘必须收集的数据

1.1 时间线

记录:

故障开始时间
首次告警时间
业务受影响时间
人工介入时间
止血动作时间
恢复时间
根因确认时间

要回答:

为什么没有更早发现?
为什么没有自动止血?
为什么影响范围这么大?

1.2 Redis 指标

收集故障前后:

  • connected_clients;
  • maxclients;
  • rejected_connections;
  • total_connections_received;
  • blocked_clients;
  • Redis CPU;
  • Redis memory;
  • network in/out;
  • slowlog;
  • latency;
  • commandstats;
  • client list 快照;
  • top client name;
  • top client addr。

1.3 应用指标

收集:

  • 实例数变化;
  • HPA 扩容记录;
  • 发布时间;
  • 版本变化;
  • 连接池 active/idle/wait;
  • Redis 请求量;
  • Redis 错误率;
  • Redis 超时;
  • 线程池使用率;
  • GC;
  • 应用重启记录;
  • 业务接口 RT 和错误率。

1.4 变更记录

排查故障前是否有:

  • 代码发布;
  • 配置变更;
  • Redis 参数变更;
  • 扩容;
  • 活动上线;
  • 定时任务启动;
  • 数据迁移;
  • 网络变更;
  • 云厂商维护;
  • 业务流量突增。

2. 根因分类

根因必须归类,不能只写:

Redis 连接数过高

这不是根因。

应该明确到以下粒度:

2.1 代码问题

例如:

activity-service v1.2.3 中每次请求创建 RedissonClient,未复用连接池,导致单实例连接数从 20 上升到 300。

2.2 配置问题

例如:

JedisPool maxTotal 从 20 被误改为 200,服务有 150 个实例,理论连接上限从 3000 增加到 30000。

2.3 扩容问题

例如:

HPA maxReplicas 设置为 1000,未纳入 Redis 连接预算,流量高峰时扩容导致连接数翻倍。

2.4 Redis 容量问题

例如:

Redis maxclients 10000,实际业务峰值连接预算已经达到 16000,容量评估缺失。

2.5 慢命令问题

例如:

新版本上线后增加 HGETALL 大 Hash,单次响应达到数 MB,导致客户端输出缓冲堆积,连接释放变慢。

2.6 监控缺失

例如:

只监控 Redis QPS 和 CPU,未监控 connected_clients 使用率和 rejected_connections 增量。

2.7 流程问题

例如:

发布平台未校验 Redis 连接预算,新服务接入 Redis 未经过容量评审。

3. 修复动作

3.1 修应用代码

必须检查:

  • Redis Client 是否单例;
  • 是否每请求创建连接;
  • 所有异常路径是否释放连接;
  • 是否存在异步任务不释放连接;
  • pipeline 是否关闭;
  • pub/sub 是否退订并关闭;
  • 是否无限重试;
  • 是否连接失败后疯狂重连;
  • 是否没有超时;
  • 是否重复创建多个 RedisTemplate、RedissonClient、JedisPool。

3.2 修连接池配置

统一配置模板。

示例:

redis:
  pool:
    maxTotal: 20
    maxIdle: 10
    minIdle: 2
    maxWaitMillis: 50
  timeout:
    connect: 100
    read: 100
    command: 100
  retry:
    maxAttempts: 1
  circuitBreaker:
    enabled: true

不同业务可调整,但必须评审。


3.3 修 HPA 策略

HPA 要增加外部约束:

  • Redis 连接数使用率高于 80%,禁止继续扩容;
  • Redis rejected_connections 出现,触发降级而不是扩容;
  • 应用错误率因 Redis 导致时,不应盲目扩容;
  • 最大副本数受连接预算约束。

3.4 修发布平台门禁

发布前自动检查:

当前 Redis connected_clients
Redis maxclients
服务当前实例数
服务发布后实例数
每实例 Redis maxTotal
新增连接风险
最近 30 分钟 rejected_connections
最近 30 分钟 Redis P99

不满足条件则阻断发布。


3.5 修监控告警

必须新增:

connected_clients / maxclients > 70% warning
connected_clients / maxclients > 80% critical
connected_clients / maxclients > 90% emergency
rejected_connections increase > 0 critical
total_connections_received 斜率异常 warning
blocked_clients > 0 warning
client output buffer 异常 warning
应用连接池 waiters > 0 critical
应用获取 Redis 连接耗时 P99 上升 critical

3.6 修 Redis 容量

如果确认为容量不足:

  • 调大 maxclients;
  • 调整 OS fd;
  • 增加 Redis 分片;
  • 拆分业务 Redis;
  • 引入独立读写集群;
  • 拆分 Pub/Sub;
  • 拆分 Stream 消费;
  • 对高连接业务增加 Proxy 或本地缓存;
  • 对 Serverless、短连接场景做连接复用或连接代理。

3.7 修数据结构和慢命令

如果连接堆积由慢命令引起:

  • 清理大 Key;
  • 拆分大 Hash、大 Set、大 List;
  • 禁止全量读取;
  • 分页 Scan;
  • Lua 限制执行复杂度;
  • 增加命令审计;
  • 上线前做 key size 检查;
  • 对大 Value 压缩或拆分;
  • 对热点 Key 做本地缓存或多级缓存。

4. 建立长期治理机制

4.1 Redis 接入审批

新服务接入 Redis 必须提交:

业务场景
Redis 集群
预计 QPS
峰值 QPS
实例数
HPA 最大实例数
每实例连接池大小
连接预算
Key 设计
Value 大小
TTL 策略
降级方案
压测报告
负责人

未经审批不得接入生产 Redis。


4.2 Redis 连接数配额

每个服务分配连接配额:

order-service: 3000
user-service: 2000
activity-service: 5000

超过配额告警。

如果使用 Redis ACL,可结合用户维度做统计和治理。


4.3 强制统一客户端 SDK

SDK 必须内建:

  • 单例管理;
  • 连接池上限;
  • 超时;
  • 熔断;
  • 降级;
  • 指标上报;
  • clientName;
  • 慢命令日志;
  • 大 key 风险拦截;
  • 发布版本打标。

4.4 定期容量巡检

每周或每月巡检:

Redis connected_clients 峰值
maxclients 使用率
rejected_connections 是否出现过
top client
服务实例数变化
HPA maxReplicas
未来活动容量
大促容量
慢命令
大 Key

输出容量报告。


4.5 大促前专项检查

大促、活动、春晚、秒杀前必须检查:

  • Redis maxclients;
  • OS fd;
  • 应用连接池;
  • HPA 上限;
  • 降级开关;
  • 限流开关;
  • Redis 集群容量;
  • 连接数压测;
  • 故障演练;
  • 应急 runbook;
  • 负责人值班表。

4.6 建立标准 Runbook

Runbook 内容:

  1. 如何确认连接耗尽;
  2. 如何查看 Redis connected_clients;
  3. 如何查看 maxclients;
  4. 如何查看 rejected_connections;
  5. 如何执行 CLIENT LIST;
  6. 如何定位 top client;
  7. 如何 kill 异常连接;
  8. 如何临时调大 maxclients;
  9. 如何回滚应用;
  10. 如何降级;
  11. 如何限流;
  12. 如何恢复;
  13. 如何复盘。

Runbook 要演练,不是写完放文档。


五、最终检查清单

你可以拿下面清单逐项对照现状。

事前检查清单

检查项是否完成
Redis 是否按业务隔离
核心业务是否独立 Redis
每个服务是否有 Redis 连接预算
HPA 是否纳入 Redis 连接预算
Redis maxclients 是否满足峰值需求
OS LimitNOFILE 是否足够
是否设置合理 timeouttcp-keepalive
应用是否统一 Redis SDK
Redis Client 是否单例
是否禁止每请求创建连接
连接池是否设置 maxTotal
连接池是否设置 maxWait
Redis 命令是否设置超时
是否有熔断降级
是否设置 clientName
是否监控 connected_clients
是否监控 rejected_connections
是否监控应用连接池 active/idle/wait
是否有 top client 看板
是否做过长稳测试
是否做过连接耗尽演练
发布平台是否校验连接预算
灰度是否观察连接数
大促前是否做专项容量评估

事中处理清单

步骤动作
1确认是否 ERR max number of clients reached
2暂停发布、扩容、批任务
3启动业务降级和限流
4查看 INFO clients
5查看 CONFIG GET maxclients
6查看 rejected_connections
7执行 CLIENT LIST
8按 clientName/IP 找 top client
9回滚或缩容异常应用
10分批 kill 明确异常连接
11必要时临时调大 maxclients
12检查慢命令和 blocked_clients
13观察连接数和业务错误率恢复
14确认 DB 未被回源打爆

事后治理清单

检查项是否完成
是否形成完整时间线
是否保存 Redis 指标快照
是否保存 CLIENT LIST 快照
是否确认根因服务
是否确认根因版本
是否修复连接泄漏
是否修复连接池配置
是否补充监控
是否补充告警
是否补充发布门禁
是否补充压测场景
是否补充故障演练
是否更新 Runbook
是否复盘到机制问题
是否明确长期 owner
是否设置整改截止时间

六、核心原则总结

  1. ERR max number of clients reached 不是简单调大 maxclients 就能彻底解决的问题。
  2. 必须同时治理:应用连接池、HPA、发布、监控、Redis 服务端容量、慢命令、降级限流。
  3. 每个服务必须有 Redis 连接预算。
  4. 所有 Redis 客户端必须统一封装、单例复用、设置 clientName。
  5. rejected_connections 增量必须作为严重告警。
  6. 发布和扩容必须校验 Redis 剩余连接容量。
  7. 事中优先止血,避免 Redis 故障扩散到 DB 和核心链路。
  8. 事后必须把问题沉淀成平台化门禁、监控、Runbook 和容量治理机制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值