mongodb——分布式

復(fù)制集

mongodb在集群環(huán)境中,通過復(fù)制的形式對(duì)數(shù)據(jù)進(jìn)行冗余。mongodb復(fù)制集有Primary、Secondary、Arbiter三種角色。以三節(jié)點(diǎn)為例,一般一個(gè)Primary兩個(gè)Secondary較為常見。一個(gè)復(fù)制集群最多有50個(gè)節(jié)點(diǎn),但是最多有7個(gè)投票節(jié)點(diǎn)。

  • Primary:主節(jié)點(diǎn),副本集接收寫操作的唯一成員。mongodb集群在主節(jié)點(diǎn)上接收寫操作,并寫入操作日志oplog。Secondary節(jié)點(diǎn)復(fù)制oplog并將操作應(yīng)用于自身數(shù)據(jù)集。集群最多有一個(gè)主節(jié)點(diǎn),如果主節(jié)點(diǎn)掛了,集群會(huì)重新選舉主節(jié)點(diǎn)。
  • Secondary:從節(jié)點(diǎn),維持?jǐn)?shù)據(jù)副本。從節(jié)點(diǎn)從主節(jié)點(diǎn)的操作日志中同步自己的數(shù)據(jù)。復(fù)制集可以有一個(gè)或多個(gè)從節(jié)點(diǎn)。雖然從節(jié)點(diǎn)無法接收寫操作,但是可以接收讀操作,可能讀取的不是最新數(shù)據(jù)。從節(jié)點(diǎn)可以通過配置優(yōu)先級(jí)防止執(zhí)行選舉操作,從而可以長期作為數(shù)據(jù)備份使用。可以設(shè)為隱藏節(jié)點(diǎn),從而禁止讀操作??梢耘渲脼檠訒r(shí)節(jié)點(diǎn),保留歷史的快照,用于數(shù)據(jù)庫回滾。
  • Arbiter:不保存數(shù)據(jù),也不成為主節(jié)點(diǎn)。投票節(jié)點(diǎn)僅僅是為了保持選舉成員為奇數(shù)而存在。盡量不要再主從節(jié)點(diǎn)上同時(shí)運(yùn)行頭片節(jié)點(diǎn)。不要在投票成員為奇數(shù)時(shí)引入投票節(jié)點(diǎn)。投票節(jié)點(diǎn)對(duì)硬件要求低,所以可以比較隨意的部署,只要不和主從節(jié)點(diǎn)放在一起。

選舉

通過心跳檢測(cè)確定節(jié)點(diǎn)是否存在,當(dāng)發(fā)起Primary投票時(shí),獲得大多數(shù)成員投票支持的節(jié)點(diǎn),會(huì)變?yōu)镻rimary。其他節(jié)點(diǎn)為Secondary。

假設(shè)復(fù)制集內(nèi)投票成員(后續(xù)介紹)數(shù)量為N,則大多數(shù)為 N/2 + 1,當(dāng)復(fù)制集內(nèi)存活成員數(shù)量不足大多數(shù)時(shí),整個(gè)復(fù)制集將無法選舉出Primary,復(fù)制集將無法提供寫服務(wù),處于只讀狀態(tài)。當(dāng)某個(gè)節(jié)點(diǎn)不能連接上其他節(jié)點(diǎn),那么它不能升為主節(jié)點(diǎn)。大多數(shù)的意思是大多數(shù)投票而不是大多數(shù)節(jié)點(diǎn)。

Primary選舉除了發(fā)生在復(fù)制集初始化時(shí),還有如下情況:

  • 復(fù)制集被reconfig
  • Secondary節(jié)點(diǎn)檢測(cè)到Primary宕機(jī)時(shí),會(huì)觸發(fā)新Primary的選舉
  • 當(dāng)有Primary節(jié)點(diǎn)主動(dòng)stepDown(主動(dòng)降級(jí)為Secondary)時(shí),也會(huì)觸發(fā)新的Primary選舉。

