2018年2月25日 星期日

[心得]給評估是否使用mongodb的新手

原本是用來回應苦訴mongo會掉資料的抱怨文,
所以整理了以下目前累積到的經驗和建議,

雖然有點雜亂無章懶的整理,
但有紀錄總比沒有紀錄好:

以下為3.2 ~ 3.6 之間版本為主要說明
  1. mongodb不適合做"交易"(transaction),即使是資深使用者知道如何"手作"也建議不要,完整的交易功能會讓rps減到只有1/5  (2019紀錄, mongo4.0以上開始支援)
  2. 約3~4年前wiretiger已經進入mongo體系,在2~3年前3.2出世預設引擎就已經是wiretiger, 所以懷疑mmapv3效率和安全性的可以暫時忽略mmapv3可能的問題
  3. 新手常用apt-get install安裝mongo會直接安裝到2.4問題還很多的版本,前幾樓說的狀況全部都有,所以請新手記得去找新版來用,或是常關注更新版本。
  4. journaling千萬不要關,在wiretiger支援下基本上不太消耗效能,即使是為了要讓benchmark好看,機制上是用記憶體當緩衝,讓你感覺資料已經處理完,但事實上都還沒進磁碟,等到用完記憶體,磁碟存入速度又追不上,效能就開始大幅衰退。
  5. 當壓力特大時,例如90krps, replication就會有危險,因為即使master寫的進去,但slave資料完全追不上,即使加大oplog也於事無補,最好是達到最高rps一半就要準備其他方案,除非捨棄replication架構
  6. drop collection很快,比用deleteMany({})還要快N倍,但是會造成db lock (name space),如果有"低反應時間的服務"時必注意。
  7. 玩了這麼多年大規模mongodb, 最怕不是mongo本身效率不好,而是怕硬體不好,大多都卡在硬碟IOPS 上限,改用SSD一切問題都沒了
  8. 很多使用者都以為read/write效能很高,單機可以飆到90krps,但都忘記upsert會耗掉折半,delete也是折半,update也是折半。
  9. 有遇過沒有設index在抱怨mongodb很慢,以前5個會有1個,現在比較好, 10個只會有一個
  10. 新版本mongo解開很多令人討厭的限制,例如collection 數量已經沒有上限,collection和一些命名可以並更長。
  11. 和sqldb比起來,mongodb單筆資料最大可以吃16MB,很放便某些應用,但這時候別忘記這時候瓶頸點在硬體的IO,硬碟每秒多少MB還有網路卡能承受每秒多少MB
  12. MongoDB對於用習慣sql的人來說,沒有join真的會頭痛很久,主要是因為在sql中有標準化的概念,在mongodb基本概念就是資料全展開放到json每一層之中,當然這是好處也是壞處
  13. 原本都不提供group功能,v3.x也提供了,雖然我覺得會大量使用mongodb的人其實並不需要group功能
  14. mongo在3.2還是3.4版之後出了in-memory mongodb,速度快到不要不要的,用法跟原本mongo一模一樣,而且可以和普通的mongodb點混搭,我曾設計in-memory 為master, SSD mongodb作為slave (這樣同步才追的上master),讀寫分離目前還沒看到頂,受限於測試能發出的量目前為13~15萬rps
  15. 官方的工具沒遇過狀況,archive資料都正常,放回去也OK,拉出資料愈多,每秒可以處理的量差距愈大(太進階先不說了),但我要說的是官方工具設計並不是最好的,我用自己程式取代他原有的反而效率比較好。
  16. OS有許多參數要設定,例如不要讓os作swap,一旦swap速度又會慢到想哭,寧願違背官方建議設定vm.overcommit_memory設成2還是比較妥當,只是記得設定--wiredTigerCacheSizeGB
  17. ulimit 中的 open files能開多大就是多大,每個connection都會吃掉幾個file資源,無論你connection設定多高都沒用,都會被limit.conf中的預設值卡住
  18. 如果是cluster連到mongos數量並非愈多愈好,也不是愈少愈好,操作簡單資料量少在我環境下最佳rps連線數約在50~80個,但複雜指令,單比資料肥,3k連線數也都不是問題。
  19. 很多開發者覺得好用的地方是不需要建schema,對於統計資料,或是放雜七雜八不知道什麼type的數據很方便,彈性也很大。
  20. 官方對於比較複雜架構,例如sharding中又掛replication的進階設定沒有很詳細說明,例如replication不夠用,想要在online狀況下增加slave數量,或是作主從交換都很難找到資料 (雖然我研究很久還是成功了),目前只有在需要付費的UI工具中看到有這設定
  21. 如果老闆或主管想要用mongodb,先問問用途是什麼,如果牽涉到交易,千萬不能妥協,這時候就要裝作mongodb爛到不行,仍然是2.4版的狀況,否則薪資要兩倍,準備好打包前可以撈一筆
  22. 我看很多罵,mongo都是用2.4版的角度在罵,就好像現在都iphoneX還在罵iphone6效能多差或是問題很多,覺得不是很好的討論切入點。
  23. mongodb原設計者是說設計方向本來就不是做交易用的,未來也不會支援(說的很硬),幾年過去了,最近說的比較含糊,感覺未來或許有可能開放交易功能? 但我覺得還是不要抱持樂觀的態度,要交易?請選sqldb
  24. 其實還有很多經驗可以寫,但是寫太長寫到後來想寫啥都忘了,最後給選擇mongodb評估的人建議,想要寫入讀取高效,資料處理便利,json data愛用者,低延遲query的服務可考慮,要做交易的,各種搶票的,會大量更新同筆資料,的不建議,要做heartbeat的可以考慮in-memory mongodb, 真心覺得比redius好用,還能完全嵌入到原有的cluster之中

