(一)分片的由來
隨着系統的業務量越來越大,業務系統往往會出現這樣一些特點:
- 高吞吐量
- 高並發
- 超大規模的數據量
高並發的業務可能會耗盡服務器的CPU,高吞吐量、超大規模的數據量也會帶來內存、磁盤的壓力。
對於這類問題,解決系統增長的方法有2種:垂直擴展和水平擴展。
- 垂直擴展主要是增加單個服務器的資源。例如:使用增強大的CPU、增加更多的內存、使用固態硬盤等。
- 水平擴展主要是增加服務器。雖然單台服務器的整體速度或者容量都比較低,但如果每台服務器只處理工作量的一部分,則與單台服務器相比,可以提供更多的資源,提高效率。
垂直擴展終歸有一個上限,例如,我已經用了最好的CPU、服務器主板也已經插滿了內存、也使用了SSD存儲設備,可是依然還是無法滿足需求。那么這個時候就不得不考慮使用水平擴展了,通過增加機器,將業務、數據拆分到不同的機器上,實現業務的分流。
MongoDB是如何實現水平擴展的呢?Sharding,中文即分片。分片是指將數據拆分,將其分散放在不同主機上的過程。
(二)何時分片
如果在系統建設初期,就能夠較為准確的評估出將來的業務量,那么直接在建設系統時就實施分片是最好的。但是在實際應用中,我們很難評估出將來的業務量大小,所以最好是在業務運行一段時間之后進行分片,當然,也不能在業務運行了幾乎達到滿負載運行時才進行分片,因為在近乎滿負載的集群上不停機進行分片是非常困難的。通常,分片用來:
- 增加可用RAM
- 增加可用磁盤空間
- 減輕單台服務器的負載
- 處理單台服務器無法處理的吞吐量
(三)分片集群架構
一個完整的分片集群的架構如下圖
其核心主要包括:mongos、config server、shard三部分。
(3.1)mongos
mongos是查詢路由,在客戶端程序和分片之間提供接口,用戶如果要訪問mongodb分片數據庫,必須使用mongos。部署多個mongos可支持高可用性和可拓展性,一個常見的模式是在每個應用服務器上部署一個mongos,以減少應用程序和mongos之間的網絡延遲。
mongos從配置服務器讀取分片集群元數據並緩存下來,利用元數據,實現對客戶端讀寫操作的路由。
(3.1.1)mongos如何處理查詢修飾符
sort :如果查詢語句不包含排序,則mongos實例將打開結果游標,對該游標分片上的所有游標進行輪詢。
limit :如果使用limit限制了結果集大小,則mongos會將limit操作下發到分片上,然后再將limit操作用於分片返回的結果。
skip :如果查詢中使用了skip,則不能將skip傳給分片,而是從分片檢索未跳過的結果,並將組裝完結果后跳過指定的文檔數量
(3.1.2)確認與mongos實例的連接
要檢測客戶端是否連接到mongos,使用isMaster命令,當連接到mongos時,會返回"msg" : "isdbgrid"。
db.isMaster() /* 1 */ { "ismaster" : true, "msg" : "isdbgrid", "maxBsonObjectSize" : 16777216, "maxMessageSizeBytes" : 48000000, "maxWriteBatchSize" : 100000, "localTime" : ISODate("2021-01-15T07:00:23.585Z"), "logicalSessionTimeoutMinutes" : 30, "connectionId" : 42, "maxWireVersion" : 8, "minWireVersion" : 0, "ok" : 1.0, "operationTime" : Timestamp(1610694017, 2), "$clusterTime" : { "clusterTime" : Timestamp(1610694017, 2), "signature" : { "hash" : { "$binary" : "AAAAAAAAAAAAAAAAAAAAAAAAAAA=", "$type" : "00" }, "keyId" : NumberLong(0) } } }
(3.1.3)目標操作和廣播操作
在分片集群中,最快的操作是使用mongos通過shard key路由到單個分片上,這種目標操作使用shard key定位滿足查詢的文檔分片或分片子集。對於不包含分片鍵的查詢,mongos必須查詢所有的分片,然后將結果返回給客戶端,這些“scatter/gather”查詢可能會消耗更多的時間。
(3.1.4)元數據操作
mongos使用"majority"寫關注操作元數據:
命令 方法 ------------- ---------------- addShard sh.addShard() create db.createCollection() drop db.collection.drop() dropDatabase db.dropDatabase() enableSharding sh.enableSharding() movePrimary renameCollection db.collection.renameCollection() shardCollection sh.shardCollection() removeShard setFeatureCompatibilityVersion
(3.1.5)FCV兼容性
從MongoDB 4.0開始,mongos嘗試連接mongod實例時,如果mongos功能兼容版本(feature compatibility version,fcv)小於mongod,則會造成mongos的二進制文件崩潰。例如:
- 不能使用fcv是4.0版本的mongos連接到fcv是4.2版本的分片集群
- 可以使用fcv是4.2版本的mongos連接到fcv是4.0版本的分片集群
(3.2)config server
配置服務器存儲集群的元數據,元數據反映分片集群的內所有數據和組件的狀態和組織方式,元數據包含每個分片上的塊列表以及定義塊的范圍。從3.4版本開始,已棄用鏡像服務器用作配置服務器(SCCC),config Server必須部署為副本集架構(CSRS)。
Mongos實例緩存配置服務器的數據,並使用它路由讀和寫操作到正確的分片。當元數據發生改變的時候(例如:添加新的分片、chunks分裂),mongos更新緩存數據。此外,配置服務器還存儲基於角色的用戶權限信息。MongoDB也是用配置服務器管理分布式鎖。每個分片集群都必須有自己的配置服務器,不能共享同一個配置服務器,配置服務器必須運行在WiredTiger存儲。
(3.2.1)配置服務器的讀寫操作
在配置服務器上存在admin和config數據庫,admin數據庫包含身份驗證以及授權相關的集合及其它的system.*集合,config數據庫包含分片集群元數據的集合,當元數據發生變更時,MongoDB會將數據寫入到config服務器。在做操作或者維護期間,我們應該避免直接去寫配置服務器。當我們從副本集配置服務器讀數據時,MongoDB使用”majority”讀關注,以避免幻讀;當我們從副本集配置服務器寫數據時,MongoDB使用”majority”寫關注,以確保數據不會丟失。
(3.2.2)配置服務器可用性
如果配置副本集丟失其主服務器並且無法選舉主節點,則集群元數據變為只讀,此時仍然可以從集群中讀和寫數據,但是不能夠執行chunk合並、分裂等改變元數據的操作。
如果所有的副本集服務器不可用,集群將變得不可用。為了確保配置服務器保持可用和完整,備份就顯得十分重要,配置服務器數據量很小,備份對主機的性能影響也相對較小。
(3.3.3)分片集群的元數據
分片集群的元數據存儲在配置服務器的config數據庫中。通常,永遠不要直接編輯config數據庫的內容,config數據庫包含以下集合:
use config show collections ------------------------------ actionlog changelog chunks collections databases lockpings locks migrations mongos shards system.sessions tags transactions version
(3.3)Shard
shard是存儲數據的地方,每個shard包含集合的一部分數據,從3.6版本開始,每個shard必須部署為副本集(replica set)架構。
(3.3.1)主分片的概念
分片集群中的每個數據庫都有一個主分片,其中包含該數據庫所有未分片的集合。當在分片集群中創建一個新的數據庫時,mongos會為新數據庫選擇一個分片作為主分片。選擇的機制為:選擇數據量少的分片作為新數據庫的主分片。如下圖:集群存在2個分片,對於Collection2集合,沒有實施分片,則將全部數據存放在其主分片上。
特別注意:
主分片與副本集的主節點沒有任何關系。
【完】
相關文檔合集: 1. MongoDB Sharding(一) -- 分片的概念 |