一次线上故障的复盘:连接池打满之后,我们改了三处地方

举报
yd_210745649 发表于 2026/11/04 16:11:24 2026/11/04
【摘要】 二号每日文章草稿:一次线上故障的复盘:连接池打满之后,我们改了三处地方线上出问题那天,现象很直接:接口大面积超时,错误日志里全是等待连接超时。查下来不是数据库挂了,是应用的连接池被打满了。 当时的数据应用实例:4 台,每台连接池上限 50,总共 200 个连接。正常情况下,每台同时在用的连接大概 20 个左右。故障高峰:某段慢查询把单次查询时间从平均 30 毫秒拖到了 2 秒以上,连接迟迟...

二号每日文章草稿:一次线上故障的复盘:连接池打满之后,我们改了三处地方

线上出问题那天,现象很直接:接口大面积超时,错误日志里全是等待连接超时。查下来不是数据库挂了,是应用的连接池被打满了。

当时的数据

  • 应用实例:4 台,每台连接池上限 50,总共 200 个连接。
  • 正常情况下,每台同时在用的连接大概 20 个左右。
  • 故障高峰:某段慢查询把单次查询时间从平均 30 毫秒拖到了 2 秒以上,连接迟迟不还,4 台实例的在用连接很快顶到了上限。
  • 后续请求排队等连接,等待超过 5 秒就超时,超时又触发上游重试,重试又来抢连接,越抢越满。

这个链条里,慢查询是起因,连接池打满是放大器,重试是第二次放大。

改的第一处:把慢查询找出来,先止血

我们先把慢查询日志打开,按耗时排序,前 10 条里有 3 条是同一张表的大范围扫描。表里有 800 万行,查询条件里有个字段没建索引,执行计划是全表扫描。

处理办法很具体:给那个字段加了索引,查询从 2 秒以上降到 40 毫秒以内。加索引是在业务低峰做的,执行时间 3 分钟,期间没有锁表导致写入阻塞。

止血之后,在用连接从满格回落到每台 25 个左右。

改的第二处:连接池参数按实测改,不按默认值

原来每台池子 50 个,等待超时 5 秒,最大空闲时间 10 分钟。改完之后:

  • 每台池子上限从 50 降到 30。不是越大越好,池子越大,数据库那边同时在线的连接越多,数据库本身的线程切换和锁竞争也会变大。实测 30 个够用,峰值在用连接在 28 个以下。
  • 等待超时从 5 秒降到 1 秒。等 5 秒再超时,用户早就走了,还白白占着排队位置。1 秒超时后快速失败,至少让调用方能立刻走降级,而不是在队列里排 5 秒。
  • 空闲回收从 10 分钟改到 2 分钟,空闲连接及时还回去,数据库那边的空闲连接数从 180 个降到 60 个左右。

改完压测:模拟慢查询重现,单台在用连接顶到 30 后,后续请求 1 秒内快速失败,不再出现 5 秒排队超时堆积。

改的第三处:重试加熔断,不让重试把池子打满第二次

原来上游重试是无差别的:超时就重试,最多 3 次。故障时重试流量是正常流量的 2.8 倍。

改成:

  • 只有读请求可以重试,写请求不重试,避免重复写入。
  • 重试最多 1 次,且重试间隔 200 毫秒,不立即重试。
  • 连续 10 次超时后,熔断 30 秒,这 30 秒内直接走降级返回,不再发请求打数据库。

熔断这 30 秒里,降级返回的是缓存里的上一份结果,页面能打开,只是数据不是最新。故障演练里,熔断触发后,数据库在用连接在 10 秒内从 120 个降到 40 个以下。

复盘时记下的三条

  1. 连接池打满很少是池子本身的问题,先看是谁占着连接不还,慢查询日志比池子参数更重要。
  2. 池子上限不是越大越好,要按数据库能承受的并发和实测峰值定。
  3. 重试必须有限制,没有熔断的重试在故障时会把一次小故障放大成全站故障。

这三处改完之后,同一类慢查询又出现过一次,在用连接顶到 28 个就停住了,没有再打满,也没有触发大面积超时。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。