news 2026/11/6 1:41:02

Redis 从 0 到 1(二十五):连接池又打满了——PoolSize 公式、泄漏排查与 PoolStats

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Redis 从 0 到 1(二十五):连接池又打满了——PoolSize 公式、泄漏排查与 PoolStats

我不会起名字322· 后端 / 算法 / 数据库

📘 技术栈 | 🧩 力扣 Hot100 | 🐹 Go 项目 | 🟥 Redis | 🐬 MySQL

文章目录

  • Redis 从 0 到 1(二十五):连接池又打满了——PoolSize 公式、泄漏排查与 PoolStats
    • 一、现象:timeout 就加池,加完还是 timeout
    • 二、PoolSize 计算公式(收藏点 1)
    • 三、用 PoolStats 的 4 个指标判断病因(收藏点 2)
    • 四、Go 实操:PoolStats 监控与典型泄漏(收藏点 3)
    • 五、服务端配套配置(收藏点 4)
    • 六、排查步骤:connection pool timeout
    • 七、总结

Redis 从 0 到 1(二十五):连接池又打满了——PoolSize 公式、泄漏排查与 PoolStats

上一篇《Redis 从 0 到 1(二十四):1 万次 GET 从 800ms 降到 9ms——Pipeline 的 Go 压测》我们把 1 万次 RTT 压成 50 次,链接:https://blog.csdn.net/2501_92769340/article/details/167399903 。
本篇处理优化的"最后一公里":连接池。流量一涨就connection pool timeout,加 PoolSize 真的有用吗?

一、现象:timeout 就加池,加完还是 timeout

服务 QPS 涨到 3000 后开始报connection pool timeout。第一反应该是把 PoolSize 从 20 调到 50——没用,又调到 100——报得更频繁了。最后定位到真相:不是池太小,是连接泄漏。有段代码拿到连接执行命令后,在错误分支提前 return,连接没归还(虽然 go-redis 用完后自动回池,但阻塞在慢命令上的连接占用时间被拉长)。

加池为什么可能更糟:池越大,慢命令并发越多,Redis 单线程排队越长,单命令 RTT 越高 → 每条连接占用更久 → 更需要连接……恶性循环。池大小必须按公式来。

二、PoolSize 计算公式(收藏点 1)

所需连接数 ≈ 峰值 QPS × 平均单命令耗时(秒)× 安全系数(1.2~1.5) 例:3000 QPS,平均命令耗时 2ms(含 RTT) → 3000 × 0.002 × 1.3 ≈ 8 个连接

对照直觉检查:如果你的 PoolSize 算出 8,实际配了 100,多出来的 92 个连接只会制造"能发更多并发命令"的假象,把 Redis 的排队延迟推高。

还要同时看服务端:maxclients(默认 10000)减去保留(约 32),是所有客户端加起来的天花板。几十个微服务实例 × 每实例 100 连接 = 可能顶到 maxclients,出现ERR max number of clients reached(第 34 篇专门排查)。

三、用 PoolStats 的 4 个指标判断病因(收藏点 2)

go-redis 暴露rdb.PoolStats(),4 个关键指标:

指标含义什么时候报警
Timeouts从池取连接超时次数>0 就说明池不够或泄漏;这是症状指标
TotalConnsvsPoolSize当前连接数/上限TotalConns 长期顶满 PoolSize = 池满
Hits/(Hits+Misses)池命中率<90% 说明连接复用差(频繁建连)
StaleConns被服务端断掉的死连接持续增长说明配平没做好(第 2 篇)

判断逻辑:

  • Timeouts涨 +TotalConns顶满 + 慢查询多 →池不小,是命令慢(去第 21 篇),加池无效;
  • Timeouts涨 +TotalConns顶满 +Hits高 + 命令很快 →真池小,按公式加;
  • Timeouts涨 +TotalConns波动大、新连接创建频繁 →有地方没复用连接(代码里反复 NewClient?)。

四、Go 实操:PoolStats 监控与典型泄漏(收藏点 3)

监控上报(Prometheus 格式,第 35 篇接采集):

