上面的(http://www.cnblogs.com/guoyuanwei/p/3565088.html)介紹了部署了一個默認的分片集羣,對mongoDB的分片集羣有了大概的認識,到目前爲止咱們尚未在集羣上創建其它數據庫,mongoDB的分片是基於集合(表)來進行的,所以要對一個集合分片,必須先使其所在的數據庫支持分片。如何使一個集合分片?如何選擇分片用到的片鍵?平衡器如何使chunks塊在片中遷移?分片的讀寫狀況怎麼樣?接下來將探討這些問題。html
(1)鏈接到上面所配置集羣中的mongos實例數據庫
> mongo --port 40009分佈式
(2)在集羣中建立數據庫eshop和集合usersspa
mongos> use eshophtm
switched to db eshopblog
mongos> db.users.insert({userid:1,username:"lili",city:"beijing"})索引
此時在集合users中只有一條記錄:ci
{ "_id" : ObjectId("521dcce715ce3967f964c00b"), "userid" : 1, "username" : "lili", "city" : "beijing" }文檔
觀察集羣的狀態信息,字段databases會增長一條記錄,其它字段與初始化的集羣信息相同:部署
mongos> sh.status()
databases:
{ "_id" : "eshop", "partitioned" : false, "primary" : "rs0" }
能夠看到此時數據庫eshop還沒支持分片,且數據庫中全部未分片的集合將保存在片rs0中;經過查看磁盤上的數據文件,此時會產生eshop.0、eshop.一、eshop.ns三個文件且位於rs0所對應的數據目錄中,集羣中chunks集合爲空,由於如今尚未對集合users分片。
(3)分片
mongoDB的分片是基於範圍的,也就是說任何一個文檔必定位於指定片鍵的某個範圍內,一旦片鍵選擇好後,chunks就會按照片鍵來將一部分documents從邏輯上組合在一塊兒。這裏對users集合選擇"city"字段做爲片鍵來分片,假如如今"city"字段值有"beijing"、"guangzhou"、"changsha",初始的時候隨機的向集羣中插入包含以上字段值的文檔,此時因爲chunks的大小未達到默認的閾值64MB或100000個文檔,集羣中應該只有一個chunk,隨着繼續插入文檔,超過閾值的chunk會被分割成兩個chunks,最終的chunks和片鍵分佈可能以下表格所示。表格只是大致上描述了分片的狀況,實際可能有所變化,其中-∞表示全部鍵值小於"beijing"的文檔,∞表示全部鍵值大於"guangzhou"的文檔。這裏還要強調一點就是chunks所包含的文檔,並非物理上的包含,它是一種邏輯包含,它只表示帶有片鍵的文檔會落在哪一個範圍內,而這個範圍的文檔對應的chunk位於哪一個片是能夠查詢到的,後續的讀寫操做就定位到這個片上的具體集合中進行。
開始鍵值 |
結束鍵值 |
所在分片 |
-∞ |
beijing |
rs0 |
beijing |
changsha |
rs1 |
changsha |
guangzhou |
rs0 |
guangzhou |
∞ |
rs1 |
下面繼續經過命令使集合users分片,使集合分片必須先使其所在的數據庫支持分片,以下:
mongos> sh.enableSharding("eshop") //使數據庫支持分片
對已有數據的集合進行分片,必須先在所選擇的片鍵上建立一個索引,若是集合初始時沒有任何數據,則mongoDB會自動在所選擇的的片鍵上建立一個索引。
mongos> db.users.ensureIndex({city:1}) //建立基於片鍵的索引
mongos> sh.shardCollection("eshop.users",{city:1}) //使集合分片
成功執行上面命令後,再次查看集羣狀態信息:
mongos> sh.status()
--- Sharding Status ---
sharding version: {
"_id" : 1,
"version" : 3,
"minCompatibleVersion" : 3,
"currentVersion" : 4,
"clusterId" : ObjectId("521b11e0a663075416070c04")
}
shards:
{ "_id" : "rs0", "host" : "rs0/GUO:40000,GUO:40001" }
{ "_id" : "rs1", "host" : "rs1/GUO:40003,GUO:40004" }
databases:
{ "_id" : "admin", "partitioned" : false, "primary" : "config" }
{ "_id" : "eshop", "partitioned" : true, "primary" : "rs0" } //數據庫已支持分片
eshop.users //分片的集合
shard key: { "city" : 1 } //片鍵
chunks: //全部塊信息
rs0 1 //當前只有1個塊在片rs0上
{ "city" : { "$minKey" : 1 } } -->> { "city" : { "$maxKe
y" : 1 } } on : rs0 { "t" : 1, "i" : 0 } //此塊的包含鍵值範圍是-∞到∞,且在片rs0上,由於此時集合中只有一條記錄,還未進行塊的分割、遷移
(4)繼續插入數據使集合自動分片
爲了觀察到集合被分紅多個chunk,並分佈在多個片上,繼續插入一些數據進行分析。
> for(var i = 1; i<10000;i++) db.users.insert({userid:i,username:"lili"+i,city:"beijing"})
> for(var i = 0; i<10000;i++) db.users.insert({userid:i,username:"xiaoming"+i,city:"changsha"})
> for(var i = 0; i<10000;i++) db.users.insert({userid:i,username:"xiaoqiang"+i,city:"guangzhou"})
經過以上三次循環插入文檔後,第一個chunk的大小會超過64MB時,出現chunk分割與遷移的過程。再次觀察集羣的狀態信息,字段databases值變爲:
databases:
{ "_id" : "admin", "partitioned" : false, "primary" : "config" }
{ "_id" : "eshop", "partitioned" : true, "primary" : "rs0" }
eshop.users
shard key: { "city" : 1 }
chunks:
rs1 1
rs0 2
{ "city" : { "$minKey" : 1 } } -->> { "city" : "beijing"
} on : rs1 { "t" : 2, "i" : 0 } //塊區間
{ "city" : "beijing" } -->> { "city" : "guangzhou" } on
: rs0 { "t" : 2, "i" : 1 } //塊區間
{ "city" : "guangzhou" } -->> { "city" : { "$maxKey" : 1
} } on : rs0 { "t" : 1, "i" : 4 } //塊區間
說明此時集羣中有三個塊,其中在片rs0上有兩個塊,在片rs1上有一個塊,每一個塊包含必定區間範圍的文檔。爲了更加清楚的知道這些塊是如何分割和遷移的,能夠查看changelog集合中的記錄信息進行分析。
從命令db.changelog.find()輸出內容中能夠看到有如下幾步:
第一步:分割大於64MB的塊,原來此塊的片鍵的區間範圍是-∞到∞,分割後區間變爲-∞到"beijing"、"beijing"到∞兩個區間。
第二步:隨着繼續插入文檔,區間"beijing"到∞所包含的塊的大小超過64MB,此時這個區間又被分割爲"beijing"到"guangzhou"、"guangzhou"到∞這兩個區間。
第三步:通過上面的分割,如今至關於有三個區間塊了,這一步作的就是將區間-∞到"beijing"對應的chunk從片rs0遷移到片rs1,最終結果是分片rs0上包含"beijing"到"guangzhou"、"guangzhou"到∞兩個區間的塊,分片rs1上包含區間-∞到"beijing"的塊。
上面循環插入文檔時還插入了片鍵值爲"changsha"的記錄,這個片鍵的記錄應該都位於區間"beijing"到"guangzhou"所對應的chunk上,只不過因爲chunk的大小還未達到64MB,因此還未進行分割,若是繼續插入此片鍵的文檔,區間可能會被分割爲"beijing"到"changsha"、"changsha"到"guangzhou"這兩個區間塊。依次類推,mongoDB就是這樣來實現海量數據的分佈式存儲的,同時因爲每一個片又是由複製集組成,保證了數據的可靠性。