笔者前段时间开发一个新项目的某个功能模块,要读取老游戏中某个Mongo数据库(计做A库),连续读A库中的6个集合(至关于MySQL的6张表)取数据,在测试环境,单次操做时是10ms内,可是并发测试状况下,好比1s内100个并发时,读取A库6个集合的耗时能达到2s以上,甚至7,8s,且n个并发请求几乎同时完成,可是在我本地环境,并发下,平均一次操做也在几十ms到100多ms上下浮动,并发请求也比较正常mongodb
下面讲述一下整个处理过程数据库
虽然使用MongoDB的经验很少,可是在个人认知里,MongoDB的读取性能不可能如此低,否则如何投入生产环境?后端
那么,究竟是哪里出了问题呢?安全
对比本地环境和测试环境使用方式,发现一个区别,我本地环境在Docker中跑的Mongo容器实例,为了方便,并无设置用户名和密码,直接ip+端口号链接,而测试环境用了用户名密码,无论三七二十一,按照高中时候学的生物学中对照实验的思路,目前就只发现一个区别,先进行验证并发
本地链接Mongo的url 127.0.0.1:27017
先按照网上的教程,给Admin数据库创建一个管理员帐号,拥有Mongo实例中读写任何一个db的权限性能
db.createUser({user:"root",pwd:"123456",roles:[{role:"userAdminAnyDatabase",db:"admin"}]})
使用帐号密码后,无并发时,仍然是ms级别,可是发现,本地环境和测试环境同样,并发时,耗时达到数秒,且n个并发请求几乎同时完成,好像某个操做致使阻塞,而后这个阻塞操做完成后,没有阻塞只会,并发读取操做正常执行,能够肯定是Mongo数据库的帐号管理相关问题测试
为啥帐号模块会致使这么大的缺陷?lua
经过神器Google搜索,看了n篇博客,发现一篇12年的博客url
该文做者在生产环境使用Mongo数据库,有性能问题,其中一个 关键点是,Mongo数据库, 若是有用户名和密码,在每次创建数据库链接时,都会验证用户名密码,建议在生产环境不要使用用户名和密码,经过禁止外网访问,经过内网ip以及限制ip的方式,访问mongo数据库
因为线上老项目是lua写的,公司已经一年多未进行代码维护,且准备后面新项目上线后,直接下线老项目,笔者以及公司其余后端,都不懂lua,为了不致使不可预料的问题,同时,在我看来,用户名和密码,对于数据库而言是最重要的安全模块,全球那么多公司在使用,就算帐号验证有必定的性能损耗,可是也不可能有这么大的问题,应该仍是我本身使用方面的问题,继续深刻寻找缘由code
经过请教一位同事,公司另外一个基础服务(计做B服务吧)在生产环境也用了MongoDB,且流量也很大,并无问题,经过对比
个人方式: user:123456@127.0.0.1:27017/admin 而后在代码中经过use,切换到baby库 B服务的方式: 针对baby数据库创建一个帐号,由baby库受权 user:123456@127.0.0.1:27017/baby?authSource=baby&maxPoolSize=50
区别在于我是跳转到baby库,而正常环境下是使用该数据库下的用户
说明数据库受权耗时以及数据库切换也比较耗时,为啥会耗时,看到一篇博客讲到了Mongo的帐号受权原理,知道了创建链接数据库受权时会致使库级锁(即链接a在使用时,链接b进行受权,也会致使baby库锁定,链接a被阻塞)
因而接着本地也适用B服务同样的方式,经过baby库下创建user帐号,直连的方式链接,本地环境耗时正常,并发下读取6个集合,在100ms之内,属于正常性能,可是发到测试环境,并发下虽然耗时减小了,相对于以前的8s,如今依然有1s多的延迟
链接数据库方式同样,可是耗时差异很大,通过上一步知道了耗时是由于数据库锁机制致使的问题,后面在Google上搜Mongo锁机制,在知乎上看到了一个回答
mongodb 最初是全局锁,后来库锁,接着3.0进化到表锁了... 如今使用 WiredTiger 能够实现文档锁...
对比了测试环境和本地环境的版本,本地是最新的,已是3.6版本,测试环境仍是2.6版本,属于库锁
到此,能够知道问题所在了,MongoDB帐号受权机制以及数据库锁机制
以上只是我我的解决这个问题的全过程,博客写的不够思路清晰,过去了半个月,细节也记得不是很清楚了了,但愿能给技术圈有所贡献,谢谢支持