MongoDB 的集羣架構與設計
一、前言
MongoDB 有三種集羣架構模式,分別爲主從複製(Master-Slaver)、副本集(Replica Set)和分片(Sharding)模式。
-
Master-Slaver 是一種主從複製的模式,目前已經不推薦使用。
-
Replica Set 模式取代了 Master-Slaver 模式,是一種互爲主從的關係。Replica Set 將數據複製多份保存,不同服務器保存同一份數據,在出現故障時自動切換,實現故障轉移,在實際生產中非常實用。
-
Sharding 模式適合處理大量數據,它將數據分開存儲,不同服務器保存不同的數據,所有服務器數據的總和即爲整個數據集。
二、主從複製模式
MongoDB 提供的第一種冗餘策略就是 Master-Slave 策略,這個也是分佈式系統最開始的冗餘策略,這種是一種熱備策略。
Master-Slave 架構一般用於備份或者做讀寫分離,一般是一主一從設計和一主多從設計。
Master-Slave 由主從角色構成:
Master (主)
可讀可寫,當數據有修改的時候,會將 Oplog 同步到所有連接的 Salve 上去。
Slave (從)
只讀,所有的 Slave 從 Master 同步數據,從節點與從節點之間不感知。
如圖:
2.1 主從複製對讀寫分離的思考
主從複製老生常談的問題:數據不一致的問題。
根本原因在於只有 Master 節點可以寫,Slave 節點只能同步 Master 數據並對外提供讀服務,當你查詢 Slave 節點的數據時,由於網絡延遲等其它因素導致 Slave 節點還沒有完全同步 Master 節點的數據,這就會導致主從不一致,跟 MySQL 的主從複製如出一轍,只不過 MySQL 時 binlog 同步,而 MongoDB 是 oplog 同步。
所以,總結來說:讀寫分離的架構只適合特定場景,對於必須需要數據強一致的場景是不合適這種讀寫分離的。
2.2 主從複製對容災的思考
當 Master 節點出現故障的時候,由於 Slave 節點有備份數據,可以通過人爲 Check 和操作,手動把 Slave 節點指定爲 Master 節點,這樣又能對外提供服務了。
-
Master-Slave 只區分兩種角色:Master 節點,Slave 節點;
-
Master-Slave 的角色是靜態配置的,不能自動切換角色,必須人爲指定;
-
用戶只能寫 Master 節點,Slave 節點只能從 Master 拉數據;
-
還有一個關鍵點:Slave 節點只和 Master 通信,Slave 之間相互不感知,這種好處對於 Master 來說優點是非常輕量,缺點是:系統明顯存在單點,那麼多 Slave 只能從 Master 拉數據,而無法提供自己的判斷;
MongoDB 3.6 起已不推薦使用主從模式,自 MongoDB 3.2 起,分片羣集組件已棄用主從複製。因爲 Master-Slave 其中 Master 宕機後不能自動恢復,只能靠人爲操作,可靠性也差,操作不當就存在丟數據的風險。
三、副本集模式
3.1 副本集模式角色
副本集(Replica Set)是 mongod 的實例集合,包含三類節點角色:
Primary( 主節點 )
只有 Primary 是可讀可寫的,Primary 接收所有的寫請求,然後把數據同步到所有 Secondary 。一個 Replica Set 只有一個 Primary 節點,當 Primary 掛掉後,其他 Secondary 或者 Arbiter 節點會重新選舉出來一個 Primary 節點,這樣就又可以提供服務了。
讀請求默認是發到 Primary 節點處理,如果需要故意轉發到 Secondary 需要客戶端修改一下配置(注意:是客戶端配置,決策權在客戶端)。
那有人又會想了,這裏也存在 Primary 和 Secondary 節點角色的分類,豈不是也存在單點問題?
這裏和 Master-Slave 模式的最大區別在於,Primary 角色是通過整個集羣共同選舉出來的,人人都可能成爲 Primary ,人人最開始只是 Secondary ,而這個選舉過程完全自動,不需要人爲參與。
Secondary( 副本節點 )
數據副本節點,當主節點掛掉的時候,參與選主。
思考一個問題:Secondary 和 Master-Slave 模式的 Slave 角色有什麼區別?
最根本的一個不同在於:Secondary 相互有心跳,Secondary 可以作爲數據源,Replica 可以是一種鏈式的複製模式。
Arbiter( 仲裁者 )
不存數據,不會被選爲主,只進行選主投票。使用 Arbiter 可以減輕在減少數據的冗餘備份,又能提供高可用的能力。
如下圖:
3.2 爲什麼要使用副本集?
3.2.1 高可用
-
防止設備(服務器、網絡)故障
-
提供自動 failover 功能
-
技術來保證高可用
3.2.2 災難恢復
- 當發生故障時,可以從其他節點恢復,用於備份。
3.2.3 功能隔離
-
我們可以在備節點上執行讀操作,減少主節點的壓力
-
比如:用於分析、報表,數據挖掘,系統任務等。
3.3 副本集集羣架構原理
一個副本集中Primary
節點上能夠完成讀寫操作,Secondary
節點僅能用於讀操作。Primary
節點需要記錄所有改變數據庫狀態的操作,這些記錄保存在 oplog
中,這個文件存儲在 local
數據庫,各個Secondary
節點通過此 oplog
來複制數據並應用於本地,保持本地的數據與主節點的一致。oplog
具有冪等性,即無論執行幾次其結果一致,這個比 mysql
的二進制日誌更好用。
oplog
的組成結構
{
"ts" : Timestamp(1446011584, 2),
"h" : NumberLong("1687359108795812092"),
"v" : 2,
"op" : "i",
"ns" : "test.nosql",
"o" : { "_id" : ObjectId("563062c0b085733f34ab4129"), "name" : "mongodb", "score" : "10"}
}
ts:操作時間,當前timestamp + 計數器,計數器每秒都被重置
h:操作的全局唯一標識
v:oplog版本信息
op:操作類型
i:插入操作
u:更新操作
d:刪除操作
c:執行命令(如createDatabase,dropDatabase)
n:空操作,特殊用途
ns:操作針對的集合
o:操作內容
o2:更新查詢條件,僅update操作包含該字段
副本集數據同步分爲初始化同步
和keep複製同步
。初始化同步指全量從主節點同步數據,如果Primary
節點數據量比較大同步時間會比較長。而keep
複製指初始化同步過後,節點之間的實時同步一般是增量同步。
初始化同步有以下兩種情況會觸發:
-
Secondary 第一次加入。
-
Secondary 落後的數據量超過了 oplog 的大小,這樣也會被全量複製。
MongoDB
的Primary
節點選舉基於心跳觸發。一個複製集N
個節點中的任意兩個節點維持心跳,每個節點維護其他N-1
個節點的狀態。
心跳檢測:
整個集羣需要保持一定的通信才能知道哪些節點活着哪些節點掛掉。mongodb
節點會向副本集中的其他節點每2秒
就會發送一次pings
包,如果其他節點在10秒鐘
之內沒有返回就標示爲不能訪問。每個節點內部都會維護一個狀態映射表,表明當前每個節點是什麼角色、日誌時間戳等關鍵信息。如果主節點發現自己無法與大部分節點通訊則把自己降級爲secondary
只讀節點。
主節點選舉觸發的時機:
第一次初始化一個副本集
-
Secondary
節點權重比Primary
節點高時,發起替換選舉
-
Secondary
節點發現集羣中沒有Primary
時,發起選舉
-
Primary
節點不能訪問到大部分 (Majority
) 成員時主動降級
當觸發選舉時,Secondary
節點嘗試將自身選舉爲Primary
。主節點選舉是一個二階段過程 + 多數派協議。
第一階段:
檢測自身是否有被選舉的資格,如果符合資格會向其它節點發起本節點是否有選舉資格的 FreshnessCheck
,進行同僚仲裁。
第二階段:
發起者向集羣中存活節點發送Elect
(選舉) 請求,仲裁者收到請求的節點會執行一系列合法性檢查,如果檢查通過,則仲裁者 (一個複製集中最多50
個節點,其中只有 7 個具有投票權) 給發起者投一票。
pv0
通過30
秒選舉鎖防止一次選舉中兩次投票。
pv1
使用了terms
(一個單調遞增的選舉計數器)來防止在一次選舉中投兩次票的情況。
多數派協議:
發起者如果獲得超過半數的投票,則選舉通過,自身成爲Primary
節點。獲得低於半數選票的原因,除了常見的網絡問題外,相同優先級的節點同時通過第一階段的同僚仲裁併進入第二階段也是一個原因。因此,當選票不足時,會sleep[0,1]
秒內的隨機時間,之後再次嘗試選舉。
四、分片模式
4.1 什麼是分片
分片 (sharding
) 是MongoDB
用來將大型集合水平分割到不同服務器(或者副本集)上所採用的方法。不需要功能強大的大型計算機就可以存儲更多的數據,處理更大的負載。
4.2 爲什麼要分片
-
存儲容量需求超出單機磁盤容量。
-
活躍的數據集超出單機內存容量,導致很多請求都要從磁盤讀取數據,影響性能。
-
IOPS
超出單個MongoDB
節點的服務能力,隨着數據的增長,單機實例的瓶頸會越來越明顯。 -
副本集具有節點數量限制。
垂直擴展
:增加更多的 CPU 和存儲資源來擴展容量。
水平擴展
:將數據集分佈在多個服務器上,水平擴展即分片。
4.3 分片的工作原理
整體架構圖:
詳細架構圖:
分片集羣由以下 3 個服務組成:
-
Router Server
: 數據庫集羣的請求入口,所有請求都通過Router
(mongos
) 進行協調,不需要在應用程序添加一個路由選擇器,Router
(mongos
) 就是一個請求分發中心它負責把應用程序的請求轉發到對應的Shard
服務器上。 -
Shards Server
: 每個shard
由一個或多個mongod
進程組成,用於存儲數據。 -
Config Server
: 配置服務器。存儲所有數據庫元信息(路由、分片)的配置。
4.3.1 片鍵 (shard key)
爲了在數據集合中分配文檔,MongoDB 使用分片主鍵分割集合。
4.3.2 區塊 (chunk)
在一個shard server
內部,MongoDB
還是會把數據分爲chunks
,每個chunk
代表這個shard server
內部一部分數據。MongoDB
分割分片數據到區塊,每一個區塊包含基於分片主鍵的左閉右開的區間範圍。
4.3.3 分片策略
4.3.3.1 hash 分片 (Hashed Sharding)
把 Key 作爲輸入,輸入到一個 Hash 函數中,計算出一個整數值,值的集合形成了一個值域,我們按照固定步長去切分這個值域,每一個片叫做 Chunk ,這裏的 Chunk 則就是整數的一段範圍而已。
優點:
-
計算速度快
-
均衡性好,純隨機
缺點:
- 正因爲純隨機,排序列舉的性能極差,比如你如果按照 name 這個字段去列舉數據,你會發現幾乎所有的 Shard 都要參與進來;
4.3.3.2 範圍分片 (Ranged Sharding)
優點:
- 對排序列舉場景非常友好,因爲數據本來就是按照順序依次放在 Shard 上的,排序列舉的時候,順序讀即可,非常快速;
缺點:
- 容易導致熱點,舉個例子,如果 Sharding Key 都有相同前綴,那麼大概率會分配到同一個 Shard 上,就盯着這個 Shard 寫,其他 Shard 空閒的很,卻幫不上忙;
4.3.3.3 zone 分片 (Zones in Sharded Clusters)
簡單來說 Zone 實際上像是範圍分片的另一個版本,你爲一定範圍內的片鍵制定一個 Zone,然後再將一些分片加入到這個 Zone 中,於是這一範圍內的數據最終就將存儲在這個 Zone 中的分片上。
五、總結
本文介紹了 3 種 MongoDB 的高可用架構,Master-Slave 模式,Replica Set 模式,Sharding 模式,這也是常見的架構演進的過程,是不是有點恍惚,Redis 也是類似這種架構的演進。
-
MongoDB Master-Slave 已經不推薦,甚至新版已經不支持這種冗餘模式;
-
Replica Set 通過數據多副本,組件冗餘提高了可靠性,並且通過分佈式自動選主算法,減少了停服時間窗,提高了可用性;
-
Sharding 模式通過橫向擴容的方式,爲用戶提供了近乎無限的空間;
-
MongoDB 客戶端掌握了很大的配置權限,通過指定寫多數策略和 strong 模式(只從主節點讀數據)能保證數據的高可靠和強一致性;
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/_JCoJmwxITuiS46IiH_7_Q