記錄一次併發讀取MongoDB的踩坑過程

出現的問題

筆者前段時間開發一個新項目的某個功能模塊,要讀取老遊戲中某個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帳號受權機制以及數據庫鎖機制

總結

  • 感興趣的客觀能夠搜索MongoDB鎖機制相關博客,網上文章不少,我就不在此囉嗦了
  • Mongo數據庫,在生產環境,儘可能經過限制內網ip才能夠訪問的方式保證安全,防止攻擊
  • 其次,不要經過admin管理員用戶鏈接數據庫,該帳號只是作爲管理員使用,而不該該做爲生產環境使用,MongoDB的思想是帳號和數據庫綁定,而不是實例,MySQL是一個MySQL實例對應帳號,不針對某db
  • 儘可能使用3.X的新版本MongoDB,數據庫鎖已經完善

以上只是我我的解決這個問題的全過程,博客寫的不夠思路清晰,過去了半個月,細節也記得不是很清楚了了,但願能給技術圈有所貢獻,謝謝支持

相關文章
相關標籤/搜索