前言
前面我們了解了 MongoDB 中的索引,事務,鎖等知識點。線上使用的 MongoDB 大部分的場景我們都會考慮使用分佈式結構,這裡我們來了解一下 MongoDB 中的分佈式架構。
MongoDB 中常用的分佈式架構有下面幾種:
1、Replica Set 副本集模式:一個 Primary 節點用於寫入數據,其它的 Secondary 節點用於查詢數據,適合讀寫少的場景,是目前較為主流的架構方式,Primary 節點掛了,會自動從 Secondary 節點選出新的 Primary 節點,提供數據寫入操作;
2、Master-Slaver 主從副本的模式:也是主節點寫入,數據同步到 Slave 節點,Slave 節點提供數據查詢,最大的問題就是可用性差,MongoDB 3.6 起已不推薦使用主從模式,自 MongoDB 3.2 起,分片群集組件已棄用主從復制。因為 Master-Slave 其中 Master 宕機後不能自動恢復,隻能靠人為操作,可靠性也差,操作不當就存在丟數據的風險,這種模式被 Replica Set 所替代 ;
3、Sharding 分片模式:將不同的數據分配在不同的機器中,也就是數據的橫向擴展,單個機器隻存儲整個數據中的一部分,這樣通過橫向增加機器的數量來提高集群的存儲和計算能力。
因為 Master-Slaver 模式已經在新版本中棄用了,下面主要來介紹下 Replica Set 模式和 Sharding 模式。
Replica Set 副本集模式
MongoDB 中的 Replica Set 副本集模式,可以簡單理解為一主多從的集群,包括一個主節點(primary)和多個副本節點(Secondaries)。
主節點隻有一個,所有的寫操作都在主節點中進行,副本節點可以有多個,通過同步主節點的操作日志(oplog)來備份主節點數據。
在主節點掛掉之後,有選舉節點功能會自動從從節點中選出一個新的主節點,如果一個從節點,從節點也會自動從集群中剔除,保證集群的數據讀操作不受影響。
搭建一個副本集集群最少需要三個節點:一個主節點,兩個備份節點,如果三個節點分佈合理,基本可以保證線上數據 99.9% 安全。
![](https://news.xinpengboligang.com/upload/keji/72bfcd644a7bfce275cb88632f8650c4.jpeg)
在集群隻有是三個節點的情況下,當主節點超過配置的 electionTimeoutMillis 時間段(默認情況下為 10 秒)內未與集合中的其他成員進行通信時,主節點就會被認為是異常了,兩個副本節點也會進行選舉,重新選出一個新的主節點。
![](https://news.xinpengboligang.com/upload/keji/5cb3515cd84fdd39b3c07fe79c99fd73.jpeg)
在默認復制設置的情況下,從一個集群開始選舉新主節點到選舉完成的中間時間通常不超過 12 秒。中間包括將主節點標記不可用,發起並完成選舉所需要的時間。在選舉的過程中,就意味著集群暫時不能提供寫入操作,時間越久集群不可寫入的時間也就是越久。
關於副本節點的屬性,這裡來主要的介紹下:priority、hidden、slaveDelay、tags、votes。
粉絲福利, 免費領取C/C 開發學習資料包、技術視頻/項目代碼,1000道大廠面試題,內容包括(C 基礎,網絡編程,數據庫,中間件,後端開發,音視頻開發,Qt開發,遊戲開發,Linux內核等進階學習資料和最佳學習路線)↓↓↓↓有需要的朋友可以進企鵝裙927239107領取哦~↓↓
- priority
對於副本節點,可以通過該屬性增大或者減小該節點被選舉為主節點的可能性,取值范圍是 0-1000(如果是 arbiters,則取值隻有 0 或者 1),數據越大,成為主節點的可能性越大,如果被配置為 0,那麼他就不能被選舉成為主節點,而且也不能主動發起選舉。
比如說集群中的某幾臺機器配置較高,希望主節點主要在這幾臺機器中產生,那麼我們就可以通過設置 priority 的大小來實現。
- hidden
隱藏節點可以從主節點同步數據,但對客戶端不可見,在 mongo shell 執行 db.isMaster() 方法也不會展示該節點,隱藏節點必須 Priority 為 0,即不可以被選舉成為主節點。但是如果有配置選舉權限的話,可以參與選舉。
因為隱藏節點對客戶端不可見,所以對於備份數據或者一些定時腳本可以直接連到隱藏節點,有大的慢查詢也不會影響到集群本身對外提供的服務。
![](https://news.xinpengboligang.com/upload/keji/6b600d6a361e5746622c5b3e2842c577.jpeg)
- slaveDelay
延遲從主節點同步數據,比如延遲節點時間配置為 1 小時,現在的時間是 10 點鐘,那麼從節點同步到的數據就是 9 點之前的數據。
隱藏節點有什麼作用呢?其中有一個和重要的作用就是防止數據庫誤操作,比如當我們對數據的進行大批量的刪除或者更新操作,為了防止出現意外,我們可能會考慮事先備份一下數據,當操作出現異常的時候,我們還能根據備份進行復原回滾操作。有了延遲節點,因為延遲節點還沒及時同步到最新的數據,我們就可以基於延遲節點進行數據庫的復原操作。
![](https://news.xinpengboligang.com/upload/keji/8d6f9c515d742ee2f246e60b0afe6ba4.jpeg)
- tags
支持對副本集打成員標簽,在查詢數據時會用到,比如找到對應標簽的副本節點,然後從該節點讀取數據,可以根據標簽對節點分類,查詢數據時不同服務的客戶端指定其對應的標簽的節點,對某個標簽的節點數量進行增加或減少,也不怕會影響到使用其他標簽的服務。
- votes
表示節點是否有權限參與選舉。
副本集寫和讀的特性
寫關註 (Write concern)
副本集寫關註是指寫入一條數據,主節點處理完成之後,需要其它承載副本的節點也確認寫成功之後,才能給客戶端返回寫入數據成功。
這個功能主要是解決主節點掛掉之後,數據還沒來得及同步到從節點,進而導致數據丟失的問題。
可以配置節點個數,默認配置 {“w”:1},這樣表示主節點寫入數據成功即可給客戶端返回成功,“w” 配置為 2,則表示除了主節點,還需要收到其中一個副本節點返回寫入成功,“w” 還可以配置為 "majority",表示需要集群中大多數承載數據且有選舉權限的節點返回寫入成功。
比如下面的栗子,寫請求裡面帶了 w : “majority" ,那麼主節點寫入完成後,數據同步到第一個副本節點,且第一個副本節點回復數據寫入成功後,才給客戶端返回成功。
![](https://news.xinpengboligang.com/upload/keji/52f33137147fa8ad6e3834c220ee1969.jpeg)
一般有兩種使用策略
1、修改副本集的配置
cfg = rs.conf()
cfg.settings.getLastErrorDefaults = { w: "majority", wtimeout: 5000 }
rs.reconfig(cfg)
2、單個數據插入或者修改的時候攜帶該參數
db.products.insert(
{ item: "envelopes", qty : 100, type: "Clasp" },
{ writeConcern: { w: "majority" , wtimeout: 5000 } }
)
讀偏好 (Read preference)
讀和寫不一樣, 為了保持一致,寫隻能通過主節點,但是讀可以選擇主節點,也可以選擇副本節點。區別是主節點數據最新,副本節點因為同步問題可能會有延遲,但從副本節點讀取數據可以分散對主節點的壓力。
![](https://news.xinpengboligang.com/upload/keji/5e61ca3315a004b63224e28ded9a3853.jpeg)
來看下 5 種讀偏好模式的具體特點
![](https://news.xinpengboligang.com/upload/keji/6c2def3ef6664925b93e6f0cafb09dd9.jpeg)
Sharding 分片模式
分片將數據分佈式在不同的機器中。MongoDB 使用分片來支持具有非常大數據集和高吞吐量操作的部署。
當數據量的數據逐漸變大或者數據的請求變大之後,機器我們就會考慮到升級,通常會有兩種方式:垂直擴展和水平擴展。
垂直擴展:垂直擴展就是提高單個機器的性能,使用更高的 CPU,增加更多的 RAM 或者存儲空間。但是單個的機器的性能總歸是有上限的,因此垂直擴展理論上是有上限的。
水平擴展:水平擴展將系統數據集和負載均勻的分配到多個服務器中,根據實際的需求,增加服務器,就能提高整體的容量和性能。雖然單個機器的總速度或容量可能不高,但每臺機器處理整體工作負載的一個子集,相比單一的高速大容量服務器,可能提供更好的效率。擴展部署的容量隻需根據需要添加額外的服務器,與單機的高端硬件相比,這可能是更低的總體成本。代價則是增加了部署的基礎設施和維護的復雜性。
分片的優勢
讀寫
MongoDB 在分片集群上的分片上分散讀寫,允許每個分片處理集群操作的一部分。通過添加更多的分片,可以在集群中水平擴展讀寫工作負載。
對於包含分片鍵或符合分片鍵的前綴查詢的操作,mongos 可以將查詢定向到特定的分片或分片集,這樣的查詢是很高效的,如果不攜帶分片鍵,就需要將操作廣播到集群中的每個分片中。
從 MongoDB 4.4 開始,mongos 可以支持對沖讀取以最小化延遲,什麼是對沖讀,分片集群中,mongos 節點會把一個客戶端的讀請求同時發送給某個 Shard 分片的多個副本集節點,最後選擇響應最快節點的返回結果回復給客戶端,來減少業務側感知到的延遲。
存儲容量
分片在集群中的分片上分配數據,允許每個分片包含總集群數據的一個子集。隨著數據集的增長,添加額外的分片可以增加集群的存儲容量。
高可用性
配置服務器和分片作為副本集的部署提供了增強的可用性。
即使一個或多個分片副本集完全不可用,分片集群仍可以繼續執行部分讀寫操作。也就是說,雖然無法訪問不可用分片上的數據,但針對可用分片的讀寫操作仍然可以成功。
MongoDB 分片的組件
MongoDB 中的 Sharding 分片模式由下面幾個組件組成:
- 分片(shard):每個分片包含一部分分片數據。每個分片可以部署為一個副本集;
- mongos:mongos 作為查詢路由器,提供客戶端應用程序與分片集群之間的接口。從 MongoDB 4.4 開始,mongos 可以支持對沖讀取(hedged reads)以最小化延遲;
- 配置服務器(config servers):配置服務器存儲集群的元數據和配置設置。
![](https://news.xinpengboligang.com/upload/keji/74a983db982220e40114487d03cc8f68.jpeg)
分片鍵
MongoDB 在集合級別分片數據,將收集數據分佈在集群中的各個分片上。
MongoDB 使用分片鍵在各個分片之間分發集合中的文檔。分片鍵由文檔中的一個或多個字段組成。
在 4.2 及之前的版本中,分片集合中的每個文檔都必須存在分片鍵字段。
從 4.4 版本開始,在分片集合中的文檔可以缺少分片鍵字段。
可以選擇集群中的分片鍵
在 MongoDB 4.2 及以前的版本裡,一旦完成分片,分片鍵的選擇就不能更改了。
從 MongoDB 4.4 開始,可以通過添加一個後綴字段或多個字段到現有的分片鍵來優化分片鍵。
從 MongoDB 5.0 開始,可以通過更改集合的分片鍵來重新分片集合。
要對集合進行分片處理,集合必須有一個以分片鍵開頭的索引,如果集合本身沒有對應的索引,在指定分片的時候會創建對應的索引。
chunk 是什麼
我們知道 MongoDB 的分片集群,數據會被均勻的分佈在不同的 shard 中,對於每一個 shard 中的數據,是存儲在一個個的 chunk 中的,每個 chunk 代表 shard 中的一部分數據。
chunk 有什麼作用:
1、Splitting:當一個 chunk 的大小超過配置的 chunk size ,MongoDB 的進程會把這個 chunk 切分成更小的 chunk ,避免 chunk 過大的情況出現;
2、Balancing:在 MongoDB 中,balancer 是一個後臺的進程,負責 chunk 的轉移,從而均衡各個 shard server 的負載。
簡單就是使用 chunk 存儲數據,方便集群進行數據在分片集群中進行數據的均衡遷移操作。
chunk 的大小選擇很重要,集群默認的大小是 64 兆,可以根據業務大小進行調節。
- 較小的 chunksize
優點:數據均衡和遷移速度快,數據分佈更均勻;
缺點:數據分裂頻繁,路由節點消耗更多資源。
- 較大的 chunksize
優點:數據分裂少;
缺點:數據塊移動集中消耗 IO 資源。
分片的算法
MongoDB 中支持兩種分片策略來跨分片集群分佈數據。哈希分片和范圍分片。
哈希分片
哈希分片會計算分片鍵字段值的哈希,然後根據哈希分片鍵值,每個塊分配一個范圍。
![](https://news.xinpengboligang.com/upload/keji/7cc8ee3d42a44c4c08789805aa01d28a.jpeg)
雖然一系列分片鍵可能是“接近”的,但它們的哈希值不太可能在同一個塊上。基於哈希值的數據分佈有助於更加均勻地分佈數據,特別是在分片鍵單調變化的數據集中。
對於 MongoDB 中的查詢,如果查詢中包含分片鍵,那麼能定位到具體的分片直接查詢,否則就要廣播查詢到集群中所有的分片了。
mongos 在接收到所有分片的響應後,將合並數據並返回結果文檔。廣播操作的性能取決於集群的整體負載,以及網絡延遲、各個分片的負載和每個分片返回的文檔數量等因素。所有在使用哈希分片方式部署的集群,我們應該減少可能導致廣播的查詢。
![](https://news.xinpengboligang.com/upload/keji/dd8d1a13c1e904d7367a468e0d67ae13.jpeg)
一般哈希對於范圍查詢都支持的很差。
范圍分片
MongoDB 中分片鍵劃分數會根據數據范圍,將不同范圍內的數據劃分到不同的分片中,同一個范圍內的數據就能夠分佈在同一個分片中了。
這樣針對連續范圍的查詢就能夠高效的執行了。
![](https://news.xinpengboligang.com/upload/keji/55b163ca8fb5f680829b36e9b7ad8607.jpeg)
總結
1、Replica Set 副本集模式:一個 Primary 節點用於寫入數據,其它的 Secondary 節點用於查詢數據,適合讀寫少的場景,是目前較為主流的架構方式,Primary 節點掛了,會自動從 Secondary 節點選出新的 Primary 節點,提供數據寫入操作;
2、Sharding 分片模式:將不同的數據分配在不同的機器中,也就是數據的橫向擴展,單個機器隻存儲整個數據中的一部分,這樣通過橫向增加機器的數量來提高集群的存儲和計算能力;