後續補充:
  1. 怕journaling沒寫到磁碟,可以在參數加上j=True Python範例:db.col.insert(data, j=True)
  2. 用replication,又大玩讀寫分離,怕資料不同可以設定write concern
  3. 2017年中3.x全部改新版預設write concern為majority,可能是大家抱怨掉資料,或是避免開發者哭餓,所以從原本預設為0全部改為majority,意思不難理解,三台同步,要兩台寫入資料才讀的到資料,但是對於要求高速和高吞吐量的服務來說,在那時都碰到一個莫名其妙的大牆。(query等很久慢到不行)
  4. 想當然j=True 先將journal資料寫入磁碟,會比只寫入記憶體慢,慢多少我還沒試,畢竟我還是比較喜歡追求速度(誤)
  5. 想在大型伺服器(非個人桌機),使用大量使用記憶體暫存的能力,去拉高mongo效能,或是in-memory mongodb,務必要去調整numa(不過設定太進階了,自己去找資料)。如果沒調整numa,使用愈多記憶體,速度反而會愈慢。
  6. mongo 3.x之後支援spark
  7. 官方提供SQL Driver for MongoDB (沒用過之後有人用也歡迎提說心得)
  8. mongo有提供專門給log用名為Capped Collections(https://goo.gl/CXvMTs),但設定之後就不可以改變,效能更好,預設TTL和rotate缺點是只能是固定的col size
  9. sharding是capability增加,但效率會隨愈多台逐降,如果對資料庫操作"非常"熟悉,可考慮單架mongod,用map_hash_id去自己拼cluster,效能更棒
  10. mongo有aggregate的功能,很有趣也可以做很靈活的操作,但是如果使用db的人很多,建議還是把這些耗DB效能的處理移到外部
  11. 很多新手只會下尋條件,但是不會去filter欄位,這功能像似SQL語法中的select,可以大幅減少頻寬和client端記憶體的消耗,通常都是到使用量很大開發者才開始注意到這點。
  12. skip一旦大於某個數量級,效能會大幅度衰退,進而影響到整個資料庫使用,所以skip不是萬能的,我是用演算法將skip減半,或是用其他方法直接取得資料,而不是濫用skip
  13. 很多人以為加上index大部份都可以加速,但事實上mongo index還是有限制:
    a. 正则表达式及非操作符,如 $nin, $not, 等不支援。(官方文件是說,用$nin或$not會因為匹配大多數結果,所以設index並不會比沒設index好)
  14. b. 算術操作不支援 $mod,及延伸操作$where不支援
  15. 2.6版後index超過1024長度就不會幫你建index, 直接噴exception
  16. 一個collection 最大不能超過64個indexes, 複合indexes不能超過31個
  17. 3.2版後array內部值可以建index
  18. 3.4版後可以讓aggregate寫到記憶體(allowDiskUse: true),就不會被16MB給限制住
  19. insert_many若沒有其他特別原因,可以加ordered=False參數,好處是速度加快,而且有其中一筆資料出錯,也不會影響到其他資料塞入,當然資料性質需要排序或是整體完整性的話例外。

1 則留言: