mongodb分片初探

  分片(sharding)是指將數(shù)據(jù)庫拆分,將其拆分到不同機器的過程,有時也用分區(qū)(partitioning)來表示,它是 MongoDB 為應(yīng)對數(shù)據(jù)增長需求而采取的辦法。
為什么要分片
  • 增加單臺服務(wù)器可用的磁盤空間
  • 減輕單臺服務(wù)器的負載
  • 處理單個mongod無法承受的吞吐量
分片原理
  在搭建mongodb分片集群之前,我們需要先了解一下其架構(gòu)和原理,下圖是mongodb分片集群的架構(gòu)圖:
mongodb shard.png
 mongodb分片集群由三大組件組成:mongos路由、配置服務(wù)器config Server和分片shard,下面一一介紹它們的作用。
mongos路由
 mongos是一個前置路由,我們的應(yīng)用客戶端并不是直接與分片連接,而是與mongos路由連接,mongos接收到客戶端請求后根據(jù)查詢信息將請求任務(wù)分發(fā)到對應(yīng)的分片,在正式生產(chǎn)環(huán)境中,為確保高可用性,一般會配置兩臺以上的mongos路由,以確保當(dāng)其中一臺宕機后集群還能保持高可用。
配置服務(wù)器
  配置服務(wù)器相當(dāng)于集群的大腦,它存儲了集群元信息:集群中有哪些分片、分片的是哪些集合以及數(shù)據(jù)塊的分布集群啟動后,當(dāng)接收到請求時,如果mongos路由沒有緩存配置服務(wù)器的元信息,會先從配置服務(wù)器獲取分片集群對于的映射信息。同樣的,為了保持集群的高可用,一般會配置多臺配置服務(wù)器。
shard分片
   分片是存儲了一個集合部分數(shù)據(jù)的MongoDB實例,每個分片 可以是一臺服務(wù)器運行單獨一個Mongod實例,但是為了提高系統(tǒng)的可靠性實現(xiàn)自動故障恢復(fù),一個分片應(yīng)該是一個復(fù)制集。

  通過分片,我們將一個集合拆分為多個數(shù)據(jù)塊,這些數(shù)據(jù)塊分別部署在不同的機器上,這樣可以做到增加單臺機器的磁盤可用空間,同時將查詢分配到不同的機器上,減輕單臺機器的負載。
如何分片
   在搭建集群分片之前,我們需要先明確各個組件的數(shù)量和服務(wù)器的數(shù)量,我們需要搭建1個mongos路由進程,3個配置服務(wù)器進程和3個分片進程,為方便起見,我們把2個mongos路由和3個配置服務(wù)器都放在同一臺服務(wù)器,通過不同的端口號來運行,但是3個分片我們用了3臺不同的服務(wù)器(其實在同一臺服務(wù)器也是可以的),組件和服務(wù)器配置總體如下:
  • 機器 10.20.11.225 :1個mongos路由進程,3個配置服務(wù)器進行
  • 機器 10.20.20.239 :第一個分片
  • 機器 10.20.21.27 :第二個分片
  • 機器 10.20.23.50 :第三個分片
配置config server
  配置服務(wù)器是一個普通的mongod進程,我們在10.20.11.225機器上配置了3個mongod進程,端口號分別是:20000、20001和20002,以20000端口的進程為例,其配置如下:
dbpath=/root/fmm/software/mongodb/data/config_20000/
#日志文件
logpath=/root/fmm/software/mongodb/log/config_20000.log
#日志追加
logappend=true
#端口
port = 20000
#最大連接數(shù)
maxConns = 50
pidfilepath = /root/fmm/software/mongodb/log/config_20000.pid
#日志,redo log
journal = true
#守護進程模式
fork = true
configsvr = true

20001和20002端口的mongod進程的配置只是端口號、日志和數(shù)據(jù)保存路徑不同而已,然后就分別啟動這三個實例:

./mongod -f ../config/config_20000.conf
./mongod -f ../config/config_20001.conf
./mongod -f ../config/config_20002.conf
配置mongos路由
   mongos路由是提供給客戶端連接集群的,我們只配置一個就行了,但是在正式生產(chǎn)環(huán)境上,為了集群的高可用,我們需要配置兩臺以上的mongos路由,在10.20.11.225機器上我們用30000端口開啟一個mongod進行來運行mongos路由,器配置如下:
