久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

Mongos與集群均衡怎么理解

155次閱讀
沒有評論

共計 4672 個字符,預計需要花費 12 分鐘才能閱讀完成。

本篇內容主要講解“Mongos 與集群均衡怎么理解”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓丸趣 TV 小編來帶大家學習“Mongos 與集群均衡怎么理解”吧!

mongodb 可以以單復制集的方式運行,client 直連 mongod 讀取數據。
單復制集的方式下,數據的水平擴展的責任推給了業務層解決(分實例,分庫分表),mongodb 原生提供集群方案,該方案的簡要架構如下:

mongodb 集群是一個典型的去中心化分布式集群。mongodb 集群主要為用戶解決了如下問題:

元數據的一致性與高可用(Consistency + Partition Torrence)

業務數據的多備份容災(由復制集技術保證)

動態自動分片

動態自動數據均衡
下文通過介紹 mongodb 集群中各個組成部分,逐步深入剖析 mongodb 集群原理。

ConfigServer

mongodb 元數據全部存放在 configServer 中,configServer 是由一組(至少三個)mongod 實例組成的集群。
configServer 的唯一功能是提供元數據的增刪改查。和大多數元數據管理系統(etcd,zookeeper)類似,也是保證一致性與分區容錯性。本身不具備中心化的調度功能。

ConfigServer 與復制集

ConfigServer 的分區容錯性 (P) 和數據一致性 (C) 是復制集本身的性質。
MongoDb 的讀寫一致性由 WriteConcern 和 ReadConcern 兩個參數保證。
兩者組合可以得到不同的一致性等級。
指定 writeConcern:majority 可以保證寫入數據不丟失,不會因選舉新主節點而被回滾掉。
readConcern:majority + writeConcern:majority 可以保證強一致性的讀
readConcern:local + writeConcern:majority 可以保證最終一致性的讀
mongodb 對 configServer 全部指定 writeConcern:majority 的寫入方式,因此元數據可以保證不丟失。
對 configServer 的讀指定了 ReadPreference:PrimaryOnly 的方式,在 CAP 中舍棄了 A 與 P 得到了元數據的強一致性讀。

Mongos 數據自動分片

對于一個讀寫操作,mongos 需要知道應該將其路由到哪個復制集上,mongos 通過將片鍵空間劃分為若干個區間,計算出一個操作的片鍵的所屬區間對應的復制集來實現路由。

Collection1 被劃分為 4 個 chunk,其中
chunk1 包含(-INF,1) , chunk3 包含[20, 99) 的數據,放在 shard1 上。
chunk2 包含 [1,20), chunk4 包含[99, INF) 的數據,放在 shard2 上。
chunk 的信息存放在 configServer 的 mongod 實例的 config.chunks 表中,格式如下:

{ 
  _id  :  mydb.foo-a_\ cat\ , 
  lastmod  : Timestamp(1000, 3), 
  lastmodEpoch  : ObjectId(5078407bd58b175c5c225fdc), 
  ns  :  mydb.foo , 
  min  : {  animal  :  cat  }, 
  max  : {  animal  :  dog  }, 
  shard  :  shard0004 
}

值得注意的是:chunk 是一個邏輯上的組織結構,并不涉及到底層的文件組織方式。

啟發式觸發 chunk 分裂

mongodb 默認配置下,每個 chunk 大小為 16MB。超過該大小就需要執行 chunk 分裂。chunk 分裂是由 mongos 發起的,而數據放在 mongod 處,因此 mongos 無法準確判斷每個增刪改操作后某個 chunk 的數據實際大小。因此 mongos 采用了一種啟發式的觸發分裂方式:
mongos 在內存中記錄一份 chunk_id – incr_delta 的哈希表。
對于 insert 和 update 操作,估算出 incr_delta 的上界(WriteOp::targetWrites), 當 incr_delta 超過閾值時,執行 chunk 分裂。
值得注意的是:

1) chunk_id- incr_delta 是維護在 mongos 內存里的一份數據,重啟后丟失
2) 不同 mongos 之間的這份數據相互獨立
3) 不帶 shardkey 的 update 無法對 chunk_id- incr_delta 作用

因此這個啟發式的分裂方式很不精確,而除了手工以命令的方式分裂之外,這是 mongos 自帶的唯一的 chunk 分裂方式。

chunk 分裂的執行過程

1) 向對應的 mongod 發起 splitVector 命令,獲得一個 chunk 的可分裂點
2) mongos 拿到這些分裂點后,向 mongod 發起 splitChunk 命令

splitVector 執行過程:

1) 計算出 collection 的文檔的 avgRecSize= coll.size/ coll.count
2) 計算出分裂后的 chunk 中,每個 chunk 應該有的 count 數,split_count = maxChunkSize / (2 * avgRecSize)
3) 線性遍歷 collection 的 shardkey 對應的 index 的 [chunk_min_index, chunk_max_index] 范圍,在遍歷過程中利用 split_count 分割出若干 spli

splitChunk 執行過程:

1) 獲得待執行 collection 的分布式鎖(向 configSvr 的 mongod 中寫入一條記錄實現)
2) 刷新(向 configSvr 讀?。┍?shard 的版本號,檢查是否和命令發起者攜帶的版本號一致
3) 向 configSvr 中寫入分裂后的 chunk 信息,成功后修改本地的 chunk 信息與 shard 的版本號
4) 向 configSvr 中寫入變更日志
5) 通知 mongos 操作完成,mongos 修改自身元數據

chunk 分裂的執行流程圖:

問題與思考

