分片集羣

閱讀目錄

Shard 分片集羣

 

簡述

爲何要分片

  1. 減少單機請求數,降低單機負載,提高總負載
  2. 減少單機的存儲空間,提高總存空間。

此處輸入圖片的描述

常見的mongodb sharding 服務器架構

此處輸入圖片的描述
要構建一個 MongoDB Sharding Cluster,需要三種角色:

Shard Server
即存儲實際數據的分片,每個Shard可以是一個mongod實例,也可以是一組mongod實例構成的Replication Set。爲了實現每個Shard內部的auto-failover(自動故障切換),MongoDB官方建議每個Shard爲一組Replica Set。

Config Server
爲了將一個特定的collection存儲在多個shard中,需要爲該collection指定一個shard key(片鍵),例如{age: 1} ,shard key可以決定該條記錄屬於哪個chunk(分片是以chunk爲單位,後續會介紹)。Config Servers就是用來存儲:所有shard節點的配置信息、每個chunk的shard key範圍、chunk在各shard的分佈情況、該集羣中所有DB和collection的sharding配置信息。

Route Process
這是一個前端路由,客戶端由此接入,然後詢問Config Servers需要到哪個Shard上查詢或保存記錄,再連接相應的Shard進行操作,最後將結果返回給客戶端。客戶端只需要將原本發給mongod的查詢或更新請求原封不動地發給Routing Process,而不必關心所操作的記錄存儲在哪個Shard上。(所有操作在mongos上操作即可)

配置分片服務器

下面我們在同一臺物理機器上構建一個簡單的 Sharding Cluster:
此處輸入圖片的描述

Shard Server 1:27017
Shard Server 2:27018
Config Server :27027
Route Process:40000

步驟一: 啓動Shard Server

mkdir -p ./data/shard/s0 ./data/shard/s1  #創建數據目錄
mkdir -p ./data/shard/log # 創建日誌目錄

./bin/mongod --port 27017 --dbpath /usr/local/mongodb/data/shard/s0 --fork --logpath /usr/local/mongodb/data/shard/log/s0.log # 啓動Shard Server實例1

./bin/mongod --port 27018 --dbpath /usr/local/mongodb/data/shard/s1 --fork --logpath /usr/local/mongodb/data/shard/log/s1.log # 啓動Shard Server實例2

步驟二: 啓動Config Server

mkdir -p ./data/shard/config #創建數據目錄

./bin/mongod --port 27027 --dbpath /usr/local/mongodb/data/shard/config --fork --logpath /usr/local/mongodb/data/shard/log/config.log #啓動Config Server實例

注意,這裏我們完全可以像啓動普通mongodb服務一樣啓動,不需要添加—shardsvr和configsvr參數。因爲這兩個參數的作用就是改變啓動端口的,所以我們自行指定了端口就可以

步驟三: 啓動Route Process

./bin/mongos --port 4000 --configdb localhost:27027 --fork --logpath /usr/local/mongodb/data/shard/log/route.log --chunkSize=1 # 啓動Route Server實例

mongos啓動參數中,chunkSize這一項是用來指定chunk的大小的,單位是MB,默認大小爲200MB,爲了方便測試Sharding效果,我們把chunkSize指定爲 1MB。意思是當這個分片中插入的數據大於1M時開始進行數據轉移

步驟四: 配置Sharding

# 我們使用MongoDB Shell登錄到mongos,添加Shard節點
./bin/mongo admin --port 40000 #此操作需要連接admin庫
> db.runCommand({ addshard:"localhost:27017" }) #添加 Shard Server 或者用 sh.addshard()命令來添加,下同;
{ "shardAdded" : "shard0000", "ok" : 1 }
> db.runCommand({ addshard:"localhost:27018" })
{ "shardAdded" : "shard0001", "ok" : 1 }

> db.runCommand({ enablesharding:"test" }) #設置分片存儲的數據庫
{ "ok" : 1 }

> db.runCommand({ shardcollection: "test.users", key: { id:1 }}) # 設置分片的集合名稱。且必須指定Shard Key,系統會自動創建索引,然後根據這個shard Key來計算
{ "collectionsharded" : "test.users", "ok" : 1 }

 > sh.status(); #查看片的狀態
 > printShardingStatus(db.getSisterDB("config"),1); # 查看片狀態(完整版);
 > db.stats(); # 查看所有的分片服務器狀態
 

注意這裏我們要注意片鍵的選擇,選擇片鍵時需要根據具體業務的數據形態來選擇,切不可隨意選擇,實際中尤其不要輕易選擇自增_id作爲片鍵,除非你很清楚你這麼做的目的,具體原因我不在此分析,根據經驗推薦一種較合理的片鍵方式,“自增字段+查詢字段”,沒錯,片鍵可以是多個字段的組合。

另外這裏說明一點,分片的機制:mongodb不是從單篇文檔的級別,絕對平均的散落在各個片上, 而是N篇文檔,形成一個塊"chunk",優先放在某個片上, 當這片上的chunk,比另一個片的chunk區別比較大時(>=3) ,會把本片上的chunk,移到另一個片上, 以chunk爲單位,維護片之間的數據均衡。

也就是說,一開始插入數據時,數據是隻插入到其中一塊分片上的,插入完畢後,mongodb內部開始在各片之間進行數據的移動,這個過程可能不是立即的,mongodb足夠智能會根據當前負載決定是立即進行移動還是稍後移動。
在插入數據後,立馬執行db.users.stats();兩次可以驗證如上所說。

這種分片機制,節省了人工維護成本,但是由於其是優先往某個片上插入,等到chunk失衡時,再移動chunk,並且隨着數據的增多,shard的實例之間,有chunk來回移動的現象,這將會爲服務器帶來很大的IO開銷,解決這種開銷的方法,就是手動預先分片;

手動預先分片

以shop.user表爲例

sh.shardCollection(‘shop.user’,{userid:1}); # user表用userid做shard key

for(var i=1;i<=40;i++) { sh.splitAt('shop.user',{userid:i*1000}) } # 預先在1K 2K...40K這樣的界限切好chunk(雖然chunk是空的), 這些chunk將會均勻移動到各片上.

通過mongos添加user數據. 數據會添加到預先分配好的chunk上, chunk就不會來回移動了.

repliction set and shard

一般mongoDB如果真的到了分片的級別後,那片服務器避無可免的要用到複製集,部署的基本思路同上,只需要注意兩點:

sh.addShard( host ) server:port OR setname/server:port # 如果是複製集的片服務器,我們應該複製集的名稱寫在前面比如
sh.addShard('ras/192.168.42.168:27017'); # 27017也就是複製集中的primary

另外在啓動本機的mongod服務的時候,最好把ip也給寫進去,否則有可能會有不可預知的錯誤;

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章