背景
在实际工作中会遇到不少性能问题,比如内存泄露、内存溢出、连接数达到上限、cpu使用率过高、慢响应等场景问题。不过印象比较深刻的是财税业务项目中遇到的内存溢出问题。
负责的金融调解项目准备上线迭代的需求,就是增加数据上报的服务(oplog)。因为业务会涉及到对账金额安全,需要请求oplog来记录用户操作行为以及资损校验。mangodb数据库存储上报的数据,后台可以查询数据上报结果。
场景问题复现
本来以为是简单的数据上报服务并没有进行性能测试,但在需求上线后不到10分钟,线上监控平台就发出了内存溢出报警,内存使用率超99%。我们第一时间进行版本的回滚,并开始在测试环境复现问题。通过模拟线上并发数,加压到200并发,服务器的内存使用率呈现递增情况,出现内存泄漏,最后导致内存溢出,复现了线上的问题。
问题定位分析
复现问题后,我们采用了以下步骤进行定位:
1、打印被测服务oplog的运行日志,发现数据库读写时间从一开始0.5秒,随着压测持续时间增加,数据读写时间也对应增加,影响到了整个事务的处理响应时间。
2、定位数据读写。我们查看了mangodb数据库的sql语句,只是简单的单表写入情况,并没有复杂的联表查询,便排除了sql问题。
3、查看数据库连接池。通过数据库监控平台,我们发现了连接池达到了上限。当时连接池上限只有50个,导致了后续的新增连接数阻塞等待。
- 问题分析:数据库连接数阻塞等待会导致被测服务oplog事务的阻塞等待。当有新的接口请求被测服务oplog,之前的许多请求会由于数据读写的过程没有处理完成还在等待,导致事务的资源一直积压,没法及时释放,不断占着内存空间,最后出现内存溢出问题。
解决方法
-
方案一:提高数据库连接池上限。但由于当时配置的连接池上限是最优情况,再往上调整可能会出现数据慢响应的情况。所以该方案并不可靠,未被采取。
-
方案二:增加Redis和计时器。将被测服务oplog先写入redis,可以提高数据读写速率,同时可以减轻mangodb数据库的压力。redis的增量数据会定期淘汰,缓存时间10分钟。所以需要增加计时器,每1分钟就将redis的数据写入mangodb数据库。这样对于mangodb来说,也只有一个连接数。
-
采取了方案二后,我们重新测试进行版本发布上线,内存溢出问题没有出现,得以解决。
复盘总结
问题解决后,我们也第一时间进行了完整的线上复盘。从我们测试的角度来说,根本原因是因为我们这边没有做性能测试,没有提前规避问题,当时也觉得只是个简单的数据采集,所以也没考虑到要做性能问题,所以后来的评审时,我们增加多了一个环节,是否需要进行性能测试这样一个评审环节,这就是我们之前遇到的性能问题的一个情况。
评论区