成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

MongoDB疑難解析:為什么升級(jí)之后負(fù)載升高了?-創(chuàng)新互聯(lián)

本文是“我和MongoDB的故事”征文比賽的二等獎(jiǎng)得主李鵬沖的文章。下面我們一起來欣賞下。

專注于為中小企業(yè)提供成都網(wǎng)站設(shè)計(jì)、網(wǎng)站制作服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)赫山免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了成百上千家企業(yè)的穩(wěn)健成長(zhǎng),幫助中小企業(yè)通過網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。

問題

近期線上一個(gè)三分片集群從 3.2 版本升級(jí)到 4.0 版本以后,集群節(jié)點(diǎn)的 CPU 的負(fù)載升高了很多(10% -> 40%), 除了版本的升級(jí),項(xiàng)目邏輯和操作量均無變化。關(guān)閉 Balancer 以后 CPU 負(fù)載回歸正常,穩(wěn)定在 10% 以下。為此,只能經(jīng)常關(guān)閉當(dāng)前正在寫入表的 balancer , 每周二打開 balancer 開啟均衡,在此期間節(jié)點(diǎn)的 CPU 負(fù)載持續(xù)穩(wěn)定在 40% 。集群有 3 個(gè)分片,除了 MongoDB 版本的變化,項(xiàng)目本身的邏輯無任何變化。那么升級(jí)以后 CPU 負(fù)載較大變化的背后是什么原因呢?

監(jiān)控與日志

首先可以明確,升級(jí)以后 CPU 負(fù)載升高和 balancer 遷移數(shù)據(jù)有關(guān)。觀察升級(jí)以后 4.0 版本,周二打開 balancer 期間的負(fù)載情況和 mongostat 結(jié)果:

MongoDB疑難解析:為什么升級(jí)之后負(fù)載升高了?

可以發(fā)現(xiàn),CPU 負(fù)載升高和 delete 數(shù)據(jù)的情況很吻合。而遷移數(shù)據(jù)數(shù)據(jù)之后源節(jié)點(diǎn)需要?jiǎng)h除遷移走的數(shù)據(jù),所以肯定有大量的 delete 。遷移數(shù)據(jù)之后的刪除也會(huì)有如下的日志:

  • 53094:2019-10-08T10:09:24.035199+08:00 I SHARDING [Collection Range Deleter] No documents remain to delete in dt2log.tbl_log_item_20191001 range [{ _id: -3074457345618258602 }, { _ id: -3033667061349287050 })

53095:2019-10-08T10:09:24.035222+08:00 I SHARDING [Collection Range Deleter] Waiting for m ajority replication of local deletions in dt2log.tbl_log_item_20191001 range [{ _id: -3074 457345618258602 }, { _id: -3033667061349287050 })

53096:2019-10-08T10:09:24.035274+08:00 I SHARDING [Collection Range Deleter] Finished dele ting documents in dt2log.tbl_log_item_20191001 range [{ _id: -3074457345618258602 }, { _id

-3033667061349287050 })

所以從監(jiān)控和日志判斷, CPU 負(fù)載較高主要是因?yàn)檫w移數(shù)據(jù)之后的刪除導(dǎo)致。而且集群的表都是 {_id : hashed} 分片類型的表,數(shù)據(jù)量較大,但是每條數(shù)據(jù)較小,平均每個(gè) chunk 10w+ 的文檔數(shù),刪除數(shù)據(jù)速度約 200-300/s ,所以移動(dòng)一個(gè) chunk 導(dǎo)致的刪除就會(huì)持續(xù) 10 分鐘左右。

統(tǒng)計(jì)最近2個(gè)周期,開啟 balancer 以后 moveChunk 的情況:

MongoDB疑難解析:為什么升級(jí)之后負(fù)載升高了?

從上表可知此場(chǎng)景下, {_id : hashed} 分片類型集合數(shù)據(jù)基本已經(jīng)均勻了,不必重啟開啟 balancer 。因?yàn)?每個(gè)chunk 文檔數(shù)較多,刪除會(huì)比較耗資源。

關(guān)閉表的 balancer 可以解決升級(jí)之后負(fù)載升高的問題,但是竟然是為何升級(jí)到 4.0 之后 CPU 負(fù)載較高, 而 3.2 版本穩(wěn)定在低位呢?這只有可能是一個(gè)原因:4.0 版本更頻繁的發(fā)生 moveChunk, 持續(xù)的刪除數(shù)據(jù)導(dǎo)致 CPU 負(fù)載一直較高;3.2 版本較少的發(fā)生 moveChunk,不用刪除數(shù)據(jù)所以負(fù)載很低。

所以本次問題的根本是: 4.0 版本和 3.2 版本的 balancer 與 moveChunk 的邏輯是否有差別?同樣的操作,為什么 4.0版本的集群會(huì)有較多的 moveChunk ?