#日志文件
logpath=/root/fmm/software/mongodb/log/mongos_30000.log
#日志追加
logappend=true
#端口
port = 30000
#最大連接數(shù)
maxConns = 50
pidfilepath = /root/fmm/software/mongodb/log/mongos_30000.pid
#日志,redo log
#journal = true
#守護進程模式
fork = true
configdb=10.20.11.225:20000,10.20.11.225:20001,10.20.11.225:20002

mongos路由不需要保存數(shù)據(jù),所以不用配置數(shù)據(jù)保存地址,但是一定要配置logpath ,方便我們定位問題,配置中最重要的配置是configdb,需要配置的是3臺配置服務(wù)器的地址,需要注意的是配置服務(wù)器的地址不能寫成localhost或者127.0.0.1,否則會報錯,配置完后我們需要啟動mongos進程,命令如下:

./mongos -f ../config/mongos_30000.conf
配置分片服務(wù)器
  分片服務(wù)器上保存著集合的部分數(shù)據(jù),我們分別在 10.20.20.239、10.20.21.27、10.20.23.50三臺服務(wù)器上啟動三個mongod進程,端口號都是40000,配置如下:
dbpath=/root/fmm/software/mongodb/data/
#日志文件
logpath=/root/fmm/software/mongodb/log/mongodb_shard.log
#日志追加
logappend=true
#端口
port = 40000
#最大連接數(shù)
maxConns = 50
pidfilepath = /root/fmm/software/mongodb/log/mongodb_shard.pid
#日志,redo log
journal = true
#守護進程模式
fork = true

配置完之后就可以直接啟動了,命令如下:

./mongod -f ../config/./mongod

所有組件配置完之后,我們可以登陸mongos路由,查看整個集群信息:

./mongo --port=30000
mongos> sh.status()
--- Sharding Status --- 
  sharding version: {
    "_id" : 1,
    "minCompatibleVersion" : 5,
    "currentVersion" : 6,
    "clusterId" : ObjectId("5885a29be970437923e2aa86")
}
  shards:
  balancer:
    Currently enabled:  yes
    Currently running:  no
    Failed balancer rounds in last 5 attempts:  0
    Migration Results for the last 24 hours: 
        No recent migrations
  databases:
    {  "_id" : "admin",  "partitioned" : false,  "primary" : "config" }
添加分片

我們需要把三臺分片服務(wù)器添加到集群中,操作如下:

mongos> sh.addShard("10.20.20.239:40000")
{ "shardAdded" : "shard0000", "ok" : 1 }
mongos> sh.addShard("10.20.21.27:40000")
{ "shardAdded" : "shard0001", "ok" : 1 }
mongos> sh.addShard("10.20.23.50:40000")
{ "shardAdded" : "shard0002", "ok" : 1 }

添加完之后再看看集群信息,可以看到三個分片已經(jīng)被添加到集群了:

mongos> sh.status()
--- Sharding Status --- 
  sharding version: {
    "_id" : 1,
    "minCompatibleVersion" : 5,
    "currentVersion" : 6,
    "clusterId" : ObjectId("5885a29be970437923e2aa86")
}
  shards:
    {  "_id" : "shard0000",  "host" : "10.20.20.239:40000" }
    {  "_id" : "shard0001",  "host" : "10.20.21.27:40000" }
    {  "_id" : "shard0002",  "host" : "10.20.23.50:40000" }
  balancer:
    Currently enabled:  yes
    Currently running:  no
    Failed balancer rounds in last 5 attempts:  0
    Migration Results for the last 24 hours: 
        No recent migrations
  databases:
    {  "_id" : "admin",  "partitioned" : false,  "primary" : "config" }
開啟分片
   開啟分片首先需要對數(shù)據(jù)庫啟用分片,然后才能對數(shù)據(jù)庫的集合開啟分片功能,對集合開啟分片功能時需要確定片鍵,片鍵與索引類似,是集合的某一個或者多個字段,mongodb會根據(jù)這個片鍵對數(shù)據(jù)進行拆分。在進行分片時,片鍵的選擇是非常最要的一件事,可以說是整個分片過程中最為重要的一步,所以需要非常謹慎地選擇片鍵,這個可以單獨拿出來寫一篇很長的文章了,這里不做過多的描述。

