2015年10月20日 星期二

[MongoDB] MongoDB Performance Optimization

曾經碰過 MongoDB 效能問題,資料筆數已達到兆,硬碟也達到 TB,這個問題會造成:

  1. MongoDB 不定時當機,頻率大概一個月一次
  2. 在人多時,某些查詢的 Response time 會很大,最長時可達到 3600s 左右
  3. 以上述的查詢如果一多,會佔住資源,同時也會連帶影響到其他查詢,並拖慢整體速度

大致發生原因如下:

  1. MongoDB 本身是 Document base 資料儲存,適合資料完整儲存,跟 RDBMS 不同的是 RDBMS 會做正規化,之後使用 join 方式 (或多次查詢) 產生 Document。在該系統的 Data Schema 設計上還是使用 RDBMS 的邏輯,故資料需要多次查詢才能產生 Document。
  2. 大部份主要查詢的條件,需要的 index 沒有建立
  3. Page Faults 機率高
  4. 在某些情況下,資料查詢資料數多時很慢
  5. Primary 的 Loading 很重,Secondary 都沒有存取
  6. Database Level lock 會影響到 Read Write Concurrent 的數量

解決的方法也分別如下

  1. 功能 Data Schema 設計上要考量的點。
  2. 建立要用到的 index,使用 Compound Index 來減少所要建立的 index 數量,保持原 specn 不變原則下,同時也要更改程式查詢條件的順序,符合 Compound Index 使用限制。
  3. 提高 memory。
移除用不到的 index,MongoDB會儘力將 index 索引放入 memory,移除用不到的 index 可以讓需要的 index 放入 memory 中。另外依據 index 的 field 有時 index 的資料量會大於真正的實體資料,故也能減少硬碟使用量。
  1. MongoDB 在做分頁就存在的問題,例如 skip or it 在查詢較後面的資料會變慢(跟有無加 limit 沒關係)。所以一般做分頁是直接用條件方式過濾,例如 _id < ‘xxxx’ 會快很多,這可能跟 mongodb 存資料的方式有關。大部份查到的案例是大家在用 remove 有發現這個現象,所以才有 TTL index 的出現吧?所以如果存在一個功能在需要取得全部的資料時,就變的很可怕。跟 PM 商量該業務邏輯是不是可以用其他方式處理,來避開此問題。
  2. 這是程式在建 connection 時並沒有把 Secondary 寫入所致。和 Read Preferences 並沒有設定,修正程式即可。
  3. 當時沒時間做,修完上述五項後,就沒在當過機了。解法有二,更新 3.0,3.0 有 Document Level Lock。另一個是 WhoCall 宋先生在 PHP Conf 2014 分享的一個 Database 一個 Collection,把 Database 當成 Collection 來使用,也是要實驗過才曉得。

處理的方法:

  1. 打開 slow log,整理問題
  2. 學習 MongoDB (大部份資料官網都有寫)
  3. 建立實驗環境
  4. 用 slow log 的 query 在實驗環境上測試,並同時確認使用該查詢的程式碼,可以使用 explain 看查詢狀況 ( status 看 MongoDB 狀況)
  5. 修正問題點,再看實驗結果。不對,就重複步驟 4, 5,直到所有查詢平均能在 1s 左右完成,花最多時間在這裡
  6. 佈署到 Staging,測試系統
  7. 測試沒問題,佈署到 Production

針對優化大致會碰到地方,整理了份心智圖
可以方便去尋找可能的效能問題點






Ref:
https://docs.mongodb.org/manual/core/crud-introduction/
https://docs.google.com/file/d/0B-59_4gDCY8XamJ6X0NySXhZdnM/edit?pli=1


沒有留言:

張貼留言