擼代碼:splitChunk、balancer與moveChunk

當(dāng)通過 mongos 發(fā)生插入和更新刪除操作時(shí),mongos 會(huì)估算對(duì)應(yīng) chunks 的數(shù)據(jù)量的大小,滿足條件會(huì)觸發(fā)splitChunk 的操作,splitChunk 之后可能會(huì)導(dǎo)致集群的 chunk 分布不均勻。balancer 檢測(cè)數(shù)據(jù)的分布情況,當(dāng)數(shù)據(jù)分配不均勻時(shí),發(fā)起 moveChunk 任務(wù),將數(shù)據(jù)從 chunks 較多的分片遷移到 chunks 較少的分片,遷移之后源節(jié)點(diǎn)會(huì)異步刪除遷移走的 chunk 數(shù)據(jù)。

3.2 版本和 4.0 版本,此部分邏輯大的區(qū)別就是, 3.2 版本 balancer 在 mongos,4.0 版本在 config(3.4版本開始),moveChunk 過程和刪除數(shù)據(jù)的邏輯基本沒有差異。

splitChunk

split chunks 一般是在插入、更新、刪除數(shù)據(jù)時(shí),由 mongos 發(fā)出到分片的 splitVector 命令,此時(shí)分片才會(huì)判斷是否需要 split 。但是 mongos 并不知道每個(gè) chunk 真正的數(shù)據(jù)量,是利用一個(gè)簡(jiǎn)單的估算算法判斷的。

  • 啟動(dòng)時(shí),mongos 默認(rèn)每個(gè) chunk 的原始大小為 0-1/5 maxChunkSize 范圍取個(gè)隨機(jī)值 ;

  • 之后 chunk 內(nèi)數(shù)據(jù),每次 update/insert 操作時(shí),chunkSize = chunkSize + docSize;

  • 當(dāng) chunkSize > maxChunkSize/5 時(shí),觸發(fā)一次可能 split chunk 的操作; 到 分片mongod 執(zhí)行 splitVector命令 ,splitVector 命令返回 chunk 的分割點(diǎn),如果返回為空那么不需要 split ,否則 繼續(xù) splitChunk。

也就是說,splitChunk 操作有滯后性,即使數(shù)據(jù)分布均衡,也有可能 splitChunk 執(zhí)行時(shí)間的差異導(dǎo)致 chunks 分布存在中間的不均勻狀態(tài),導(dǎo)致大量的 moveChunk 。

balancer

無論 3.2 還是 4.0 的 balancer ,默認(rèn)的檢測(cè)周期為 10s , 如果發(fā)生了 moveChunk ,檢測(cè)周期為 1s 。balancer 基本過程也大致相同:

  • config.shards 讀取分片信息 ;

  • config.collections 讀取所有集合信息,并且隨機(jī)排序保存到一個(gè)數(shù)組中;

  • 對(duì)每個(gè)集合從 config.chunks 讀取 chunks 的信息;

  • 含有最多 chunks 數(shù)量 (maxChunksNum)的分片為源分片,含有最少 chunks 數(shù)量(minChunksNum)的分片為目的分片; 如果 maxChunksNum – minChunksNum 大于遷移的閾值 (threshold), 那么就是不均衡狀態(tài),需要遷移,源分片的 chunks 第一個(gè) chunk 為待遷移的 chunk ,構(gòu)造一個(gè)遷移任務(wù)(源分片,目的分片,chunk)。

每次 balancer 會(huì)檢測(cè)所有集合的情況,每個(gè)集合最多一個(gè)遷移任務(wù) ; 而且構(gòu)造遷移任務(wù)時(shí),如果某個(gè)集合含有最多數(shù)量的分片或者最少數(shù)量 chunks 的分片,已經(jīng)屬于某一個(gè)遷移任務(wù),那么此集合本輪 balancer 不會(huì)發(fā)生遷移。最后,本次檢測(cè)出的遷移任務(wù)完成以后才開始下次 balancer 過程。

balancer 過程中,會(huì)對(duì)集合做一次隨機(jī)排序,當(dāng)有多個(gè)集合的數(shù)據(jù)需要均衡時(shí),遷移時(shí)也是隨機(jī)的,并不是遷移完一個(gè)集合開始下一個(gè)集合。

重點(diǎn)關(guān)注上述的遷移閾值,就是這個(gè)遷移的閾值 threshold 在 3.2 和 4.0 版本有所不同。

3.2 版本, chunks 數(shù)量小于 20 的時(shí)候?yàn)?2, 小于 80 的時(shí)候?yàn)?4, 大于 80 的時(shí)候?yàn)?8 。也就是說假設(shè)兩分片集群,某個(gè)表有 100 個(gè)chunk , 每個(gè)分片分別有 47 和 53 個(gè)chunk 。那么此時(shí) balance 認(rèn)為是均衡的,不會(huì)發(fā)生遷移。

