mongodb分片擴展架構
[TOC]
一、簡介
MongoDB目前3大核心優勢:『靈活模式』+ 『高可用性』 + 『可擴展性』,通過json文檔來實現靈活模式,通過復制集來保證高可用,通過Sharded cluster來保證可擴展性。
MongoDB 分片集群Sharded Cluster通過將數據分散存儲到多個分片(Shard)上來實現高可擴展性。
當MongoDB復制集遇到下面的業務場景時,你就需要考慮使用Sharded cluster
- 存儲容量需求超出單機磁盤容量
- 活躍的數據集超出單機內存容量,導致很多請求都要從磁盤讀取數據,影響性能
- 寫IOPS超出單個MongoDB節點的寫服務能力
如上圖所示,Sharding Cluster使得集合的數據可以分散到多個Shard(復制集或者單個Mongod節點)存儲,使得MongoDB具備了橫向擴展(Scale out)的能力,豐富了MongoDB的應用場景。
二、分片集群
實現分片集群時,MongoDB 引入 Config Server 來存儲集群的元數據,引入 mongos 作為應用訪問的入口,mongos 從 Config Server 讀取路由信息,並將請求路由到後端對應的 Shard 上。
Diagram of a sample sharded cluster for production purposes. Contains exactly 3 config servers, 2 or more mongos
query routers, and at least 2 shards. The shards are replica sets.
![技術分享圖片](http://image.bubuko.com/info/201803/20180313223500517214.png)
角色說明
A.數據分片(Shards)
用來保存數據,保證數據的高可用性和一致性。可以是一個單獨的mongod實例,也可以是一個副本集。
在生產環境下Shard一般是一個Replica Set,以防止該數據片的單點故障。所有Shard中有一個PrimaryShard,裏面包含未進行劃分的數據集合:
B.配置服務器(Config servers)
保存集群的元數據(metadata),包含各個Shard的路由規則。
C.查詢路由(Query Routers)
Mongos是Sharded cluster的訪問入口,其本身並不持久化數據(Sharded cluster所有的元數據都會存儲到Config Server,而用戶的數據則會分散存儲到各個shard)
Sharding集群可以有一個mongos,也可以有多mongos以減輕客戶端請求的壓力。
三、數據分布策略
Sharded cluster支持將單個集合的數據分散存儲在多個shard上,用戶可以指定根據集合內文檔的某個字段即shard key來分布數據,
目前主要支持2種數據分布的策略,範圍分片(Range based sharding)或hash分片(Hash based sharding)。
範圍分片
Diagram of the shard key value space segmented into smaller ranges or chunks.
如上圖所示,集合根據x字段來分片,x的取值範圍為[minKey, maxKey](x為整型,這裏的minKey、maxKey為整型的最小值和最大值),將整個取值範圍劃分為多個chunk,每個chunk(通常配置為64MB)包含其中一小段的數據。
Chunk1包含x的取值在[minKey, -75)的所有文檔,而Chunk2包含x取值在[-75, 25)之間的所有文檔... 每個chunk的數據都存儲在同一個Shard上,每個Shard可以存儲很多個chunk,chunk存儲在哪個shard的信息會存儲在Config server種,mongos也會根據各個shard上的chunk的數量來自動做負載均衡。
範圍分片能很好的滿足『範圍查詢』的需求,比如想查詢x的值在[-30, 10]之間的所有文檔,這時mongos直接能將請求路由到Chunk2,就能查詢出所有符合條件的文檔。
範圍分片的缺點在於,如果shardkey有明顯遞增(或者遞減)趨勢,則新插入的文檔多會分布到同一個chunk,無法擴展寫的能力,比如使用_id作為shard key,而MongoDB自動生成的id高位是時間戳,是持續遞增的。
HASH分片
Hash分片是根據用戶的shard key計算hash值(64bit整型),根據hash值按照『範圍分片』的策略將文檔分布到不同的chunk。
Diagram of the hashed based segmentation.
Hash分片與範圍分片互補,能將文檔隨機的分散到各個chunk,充分的擴展寫能力,彌補了範圍分片的不足,但不能高效的服務範圍查詢,所有的範圍查詢要分發到後端所有的Shard才能找出滿足條件的文檔。
合理的選擇shard key
選擇shard key時,要根據業務的需求及『範圍分片』和『Hash分片』2種方式的優缺點合理選擇,同時還要註意shard key的取值一定要足夠多,否則會出現單個jumbo chunk,即單個chunk非常大並且無法分裂(split);比如某集合存儲用戶的信息,按照age字段分片,而age的取值非常有限,必定會導致單個chunk非常大。
四、Mongos訪問模式
所有的請求都由mongos來路由、分發、合並,這些動作對客戶端driver透明,用戶連接mongos就像連接mongod一樣使用。
Mongos會根據請求類型及shard key將請求路由到對應的Shard,因此不同的操作請求存在不同限制。
查詢請求
查詢請求不包含shard key,則必須將查詢分發到所有的shard,然後合並查詢結果返回給客戶端
查詢請求包含shard key,則直接根據shard key計算出需要查詢的chunk,向對應的shard發送查詢請求插入請求
寫操作必須包含shard key,mongos根據shard key算出文檔應該存儲到哪個chunk,然後將寫請求發送到chunk所在的shard。更新/刪除請求
更新、刪除請求的查詢條件必須包含shard key或者_id,如果是包含shard key,則直接路由到指定的chunk,如果只包含_id,則需將請求發送至所有的shard。其他命令請求
除增刪改查外的其他命令請求處理方式都不盡相同,有各自的處理邏輯,比如listDatabases命令,會向每個Shard及Config Server轉發listDatabases請求,然後將結果進行合並。
如何連接
一個典型的ConnectURI 結構如下:
mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]
//說明
- mongodb:// 前綴,代表這是一個Connection String;
- username:password@ 如果啟用了鑒權,需要指定用戶密碼;
- hostX:portX多個 mongos 的地址列表;
- /database鑒權時,用戶帳號所屬的數據庫;
- ?options 指定額外的連接選項,比如指定readPreference=secondaryPreferred實現讀寫分離
分片集群可以提供多個 mongos 實現現負載均衡;而當某個 mongos 故障時,客戶端也能自動進行 failover,將請求都分散到狀態正常的 mongos 上。
當 mongos 數量很多時,還可以按應用來將 mongos 進行分組,比如有2個應用 A、B、有4個 mongos,可以讓應用 A 訪問 mongos 1-2(URI 裏只指定 mongos 1-2 的地址),
應用 B 來訪問 mongos 3-4(URI 裏只指定 mongos 3-4 的地址),根據這種方法來實現應用間的訪問隔離(應用訪問的 mongos 彼此隔離,但後端 Shard 仍然是共享的),如下圖
五、Config元數據
Config server存儲Sharded cluster的所有元數據,所有的元數據都存儲在config數據庫,
3.2版本後,Config Server可部署為一個獨立的復制集,極大的方便了Sharded cluster的運維管理。
config數據集合如下表所示:
集合名稱 | 說明 |
---|---|
config.shards | 存儲各個Shard的信息,可通過addShard、removeShard命令來動態的從Sharded cluster裏增加或移除shard |
config.databases | 存儲所有數據庫的信息,包括DB是否開啟分片,primary shard信息,對於數據庫內沒有開啟分片的集合,所有的數據都會存儲在數據庫的primary shard上 |
config.colletions | 數據分片是針對集合維度的,某個數據庫開啟分片功能後,如果需要讓其中的集合分片存儲,則需調用shardCollection命令來針對集合開啟分片。 |
config.chunks | 集合分片開啟後,默認會創建一個新的chunk,shard key取值[minKey, maxKey]內的文檔(即所有的文檔)都會存儲到這個chunk。當使用Hash分片策略時,可以預先創建多個chunk,以減少chunk的遷移 |
config.settings | 存儲sharded cluster的配置信息,比如chunk size,是否開啟balancer等 |
config.tags | 主要存儲sharding cluster標簽(tag)相關的你洗,以實現根據tag來分布chunk的功能 |
config.changelog | 主要存儲sharding cluster裏的所有變更操作,比如balancer遷移chunk的動作就會記錄到changelog裏。 |
config.mongos | 存儲當前集群所有mongos的信息 |
config.locks | 存儲鎖相關的信息,對某個集合進行操作時,比如moveChunk,需要先獲取鎖,避免多個mongos同時遷移同一個集合的chunk。 |
六、分片均衡
Mongodb 實現了自動分片均衡,均衡器是一個在後臺對分片chunk進行監控的進程,當某個shard的chunks差異數量到達閾值時,將自動開始在shard中間遷移chunk數據庫以達到均衡目的。整個遷移過程對應用層是透明的,從3.4版本開始,均衡器不再由Mongos執行,而是由Config副本集的主節點來處理。
遷移過程中對集群性能存在一定影響,因此一般可以通過設置均衡窗口對齊到業務閑時段。
閾值參考表
|Number of Chunks| Migration Threshold|
|-|-|
|Fewer than 20| 2||
|20-79| 4|
|80 and greater| 8|
遷移過程
- 均衡器向源shard發送moveChunk命令;
- 源shard執行內部的moveChunk流程,過程中數據操作仍然指向當前shard
- 目標shard構建缺失的索引;
- 目標shard請求並接收chunk副本數據;
- 在chunk接收到後,目標shard向源shard確認是否存在增量更新數據,若存在則繼續同步;
- 完全同步後,源shard通知config副本集更新元數據庫,將chunk的位置更新為目標shard
- 在更新完元數據庫後並確保沒有關聯cursor的情況下,源shard刪除被遷移的chunk副本。
參考文檔
mongodb shard cluster原理
http://www.mongoing.com/archives/2782
mongo中文社區-高可用mongodb集群
https://yq.aliyun.com/articles/61516
官網-mongodb分片集群
https://docs.mongodb.com/manual/core/sharding-balancer-administration/
mongodb分片擴展架構