性能常识 1000 并发下的生产压测绝对实战

NiMail · 2025年11月30日 · 最后由 NiMail 回复于 2025年12月03日 · 4279 次阅读


还是上次的问题https://testerhome.com/topics/43220DB 的连接池满导致的内存暴涨。但是实际上这个病症却存在这千丝万缕的问题。比如说,,上次其实已经确定到了是
1、到底现有的配置多少并发会导致 db 连接池打满?
2、db 连接池打满是什么样子?
3、我已经配置了弹性伸缩,也就是内存达到 80% 就应该要新启动一个实例,一起扛流量,为什么没有效果?
4、为什么没有出现故障转移?内存打满了,按道理应该转移到新的实例
5、如果流量真的大,配置实在撑不下怎么处理?

反正很多问题,总感觉搞研发的就像医生,遇到一个病例就需要去根据数据去分析病因,只有这样才能从根本上治愈。而如果只是片面的经验有时候可能不准,所以这是我不太相信中医的原因。

要想排查和解决这些问题,必须要能复现问题。最简单的就是把 db 的连接池调低,我设置 20。

然后压测。压测配置可以借鉴https://testerhome.com/topics/43010

顺便介绍下我的服务配置:
部署是用云的 K8S
NiMail.cn 的 A 业务接口服务 0.3 cpu 0.5G
NiMail.cn 的 B 关联服务(A 需要调用 B 去查询数据)0.3cpu 0.5G
mysql(4c 8G)压测没有压力,也就是链接并没有全部进来

压测发现,只要一跑,内存就会爆炸。B 服务打日志发现,mysql 的链接状态是跑满,等待数量爆涨,sql 语句耗时大部分都很长 十几秒 上百秒;
B 服务长时间没有响应,导致 A 服务也内存上涨。这个现象可以解释上述问题 2 的情况。估计大部分系统都是这样的,当然如果设置了超时就会出现大量报错,下面会提到。

从服务伸缩看,确实会新起一个示例,但是并没有走新实例。也就是新的实例没有接收到流量。。。
通过各种分析,最终能够确定:K8S 的 service 只是类似 dns 效果,对于长连接来说没有负载均衡和故障转移功能支持。所以要能实现上述问题的 3、4,必须得改。于是我改造了下,策略是,负载均衡和故障转移我这边中间件实现,然后 service 改成 service headless 可以获取多个 pod ip。然后定时去检测 IP,中间件实现故障转移。改动是有点大,反正是自己的项目,随便折腾了。

继续压测发现,一个 pod 打满内存,新起一个新 pod,然后马上又打满,又新起来一个 pod 。。。其实这个现象是正常的了,至少 3、4 的问题是解决了。

那到 1 的问题了,到底配置多少并发才能打满呢?我就按这样的数据跑,从 5 个并发开始,每次叠加 5 个,最终感觉差不多是 20 左右,也就对应 db 的连接数。其实这里应该要看业务,我这个是直接查 db,所以每个请求都会 sql 查询,有些有缓存的那就会大很多很多,这里是经验哦,有些业务复杂,各种 SQL,那这样会低。最终还是要归于业务。这样我就调到 400,然后启动 2 个 pod,也就是一起 800,直接压,然后看数据

跑到 1000 也是正常的,资源没有起来,两个资源都很稳定和占用较低。查看接口的错误率是 0.4%,应该是比较符合要求了。

还有一个是问题 5,如果流量真的大了,怎么处理。这个问题我还没解决,但是看别人说是限流、设置超时时间。超时时间我也在 A 的中间件中进行配置,但是当流量大的时候发现大量的超时报错,接口失败率非常高,而且 sql 的执行还是有很多耗时挂在那。感觉不是很理想,应该还是要在 SQL 那边也配置查询超时时间,直接退出掉。目前这个实践还没有搞完,这一轮下来东西太多了。限流的话也还没做,因为感觉要找一个好的策略,比如页面刷新可能有 3 个请求,如果限流限制其中的一个,剩下两个只要其一被限制了页面功能一样用不了,一样影响全部用户。最好的策略是影响部分用户,而另外一部分可以使用。

慢慢摸索吧!

共收到 9 条回复 时间 点赞

先自己推一个😂

有个问题比较好奇
既然是 db 连接数不够, 为啥要改负载均衡, 不应该是调整 mysql 连接池配置、优化 sql/索引/锁, 及时释放连接, 避免长期占用
pod 再多也 db 还是连接数不足, 拥堵不更严重了吗

👏 很好的实践

吼猴 回复

不是只争对一个问题呢,是整个链路进行调试和优化。是 db 链接不够 暴露出故障转移问题,也就是故障转移也有问题。不然都打到一个实例上,db 的连接数也不好一直加,而且没有故障转移和负载均衡了

小鹏友 回复

跑完感觉可以跳槽了 哈哈

NiMail 回复

很不错的实践,期待后续

NiMail 回复

「我已经配置了弹性伸缩,也就是内存达到 80% 就应该要新启动一个实例」这个策略 k8s 应该只会申请资源, 不会启动新 pod
故障转移一般是 k8s 通过探针检测到 pod 不可用才会启动, 如果探针接口不受数据库影响那么 k8s 看来 pod 是可用的.
针对长连接的问题, 一般在服务层上接一个网关, 简单点就是加个 nginx(或者 ingress-inginx) 并配置负载均衡算法, 避免 http 长连接都发到一个后端 pod.

iceman03 回复

后续已经没有了,搞完了

吼猴 回复

我的配置会新启动 pod;
他的探针不一定准,对方建议是自己做故障转移,这也是一起解决您说的第三点网关;
目前我的做法是自己改中间件,实现负载均衡和故障转移

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册