int threshold = 8;
if (balancedLastTime || distribution.totalChunks() < 20) threshold = 2;
else if (distribution.totalChunks() < 80) threshold = 4;

4.0 版本,chunks 數(shù)量差距大于 2 的時(shí)候就會(huì)發(fā)生遷移。同樣的上述例子中,每個(gè)分片分別有 47 和 53 個(gè) chunk時(shí), balance 認(rèn)為是不均衡的,會(huì)發(fā)生遷移。

const size_t kDefaultImbalanceThreshold = 2; const size_t kAggressiveImbalanceThreshold = 1;
const size_t imbalanceThreshold = (shouldAggressivelyBalance || distribution.totalChunks()
< 20)
? kAggressiveImbalanceThreshold: kDefaultImbalanceThreshold;
// 這里雖然有個(gè) 1 ,但是實(shí)際差距為 1 的時(shí)候不會(huì)發(fā)生遷移,因?yàn)榕袛噙w移時(shí),還有一個(gè)指標(biāo):平均每個(gè)分片的大 ch
unks 數(shù)量,只有當(dāng) chunks 數(shù)量大于這個(gè)值的時(shí)候才會(huì)發(fā)生遷移。
const size_t idealNumberOfChunksPerShardForTag = (totalNumberOfChunksWithTag / totalNumberOfShardsWithTag) + (totalNumberOfChunksWithTag % totalNumberOfShardsWithTag ? 1 : 0);

關(guān)于此閾值,官方文檔也有介紹:

To minimize the impact of balancing on the cluster, the balancer only begins balancing after the distribution of chunks for a sharded collection has reached certain thresholds. The thresholds apply to the difference in number of chunks between the shard with the most chunks for the collection and the shard with the fewest chunks for that collection. The balancer has the following thresholds:

MongoDB疑難解析:為什么升級(jí)之后負(fù)載升高了?

The balancer stops running on the target collection when the difference between the number of chunks on any two shards for that collection is less than two, or a chunk migration fails.

但是從代碼上,從3.4 版本開始,此閾值的邏輯就已經(jīng)變化了,但是文檔并沒有更新。

moveChunk

moveChunk 是一個(gè)比較復(fù)雜的動(dòng)作, 大致過程如下:

MongoDB疑難解析:為什么升級(jí)之后負(fù)載升高了?

目的分片,首先要?jiǎng)h除要移動(dòng)的 chunk 的數(shù)據(jù)。所以會(huì)有一個(gè)刪除任務(wù)。

可以在 config.settings 設(shè)置 _secondaryThrottle 和 waitForDelete 設(shè)置 moveChunk 過程中 插入數(shù)據(jù)和刪除數(shù)據(jù)的 write concern

  • _secondaryThrottle: true 表示 balancer 插入數(shù)據(jù)時(shí),至少等待一個(gè) secondary 節(jié)點(diǎn)回復(fù);false 表示不等待寫到 secondary 節(jié)點(diǎn); 也可以直接設(shè)置為 write concern ,則遷移時(shí)使用這個(gè) write concern . 3.2 版本默認(rèn) true, 3.4 開始版本默認(rèn) false;

  • waitForDelete: 遷移一個(gè) chunk 數(shù)據(jù)以后,是否同步等待數(shù)據(jù)刪除完畢;默認(rèn)為 false , 由一個(gè)單獨(dú)的線程異步刪除孤兒數(shù)據(jù)。

設(shè)置方式如下:

use config db.settings.update(
{ "_id" : "balancer" },
{ $set : { "_secondaryThrottle" : { "w": "majority" } ,"_waitForDelete" : true } },
{ upsert : true }
)

3.2 版本 _secondaryThrottle 默認(rèn) true, 3.4 開始版本默認(rèn) false,所以 3 .2 版本和4.0 版本 moveChunk 遷移數(shù)據(jù)時(shí),4.0版本會(huì)更快完成,遷移中 目的分片的每秒 insert 量級(jí)也會(huì)更多,對(duì) CPU 負(fù)載也會(huì)有些許的影響。

另外,3.4.18/3.6.10/4.0.5 及之后版本,還有以下參數(shù) (Parameter) 調(diào)整插入數(shù)據(jù)的速度:

  • migrateCloneInsertionBatchDelayMS: 遷移數(shù)據(jù)時(shí),每次插入的間隔,默認(rèn) 0 不等待。

  • migrateCloneInsertionBatchSize: 遷移數(shù)據(jù)時(shí),每次插入的數(shù)量,默認(rèn)為 0 無限制。

設(shè)置方式如下:

db.adminCommand({setParameter:1,migrateCloneInsertionBatchDelayMS:0})
db.adminCommand({setParameter:1,migrateCloneInsertionBatchSize:0})