Primary的選舉受節(jié)點(diǎn)間心跳、優(yōu)先級(jí)、oplog時(shí)間等多種因素影響。

  1. 復(fù)制集成員間默認(rèn)每2s會(huì)發(fā)送一次心跳信息,如果10s未收到某個(gè)節(jié)點(diǎn)的心跳,則認(rèn)為該節(jié)點(diǎn)已宕機(jī);如果宕機(jī)的節(jié)點(diǎn)為Primary,Secondary(前提是可被選為Primary)會(huì)發(fā)起新的Primary選舉。
  2. 每個(gè)節(jié)點(diǎn)都傾向于投票給優(yōu)先級(jí)最高的節(jié)點(diǎn)。優(yōu)先級(jí)為0的節(jié)點(diǎn)不會(huì)主動(dòng)發(fā)起選舉。當(dāng)Primary發(fā)現(xiàn)優(yōu)先級(jí)更高的Secondary,并且該Secondary的數(shù)據(jù)落后在10s以內(nèi),則Primary會(huì)主動(dòng)降級(jí),讓優(yōu)先級(jí)更高的Secondary有機(jī)會(huì)成為Primary節(jié)點(diǎn)。

Priority0和Vote0:前者是優(yōu)先級(jí),表示不會(huì)被選為Primary,但是可能投票;后者為投票權(quán),表示不參與投票,但是可能被選為Primary。

  1. 擁有最新optime(最近一條oplog的時(shí)間戳)的節(jié)點(diǎn)才能被選為Primary。
  2. 只有更大多數(shù)投票節(jié)點(diǎn)間保持網(wǎng)絡(luò)連通,才有機(jī)會(huì)被選Primary;如果Primary與大多數(shù)的節(jié)點(diǎn)斷開連接,Primary會(huì)主動(dòng)降級(jí)為Secondary。當(dāng)發(fā)生網(wǎng)絡(luò)分區(qū)時(shí),可能在短時(shí)間內(nèi)出現(xiàn)多個(gè)Primary,故Driver在寫入時(shí),最好設(shè)置『大多數(shù)成功』的策略,這樣即使出現(xiàn)多個(gè)Primary,也只有一個(gè)Primary能成功寫入大多數(shù)。

數(shù)據(jù)同步

數(shù)據(jù)同步通過oplog日志完成。Primary上的寫操作完成后,會(huì)向特殊的local.oplog.rs特殊集合寫入一條oplog,Secondary不斷的從Primary取新的oplog并應(yīng)用于自身。
因oplog的數(shù)據(jù)會(huì)不斷增加,local.oplog.rs被設(shè)置成為一個(gè)capped集合,當(dāng)容量達(dá)到配置上限時(shí),會(huì)將最舊的數(shù)據(jù)刪除掉。另外考慮到oplog在Secondary上可能重復(fù)應(yīng)用,oplog必須具有冪等性,即重復(fù)應(yīng)用也會(huì)得到相同的結(jié)果。
當(dāng) Secondary初次同步數(shù)據(jù)時(shí),會(huì)先進(jìn)行初始化同步。從Primary(或其他數(shù)據(jù)更新的Secondary)同步全量數(shù)據(jù),然后不斷通過tailable cursor(游標(biāo))從Primary的local.oplog.rs集合里查詢最新的oplog并應(yīng)用到自身。
初始化同步過程如下:

  1. 從T1時(shí)間開始,從Primary同步所有數(shù)據(jù)庫數(shù)據(jù)(除了local)。假設(shè)T2完成同步。并完成_id索引的創(chuàng)建。
  2. 從Primary同步T1-T2時(shí)間段內(nèi)的所有操作日志oplog??赡懿糠植僮饕呀?jīng)包含在第一步的數(shù)據(jù)中,但是由于oplog的冪等性,可以重復(fù)應(yīng)用。
  3. 根據(jù)Primary的索引設(shè)置,在Secondary上設(shè)置索引。