在這里我們創(chuàng)建了一個名為"shardtest"的數(shù)據(jù)庫,數(shù)據(jù)庫中有一張"user"表,user表有name,age,和sex三個字段,我們選擇用age作為片鍵,對該集合進行分片( 這是一個木有數(shù)據(jù)的空集合),操作如下:

mongos> sh.enableSharding("shardtest")       ##對數(shù)據(jù)庫開啟分片
mongos> sh.shardCollection("shardtest.user",{"age":1})   ##對集合user以age作為片鍵進行分片
mongos> sh.status()
--- Sharding Status --- 
  sharding version: {
    "_id" : 1,
    "minCompatibleVersion" : 5,
    "currentVersion" : 6,
    "clusterId" : ObjectId("5885a29be970437923e2aa86")
}
  shards:
    {  "_id" : "shard0000",  "host" : "10.20.20.239:40000" }
    {  "_id" : "shard0001",  "host" : "10.20.21.27:40000" }
    {  "_id" : "shard0002",  "host" : "10.20.23.50:40000" }
  balancer:
    Currently enabled:  yes
    Currently running:  no
    Failed balancer rounds in last 5 attempts:  0
    Migration Results for the last 24 hours: 
        No recent migrations
  databases:
    {  "_id" : "admin",  "partitioned" : false,  "primary" : "config" }
    {  "_id" : "test",  "partitioned" : false,  "primary" : "shard0000" }
    {  "_id" : "shardtest",  "partitioned" : true,  "primary" : "shard0000" }
        shardtest.user
            shard key: { "age" : 1 }
            chunks:
                shard0000   1
            { "age" : { "$minKey" : 1 } } -->> { "age" : { "$maxKey" : 1 } } on : shard0000 Timestamp(1, 0)
  我們可以看到,由于目前集合中沒有數(shù)據(jù),所以新分片的集合起初只有一塊,此塊的范圍是負無窮到正無窮,在shell中用$minKey和$maxKey表示,隨著塊的增長,mongodb會自動降其分成兩塊。
  我們用腳本插入10w條數(shù)據(jù),年齡大小為1~100之間任一值,插入之后,我們再看看其狀態(tài):
mongos> sh.status()
--- Sharding Status --- 
  sharding version: {
    "_id" : 1,
    "minCompatibleVersion" : 5,
    "currentVersion" : 6,
    "clusterId" : ObjectId("5885b5067fefeb309298d15a")
}
  shards:
    {  "_id" : "shard0000",  "host" : "10.20.20.239:40000" }
    {  "_id" : "shard0001",  "host" : "10.20.21.27:40000" }
    {  "_id" : "shard0002",  "host" : "10.20.23.50:40000" }
  balancer:
    Currently enabled:  yes
    Currently running:  yes
    Failed balancer rounds in last 5 attempts:  0
    Migration Results for the last 24 hours: 
        2 : Success
  databases:
    {  "_id" : "admin",  "partitioned" : false,  "primary" : "config" }
    {  "_id" : "test",  "partitioned" : false,  "primary" : "shard0000" }
    {  "_id" : "shardtest",  "partitioned" : true,  "primary" : "shard0000" }
        shardtest.user
            shard key: { "age" : 1 }
            chunks:
                shard0000   1
                shard0001   1
                shard0002   1
            { "age" : { "$minKey" : 1 } } -->> { "age" : 17 } on : shard0001 Timestamp(2, 0) 
            { "age" : 17 } -->> { "age" : 81 } on : shard0002 Timestamp(3, 0) 
            { "age" : 81 } -->> { "age" : { "$maxKey" : 1 } } on : shard0000 Timestamp(3, 1) 
   可以看到數(shù)據(jù)被隨意插入到三個分片中,如果各個片中的數(shù)據(jù)不均衡,那么這時候mongodb的均衡器就會發(fā)揮作用了,平衡器的作用是管理數(shù)據(jù)數(shù)據(jù)塊的移動, 當(dāng)一個集合的數(shù)據(jù)塊在集群中分布達到移動閾值(Migration Thresholds)的時候,平衡器就將數(shù)目最多的分片上的數(shù)據(jù)塊移動到數(shù)目比較少的分片上,平衡器內(nèi)容比較多,這里不做細講了。至此,我們已經(jīng)初步完成了分片。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

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