異步刪除數(shù)據(jù)線程

3.2 和 4.0 版本的異步刪除線程具體實(shí)現(xiàn)略有不同,但是,根本過程還是一致的,用一個(gè)隊(duì)列保存需要?jiǎng)h除的 range, 循環(huán)的取隊(duì)列的數(shù)據(jù)刪除數(shù)據(jù)。所以異步刪除數(shù)據(jù)線程是按照 chunk 進(jìn)入隊(duì)列的順序,逐個(gè)刪除。總?cè)肟冢?/p>

3.2 版本 db/range_deleter.cpp 線程入口 RangeDeleter::doWork()
4.0 版本 db/s/metadata_manager.cpp scheduleCleanup 時(shí)會(huì)有一個(gè)唯一的線程執(zhí)行清理任務(wù)

4.0 版本在刪除數(shù)據(jù)時(shí),按批刪除數(shù)據(jù),每次刪除數(shù)量計(jì)算方式如下:

maxToDelete = rangeDeleterBatchSize.load();
if (maxToDelete <= 0) {
maxToDelete = std::max(int(internalQueryExecYieldIterations.load()), 1); // 128
}

有較多的參數(shù)可以靈活的控制刪除速度,默認(rèn)情況下,900s 以后開始清理 chunks 的數(shù)據(jù),每次清理 128 個(gè)文檔,每隔 20ms 刪除一次。具體通過以下參數(shù)設(shè)置:

  • rangeDeleterBatchDelayMS: 刪除每個(gè) chunk 數(shù)據(jù)的時(shí)候分批次刪除,每批之間間隔的時(shí)間,單位 ms,默認(rèn) 20ms;

  • internalQueryExecYieldIterations: 默認(rèn)為 128;

  • rangeDeleterBatchSize:每次刪除數(shù)據(jù)的數(shù)量,默認(rèn)即為0;為0時(shí) ,則每次刪除的數(shù)量為max(internalQueryExecYieldIterations,1),

  • orphanCleanupDelaySecs: moveChunk 以后延遲刪除數(shù)據(jù)的時(shí)間,單位 s ,默認(rèn) 900 s

總結(jié)

  • moveChunk 可能對(duì)系統(tǒng)的負(fù)載產(chǎn)生影響,主要是刪除數(shù)據(jù)階段的影響,一般遷移中的插入數(shù)據(jù)影響較??;

  • 3.4 及之后的版本存在 balancer 遷移閾值較低的問題,可能會(huì)更頻繁的產(chǎn)生 moveChunk;

  • 文檔數(shù)據(jù)多而小的表,而且是 hashed 分片,本應(yīng)預(yù)分配一定的 chunk 以后永久關(guān)閉表的 balancer。開啟balancer 時(shí),3.2 版本因?yàn)榫忾撝递^大,較少發(fā)生 moveChunk 遷移數(shù)據(jù),所以負(fù)載較低; 4.0 版本均衡閾值很小,更容易發(fā)生遷移,頻繁的遷移之后刪除數(shù)據(jù)導(dǎo)致負(fù)載較高。

作者:李鵬沖

網(wǎng)易游戲高級(jí)運(yùn)維工程師,MongoDB和MySQL數(shù)據(jù)庫愛好者,目前專注于SAAS平臺(tái)的開發(fā)與運(yùn)維工作。

感謝MongoDB官方,錦木信息和Tapdata對(duì)活動(dòng)的大力支持!

進(jìn)入MongoDB技術(shù)交流群/投稿/合作 請(qǐng)?zhí)砑由鐓^(qū)助理小英微信 (ID:mongoingcom),添加請(qǐng)備注mongo

名稱欄目:MongoDB疑難解析:為什么升級(jí)之后負(fù)載升高了?-創(chuàng)新互聯(lián)
轉(zhuǎn)載來于:http://jinyejixie.com/article12/dipigc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站制作、外貿(mào)網(wǎng)站建設(shè)App開發(fā)、網(wǎng)頁設(shè)計(jì)公司、虛擬主機(jī)、ChatGPT

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

h5響應(yīng)式網(wǎng)站建設(shè)
呼图壁县| 调兵山市| 屏东县| 汉中市| 都江堰市| 合作市| 旌德县| 阿拉尔市| 上思县| 云梦县| 运城市| 顺平县| 河曲县| 博客| 仲巴县| 九江市| 昌都县| 汤阴县| 望都县| 连城县| 沙坪坝区| 德兴市| 东乡族自治县| 永昌县| 扎鲁特旗| 湘阴县| 石阡县| 合江县| 新竹县| 乌审旗| 宜阳县| 桐庐县| 定陶县| 武宁县| 方山县| 泽普县| SHOW| 互助| 民丰县| 阜康市| 广宁县|