初始同步結(jié)束后,會(huì)進(jìn)入增量同步。
1、 Sencondary 初始化同步完成之后,開始增量復(fù)制,通過produce線程在Primary oplog.rs集合上建立cursor,并且實(shí)時(shí)請(qǐng)求獲取數(shù)據(jù)。
2、 Primary 返回oplog 數(shù)據(jù)給Secondary。
3、 Sencondary 讀取到Primary 發(fā)送過來的oplog,將其寫入到隊(duì)列中。
4、 Sencondary 的同步線程會(huì)通過tryPopAndWaitForMore方法一直消費(fèi)隊(duì)列,當(dāng)每次總數(shù)據(jù)大于100MB,或者已經(jīng)取到部分?jǐn)?shù)據(jù)但沒到100MB,但是目前隊(duì)列沒數(shù)據(jù)了,這個(gè)時(shí)候會(huì)阻塞等待一秒,如果還沒有數(shù)據(jù)則本次取數(shù)據(jù)完成,將數(shù)據(jù)給prefetchOps方法處理,prefetchOps方法主要將數(shù)據(jù)以database級(jí)別切分,便于后面多線程寫入到數(shù)據(jù)庫中。如果采用的WiredTiger引擎,那這里是以Docment ID 進(jìn)行切分。
5、 最終將劃分好的數(shù)據(jù)以多線程的方式批量寫入到數(shù)據(jù)庫中(在從庫批量寫入數(shù)據(jù)的時(shí)候MongoDB會(huì)阻塞所有的讀)。
6、 然后再將Queue中的Oplog數(shù)據(jù)寫入到Sencondary中的oplog.rs集合中。

讀操作

默認(rèn)情況下,所有的讀操作發(fā)送到Primary節(jié)點(diǎn)。Driver可通過設(shè)置Read Preference來將讀請(qǐng)求路由到其他的節(jié)點(diǎn)。

  • primary:默認(rèn)規(guī)則,所有讀請(qǐng)求發(fā)到Primary。
  • primaryPreferred:Primary優(yōu)先。如果Primary不可達(dá),請(qǐng)求Secondary。
  • secondary:所有讀請(qǐng)求發(fā)到Secondary。
  • secondaryPreferred:Secondary優(yōu)先。當(dāng)所有Secondary不可達(dá),請(qǐng)求Primary。
  • nearest:讀請(qǐng)求發(fā)送到最近的節(jié)點(diǎn)(通過ping探測(cè))。

寫操作

默認(rèn)情況下,Primary完成寫操作即返回。Driver可通過設(shè)置Write Concern來設(shè)置寫成功的規(guī)則。集群寫請(qǐng)求使用{ w : majority},即大多數(shù)節(jié)點(diǎn)寫成功。

異?;貪L:當(dāng)一個(gè)Primary冗機(jī),如果有數(shù)據(jù)未同步到Secondary,當(dāng)原Primary重新加入時(shí),如果新的Primary上已經(jīng)發(fā)生了寫操作,則原Primary需要回滾部分操作,以便集群與新的Primary數(shù)據(jù)保持一致。這里如果Write Concern設(shè)置不是majority,則會(huì)出現(xiàn)寫入丟失。

分片

分片是為了應(yīng)對(duì)高吞吐量和高并發(fā)量。通過水平分片,將數(shù)據(jù)集分散到不同的服務(wù)器節(jié)點(diǎn)上,提高整體的吞吐量和并發(fā)量。分片與復(fù)制集不同,復(fù)制集每個(gè)復(fù)制持有全部的數(shù)據(jù)(新寫入的可能沒有),而分片是將所有數(shù)據(jù)分散到不同的節(jié)點(diǎn)上,每個(gè)分片持有部分?jǐn)?shù)據(jù)。比如,1TB的數(shù)據(jù),共有四個(gè)分片,則每個(gè)分片可能只持有256GB的數(shù)據(jù);如果40個(gè)分片,那么每個(gè)分片可能只持有25GB數(shù)據(jù)。

