Part1:寫在最前html
在副本集架構中,當咱們面臨寫多讀少,且大多數寫爲update操做時,WT引擎的瓶頸初顯。這直接致使業務反饋寫入操做耗時較久等異常。爲此,Percona版本的MongoDB裏支持rocksDB存儲引擎,應對寫比較多的時候會顯得更加從容。web
Part2:背景mongodb
在業務大量更新的場景中咱們發現WT存儲引擎的disk lantency會比較高,在嘗試調大cache_size和併發數、eviction後效果不佳,所以咱們嘗試使用rocksDB引擎代替。安全
Part3:措施微信
將write concern從majority變動爲1,觀察效果session
w: 數據寫入到number個節點才向用客戶端確認{w: 0} 對客戶端的寫入不須要發送任何確認,適用於性能要求高,但不關注正確性的場景架構
{w: 1} 默認的writeConcern,數據寫入到Primary就向客戶端發送確認併發
{w: 「majority」} 數據寫入到副本集大多數成員後向客戶端發送確認,適用於對數據安全性要求比較高的場景,該選項會下降寫入性能app
j: 寫入操做的journal持久化後才向客戶端確認默認爲」{j: false},若是要求Primary寫入持久化了才向客戶端確認,則指定該選項爲true運維
以前開了majority,慢的同時,在3.2.6版本後,也會同時開啓journal日誌的磁盤寫入,致使磁盤耗時增長,進而致使寫入更慢,把writeconcern改到1,能夠提高寫入速率
相關參數
writeConcernMajorityJournalDefault
Part4:日誌抓取
2018-08-21T01:00:50.096+0800 I COMMAND [conn4072412] command kgcxxxt.$cmd command: update { update: "col", ordered: true, writeConcern: { w: "majority" }, $db: "kgcxxxt" } numYields:0 reslen:295 locks:{ Global: { acquireCount: { r: 2, w: 2 } }, Database: { acquireCount: { w: 2 } }, Collection: { acquireCount: { w: 1 } }, oplog: { acquireCount: { w: 1 } } } protocol:op_query 137ms
....
....
2018-08-21T01:00:50.096+0800 I COMMAND [conn4072176] command kgcxxxt.$cmd command: update { update: "col", ordered: true, writeConcern: { w: "majority" }, $db: "kgcxxxt" } numYields:0 reslen:295 locks:{ Global: { acquireCount: { r: 2, w: 2 } }, Database: { acquireCount: { w: 2 } }, Collection: { acquireCount: { w: 1 } }, oplog: { acquireCount: { w: 1 } } } protocol:op_query 137ms
Part5:監控
替換爲write concern 1後,qps提升到15k
Part6:調大相關參數
嘗試調大cache_size和eviction db.adminCommand({setParameter: 1, wiredTigerEngineRuntimeConfig: "cache_size=90G"}) db.adminCommand({setParameter: 1, wiredTigerEngineRuntimeConfig: "eviction=(threads_min=1,threads_max=8)"})
能夠看出,在調大參數後排隊的狀況降下來了
可是這一好景不長,沒過多久依舊出現了咱們不但願看到的狀況,所以後續咱們決定採用rocksDB引擎。
Part1:總體架構
原有集羣爲3節點副本集架構,均使用WT存儲引擎。咱們將其中一臺從庫換爲rocksDB存儲引擎,觀察disk lantancy狀況。
如上圖所示,能夠看出主節點的QPS狀況。
Part2:rocksDB引擎從庫
咱們將其中一臺從庫配置爲rocksDB引擎,RocksDB相對WT一大改進是採用LSM樹存儲引擎。Wiredtiger 基於 btree 結構組織數據,在一些極端場景下,由於 Cache eviction 及寫入放大的問題,可能致使 Write hang,細節能夠到 MongoDB jira 上了解相關的issue,針對這些問題 MongoDB 官方團隊一直在優化,咱們也看到 Wiredtiger 穩定性在不斷提高;而 RocksDB 是基於 LSM tree 結構組織數據,其針對寫入作了優化,將隨機寫入轉換成了順序寫入,能保證持續高效的數據寫入。在替換其中一臺從庫爲rocksDB引擎後,咱們將其與另一臺WT引擎的從庫進行disk lantency的對比。
下圖爲使用lsm Tree 結構的rocksDB存儲引擎從庫的disk lantency,能夠看出都在1ms內。
其qps以下圖所示,repl_delete在3k左右且連續穩定。
Part3:WT引擎從庫
下圖爲使用WT存儲引擎從庫,其disk lantency和主庫同樣,寫入的lantency達到了8ms,讀也有4ms
其qps在2.3k左右,且監控出現斷點,從庫出現因壓力大登陸超時的狀況。
Part4:RocksDB引擎配置參數
storage: engine: rocksdb useDeprecatedMongoRocks: true dbPath: /home/work/mongodb/mongo_28000/data/db_28000 indexBuildRetry: true journal: enabled: true commitIntervalMs: 100 rocksdb: cacheSizeGB: 10 compression: snappy maxWriteMBPerSec: 1024 configString: write_buffer_size=512M;level0_slowdown_writes_trigger=12;min_write_buffer_number_to_merge=2; crashSafeCounters: false counters: true singleDeleteIndex: false
註釋1
#storage Options storage: engine: "rocksdb" useDeprecatedMongoRocks: true ##percona 3.6版本須要加 dbPath: /home/work/mongodb/mongo_10001/data rocksdb: cacheSizeGB: 10 # 默認是30% of physical memory compression: snappy maxWriteMBPerSec: 1024 #單位MB,rocks writes to storage 的速度,下降這個值能夠減小讀延遲刺尖,但該值過低會下降寫入速度 configString: write_buffer_size=512M;level0_slowdown_writes_trigger=12;min_write_buffer_number_to_merge=2; crashSafeCounters: false #指定crash以後是否正確計數,開啓這個選項可能影響性能 counters: true #(默認開)指定是否使用advanced counters,關閉它能夠提升寫性能 singleDeleteIndex: false
在添加 configString: write_buffer_size=512M;level0_slowdown_writes_trigger=12;min_write_buffer_number_to_merge=2; 參數後,磁盤延遲進一步下降,iops也進一步下降
這裏須要注意的是,percona從3.6版本起不建議使用rocksdb,可能在下一個大版本移除,至因而否選用,要根據實際狀況出發,最好可以拉上業務一塊兒進行一個壓測,知足業務需求的,就是最好的。
https://www.percona.com/doc/percona-server-for-mongodb/LATEST/mongorocks.html
註釋2
rocksdb參數的調節通常是在三個因素之間作平衡:寫放大、讀放大、空間放大 1.flush選項: write_buffer_size: memtable的最大size,若是超過了這個值,RocksDB就會將其變成immutablememtable,並在使用另外一個新的memtable max_write_buffer_number: 最大memtable的個數,若是activememtablefull了,而且activememtable加上immutablememtable的個數已經到了這個閥值,RocksDB就會中止後續的寫入。一般這都是寫入太快可是flush不及時形成的。 min_write_buffer_number_to_merge: 在flush到level0以前,最少須要被merge的memtable個數。若是這個值是2,那麼當至少有兩個immutable的memtable的時候,RocksDB會將這兩個immutablememtable先merge,再flush到level0。預先merge能減少須要寫入的key的數據,譬如一個key在不一樣的memtable裏面都有修改,那麼咱們能夠merge成一次修改。但這個值太大了會影響讀取性能,由於Get會遍歷全部的memtable來看這個key是否存在。 舉例:write_buffer_size=512MB;max_write_buffer_number=5;min_write_buffer_number_to_merge=2; 假設寫入速率是16MB/s,那麼每32s的時間都會有一個新的memtable生成,每64s的時間就會有兩個memtable開始merge。取決於實際的數據,須要flush到level0的大小可能在512MB和1024MB之間,一次flush也可能須要幾秒的時間 (取決於盤的順序寫入速度)。最多有5個memtable,當達到這個閥值,RocksDB就會組織後續的寫入了。 2.LevelStyleCompaction: level0_slowdown_writes_trigger: 當level0的文件數據達到這個值的時候,就開始進行level0到level1的compaction。因此一般level0的大小就是write_buffer_size*min_write_buffer_number_to_merge*level0_file_num_compaction_trigger。 max_background_compactions: 是指後臺壓縮的最大併發線程數,默認爲1,但爲了充分利用你的CPU和存儲,能夠將該值配置爲機器核數 max_background_flushes: 併發執行flush操做的最大線程數,一般設置爲1已是足夠了。
以下是使用 sysbench 進行的一個簡單的 insert 測試,insert 的集合默認帶一個二級索引,在剛開始 Wiredtiger 的寫入性能遠超 RocksDB,而隨着數據量愈來愈大,WT的寫入能力開始降低,而 RocksDB 的寫入一直比較穩定。
更多 Wiredtiger、Mongorocks 的對比能夠參考 Facebook 大神在 Percona Live 上的技術分享。
https://www.percona.com/live/17/sessions/comparing-mongorocks-wiredtiger-and-mmapv1-performance-and-efficiency?spm=a2c4e.11153940.blogcont231377.21.6c457b684BOXvj
——總結——
經過本文,咱們瞭解到RocksDB引擎的特色和與WT存儲引擎的disk lantency對比,不一樣的業務場景不一樣,所以具體使用什麼存儲引擎,還須要結合具體業務來進行評估。因爲筆者的水平有限,編寫時間也很倉促,文中不免會出現一些錯誤或者不許確的地方,不妥之處懇請讀者批評指正。喜歡筆者的文章,右上角點一波關注,謝謝~
參考資料:
https://www.percona.com/doc/percona-server-for-mongodb/LATEST/mongorocks.html
https://yq.aliyun.com/articles/231377
歷經1年時間,和個人摯友張甦先生合著了這本《MongoDB運維實戰》,感謝電子工業出版社,感謝張甦先生讓我圓了出書夢!感謝友東哥、李丹哥、李彬哥、張良哥的書評!感謝友飛哥、汝林哥在我入職小米以來工做上的指導和幫助!感謝個人愛人李愛璇女士,沒有你在背後支持,我不可能完成這項龐大的工程。京東自營有貨,喜歡MongoDB的同窗歡迎支持!