mongodb replica set

replica set

副本集形式,類似於mysql master slave,這裏成爲primary 和 secondary,具有選舉機制,最低3臺,1主2從。

複製主要用於備份、災難恢復和讀寫分離。一個Replica Set就是一組mongod實例。Replica Set中的Primary接收所有的寫操作,Secondaries從Primary複製操作然後應用到自己的data set。

心跳檢測

在replica sets結構中,節點之間會各自向其它節點發送一個心跳檢測請求。在正常情況下,其它節點會返回一個包含自身信息的回覆包,回覆包中主要包括了下面一些信息:它們現在是什麼角色(primary 還是 secondary),它們是否能夠在必要的時候成爲 primary,以及他們當前時鐘時間等等。

節點在收到回覆包後,會用這些信息更新自己的一個狀態映射表。

當primary節點映射表發生了變化,那麼它會那自己是否還能和集羣中大多數節點進行通信,如果不能與大多數節點通信,那麼它會把自己從 primary 降級爲 secondary。

降級

在節點從 primary 降級爲 secondary 的過程中,會有一些問題出現。在 MongoDB 中,寫操作默認是通過 fire-and-forget 的模式來進行的,也就是說寫操作通常不關心是否成功,發完請求後客戶端就認爲成功了。但如果這時候 primary 進行降級操作,那麼客戶端並不知道這時候 primary 已經降級成爲 secondary 了,客戶端可能還會將後續的寫操作發送給這個節點。這時候剛剛降級的這個 secondary 可以發送一個包說“我已經不是 primary 了”,但是我們上面說過了,客戶端根本就無視你這個包。所以客戶端根本不知道這次寫入已經失敗了。

對於這個問題,你可能會說"那我們每次都使用安全寫入不就行了"(安全寫入意思是說等待服務器返回成功後客戶端才認爲寫成功了),但是很明顯,這非常不靠譜。所以我們的做法是,在一個 primary 降級成爲 secondary 後,它會將原來的所有連接關閉。這樣客戶端在下一次寫入的時候就會出現 socket 錯誤。而客戶端在發現這個錯誤之後,就會重新向集羣獲取新的 primary 的地址,並將後續的寫操作都往新的服務器上寫入。

選舉

選舉是一個獲取多數票的過程,具有一定網絡io耗時。

而當X發現現在需要一個 primary 並且自己又正好可以充當時.
它就會發起一輪選舉:X節點會向Y、Z節點各發起一個請求包:
    告知他們,我認爲我可以接管 primary 的角色,你們覺得怎麼樣?

其他節點在收到通知時,他們會進行下面幾項檢測:
    集羣中是否有一個primary了?
    他們自己的數據是否比X節點更新?
    他們自己的數據是否比X節點更新?
一旦其中某一項不滿足,pass.

如果都滿足,會反饋給X。X會告訴其他節點,我是primary。其他節點給予回饋(投票)說同意,X才正式升級爲primary。

注意:這個投票過程,有30秒間隔,單節點30秒內不能重複進行。

投票規則: 如果沒有人投反對票,並且贊成票的比例過半,那麼本輪選舉對象就能夠成爲 primary。(很民主啊,人人蔘與~)

shard(分區)

mongodb的分區功能其實比較簡單,就是根據數據對元素進行分區。只是這個邏輯可以自定義而已。

和普通的replica set集羣比起來,有什麼不同呢?

  1. 增加了route
  2. 增加了config server

步驟

1. 開啓config

	./bin/mongod --fork --dbpath data/config/ --logpath log/config.log –port 10000

2. 開啓router

	./bin/mongos --port 20000 --configdb 192.168.1.13:10000 --logpath log/mongos.log  --fork

3. 啓動各個分片服務

	./bin/mongod --dbpath data/shard1/ --logpath log/shard1.log  --fork --port 27017
	./bin/mongod --dbpath data/shard2/ --logpath log/shard1.log  --fork --port 27018
	./bin/mongod --dbpath data/shard3/ --logpath log/shard1.log  --fork --port 27019
	./bin/mongod --dbpath data/shard4/ --logpath log/shard1.log  --fork --port 27020

4. 添加分片

	./bin/mongo --port 20000
	db.runCommand({addshard:"192.168.1.13:27017",allowLocal:true })
	db.runCommand({addshard:"192.168.1.13:27018",allowLocal:true })
	db.runCommand({addshard:"192.168.1.13:27019",allowLocal:true })
	db.runCommand({addshard:"192.168.1.13:27020",allowLocal:true })

5. 默認分區規則是根據_id來的,我們也可以自定義去配置。

	sh.shardCollection('dbName.colletionName',{keyName:1});

6. 刪除分片

	db.runCommand({"removeshard":"192.168.1.13:27020"})
移除分片需要一個過程,MongoDB會把移除的片上的數據(塊)挪到其他片上,會造成一定耗時,要注意業務場景。

7. 管理分片

	db.shards.find()
	{ "_id" : "shard0000", "host" : "192.168.1.13:27017" }
	{ "_id" : "shard0000", "host" : "192.168.1.13:27018" }
	{ "_id" : "shard0000", "host" : "192.168.1.13:27019" }
	{ "_id" : "shard0000", "host" : "192.168.1.13:27020" }

分片片鍵

mongodb分片是分佈式存儲的,因此,片鍵的定義對整個性能的影響巨大。所幸,mongodb是可以自定義片鍵的。

好片鍵的要素:

1. 讀和寫的分佈
2. 數據塊的大小
3. 每個查詢命中的分片數目

從設計角度來說,其實和我們常用的mysql的邏輯分表很像。

分片集羣數據分佈方式:

基於範圍
基於Hash
基於zone/tag

分片集羣數據分佈方式-基於範圍(最常用,適合一般性業務邏輯): | | | | ------------ | ------------ | | 片鍵範圍查詢性能好 | 數據分佈可能不均勻 | |優化讀|容易有熱點| | | |

分片集羣數據分佈方式-基於哈希(適用:日誌,物聯網等高併發場景): | | | | ------------ | ------------ | | 數據分佈均勻,寫優化 | 範圍查詢效率低 | | | |

讀寫(轉圖)

分析:

  1. 如果不能命中片鍵,範圍查詢將會掃描全表(性能極地,損耗極大),結果集將在route層聚集(類似於hadoop的map reduce)
  2. 需要合理提前規劃片鍵,否則後期移動數據將需要複雜處理。
  3. 如果集羣在_id上進行了分片,則無法再在其他字段上建立唯一索引。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章