曾經碰過 MongoDB 效能問題,資料筆數已達到兆,硬碟也達到 TB,這個問題會造成:
- MongoDB 不定時當機,頻率大概一個月一次
- 在人多時,某些查詢的 Response time 會很大,最長時可達到 3600s 左右
- 以上述的查詢如果一多,會佔住資源,同時也會連帶影響到其他查詢,並拖慢整體速度
大致發生原因如下:
- MongoDB 本身是 Document base 資料儲存,適合資料完整儲存,跟 RDBMS 不同的是 RDBMS 會做正規化,之後使用 join 方式 (或多次查詢) 產生 Document。在該系統的 Data Schema 設計上還是使用 RDBMS 的邏輯,故資料需要多次查詢才能產生 Document。
- 大部份主要查詢的條件,需要的 index 沒有建立
- Page Faults 機率高
- 在某些情況下,資料查詢資料數多時很慢
- Primary 的 Loading 很重,Secondary 都沒有存取
- Database Level lock 會影響到 Read Write Concurrent 的數量
解決的方法也分別如下
- 功能 Data Schema 設計上要考量的點。
- 建立要用到的 index,使用 Compound Index 來減少所要建立的 index 數量,保持原 specn 不變原則下,同時也要更改程式查詢條件的順序,符合 Compound Index 使用限制。
- 提高 memory。
移除用不到的 index,MongoDB會儘力將 index 索引放入 memory,移除用不到的 index 可以讓需要的 index 放入 memory 中。另外依據 index 的 field 有時 index 的資料量會大於真正的實體資料,故也能減少硬碟使用量。
- MongoDB 在做分頁就存在的問題,例如 skip or it 在查詢較後面的資料會變慢(跟有無加 limit 沒關係)。所以一般做分頁是直接用條件方式過濾,例如 _id < ‘xxxx’ 會快很多,這可能跟 mongodb 存資料的方式有關。大部份查到的案例是大家在用 remove 有發現這個現象,所以才有 TTL index 的出現吧?所以如果存在一個功能在需要取得全部的資料時,就變的很可怕。跟 PM 商量該業務邏輯是不是可以用其他方式處理,來避開此問題。
- 這是程式在建 connection 時並沒有把 Secondary 寫入所致。和 Read Preferences 並沒有設定,修正程式即可。
- 當時沒時間做,修完上述五項後,就沒在當過機了。解法有二,更新 3.0,3.0 有 Document Level Lock。另一個是 WhoCall 宋先生在 PHP Conf 2014 分享的一個 Database 一個 Collection,把 Database 當成 Collection 來使用,也是要實驗過才曉得。
處理的方法:
- 打開 slow log,整理問題
- 學習 MongoDB (大部份資料官網都有寫)
- 建立實驗環境
- 用 slow log 的 query 在實驗環境上測試,並同時確認使用該查詢的程式碼,可以使用 explain 看查詢狀況 ( status 看 MongoDB 狀況)
- 修正問題點,再看實驗結果。不對,就重複步驟 4, 5,直到所有查詢平均能在 1s 左右完成,花最多時間在這裡
- 佈署到 Staging,測試系統
- 測試沒問題,佈署到 Production
針對優化大致會碰到地方,整理了份心智圖
可以方便去尋找可能的效能問題點
可以方便去尋找可能的效能問題點
Ref:
https://docs.mongodb.org/manual/core/crud-introduction/
https://docs.google.com/file/d/0B-59_4gDCY8XamJ6X0NySXhZdnM/edit?pli=1
沒有留言:
張貼留言