java mongodb driver驱动jar包_MongoDB 临时表横空出现1万+,这条语句执行前请准备好翻车的姿势

0214dadb7d2ce99eb0794e05af5d4353.png

解决问题之前,先在脑海中演绎一下当时场景

某日早上八点半,笔者接到客户反馈,门户首页待办访问异常缓慢,经常出现“访问异常,点击重试”。当时直觉告诉我,应该是大量用户高并发访问 MongoDB 库,导致 MongoDB 库连接池出问题了,因为上线发版时,功能是正常的。

96b748675bfa99880053567af7c4e3f1.png

由于是上周五晚上发版验证后,周六日使用门户的用户比较少,一直没发现问题,直到下周一才集中爆发门户访问不可用。

请开始我的表演

一开始运维组认为是加了 MongoDB 审计日志造成的,因为有大量针对 MongoDB 做写审计日志写操作,确实会降低服务器性能。 通过查看服务日志,也发现非常多的 MongoDB 访问 timeout 异常信息。

com.mongodb.MongoTimeoutException: Timed out after 30000 ms while waiting for a server that matches ReadPreferenceServerSelector{readPreference=primary}. Client view of cluster state is {type=UNKNOWN, servers=[{address=10.236.2.183:27017, type=UNKNOWN, state=CONNECTING, exception={com.mongodb.MongoSocketOpenException: Exception opening socket}, caused by {java.net.ConnectException: Connection refused (Connection refused)}}, {address=10.236.2.184:27017, type=UNKNOWN, state=CONNECTING, exception={com.mongodb.MongoSocketOpenException: Exception opening socket}, caused by {java.net.ConnectException: Connection refused (Connection refused)}}, {address=10.236.2.185:27017, type=UNKNOWN, state=CONNECTING, exception={com.mongodb.MongoSocketOpenException: Exception opening socket}, caused by {java.net.ConnectException: Connection refused (Connection refused)}}]    at com.mongodb.connection.BaseCluster.createTimeoutException(BaseCluster.java:377) ~[mongodb-driver-core-3.4.2.jar!/:na]    at com.mongodb.connection.BaseCluster.selectServer(BaseCluster.java:104) ~[mongodb-driver-core-3.4.2.jar!/:na]    at com.mongodb.binding.ClusterBinding$ClusterBindingConnectionSource.(ClusterBinding.java:75) ~[mongodb-driver-core-3.4.2.jar!/:na]    at com.mongodb.binding.ClusterBinding$ClusterBindingConnectionSource.(ClusterBinding.java:71) ~[mongodb-driver-core-3.4.2.jar!/:na]    at com.mongodb.binding.ClusterBinding.getReadConnectionSource(ClusterBinding.java:63) ~[mongodb-driver-core-3.4.2.jar!/:na]    at com.mongodb.operation.OperationHelper.withConnection(OperationHelper.java:402) ~[mongodb-driver-core-3.4.2.jar!/:na]    at com.mongodb.operation.MapReduceWithInlineResultsOperation.execute(MapReduceWithInlineResultsOperation.java:381) ~[mongodb-driver-core-3.4.2.jar!/:na]    at com.mongodb.operation.MapReduceWithInlineResultsOperation.execute(MapReduceWithInlineResultsOperation.java:70) ~[mongodb-driver-core-3.4.2.jar!/:na]    at com.mongodb.Mongo.execute(Mongo.java:836) ~[mongodb-driver-3.4.2.jar!/:na]    at com.mongodb.Mongo$2.execute(Mongo.java:823) ~[mongodb-driver-3.4.2.jar!/:na]    at com.mongodb.DBCollection.mapReduce(DBCollection.java:1278) ~[mongodb-driver-3.4.2.jar!/:na]    at org.springframework.data.mongodb.core.MongoTemplate.mapReduce(MongoTemplate.java:1406) ~[spring-data-mongodb-1.10.1.RELEASE.jar!/:na]    at org.springframework.data.mongodb.core.MongoTemplate.mapReduce(MongoTemplate.java:1383) ~[spring-data-mongodb-1.10.1.RELEASE.jar!/:na]    at com.unicom.portal.taskquery.common.TaskManager.selectPendingCountByType(TaskManager.java:1002) ~[classes!/:1.0.0]    at com.unicom.portal.taskquery.service.impl.TaskServiceImpl.getPendingInfo(TaskServiceImpl.java:233) ~[classes!/:1.0.0]    at com.unicom.portal.taskquery.controller.TaskPendController.getPendingInfo(TaskPendController.java:164) ~[classes!/:1.0.0]

同时运维人员通过监控告警发现 MongoDB 数据库的连接数达到 10499(平时监控为几百),而 MongoDB 数据库凭空多出惊人的一万多张临时表记录。

b5953af96d1a0a0071c5b9f0f748d0f7.png

查看 K8s 容器平台服务器资源情况,发现待办服务 CPU 资源使用高达 7G 多,内存使用高达 12G。平常待办服务的CPU 资源使用都是 0.00 几,明显感觉不正常。

273869e22243bb61dc2c7f56da4d75d8.png

这似乎更加验证了是加了审计日志造成的,于是运维组开始了非常耗时的 Mongos 停止并重启操作,但很遗憾的是“ Mongos 重启后不久又自动停止了”( 后来跟运维组沟通,加的审计日志跟 MongoDB 半毛钱关系都没有)。 由于这个误导,导致门户大概四十分钟不可用。笔者没办法,只能仔细分析 docker 容器日志,发现大部分错误由同一个方法造成的。

com.unicom.portal.taskquery.common.TaskManager.selectPendingCountByType(TaskManager.java:1002)

通过代码走读发现 TaskManager.selectPendingCountByType 这个方法用到了 MongoDB 的 mapReduce 方法。

org.springframework.data.mongodb.core.MongoTemplate.mapReduce

通过查阅 MongoDB 官方文档知悉, mapReduce 方法类似于 MySQL 中的 group by 语句,非常适合做表字段聚合(分组)分类统计功能。 了解 Hadoop 的同学知道,Hadoop 中的 Map 和 Reduce 会拆成多个子任务进行后台跑批计算的。而 MongoDB 的 mapReduce 方法同样如此,不同的是 mapReduce 方法会把子任务发送到不同的分片(sharding)服务器上去执行,而这个过程是非常耗时的。 平常几十个人使用这个功能不会觉察到访问有问题,但是门户每天近 12W 的用户同时在八点半之后访问这个功能,后果就不堪设想了。 结果是“ 修改后的待办待阅查询服务在读取/存储过程中会创建大量临时表,高并发时会造成待办 MongoDB 数据库频繁执行和删表操作,致使服务器资源异常占满,MongoDB 数据库进程异常关闭。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值