packagemainimport("context""fmt""time""github.com/redis/go-redis/v9""redis-0to1/redisx")funcReportPoolStats(rdb*redis.Client){t:=time.NewTicker(30*time.Second)forranget.C{fmt.Println(redisx.PoolStats(rdb))// 生产替换为 metrics 上报}}

典型泄漏场景复盘——长事务占用连接:

// ❌ 错误示范:一个 context 里串行执行 100 条命令,每条 20ms// 高峰时这个请求独占 1 条连接 2 秒;并发 50 就把 20 的池打满funcBadBatchGet(ctx context.Context,rdb*redis.Client,keys[]string){for_,k:=rangekeys{rdb.Get(ctx,k)// 逐条 RTT(第 24 篇的反面教材)}}// ✅ 修法一:Pipeline 把 2 秒压缩成 20ms,连接占用降 100 倍// ✅ 修法二:批量接口加超时上限,防止个别请求拖死连接池funcGoodBatchGet(ctx context.Context,rdb*redis.Client,keys[]string){ctx,cancel:=context.WithTimeout(ctx,200*time.Millisecond)// 兜底defercancel()// ... Pipeline 实现见第 24 篇}

第 2 篇的 redisx 封装里已经带PoolStats()输出——现在你知道它是为哪一篇准备的了。

五、服务端配套配置(收藏点 4)

# redis.conf maxclients 10000 # 天花板,按"实例数 × PoolSize + 运维余量"核算 timeout 300 # 空闲断开(客户端 ConnMaxIdleTime 要比它小,第 2 篇) tcp-keepalive 60

实例数 × PoolSize 的账要定期重算:服务从 3 个 pod 扩到 30 个,池配置不变,服务端连接数就涨了 10 倍——这就是第 34 篇《maxclients 打满但 QPS 只有 500》的事故现场预告。

六、排查步骤:connection pool timeout

  1. PoolStats()抓指标:Timeouts/TotalConns/Hits三对照(第三节判断树);
  2. 命令慢不慢:slowlog 有货 → 先治慢命令;
  3. 代码有没有逐条 RTT 循环:有 → 改 Pipeline;
  4. 真池小:按公式重算 PoolSize,同时检查服务端 maxclients 余量;
  5. 改完压测回归:Timeouts归零、TotalConns稳定在公式值附近。

七、总结

  1. PoolSize 按QPS × 单命令耗时 × 1.3算,拍脑袋加池可能适得其反;
  2. PoolStats 四指标判断树:Timeouts 是症状,Hits/TotalConns 是病因;
  3. 连接泄漏的头号形态是"逐条 RTT 的长事务",解法在第 24 篇;
  4. 服务端 maxclients 要按"实例数 × PoolSize"定期核算。

下一篇预告:连接稳了,下一篇往内存里看——下一篇《INFO memory 里 8 个关键数字——内存构成、编码转换(listpack)与容量规划》,我们搞清楚 Redis 的内存都花在哪了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/6 1:41:01

8 大网盘直链解析免登录下载快速上手:LinkSwift

8 大网盘直链解析免登录下载快速上手&#xff1a;LinkSwift 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 &#xff0c;支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼云盘 /…

作者头像 李华
网站建设 2026/11/6 1:40:57

Linux 基础与常用命令速查:从文件系统到 gcc 编译链接与 makefile

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/11/6 1:38:40

python语言-连连看v4.92修改器代码QZQ-2026-9-19

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/11/6 1:38:40

Bejeweled 3 经典模式 —— 穷举暴力试错版 v4(真零延迟)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/11/6 1:38:31

如何用 iloader 免费给 iPhone 侧载 App:10 分钟新手完整教程

如何用 iloader 免费给 iPhone 侧载 App&#xff1a;10 分钟新手完整教程 【免费下载链接】iloader User friendly sideloader 项目地址: https://gitcode.com/GitHub_Trending/iloa/iloader iloader 是一款免费的 iOS 侧载工具&#xff1a;不用越狱&#xff0c;就能把 …

作者头像 李华