久久久久久久视色,久久电影免费精品,中文亚洲欧美乱码在线观看,在线免费播放AV片

<center id="vfaef"><input id="vfaef"><table id="vfaef"></table></input></center>

    <p id="vfaef"><kbd id="vfaef"></kbd></p>

    
    
    <pre id="vfaef"><u id="vfaef"></u></pre>

      <thead id="vfaef"><input id="vfaef"></input></thead>

    1. 站長資訊網(wǎng)
      最全最豐富的資訊網(wǎng)站

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        Oppo文檔數(shù)據(jù)庫研發(fā)負(fù)責(zé)人:楊亞洲

        1.背景

        線上某集群峰值TPS超過100萬/秒左右(主要為寫流量,讀流量較少,讀寫流量做了主從讀寫分離,讀流量走從節(jié)點(diǎn),qps數(shù)百上千),峰值tps幾乎已經(jīng)到達(dá)集群上限,同時平均時延也超過100ms,隨著讀寫流量的進(jìn)一步增加,時延抖動嚴(yán)重影響業(yè)務(wù)可用性。該集群采用mongodb天然的分片模式架構(gòu),數(shù)據(jù)均衡的分布于各個分片中,添加片鍵啟用分片功能后實(shí)現(xiàn)完美的負(fù)載均衡。集群每個節(jié)點(diǎn)流量監(jiān)控如下圖所示:

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐
      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        從上圖可以看出集群流量比較大,峰值已經(jīng)突破120萬/秒,其中delete過期刪除的流量不算在總流量里面(delete由主觸發(fā)刪除,但是主上面不會顯示,只會在從節(jié)點(diǎn)拉取oplog的時候顯示)。如果算上主節(jié)點(diǎn)的delete流量,峰值總tps超過150萬/秒。

        2.軟件優(yōu)化

        在不增加服務(wù)器資源的情況下,首先做了如下軟件層面的優(yōu)化,并取得了理想的數(shù)倍性能提升:

        業(yè)務(wù)層面優(yōu)化

        Mongodb配置優(yōu)化

        存儲引擎優(yōu)化

        2.1 業(yè)務(wù)層面優(yōu)化

        該集群總文檔近百億條,每條文檔記錄默認(rèn)保存三天,業(yè)務(wù)隨機(jī)散列數(shù)據(jù)到三天后任意時間點(diǎn)隨機(jī)過期淘汰。由于文檔數(shù)目很多,白天平峰監(jiān)控可以發(fā)現(xiàn)從節(jié)點(diǎn)經(jīng)常有大量delete操作,甚至部分時間點(diǎn)delete刪除操作數(shù)已經(jīng)超過了業(yè)務(wù)方讀寫流量,因此考慮把delete過期操作放入夜間進(jìn)行,過期索引添加方法如下:

        Db.collection.createIndex( { “expireAt”: 1 }, { expireAfterSeconds: 0 } )

        上面的過期索引中expireAfterSeconds=0,代表collection集合中的文檔的過期時間點(diǎn)在expireAt時間點(diǎn)過期,例如: db.collection.insert( {

        //表示該文檔在夜間凌晨1點(diǎn)這個時間點(diǎn)將會被過期刪除

        ”expireAt”: new Date(‘July 22, 2019 01:00:00’),

        ”logEvent”: 2,

        ”logMessage”: “Success!”

        } )

        通過隨機(jī)散列expireAt在三天后的凌晨任意時間點(diǎn),即可規(guī)避白天高峰期觸發(fā)過期索引引入的集群大量delete,從而降低了高峰期集群負(fù)載,最終減少業(yè)務(wù)平均時延及抖動。

        Delete過期Tips1: expireAfterSeconds含義

        1. 在expireAt指定的絕對時間點(diǎn)過期,也就是12.22日凌晨2:01過期

        Db.collection.createIndex( { “expireAt”: 1 }, { expireAfterSeconds: 0 } )

        db.log_events.insert( { “expireAt”: new Date(Dec 22, 2019 02:01:00′),”logEvent”: 2,”logMessage”: “Success!”})

        expireAt指定的時間往后推遲expireAfterSeconds秒過期,也就是當(dāng)前時間往后推遲60秒過期

        db.log_events.insert( {“createdAt”: new Date(),”logEvent”: 2,”logMessage”: “Success!”} )

        Db.collection.createIndex( { “expireAt”: 1 }, { expireAfterSeconds: 60 } )

        Delete過期Tips2: 為何mongostat只能監(jiān)控到從節(jié)點(diǎn)有delete操作,主節(jié)點(diǎn)沒有?

        原因是過期索引只在master主節(jié)點(diǎn)觸發(fā),觸發(fā)后主節(jié)點(diǎn)會直接刪除調(diào)用對應(yīng)wiredtiger存儲引擎接口做刪除操作,不會走正常的客戶端鏈接處理流程,因此主節(jié)點(diǎn)上看不到delete統(tǒng)計。

        主節(jié)點(diǎn)過期delete后會生存對于的delete oplog信息,從節(jié)點(diǎn)通過拉取主節(jié)點(diǎn)oplog然后模擬對于client回放,這樣就保證了主數(shù)據(jù)刪除的同時從數(shù)據(jù)也得以刪除,保證數(shù)據(jù)最終一致性。從節(jié)點(diǎn)模擬client回放過程將會走正常的client鏈接過程,因此會記錄delete count統(tǒng)計,詳見如下代碼:

        官方參考如下: https://docs.mongodb.com/manual/tutorial/expire-data/

        2.2 Mongodb配置優(yōu)化(網(wǎng)絡(luò)IO復(fù)用,網(wǎng)絡(luò)IO和磁盤IO做分離)

        由于集群tps高,同時整點(diǎn)有大量推送,因此整點(diǎn)并發(fā)會更高,mongodb默認(rèn)的一個請求一個線程這種模式將會嚴(yán)重影響系統(tǒng)負(fù)載,該默認(rèn)配置不適合高并發(fā)的讀寫應(yīng)用場景。官方介紹如下:

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        2.2.1 Mongodb內(nèi)部網(wǎng)絡(luò)線程模型實(shí)現(xiàn)原理

        mongodb默認(rèn)網(wǎng)絡(luò)模型架構(gòu)是一個客戶端鏈接,mongodb會創(chuàng)建一個線程處理該鏈接fd的所有讀寫請求及磁盤IO操作。

        Mongodb默認(rèn)網(wǎng)絡(luò)線程模型不適合高并發(fā)讀寫原因如下:

        1. 在高并發(fā)的情況下,瞬間就會創(chuàng)建大量的線程,例如線上的這個集群,連接數(shù)會瞬間增加到1萬左右,也就是操作系統(tǒng)需要瞬間創(chuàng)建1萬個線程,這樣系統(tǒng)load負(fù)載就會很高。

        2. 此外,當(dāng)鏈接請求處理完,進(jìn)入流量低峰期的時候,客戶端連接池回收鏈接,這時候mongodb服務(wù)端就需要銷毀線程,這樣進(jìn)一步加劇了系統(tǒng)負(fù)載,同時進(jìn)一步增加了數(shù)據(jù)庫的抖動,特別是在PHP這種短鏈接業(yè)務(wù)中更加明顯,頻繁的創(chuàng)建線程銷毀線程造成系統(tǒng)高負(fù)債。

        3. 一個鏈接一個線程,該線程除了負(fù)責(zé)網(wǎng)絡(luò)收發(fā)外,還負(fù)責(zé)寫數(shù)據(jù)到存儲引擎,整個網(wǎng)絡(luò)I/O處理和磁盤I/O處理都由同一個線程負(fù)責(zé),本身架構(gòu)設(shè)計就是一個缺陷。

        2.2.2 網(wǎng)絡(luò)線程模型優(yōu)化方法

        為了適應(yīng)高并發(fā)的讀寫場景,mongodb-3.6開始引入serviceExecutor: adaptive配置,該配置根據(jù)請求數(shù)動態(tài)調(diào)整網(wǎng)絡(luò)線程數(shù),并盡量做到網(wǎng)絡(luò)IO復(fù)用來降低線程創(chuàng)建消耗引起的系統(tǒng)高負(fù)載問題。此外,加上serviceExecutor: adaptive配置后,借助boost:asio網(wǎng)絡(luò)模塊實(shí)現(xiàn)網(wǎng)絡(luò)IO復(fù)用,同時實(shí)現(xiàn)網(wǎng)絡(luò)IO和磁盤IO分離。這樣高并發(fā)情況下,通過網(wǎng)絡(luò)鏈接IO復(fù)用和mongodb的鎖操作來控制磁盤IO訪問線程數(shù),最終降低了大量線程創(chuàng)建和消耗帶來的高系統(tǒng)負(fù)載,最終通過該方式提升高并發(fā)讀寫性能。

        2.2.3 網(wǎng)絡(luò)線程模型優(yōu)化前后性能對比

        在該大流量集群中增加serviceExecutor: adaptive配置實(shí)現(xiàn)網(wǎng)絡(luò)IO復(fù)用及網(wǎng)絡(luò)IO與磁盤IO做分離后,該大流量集群時延大幅度降低,同時系統(tǒng)負(fù)載和慢日志也減少很多,具體如下:

        2.2.3.1 優(yōu)化前后系統(tǒng)負(fù)載對比

        驗證方式:

        該集群有多個分片,其中一個分片配置優(yōu)化后的主節(jié)點(diǎn)和同一時刻未優(yōu)化配置的主節(jié)點(diǎn)load負(fù)載比較: 未優(yōu)化配置的load

        

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        優(yōu)化配置的load

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        2.2.3.2 優(yōu)化前后慢日志對比

        驗證方式:

        該集群有多個分片,其中一個分片配置優(yōu)化后的主節(jié)點(diǎn)和同一時刻未優(yōu)化配置的主節(jié)點(diǎn)慢日志數(shù)比較:

        同一時間的慢日志數(shù)統(tǒng)計:

        未優(yōu)化配置的慢日志數(shù)(19621)

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

         優(yōu)化配置后的慢日志數(shù)(5222):

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        2.2.3.3 優(yōu)化前后平均時延對比

        驗證方式:

        該集群所有節(jié)點(diǎn)加上網(wǎng)絡(luò)IO復(fù)用配置后與默認(rèn)配置的平均時延對比如下:

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        從上圖可以看出,網(wǎng)絡(luò)IO復(fù)用后時延降低了1-2倍。

        2.3 wiredtiger存儲引擎優(yōu)化

        從上一節(jié)可以看出平均時延從200ms降低到了平均80ms左右,很顯然平均時延還是很高,如何進(jìn)一步提升性能降低時延?繼續(xù)分析集群,我們發(fā)現(xiàn)磁盤IO一會兒為0,一會兒持續(xù)性100%,并且有跌0現(xiàn)象,現(xiàn)象如下:

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        從圖中可以看出,I/O寫入一次性到2G,后面幾秒鐘內(nèi)I/O會持續(xù)性阻塞,讀寫I/O完全跌0,avgqu-sz、awit巨大,util次序性100%,在這個I/O跌0的過程中,業(yè)務(wù)方反應(yīng)的TPS同時跌0。

        此外,在大量寫入IO后很長一段時間util又持續(xù)為0%,現(xiàn)象如下:

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        總體IO負(fù)載曲線如下:

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        從圖中可以看出IO很長一段時間持續(xù)為0%,然后又飆漲到100%持續(xù)很長時間,當(dāng)IO util達(dá)到100%后,分析日志發(fā)現(xiàn)又大量滿日志,同時mongostat監(jiān)控流量發(fā)現(xiàn)如下現(xiàn)象:

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐
      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        從上可以看出我們定時通過mongostat獲取某個節(jié)點(diǎn)的狀態(tài)的時候,經(jīng)常超時,超時的時候剛好是io util=100%的時候,這時候IO跟不上客戶端寫入速度造成阻塞。

        有了以上現(xiàn)象,我們可以確定問題是由于IO跟不上客戶端寫入速度引起,第2章我們已經(jīng)做了mongodb服務(wù)層的優(yōu)化,現(xiàn)在我們開始著手wiredtiger存儲引擎層面的優(yōu)化,主要通過以下幾個方面:

        1、cachesize調(diào)整

        2、臟數(shù)據(jù)淘汰比例調(diào)整

        3、checkpoint優(yōu)化

        2.3.1 cachesize調(diào)整優(yōu)化(為何cacheSize越大性能越差)

        前面的IO分析可以看出,超時時間點(diǎn)和I/O阻塞跌0的時間點(diǎn)一致,因此如何解決I/O跌0成為了解決改問題的關(guān)鍵所在。

        找個集群平峰期(總tps50萬/s)查看當(dāng)時該節(jié)點(diǎn)的TPS,發(fā)現(xiàn)TPS不是很高,單個分片也就3-4萬左右,為何會有大量的刷盤,瞬間能夠達(dá)到10G/S,造成IO util持續(xù)性跌0(因為IO跟不上寫入速度)。繼續(xù)分析wiredtiger存儲引擎刷盤實(shí)現(xiàn)原理,wiredtiger存儲引擎是一種B+樹存儲引擎,mongodb文檔首先轉(zhuǎn)換為KV寫入wiredtiger,在寫入過程中,內(nèi)存會越來越大,當(dāng)內(nèi)存中臟數(shù)據(jù)和內(nèi)存總占用率達(dá)到一定比例,就開始刷盤。同時當(dāng)達(dá)到checkpoint限制也會觸發(fā)刷盤操作,查看任意一個mongod節(jié)點(diǎn)進(jìn)程狀態(tài),發(fā)現(xiàn)消耗的內(nèi)存過多,達(dá)到110G,如下圖所示:

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        于是查看mongod.conf配置文件,發(fā)現(xiàn)配置文件中配置的cacheSizeGB: 110G,可以看出,存儲引擎中KV總量幾乎已經(jīng)達(dá)到110G,按照5%臟頁開始刷盤的比例,峰值情況下cachesSize設(shè)置得越大,里面得臟數(shù)據(jù)就會越多,而磁盤IO能力跟不上臟數(shù)據(jù)得產(chǎn)生速度,這種情況很可能就是造成磁盤I/O瓶頸寫滿,并引起I/O跌0的原因。

        此外,查看該機(jī)器的內(nèi)存,可以看到內(nèi)存總大小為190G,其中已經(jīng)使用110G左右,幾乎是mongod的存儲引起占用,這樣會造成內(nèi)核態(tài)的page cache減少,大量寫入的時候內(nèi)核cache不足就會引起磁盤缺頁中斷。

        

        #FormatImgID_14#

        解決辦法:通過上面的分析問題可能是大量寫入的場景,臟數(shù)據(jù)太多容易造成一次性大量I/O寫入,于是我們可以考慮把存儲引擎cacheSize調(diào)小到50G,來減少同一時刻I/O寫入的量,從而規(guī)避峰值情況下一次性大量寫入的磁盤I/O打滿阻塞問題。

        2.3.2 存儲引擎dirty臟數(shù)據(jù)淘汰優(yōu)化

        調(diào)整cachesize大小解決了5s請求超時問題,對應(yīng)告警也消失了,但是問題還是存在,5S超時消失了,1s超時問題還是偶爾會出現(xiàn)。

        因此如何在調(diào)整cacheSize的情況下進(jìn)一步規(guī)避I/O大量寫的問題成為了問題解決的關(guān)鍵,進(jìn)一步分析存儲引擎原理,如何解決內(nèi)存和I/O的平衡關(guān)系成為了問題解決的關(guān)鍵,mongodb默認(rèn)存儲因為wiredtiger的cache淘汰策略相關(guān)的幾個配置如下:

        wiredtiger淘汰相關(guān)配置默認(rèn)值工作原理

        eviction_target80當(dāng)用掉的內(nèi)存超過總內(nèi)存的百分比達(dá)到 eviction_target,后臺evict線程開始淘汰

        eviction_trigger95當(dāng)用掉的內(nèi)存超過總內(nèi)存的 eviction_trigger,用戶線程也開始淘汰

        eviction_dirty_target5當(dāng)cache中臟數(shù)據(jù)比例超過 eviction_dirty_target,后臺evict線程開始淘汰

        eviction_dirty_trigger20當(dāng)cache中臟數(shù)據(jù)比例超過 eviction_dirty_trigger, 用戶線程也開始淘汰

        evict.threads_min4后臺evict線程最小數(shù)

        evict.threads_max4后臺evict線程最大數(shù)

        調(diào)整cacheSize從120G到50G后,如果臟數(shù)據(jù)比例達(dá)到5%,則極端情況下如果淘汰速度跟不上客戶端寫入速度,這樣還是容易引起I/O瓶頸,最終造成阻塞。

        解決辦法: 如何進(jìn)一步減少持續(xù)性I/O寫入,也就是如何平衡cache內(nèi)存和磁盤I/O的關(guān)系成為問題關(guān)鍵所在。從上表中可以看出,如果臟數(shù)據(jù)及總內(nèi)占用存達(dá)到一定比例,后臺線程開始選擇page進(jìn)行淘汰寫盤,如果臟數(shù)據(jù)及內(nèi)存占用比例進(jìn)一步增加,那么用戶線程就會開始做page淘汰,這是個非常危險的阻塞過程,造成用戶請求驗證阻塞。平衡cache和I/O的方法: 調(diào)整淘汰策略,讓后臺線程盡早淘汰數(shù)據(jù),避免大量刷盤,同時降低用戶線程閥值,避免用戶線程進(jìn)行page淘汰引起阻塞。優(yōu)化調(diào)整存儲引起配置如下:

         eviction_target: 75%

        eviction_trigger:97%

        eviction_dirty_target: %3

        eviction_dirty_trigger:25%

        evict.threads_min:8

        evict.threads_max:12

        總體思想是讓后臺evict盡量早點(diǎn)淘汰臟頁page到磁盤,同時調(diào)整evict淘汰線程數(shù)來加快臟數(shù)據(jù)淘汰,調(diào)整后mongostat及客戶端超時現(xiàn)象進(jìn)一步緩解。

        2.3.3 存儲引擎checkpoint優(yōu)化調(diào)整

        存儲引擎得checkpoint檢測點(diǎn),實(shí)際上就是做快照,把當(dāng)前存儲引擎的臟數(shù)據(jù)全部記錄到磁盤。觸發(fā)checkpoint的條件默認(rèn)又兩個,觸發(fā)條件如下:

        1、固定周期做一次checkpoint快照,默認(rèn)60

        2、增量的redo log(也就是journal日志)達(dá)到2G

        當(dāng)journal日志達(dá)到2G或者redo log沒有達(dá)到2G并且距離上一次時間間隔達(dá)到60s,wiredtiger將會觸發(fā)checkpoint,如果在兩次checkpoint的時間間隔類evict淘汰線程淘汰的dirty page越少,那么積壓的臟數(shù)據(jù)就會越多,也就是checkpoint的時候臟數(shù)據(jù)就會越多,造成checkpoint的時候大量的IO寫盤操作。如果我們把checkpoint的周期縮短,那么兩個checkpoint期間的臟數(shù)據(jù)相應(yīng)的也就會減少,磁盤IO 100%持續(xù)的時間也就會縮短。

        checkpoint調(diào)整后的值如下:

        checkpoint=(wait=25,log_size=1GB)

        2.3.4 存儲引擎優(yōu)化前后IO對比

        通過上面三個方面的存儲引擎優(yōu)化后,磁盤IO開始散列到各個不同的時間點(diǎn),iostat監(jiān)控優(yōu)化后的IO負(fù)載如下:

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        從上面的io負(fù)載圖可以看出,之前的IO一會兒為0%,一會兒100%現(xiàn)象有所緩解,總結(jié)如下圖所示(注: 優(yōu)化后的IO曲線只是反應(yīng)大概趨勢,和真實(shí)趨勢有些出入):

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        2.3.5 存儲引擎優(yōu)化前后時延對比

        優(yōu)化前后時延對比如下(注: 該集群有幾個業(yè)務(wù)同時使用,優(yōu)化前后時延對比如下):

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐
      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐
      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐
      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐
      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        從上圖可以看出,存儲引擎優(yōu)化后時間延遲進(jìn)一步降低并趨于平穩(wěn),從平均80ms到平均20ms左右,但是還是不完美,有抖動。

        3 服務(wù)器系統(tǒng)磁盤IO問題解決

        3.1 服務(wù)器IO硬件問題背景

        如第前面章節(jié)所述,當(dāng)wiredtiger大量淘汰數(shù)據(jù)時,發(fā)現(xiàn)只要每秒磁盤寫入量超過500M/s,接下來的幾秒鐘內(nèi)util就會持續(xù)100%,w/s幾乎跌0,于是開始懷疑磁盤硬件存在缺陷。如下圖所示:

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐
      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        從上圖可以看出磁盤為nvMe的ssd盤,查看相關(guān)數(shù)據(jù)可以看出該盤IO性能很好,支持每秒2G寫入,iops能達(dá)到15萬,而我們線上的盤只能每秒寫入最多500M。

        3.2 服務(wù)器IO硬件問題解決后性能對比

        通過大量的線下測試以及服務(wù)器廠商的配合,nvme的ssd io瓶頸問題得以解決,經(jīng)過和廠商確認(rèn)分析,最終定位到IO問題是linux內(nèi)核版本不匹配引起,如果大家nvme ssd盤有同樣問題,記得升級linux版本到3.10.0-957.27.2.el7.x86_64版本,升級后nvme ssd的IO能力達(dá)到近2G/s寫入。

        說明: 從本節(jié)開始,我們的服務(wù)器分為兩種:1. 低IO服務(wù)器,也就是沒有做操作系統(tǒng)升級的服務(wù)器,IO寫入能力500M/s,2. 高IO服務(wù)器,也就是操作系統(tǒng)升級后的服務(wù)器,IO寫入能力近2G/s.。

        于是考慮把該分片集群的主節(jié)點(diǎn)全部遷移到操作系統(tǒng)升級后的高IO服務(wù)器(為了謹(jǐn)慎,我們只替換了分片主節(jié)點(diǎn),從節(jié)點(diǎn)還是老的未升級的低IO服務(wù)器),該服務(wù)器io寫入能達(dá)到近2G/s(注意:只遷移了主節(jié)點(diǎn),從節(jié)點(diǎn)還是在之前的IO-500M/s的低IO服務(wù)器),具體的操作過程在后面章節(jié)會描述,詳見3.3章節(jié)。遷移完成后,發(fā)現(xiàn)性能得到了進(jìn)一步提升,時延遲降低到平均2-4ms/s,幾個不同業(yè)務(wù)接口看到的時延監(jiān)控如下圖所示:

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐
      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐
      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        從上圖時延可以看出,遷移主節(jié)點(diǎn)到操作系統(tǒng)升級后的高IO機(jī)器后,時延進(jìn)一步降低到平均2-4ms。

        雖然時延降低到了平均2-4ms,但是還是有很多幾十ms的尖刺,因此我們需要進(jìn)一步的優(yōu)化分析。

        3.3 硬件問題回顧及遺留問題

        在前面的分析中,我們在定位nvme ssd硬件IO問題的過程中,和廠商一起分析發(fā)現(xiàn)IO問題是由于操作系統(tǒng)版本不對引起,于是開始對線上的主從mongod實(shí)例的服務(wù)器硬件進(jìn)行升級,升級后開始替換線上該集群的實(shí)例。具體操作過程如下:

        1、為了驗證IO升級后的機(jī)器,我們替換一個分片的從節(jié)點(diǎn)為升級操作系統(tǒng)后的高IO服務(wù)器(IO問題得以解決,IO能力從之前的500M/s寫入達(dá)到了近2G/s,我們稱IO升級后的服務(wù)器為高IO服務(wù)器,未升級的服務(wù)器為低IO服務(wù)器),替換后通過iostat可以看到該從節(jié)點(diǎn)的IO 100%問題得到了很大程度的緩解,不會出現(xiàn)持續(xù)性IO跌0問題。

        2、在第1步的從節(jié)點(diǎn)在高IO服務(wù)器跑了一周后,我們確定升級后的高IO服務(wù)器運(yùn)行穩(wěn)定,為了謹(jǐn)慎起見,我們雖然確定該高IO服務(wù)器在從節(jié)點(diǎn)運(yùn)行沒有問題,但是我們需要進(jìn)一步在主節(jié)點(diǎn)驗證是否穩(wěn)定,于是我們做了一次主從切換,該高IO服務(wù)器變?yōu)橹鞴?jié)點(diǎn)運(yùn)行,也就是集群中某個分片的主節(jié)點(diǎn)服務(wù)器變?yōu)榱烁逫O服務(wù)器,但是從節(jié)點(diǎn)還是低IO服務(wù)器。

        3、當(dāng)?shù)?步的主節(jié)點(diǎn)在高IO服務(wù)器跑了數(shù)周后,我們確定主節(jié)點(diǎn)在高IO服務(wù)器運(yùn)行正常,于是我們得下結(jié)論: 升級后的服務(wù)器運(yùn)行穩(wěn)定。

        4、確定高IO服務(wù)器沒問題后,我們開始批量替換mongod實(shí)例到該服務(wù)器。為了保險起見,畢竟只驗證了一臺高IO服務(wù)器在主從運(yùn)行都沒問題,于是我們考慮只把整個集群的主節(jié)點(diǎn)替換為高IO服務(wù)器(當(dāng)時我認(rèn)為客戶端都是用的默認(rèn)配置,數(shù)據(jù)寫到主節(jié)點(diǎn)就會返回OK,雖然從節(jié)點(diǎn)IO慢,但是還是可以追上oplog速度的,這樣客戶端時延不會因為以前主節(jié)點(diǎn)IO有問題而抖動)。

        為了謹(jǐn)慎保險起見,通過上面的硬件替換升級過程,我們只替換了所有分片的主節(jié)點(diǎn),替換升級前后架構(gòu)發(fā)生了變化,原有集群硬件架構(gòu)如下圖所示:

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        所有分片主節(jié)點(diǎn)硬件升級后的架構(gòu)圖如下圖所示:

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        從上圖可知,新的集群架構(gòu),主從節(jié)點(diǎn)服務(wù)器IO能力有比較大的差距。最開始我認(rèn)為業(yè)務(wù)方默認(rèn)沒有設(shè)置WriteConncern,也就是默認(rèn)寫入到Primary就向客戶端發(fā)送確認(rèn),因此不會影響業(yè)務(wù)寫入。

        所有分片主節(jié)點(diǎn)升級為高IO服務(wù)器后,多個業(yè)務(wù)接口的時間訪問延遲降到了平均2-4ms左右,但是在超大流量沖擊的時候,還是有幾十ms的尖刺,我選取一個抖動比較典型的接口時延為例,如下圖所示:

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        從上圖可以看出,特別是在大流量沖擊的時間點(diǎn),尖刺越明顯。

        主節(jié)點(diǎn)硬件升級后續(xù)優(yōu)化

        4.1 readConcern配置優(yōu)化

        在上一節(jié),我們替換了分片的所有主節(jié)點(diǎn)為高IO服務(wù)器,從節(jié)點(diǎn)還是以前未升級的低IO服務(wù)器。由于業(yè)務(wù)方默認(rèn)沒有設(shè)置WriteConncern,因此認(rèn)為客戶端寫到主成功就會返回客戶端OK,即使從服務(wù)器性能差也不會影響客戶端寫主。

        在升級主服務(wù)器后,我繼續(xù)優(yōu)化存儲引擎把eviction_dirty_trigger:25%調(diào)整到了30%。

        由于受到超大流量的高并發(fā)沖擊,會從平峰期的幾十萬TPS瞬間飆升到百萬級別,而且該毛刺幾乎每天都會出現(xiàn)好幾次,比較容易復(fù)現(xiàn)。于是提前部署好mongostat監(jiān)控所有實(shí)例,同時在每個服務(wù)器上用Iostat監(jiān)控實(shí)時的IO狀況,同時編寫腳本實(shí)時采集db.serverstatus()、db.printSlaveReplicationInfo()、db.printReplicationInfo()等集群重要信息。

        當(dāng)某個時間點(diǎn)監(jiān)控出現(xiàn)毛刺后,于是開始分析mongostat,我們發(fā)現(xiàn)一個問題,即使在平峰期,臟數(shù)據(jù)比例也會持續(xù)增長到閥值(30%),我們知道當(dāng)臟數(shù)據(jù)比例超過eviction_dirty_trigger:30%閥值,用戶線程就會進(jìn)行evict淘汰,這樣用戶線程就會阻塞直到騰出內(nèi)存空間,因此淘汰刷盤過程業(yè)務(wù)訪問很慢。分析平峰期毛刺時間點(diǎn)對應(yīng)的mongostat監(jiān)控,發(fā)現(xiàn)如下情況:

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        從上圖可以看出,集群TPS才40-50萬左右的時候某個分片的主節(jié)點(diǎn)出現(xiàn)了臟數(shù)據(jù)達(dá)到eviction_dirty_trigger:30%閥值,于是整個集群訪問時延就會瞬間增加,原因是一個分片的用戶線程需要刷盤,導(dǎo)致這個分片的訪問時延上升(實(shí)際上其他分片的訪問時延還是正常的),最終把整體平均時延拉上去了。

          為什么普通平峰期也會有抖動?這很明顯不科學(xué)。

        于是獲取出問題的主節(jié)點(diǎn)的一些監(jiān)控信息,得出以下結(jié)論:

        1、IO正常,IO不是瓶頸。

        2、分析抖動的時候的系統(tǒng)top負(fù)載,負(fù)載正常。

        3、該分片的TPS才4萬左右,顯然沒到到分片峰值。

        4、db.printSlaveReplicationInfo()看到主從延遲較高。

        當(dāng)客戶端時延監(jiān)控發(fā)現(xiàn)時間延遲尖刺后,我們發(fā)現(xiàn)主節(jié)點(diǎn)所有現(xiàn)象一切正常,系統(tǒng)負(fù)載、IO、TPS等都沒有到達(dá)瓶頸,但是有一個唯一的異常,就是主從同步延遲持續(xù)性增加,如下圖所示:

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        同時對應(yīng)低IO服務(wù)器的從節(jié)點(diǎn)上面的io狀況如下圖:

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        從節(jié)點(diǎn)的IO性能一塌烏涂,這也正是主從延遲增加的根源。

        從上圖可以看出在時延尖刺的同樣時間點(diǎn),主從延遲超大。于是懷疑時延尖刺可能和從節(jié)點(diǎn)拉取Oplog速度有關(guān)系,于是把整個mongostat、iostat、top、db.printSlaveReplicationInfo()、db.serverstatus()等監(jiān)控持續(xù)跑了兩天,記錄下了兩天內(nèi)的一些核心系統(tǒng)和mongo監(jiān)控指標(biāo)。

        兩天后,對著客戶端時延尖刺時間點(diǎn)分析對應(yīng)監(jiān)控數(shù)據(jù),發(fā)現(xiàn)一個共同的現(xiàn)象,尖刺出現(xiàn)時間點(diǎn)和臟數(shù)據(jù)eviction_dirty_trigger超過閥值時間點(diǎn)一致,同時主從延遲在這個時間點(diǎn)都有很大的延遲。

        到這里,我越來越懷疑問題和從節(jié)點(diǎn)拉取oplog速度有關(guān)。之前認(rèn)為業(yè)務(wù)方默認(rèn)沒有設(shè)置WriteConncern,也就是默認(rèn)寫入到Primary就向客戶端發(fā)送確認(rèn),可能應(yīng)答客戶端前還有其他流程會影響服務(wù)的返回OK給客戶端。于是查看官方mongodb-3.6的Production Notes,從中發(fā)現(xiàn)了如下信息:

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        從Production Notes可以看出,mongodb-3.6默認(rèn)啟用了 read concern “majority”功能,于是懷疑抖動可能和該功能有關(guān)。為了避免臟讀,mongodb增加了該功能,啟用該功能后,mongodb為了確保帶有帶有參數(shù)readConcern(“Majority”)的客戶端讀取到的數(shù)據(jù)確實(shí)是同步到大多數(shù)實(shí)例的數(shù)據(jù),因此mongodb必須在內(nèi)存中借助snapshot 及主從通信來維護(hù)更多的版本信息,這就增加了wiredtiger存儲引擎對內(nèi)存的需求。由于從節(jié)點(diǎn)是低IO服務(wù)器,很容易造成阻塞,這樣拉取oplog的速度就會跟不上進(jìn)度,造成主節(jié)點(diǎn)消耗大量的內(nèi)存來維護(hù)快照信息,這樣就會導(dǎo)致大量的內(nèi)存消耗,最終導(dǎo)致臟數(shù)據(jù)瞬間劇增,很快達(dá)到eviction_dirty_trigger閥值,業(yè)務(wù)也因此抖動。

        說一個小插曲,因為mongodb-3.6默認(rèn)開啟enableMajorityReadConcern功能,我們在這個過程中出現(xiàn)過幾次嚴(yán)重的集群故障,業(yè)務(wù)流量有段時間突然暴漲,造成時延持續(xù)性達(dá)到幾千ms,寫入全部阻塞,現(xiàn)象如下:

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        該問題的根源也是因為enableMajorityReadConcern功能引起,由于從節(jié)點(diǎn)嚴(yán)重落后主節(jié)點(diǎn),導(dǎo)致主節(jié)點(diǎn)為了維護(hù)各種snapshot快照,消耗大量內(nèi)存,同時從節(jié)點(diǎn)和主節(jié)點(diǎn)的oplog延后,導(dǎo)致主節(jié)點(diǎn)維護(hù)了更多的內(nèi)存版本,臟數(shù)據(jù)比例持續(xù)性增長,直到從節(jié)點(diǎn)追上oplog。由于我們的業(yè)務(wù)不需要readConcert功能,因此我們考慮禁用該功能(配置文件增加配置replication.enableMajorityReadConcern=false)。

        鑒于篇幅,enableMajorityReadConcern及主從硬件IO能力不足引起的嚴(yán)重業(yè)務(wù)故障,本篇不做詳細(xì)的分析,后期會寫一篇專門的《百萬級高并發(fā)mongodb集群性能優(yōu)化采坑記》中做分享,除了ReadConcern采坑,還有其他好幾個核心采坑點(diǎn),敬請關(guān)注。

        此外,后續(xù)會專門寫一篇ReadConcern的原理及代碼實(shí)現(xiàn)分析文章,敬請關(guān)注。

        4.2 替換從節(jié)點(diǎn)服務(wù)器為升級后的高IO服務(wù)器

        除了通過replication.enableMajorityReadConcern=false在配置文件中禁用ReadConcern Majority功能,我們繼續(xù)把所有分片的從節(jié)點(diǎn)由之前的低IO服務(wù)器替換為升級后的高IO服務(wù)器,升級后所有主從硬件資源性能完全一樣,升級后集群分片架構(gòu)如下圖所示:

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        通過禁用enableMajorityReadConcern功能,并統(tǒng)一主從服務(wù)器硬件資源后,查看有抖動的一個接口的時間延遲,如下圖所示:

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        從上圖可以看出,通過MajorityReadConcern功能并且替把所有從節(jié)點(diǎn)的低IO服務(wù)器做系統(tǒng)升級后,業(yè)務(wù)時間延遲抖動的峰值進(jìn)一步降低了,從平均2-4ms降低到了1ms左右,同時,峰值毛刺從前面第3節(jié)中的80ms降低到了現(xiàn)在的峰值40ms左右。

        此外,4.1節(jié)提到的臟數(shù)據(jù)持續(xù)性突破eviction_dirty_trigger閥值引起客戶端時延飆漲到幾千ms的問題得以徹底解決。

        總結(jié): MajorityReadConcern功能禁用并升級從節(jié)點(diǎn)到高IO服務(wù)器后,總體收益如下:

        1、平均時延從2-4ms降低到1ms左右

        2、峰值時延毛刺從80ms降低到40ms

        3、之前出現(xiàn)的臟數(shù)據(jù)比例突破30%飆漲到50%的問題徹底解決。

        4、尖刺持續(xù)時間變短

        4.3 繼續(xù)優(yōu)化調(diào)整存儲引起參數(shù)

        通過前面的條優(yōu)化,我們發(fā)現(xiàn)有一個業(yè)務(wù)接口還是偶爾有40ms時延尖刺,分析發(fā)現(xiàn)主要是eviction_dirty_trigger達(dá)到了我們配置的閥值,業(yè)務(wù)線程開始淘汰page cache,這樣就造成業(yè)務(wù)線程很慢,最終導(dǎo)致平均時延尖刺。

        為了進(jìn)一步減緩時延尖刺,我們繼續(xù)在之前基礎(chǔ)上對存儲引擎調(diào)優(yōu),調(diào)整后配置如下:

        eviction_target: 75%

        eviction_trigger:97%

        eviction_dirty_target: %3

        eviction_dirty_trigger:30%

        evict.threads_min:14

        evict.threads_max:18

        checkpoint=(wait=20,log_size=1GB)

        經(jīng)過此輪的存儲引擎調(diào)優(yōu)后,該業(yè)務(wù)的核心接口時延進(jìn)一步好轉(zhuǎn),時延尖刺相比之前有了進(jìn)一步的改善,時延最大尖刺時間從前面的45ms降低到了35ms,同時尖刺出現(xiàn)的頻率明顯降低了,如下圖所示:

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        從此圖可以看出,在個別時間點(diǎn)還是有一次時延尖刺,對照該尖刺的時間點(diǎn)分析提前部署好的mongostat和iostat監(jiān)控,得到如下信息:

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        從上圖可以看出,在峰值TPS百萬級別的時候,部分節(jié)點(diǎn)evict淘汰速率已經(jīng)跟不上寫入速度,因此出現(xiàn)了用戶線程刷盤的情況。

        在這個時間點(diǎn)分析對應(yīng)機(jī)器的系統(tǒng)負(fù)載、磁盤io狀況、內(nèi)存狀況等,發(fā)現(xiàn)系統(tǒng)負(fù)載、比較正常,但是對應(yīng)服務(wù)器磁盤IO偏高,如下圖所示:

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        同時分析對應(yīng)服務(wù)器對應(yīng)時間點(diǎn)的慢日志,我們發(fā)現(xiàn)尖刺出現(xiàn)時間的的慢日志統(tǒng)計如下:

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        分析非時延尖刺時間點(diǎn),對應(yīng)慢日志統(tǒng)計如下:

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        分析兩個時間點(diǎn)慢日志可以看出,慢日志出現(xiàn)的條數(shù)和時間延遲尖刺出現(xiàn)的時間點(diǎn)一致,也就是磁盤IO負(fù)載很高的時候。

        結(jié)論:通過上面的分析可以看出,當(dāng)磁盤IO比較高(util超過50%)的時候,慢日志和時延都會增加,他們之間成正比關(guān)系,IO依然時性能瓶頸點(diǎn)。

        疑問:量高的時候通過調(diào)整存儲引擎evict和checkpoint配置,IO寫入分散到了不同時間點(diǎn),相比以起集中再一個時間點(diǎn)寫入有了很大改善。但是,還是會出現(xiàn)部分時間點(diǎn)IO寫入接近為0,其他時間點(diǎn)IO 100%的現(xiàn)象。

        5.總結(jié)

        通過軟件層面(mongodb服務(wù)配置、業(yè)務(wù)優(yōu)化、存儲引擎優(yōu)化)及硬件系統(tǒng)優(yōu)化(升級操作系統(tǒng))后,該大流量集群的核心接口時延從最初的平均成百上千ms降低到了現(xiàn)在的平均1-2ms,性能提升比較可觀,整體時延性能提升數(shù)十倍。

        優(yōu)化前主要業(yè)務(wù)接口時延:

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐
      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        在不增加物理服務(wù)器資源的基礎(chǔ)上,經(jīng)過一系列的優(yōu)化措施,最終業(yè)務(wù)方主要接口時延控制到了幾ms,如下圖所示:

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐
      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        6.遺留問題

        如4.3分析所述,當(dāng)峰值tps持續(xù)性達(dá)到100萬左右的時候,有明顯的磁盤IO問題,但是IO寫入在不同時間點(diǎn)很不均衡,有時候在流量持續(xù)性高峰期存在如下現(xiàn)象(注: 下圖只是大概反應(yīng)高峰期持續(xù)性寫入的IO趨勢狀況):

      Oppo百萬級高并發(fā)mongodb集群性能數(shù)十倍提升優(yōu)化實(shí)踐

        如上圖所示,有時候高峰期不同時間點(diǎn)磁盤IO不均衡,如果我們能把IO平均散列到各個不同時間點(diǎn),這樣或許可以解決IO瓶頸問題。我試著通過繼續(xù)調(diào)大evict線程數(shù)來達(dá)到目的,但是當(dāng)線程數(shù)超過一定值后效果不明顯。后續(xù)會持續(xù)分析wiredtiger存儲引擎代碼實(shí)現(xiàn)來了解整個機(jī)制,分析有時候磁盤IO嚴(yán)重分布不均衡代碼實(shí)現(xiàn)原理。

        7. 后續(xù)相關(guān)分享

          近期繼續(xù)分享如下主題,敬請關(guān)注:

        《百萬級高并發(fā)mongodb集群性能優(yōu)化采坑記》

        《線上典型集群抖動、不可用等問題匯總分析》

        《Mongodb文檔數(shù)據(jù)庫業(yè)務(wù)使用最佳案例分享》

        《Mongodb-3.6網(wǎng)絡(luò)IO線程模型設(shè)計及代碼實(shí)現(xiàn)》

        注意

          文章中的一些優(yōu)化方法并不是一定適用于所有mongodb場景,請根據(jù)實(shí)際業(yè)務(wù)場景和硬件物理資源進(jìn)行優(yōu)化,而不要按部就班。

        作者簡介

        楊亞洲,前滴滴出行技術(shù)專家,現(xiàn)任Oppo文檔數(shù)據(jù)庫研發(fā)負(fù)責(zé)人,一直專注于分布式緩存、高性能服務(wù)器、分布式存儲、數(shù)據(jù)庫、中間件等相關(guān)研發(fā),后續(xù)會持續(xù)分析Mongodb內(nèi)核、wiredtiger存儲引擎、rocksdb存儲引擎源碼及,相關(guān)分享會發(fā)布到我的git賬號。Github賬號地址: https://github.com/y123456yz 郵箱:yangyazhou#oppo.com

        Oppo公司互聯(lián)網(wǎng)服務(wù)簡介

        可能外界對Oppo的認(rèn)識僅僅停留在手機(jī)業(yè)務(wù),這是一種誤解。Oppo的互聯(lián)網(wǎng)業(yè)務(wù)流量絕不輸于部分一線互聯(lián)網(wǎng)公司,歡迎加入Oppo互聯(lián)網(wǎng)運(yùn)維云存儲團(tuán)隊參與公司百萬級高并發(fā)文檔數(shù)據(jù)庫研發(fā)。

      特別提醒:本網(wǎng)內(nèi)容轉(zhuǎn)載自其他媒體,目的在于傳遞更多信息,并不代表本網(wǎng)贊同其觀點(diǎn)。其原創(chuàng)性以及文中陳述文字和內(nèi)容未經(jīng)本站證實(shí),對本文以及其中全部或者部分內(nèi)容、文字的真實(shí)性、完整性、及時性本站不作任何保證或承諾,并請自行核實(shí)相關(guān)內(nèi)容。本站不承擔(dān)此類作品侵權(quán)行為的直接責(zé)任及連帶責(zé)任。如若本網(wǎng)有任何內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系我們,本站將會在24小時內(nèi)處理完畢。

      贊(0)
      分享到: 更多 (0)
      網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號