分片提供了以下優(yōu)勢(shì):

  1. 使集群透明。mongodb分片集群使用mongos的專用路由進(jìn)程,將客戶端發(fā)來的請(qǐng)求準(zhǔn)確路由到對(duì)應(yīng)的分片上去,同時(shí)將相應(yīng)拼裝返回客戶端。
  2. 提高集群可用性。將分片和復(fù)制集結(jié)合使用,在確保水平拓展的同時(shí),也確保了每份數(shù)據(jù)有相應(yīng)的備份。
  3. 易于拓展。mongodb分片機(jī)制可以保障集群的伸縮性。
    mongodb分片集群節(jié)點(diǎn):
  4. mongos:路由節(jié)點(diǎn),負(fù)責(zé)轉(zhuǎn)發(fā)客戶端請(qǐng)求。本身不保存數(shù)據(jù),也沒有分片元數(shù)據(jù),所有配置從config server中獲取。
  5. config server:配置節(jié)點(diǎn),保存了所有讀寫數(shù)據(jù)的方式、所有節(jié)點(diǎn)的信息和分片集群的配置信息。是真實(shí)數(shù)據(jù)的元數(shù)據(jù)。
  6. shard:數(shù)據(jù)節(jié)點(diǎn),存儲(chǔ)數(shù)據(jù)信息,以chunk為單位。

chunk

chunk表示shard的一部分?jǐn)?shù)據(jù)。chunk主要有兩個(gè)動(dòng)作:

  1. Splitting:當(dāng)一個(gè)chunk的大小超過了配置的chunksize,mongodb的后臺(tái)進(jìn)程會(huì)把這個(gè)chunk切分為更小的chunk,避免單個(gè)chunk過大的情況。
  2. Balancing:balancer是一個(gè)后臺(tái)進(jìn)程,負(fù)責(zé)chunk的遷移,從而平衡各個(gè)shard的負(fù)載。默認(rèn)從chunk數(shù)量最多的節(jié)點(diǎn)移動(dòng)到數(shù)量最少的節(jié)點(diǎn)。
    系統(tǒng)初始1個(gè)chunk,chunksize默認(rèn)值64M,生產(chǎn)庫上選擇適合業(yè)務(wù)的chunksize是最好的。mongoDB會(huì)自動(dòng)拆分和遷移chunks。

chunk和event的區(qū)別:chunk為分片集群中的單元,為邏輯上的存儲(chǔ)格式;event為數(shù)據(jù)實(shí)際的存儲(chǔ)格式。chunk的分裂實(shí)際是不同數(shù)據(jù)在不同節(jié)點(diǎn)的移動(dòng)過程。

chunk的分裂非常消耗IO資源,當(dāng)插入和更新時(shí),chunk才會(huì)分裂,讀數(shù)據(jù)不會(huì)觸發(fā)chunk分裂。所以chunksize的選擇很重要:小的chunksize,數(shù)據(jù)均衡是遷移速度快,數(shù)據(jù)分布更均勻,數(shù)據(jù)分裂頻繁,路由節(jié)點(diǎn)消耗更多資源,容易出現(xiàn)jumbo chunk(即shardKey 的某個(gè)取值出現(xiàn)頻率很高,這些文檔只能放到一個(gè) chunk 里,無法再分裂)而無法遷移;大的chunksize,數(shù)據(jù)分裂少,數(shù)據(jù)塊移動(dòng)集中消耗IO資源,可能導(dǎo)致數(shù)據(jù)分布不均,可能出現(xiàn) chunk 內(nèi)文檔數(shù)太多(chunk 內(nèi)文檔數(shù)不能超過 250000 )而無法遷移。通常100-200M。

分片鍵shard key

mongodb分片是以集合為單位。在集合中,數(shù)據(jù)通過片鍵被分為多個(gè)部分。片鍵就是集合中選擇一個(gè)鍵作為數(shù)據(jù)拆分的依據(jù)。
所以片鍵的選擇對(duì)分片的好壞至關(guān)重要。片鍵必須是一個(gè)索引。一個(gè)自增的片鍵總是會(huì)在同一個(gè)分片上寫入數(shù)據(jù),但是按照片鍵進(jìn)行查詢非常高效;隨機(jī)片鍵對(duì)數(shù)據(jù)均勻分布的效果更好,但是查詢時(shí)會(huì)在多個(gè)分片進(jìn)行查詢,由mongos對(duì)結(jié)果進(jìn)行歸并。