問題一:為何 mongos 在接收到 splitVector 的返回后,執行 splitChunk 要放在 mongod 執行而不是 mongos 中呢,為何不是 mongos 自己執行完了 splitChunk 再通知 mongod 修改元數據?
我們知道 chunk 元數據在三個地方持有,分別是 configServer,mongos,mongod。如果 chunk 元信息由 mongos 更改,則其他 mongos 與 mongod 都無法第一時間獲得最新元數據。可能會發生這樣的問題,如下圖描述:

Mongos 對元數據的修改還沒有被 mongod 與其他 mongos 感知,其他 mongos 與 mongod 的版本號保持一致,導致其他 mongos 寫入錯誤的 chunk。

如果 chunk 元信息由 mongod 更改,mongod 先于所有的 mongos 感知到本 shard 的元數據被更改,由于 mongos 對 mongod 的寫入請求都會帶有版本號(以發起者 mongos 的 POV 持有的版本號),mongod 發現一個讀寫帶有的版本號低于自身版本號時就會返回 StaleShardingError,從而避免對錯誤的 chunk 進行讀寫。

Mongos 對讀寫的路由

讀請求:
mongos 將讀請求路由到對應的 shard 上,如果得到 StaleShardingError,則刷新本地的元數據(從 configServer 讀取最新元數據)并重試。
寫請求:
mongos 將寫請求路由到對應的 shard 上,如果得到 StaleShardingError,并不會像讀請求一樣重試,這樣做并不合理,截至當前版本,mongos 也只是列出了一個 TODO(batch_write_exec.cpp:185)

185 // TODO: It may be necessary to refresh the cache if stale, or maybe just
186 // cancel and retarget the batch

chunk 遷移

chunk 遷移由 balancer 模塊執行,balancer 模塊并不是一個獨立的 service,而是 mongos 的一個線程模塊。同一時間只有一個 balancer 模塊在執行,這一點是 mongos 在 configServer 中注冊分布式鎖來保證的。

balancer 對于每一個 collection 的 chunk 分布,計算出這個 collection 需要進行遷移的 chunk,以及每個 chunk 需要遷移到哪個 shard 上。計算的過程在 BalancerPolicy 類中,比較瑣碎。

chunk 遷移.Step1

MigrationManager::scheduleMigrations balancer 對于每一個 collection,嘗試獲得該 collection 的分布式鎖(向 configSvr 申請),如果獲得失敗,表明該 collection 已有正在執行的搬遷任務。這一點說明對于同一張表統一時刻只能有一個搬遷任務。如果這張表分布在不同的 shard 上,完全隔離的 IO 條件可以提高并發,不過 mongos 并沒有利用起來這一點。
如果獲得鎖成功,則向源 shard 發起 moveChunk 命令

chunk 遷移.Step2

mongod 執行 moveChunk 命令
cloneStage
1) 源 mongod 根據需要遷移的 chunk 的上下限構造好查詢計劃,基于分片索引的掃描查詢。并向目標 mongod 發起 recvChunkStart  指令,讓目標 chunk 開始進入數據拉取階段。
2) 源 mongod 對此階段的修改,將 id 字段 buffer 在內存里(MigrationChunkClonerSourceLegacy 類),為了防止搬遷時速度過慢 buffer 無限制增長,buffer 大小設置為 500MB,在搬遷過程中 key 的更改量超過 buffer 大小會導致搬遷失敗。
3) 目標 mongod 在接收到 recvChunkStart 命令后

a. 基于 chunk 的 range,將本 mongod 上的可能臟數據清理掉

b. 向源發起_migrateClone 指定,通過 1)中構造好的基于分配索引的掃描查詢得到該 chunk 數據的 snapshot

c. 拷貝完 snapshot 后,向源發起_transferMods 命令,將 2)中維護在內存 buffer 中的修改

d. 源在收到_transferMods 后,通過記錄的 objid 查詢對應的 collection,將真實數據返回給目標。

e. 目標在收完_transferMods 階段的數據后,進入 steady 狀態,等待源接下來的命令。這里有必要說明的是:用戶數據源源不斷的寫入,理論上_transferMods 階段會一直有新數據,但是必須要找到一個點截斷數據流,將源的數據(搬遷對應的 chunk 的數據)設置為不可寫,才能發起路由更改。因此這里所說的“_transferMods 階段的所有數據”只是針對于某個時間點,這個時間點過后依然會有新數據進來。

f. 源心跳檢查目標是否已經處于 steady 狀態,如果是,則封禁 chunk 的寫入,向目標發起_recvChunkCommit 命令,之后源的 chunk 上就無修改了。

g. 目標收到_recvChunkCommit 命令后,拉取源 chunk 上的修改并執行,執行成功后源解禁路由并清理源 chunk 的數據

到此,相信大家對“Mongos 與集群均衡怎么理解”有了更深的了解,不妨來實際操作一番吧!這里是丸趣 TV 網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

正文完
 
丸趣
版權聲明:本站原創文章,由 丸趣 2023-08-16發表,共計4672字。
轉載說明:除特殊說明外本站除技術相關以外文章皆由網絡搜集發布,轉載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 辰溪县| 铅山县| 绥棱县| 邵阳县| 神木县| 陈巴尔虎旗| 综艺| 专栏| 宣汉县| 常熟市| 武功县| 新营市| 乌审旗| 延川县| 江津市| 鄂伦春自治旗| 佛山市| 新乐市| 绵竹市| 平谷区| 邵阳县| 留坝县| 五原县| 星子县| 永福县| 西充县| 前郭尔| 吉林省| 通河县| 平南县| 甘洛县| 灵台县| 怀柔区| 楚雄市| 北辰区| 阳江市| 荣昌县| 奈曼旗| 洛浦县| 加查县| 沅陵县|