一次应用访问数据库 IP 配成外网 IP 引发的血案

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/defonds/article/details/78445676

我们生产的渠道对接系统出现大量推送运营商信息失败的现象。问题最终定位到 mongo 身上:
.00:03:05.425 [http-nio-9100-exec-53] ERROR c.d.r.s.i.CarrierOpRepServiceImpl - 
存储运营商数据失败,Timeout waiting for a pooled item after 120000 MILLISECONDS; 
nested exception is com.mongodb.MongoTimeoutException: 
Timeout waiting for a pooled item after 120000 MILLISECONDS
org.apache.catalina.valves.ErrorReportValveinvoke(ErrorReportValve.java:79)

冰冻三尺非一日之寒,其实 mongo 的问题早已暴露出来:基本信息的推送经常出现超时,前边也已定位到 mongo 操作比较慢这里,推送的成败完全看 mongo 的心情。耽搁于其他事情一时没抽出时间来慎重处理,如今运营商信息推送大量失败忽然爆发,mongo 的问题不得不提前排上处理日程。
首先想到的当然是 mongo 的慢查询,但查看 mongo 日志,很少有超过 150 ms 的 sql 语句。
其次想到的是系统资源吃紧,比如 CPU、内存利用率过高,因为我们的那台机器上同时部署有 nginx、mongo、mysql、java 等。但这个只能说是硬件限制,换句话说,完全可以靠垂直扩展硬件来提升你的系统性能——只要你有足够的钱。但最大限度的利用硬件资源是每个系统设计师应尽的职责所在。
根据笔者的经验,任何恶劣的生产问题,始终会有一个始作俑者的点(问题的制造者),然后各种问题(如内存、CPU、I/O 以及其他,问题的受害者)集中爆发出来,然后系统运维人员被卷入其中而被各种乱象所惑而无从下手——笔者之前就碰到过一位资深 IT 处理这种问题的时候找不到要领所在,而去统计、处理各种问题受害者,完全南辕北辙了。生产事故发生时,作为处理人员应该保持头脑的冷静,综合分析找到问题的制造者,一击制敌
再次,查看问题爆发时的 mongo 连接数,已上升至 100 多个,再往后受限于整个系统的内存情况无法再升,造成上述 Timeout waiting for a pooled item 等待问题。
最后,查看整个 mongo 库数据大小、出问题的 mongo 的那张表及索引空间大小,库大小 20 G,单表几百兆,索引不到表数据空间的一半。这种级别的数据量莫说 mongo,就是 mysql 也不会有任何问题。
综上总结信息:mongo 没有慢查询,大量连接将 mongo 连接数占满而迟迟不释放,大量操作在等待连接池以致超时造成无法存储的生产故障
问题到了这里,大家应该能够分析到问题出在 mongo 结果集传输上了——大量的大的对象的传输受限于带宽限制长久占据着 mongo 连接——该应用里的 mongo 存储的是一些大的基本信息、运营商报文,笔者在系统空闲时用 MongoChef (配外网 ip 访问)根据 id 查询一条基本信息就耗用了近半分钟,事实上该条 sql 的执行只是几个毫秒级别的。

去查看该应用的 spring data mongodb 连接池配置,果然配的是外网。修改为内网 IP 访问,问题迎刃而解,这才是峰值到来时 mongo 应有的表现:

峰值处理时的系统资源消耗情况.png

猜你喜欢

转载自blog.csdn.net/defonds/article/details/78445676