片鍵不可變、片鍵必須有索引、片鍵大小限制為512bytes、片鍵用于路由查詢、MongoDB不接受已進(jìn)行collection級(jí)分片的collection上插入無片鍵的文檔(空值也不行)

為了將數(shù)據(jù)按照片鍵進(jìn)行分片,mongodb使用基于范圍的分片或者基于哈希的分片。

  • 基于范圍的分片:Mongodb按照片鍵的范圍把數(shù)據(jù)分為不同的部分。每個(gè)分片包含一定范圍的數(shù)據(jù)?;诜秶姆制瑢?duì)范圍查詢有很好的支持,但是擁有相近片鍵的文檔很可能會(huì)存儲(chǔ)在同一個(gè)分片中,寫入效率會(huì)受到影響。
  • 基于哈希的分片:哈希分片的片鍵只能使用一個(gè)字段。mongodb通過計(jì)算片鍵的哈希值,并用這個(gè)哈希值來創(chuàng)建數(shù)據(jù)塊。在使用基于哈希分片的系統(tǒng)中,擁有相近片鍵的文檔很可能不會(huì)存儲(chǔ)在同一個(gè)數(shù)據(jù)塊中,因此數(shù)據(jù)的分離性更好一些。但是對(duì)于范圍查詢,需要將查詢分發(fā)到后端所有分片中才能找出滿足條件的文檔。

分片鍵的選擇:

  1. 遞增的shard key:優(yōu)點(diǎn)是數(shù)據(jù)差距小,但是所有數(shù)據(jù)的寫入會(huì)放到最后一片上,造成部分寫熱點(diǎn)。同時(shí),隨著最后一片數(shù)據(jù)量增大,會(huì)不斷發(fā)生分裂并遷移到之前的分片上。
  2. 隨機(jī)的shard key:優(yōu)點(diǎn)是數(shù)據(jù)分布均勻,insert的寫IO均勻分布在多個(gè)片上。缺點(diǎn)是大量隨機(jī)IO。
  3. 混合型key:大方向遞增,小范圍隨機(jī)分布。為了防止出現(xiàn)大量的chunk均衡遷移,可能造成的IO壓力。我們需要設(shè)置合理分片使用策略(片鍵的選擇、分片算法(range、hash))
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 本文包括以下幾個(gè)方面: –安全措施 – 部署架構(gòu) – 系統(tǒng)優(yōu)化 – 索引設(shè)計(jì) – 備份監(jiān)控 – 模式設(shè)計(jì) – 程序...
    張偉科閱讀 4,234評(píng)論 0 9
  • NoSql數(shù)據(jù)庫優(yōu)缺點(diǎn) 在優(yōu)勢(shì)方面主要體現(xiàn)在下面幾點(diǎn): 簡單的擴(kuò)展 快速的讀寫 低廉的成本 靈活的數(shù)據(jù)模型 在不足...
    dreamer_lk閱讀 2,872評(píng)論 0 6
  • 應(yīng)用性能高低依賴于數(shù)據(jù)庫性能,MongoDB 是一個(gè)基于分布式文件存儲(chǔ)的數(shù)據(jù)庫。由 C++ 語言編寫,旨在為 WE...
    OneAPM閱讀 720評(píng)論 0 4
  • 眼睜睜看著裝滿米糊的飯盒瞬間從我手中滑落倒扣在兩腳間的地上,黑色的米糊趁機(jī)恣意地鋪灑到能觸及的空間,等半個(gè)左腳被浸...
    梧桐銳語閱讀 1,508評(píng)論 6 8
  • 云淡,風(fēng)輕,瀟瀟然。 三載同仁,今朝惜別。 雖哽咽目濕仍笑靨如花, 雖萬般惆悵卻樂得瀟灑。 風(fēng)過處, 總有暗香盈袖...
    子水閱讀 230評(píng)論 0 2

友情鏈接更多精彩內(nèi)容