復(fù)制集
mongodb在集群環(huán)境中纬乍,通過復(fù)制的形式對數(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),從而禁止讀操作驱富。可以配置為延時(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)對硬件要求低寓落,所以可以比較隨意的部署,只要不和主從節(jié)點(diǎn)放在一起荞下。
選舉
通過心跳檢測確定節(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)檢測到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í)間等多種因素影響蠢笋。
- 復(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選舉。
- 每個(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虐唠。
- 擁有最新optime(最近一條oplog的時(shí)間戳)的節(jié)點(diǎn)才能被選為Primary。
- 只有更大多數(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)用到自身价说。
初始化同步過程如下:
- 從T1時(shí)間開始辆亏,從Primary同步所有數(shù)據(jù)庫數(shù)據(jù)(除了local)。假設(shè)T2完成同步鳖目。并完成_id索引的創(chuàng)建扮叨。
- 從Primary同步T1-T2時(shí)間段內(nèi)的所有操作日志oplog×炻酰可能部分操作已經(jīng)包含在第一步的數(shù)據(jù)中甫匹,但是由于oplog的冪等性甸鸟,可以重復(fù)應(yīng)用。
- 根據(jù)Primary的索引設(shè)置兵迅,在Secondary上設(shè)置索引。
初始同步結(jié)束后薪贫,會(huì)進(jìn)入增量同步恍箭。
1、 Sencondary 初始化同步完成之后瞧省,開始增量復(fù)制扯夭,通過produce線程在Primary oplog.rs集合上建立cursor,并且實(shí)時(shí)請求獲取數(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來將讀請求路由到其他的節(jié)點(diǎn)收擦。
- primary:默認(rèn)規(guī)則贮配,所有讀請求發(fā)到Primary。
- primaryPreferred:Primary優(yōu)先塞赂。如果Primary不可達(dá)泪勒,請求Secondary。
- secondary:所有讀請求發(fā)到Secondary。
- secondaryPreferred:Secondary優(yōu)先圆存。當(dāng)所有Secondary不可達(dá)叼旋,請求Primary。
- nearest:讀請求發(fā)送到最近的節(jié)點(diǎn)(通過ping探測)沦辙。
寫操作
默認(rèn)情況下夫植,Primary完成寫操作即返回。Driver可通過設(shè)置Write Concern來設(shè)置寫成功的規(guī)則油讯。集群寫請求使用{ w : majority}详民,即大多數(shù)節(jié)點(diǎn)寫成功。
異衬岸遥回滾:當(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)對高吞吐量和高并發(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)勢:
- 使集群透明。mongodb分片集群使用mongos的專用路由進(jìn)程独泞,將客戶端發(fā)來的請求準(zhǔn)確路由到對應(yīng)的分片上去呐矾,同時(shí)將相應(yīng)拼裝返回客戶端。
- 提高集群可用性懦砂。將分片和復(fù)制集結(jié)合使用蜒犯,在確保水平拓展的同時(shí)组橄,也確保了每份數(shù)據(jù)有相應(yīng)的備份。
- 易于拓展罚随。mongodb分片機(jī)制可以保障集群的伸縮性玉工。
mongodb分片集群節(jié)點(diǎn): - mongos:路由節(jié)點(diǎn),負(fù)責(zé)轉(zhuǎn)發(fā)客戶端請求毫炉。本身不保存數(shù)據(jù)瓮栗,也沒有分片元數(shù)據(jù),所有配置從config server中獲取瞄勾。
- config server:配置節(jié)點(diǎn),保存了所有讀寫數(shù)據(jù)的方式弥激、所有節(jié)點(diǎn)的信息和分片集群的配置信息进陡。是真實(shí)數(shù)據(jù)的元數(shù)據(jù)。
- shard:數(shù)據(jù)節(jié)點(diǎn)微服,存儲(chǔ)數(shù)據(jù)信息趾疚,以chunk為單位。
chunk
chunk表示shard的一部分?jǐn)?shù)據(jù)以蕴。chunk主要有兩個(gè)動(dòng)作:
- Splitting:當(dāng)一個(gè)chunk的大小超過了配置的chunksize糙麦,mongodb的后臺(tái)進(jìn)程會(huì)把這個(gè)chunk切分為更小的chunk,避免單個(gè)chunk過大的情況丛肮。
- 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ù)。
所以片鍵的選擇對分片的好壞至關(guān)重要撵枢。片鍵必須是一個(gè)索引民晒。一個(gè)自增的片鍵總是會(huì)在同一個(gè)分片上寫入數(shù)據(jù),但是按照片鍵進(jìn)行查詢非常高效锄禽;隨機(jī)片鍵對數(shù)據(jù)均勻分布的效果更好潜必,但是查詢時(shí)會(huì)在多個(gè)分片進(jìn)行查詢,由mongos對結(jié)果進(jìn)行歸并沃但。
片鍵不可變磁滚、片鍵必須有索引、片鍵大小限制為512bytes绽慈、片鍵用于路由查詢恨旱、MongoDB不接受已進(jìn)行collection級(jí)分片的collection上插入無片鍵的文檔(空值也不行)
為了將數(shù)據(jù)按照片鍵進(jìn)行分片,mongodb使用基于范圍的分片或者基于哈希的分片坝疼。
- 基于范圍的分片:Mongodb按照片鍵的范圍把數(shù)據(jù)分為不同的部分搜贤。每個(gè)分片包含一定范圍的數(shù)據(jù)《坌祝基于范圍的分片對范圍查詢有很好的支持仪芒,但是擁有相近片鍵的文檔很可能會(huì)存儲(chǔ)在同一個(gè)分片中,寫入效率會(huì)受到影響耕陷。
- 基于哈希的分片:哈希分片的片鍵只能使用一個(gè)字段掂名。mongodb通過計(jì)算片鍵的哈希值,并用這個(gè)哈希值來創(chuàng)建數(shù)據(jù)塊哟沫。在使用基于哈希分片的系統(tǒng)中饺蔑,擁有相近片鍵的文檔很可能不會(huì)存儲(chǔ)在同一個(gè)數(shù)據(jù)塊中,因此數(shù)據(jù)的分離性更好一些嗜诀。但是對于范圍查詢猾警,需要將查詢分發(fā)到后端所有分片中才能找出滿足條件的文檔孔祸。
分片鍵的選擇:
- 遞增的shard key:優(yōu)點(diǎn)是數(shù)據(jù)差距小,但是所有數(shù)據(jù)的寫入會(huì)放到最后一片上发皿,造成部分寫熱點(diǎn)崔慧。同時(shí),隨著最后一片數(shù)據(jù)量增大穴墅,會(huì)不斷發(fā)生分裂并遷移到之前的分片上惶室。
- 隨機(jī)的shard key:優(yōu)點(diǎn)是數(shù)據(jù)分布均勻,insert的寫IO均勻分布在多個(gè)片上玄货。缺點(diǎn)是大量隨機(jī)IO皇钞。
- 混合型key:大方向遞增,小范圍隨機(jī)分布松捉。為了防止出現(xiàn)大量的chunk均衡遷移鹅士,可能造成的IO壓力。我們需要設(shè)置合理分片使用策略(片鍵的選擇惩坑、分片算法(range、hash))