1. 程式人生 > >MongoDB集群之分片技術應用 —— 學習筆記

MongoDB集群之分片技術應用 —— 學習筆記

並且 水平 副本 分享圖片 version linux 數量 ready 應用

課程鏈接:https://www.imooc.com/learn/501

一、什麽是分片?

分片:將數據進行2拆分,將數據水平的分散到不同的服務器上。
技術分享圖片

二、為什麽要分片?

  • 架構上:讀寫均衡、去中心化
  • 結構上:12節點(version<=2.6)
  • 硬件上:內存、硬盤容量限制

分片目的

改善單臺機器數據的存儲及數據吞吐性能。
提高在大量數據下隨機訪問性能。

分片(Shard)、副本集(Replication)集群對比

技術分享圖片

成員節點介紹

  • Shard節點:存儲數據的節點(單個mongod或者副本集)
  • Config server:存儲元數據,為mongos服務,將數據路由到Shard。
  • Mongos:接受前端請求,進行對應消息路由。

成員組合圖:
技術分享圖片

成員節點啟動參數

Shard節點:

  • mongod --shardsvr
  • mongod --shardsvr --rpelSet 副本集

Config server:

  • mongod --configsvr

Mongos:

  • mongos —— configdb <configdb server>

課程使用系統:Red Hat Enterprise Linux Server release 6.4 (Santiago)
課程使用MongoDB版本:v3.0.4

啟動Shard(10.156.11.233):

mongod --shardsvr --logpath=/opt/data/logs/shard.log -logappend --dbpath=/opt/mdb/ --fork --port 27017

查看mongod Shard有沒有啟動起來:

ps -aux | grep mongod
netstat -luntp | grep 27017

啟動Config(10.156.11.233):

mongod --configsvr --logpath=/opt/data/logs/config.log --logappend --dbpath=/opt/config --fork --port 27018

查看mongod Config有沒有啟動起來:

netstat -luntp | grep mongo
ps -aux | grep mongod

啟動Mongos(10.156.11.232):

mongos --port 27017 --logappend --logpath=/opt/data/logs/mongos.log --configdb 10.156.11.233:27018 --fork

查看Mongos有沒有啟動起來:

netstat -luntp | grep 27017
ps -aux | grep mongos

添加分片過程

步驟一、連接到mongos
步驟二、Add Shards
步驟三、Enable Sharding
步驟四、對一個集合進行分片

步驟二、Add Shards

  1. 單個數據庫實例:
    { addShard: "<hostname> <:port>", maxSize: <size>, name: "<shard_name>"}
  2. 副本集群:
    { addShard: "<replica_set>/<hostname> <:port>", maxSize:<size>, name: "shard_name" }
  3. 如果你的mongos和shard在同一臺機器上,添加分片不能使用“localhost”,建議使用IP。

步驟四、對一個集合進行分片

  1. db.runCommand
    ({shardcollection: " <namespoace>", key: " <key>"})
  2. unique: " true/false"
    啟動對shard key的唯一性約束
  3. shard key選擇

在10.156.11.232上的操作
這臺電腦之前已經啟動了mongos服務
輸入如下指令登陸mongos:

mongo 127.0.0.1:27017

在mongos命令行下執行如下命令,將10.156.11.232上的mongod添加進來:

mongos> use admin
mongos> db.runCommand({"addShards":"10.156.11.233:27017"})

其他:
查看目前有幾個數據庫的mongos命令:

mongos> show dbs;

創建名為“shardtest”的數據庫的mongos命令:

mongos> use shardtest

測試在數據庫shardtest中的集合userid中插入測試數據的例子:

mongos> for(i=0;i<10000;i++){db.shardtest.userid.insert({"user_id":i})};

采用如下命令來Enable剛才創建的名為“shardtest”的Sharding:

mongos> use admin
mongos> db.runCommand({enablesharding:"shardtest"})

不過這個時候它會報一個這樣的錯誤:

{ "ok": 0, "errmsg": "already enabled" }

使用如下命令啟用shardtest數據庫的userid集合對應的分片,將根據鍵user_id來進行分片:

mongos> db.runCommand({"shardcollection":"shardtest.userid",key:{"user_id":1}})

其中,"user_id"對應的1表示是按照升序來進行分片。

分片測試

在mongos命令行執行如下命令:

mongos> use config
mongos> db.shards.find()
  1. 查看集合狀態:
> use shardtest
> db.userid.stats()
  1. 查看分片狀態:
db.printShardingStatus()
  1. 寫入數據測試:
for (var i=1;i<10000000;i++>){db.userid.insert(user_id:i)}

什麽是分片片鍵:

集合裏面選一個鍵,用該鍵的值作為數據拆分的依據。
技術分享圖片

什麽是Chunk:

MongoDB分片後,存儲數據的但願快,默認大小:64MB。

Chunk拆分

數據塊(chunk)的拆分:
記錄每個塊中插入多少數據,一旦達到某個閾值,執行檢查是否需要拆分塊,需要則更新config服務器上這個塊的元信息。

Balancing

數據塊平衡:
均衡器負責數據的遷移,會周期性的檢查分片是否存在不均衡,如果存在則會進行塊的遷移。
註意:均衡器進行均衡的條件是 塊數量的多少 ,而不是塊大小。

哈希分片

哈辛分片(hash key):
分片過程中利用哈希索引作為分片的單個鍵。

  • 哈希分片的片鍵只能使用一個字段
  • 哈希片鍵最大的好處就是保證數據在各個節點分布基本均勻
    shardcollection ==> {userid:"hashed"}

233上進行如下操作來進行分片:

mongos> db.userid_hash.insert({userid:11})
mongos> db.userid_hash.insert({userid:22})
mongos> use shardtest
mongos> db.userid_hash.ensureIndex({userid:"hash"})
mongos> use admin
mongos> db.runCommand({"shardcollection":"shardtest.userid_hash","key":{userid:"hashed"}})

插入一些數據進行測試:

mongos> use shardtest
mongos> for(i=0;i<100000;i++>{db.userid_hash.insert({userid:i})})

查看效果:

mongos> use shardtest
mongos> db.userid_hash.stats()
mongos> db.printShardingStatus()

如何選擇合適片鍵

選擇片鍵的好壞很大程度上影響集群的性能,容量和功能。

考慮因素一、數據塊的大小
印象:片鍵相同導致數據塊不拆分,容易形成大的數據塊,導致數據不均。

考慮因素二、數據寫均勻分布
影響:單調遞增的_id或時間戳作為片鍵,這樣將會導致你一直往最後一個副本集中添加數據。

請求查詢機制

方式一、Routed Request
技術分享圖片

方式二、Scatter Gather Request
技術分享圖片

方式三、Distributed Merge Sort Req
技術分享圖片

手動分片

為什麽要手動分片?
為了減少自動平衡過程帶來的IO等資源消耗。

前提:

  1. 關閉自動平衡,關閉auto balence;
  2. 充分了解數據,並對數據進行預先劃分。

步驟一、關閉自動平衡
關閉方式:sh.stopBalancer()
(啟動方式:sh.startBalancer()
此時平衡器狀態:CurrentLy enabled: no

步驟二、分片切割

> use admin
> db.runCommand({"enablesharding":"myapp"})
> db.runCommand({"shardcollection":"myapp.users","key":{"email":1}})
for (var x=97;x<97+26;x++) {
    for (var y=97;y<97+26;y+=6) {
        var prefix = String.fromCharCode(x) + String.fromCharCode(y);
        db.runCommand({
            split: "myapp.users",
            middle: { email: prefix }
        });
    }
}

步驟三、手動移動分割快

var shServer = [
    "ShardServer 1",
    "ShardServer 2",
    "ShardServer 3",
    "ShardServer 4",
    "ShardServer 5",
]
for (var x=97;x<97+26;x++) {
    for (var y=97;y<97+26;y+=6) {
        var prefix = String.fromCharCode(x) + String.fromCharCode(y);
        db.runCommand({
            moveChunk: "myapp.users",
            find: { email: prefix },
            to: shServer[(y-97)/6]
        });
    }
}

實踐:
首先登陸233的mongos
執行如下命令來關閉平衡:

mongos> sh.stopBalancer()

然後執行下面代碼:

mongos> for (var x=97;x<97+26;x++) {
    for (var y=97;y<97+26;y+=6) {
        var prefix = String.fromCharCode(x) + String.fromCharCode(y);
        db.runCommand({
            split: "myapp.users",
            middle: { email: prefix }
        });
    }
}
mongos> var shServer = [
    "10.156.11.232:27016",
    "10.156.11.232:27017",
    "10.156.11.232:27016",
    "10.156.11.232:27017",
    "10.156.11.232:27016",
]
mongos> for (var x=97;x<97+26;x++) {
    for (var y=97;y<97+26;y+=6) {
        var prefix = String.fromCharCode(x) + String.fromCharCode(y);
        db.runCommand({
            moveChunk: "myapp.users",
            find: { email: prefix },
            to: shServer[(y-97)/6]
        });
    }
}

常用部署場景

場景一
技術分享圖片

場景二
技術分享圖片

考慮因素:
一、預估數據增長量
二、預估集群的訪問量
三、預估投入成本(硬件、人員維護等)

場景一部署

機器規劃:
技術分享圖片

三臺電腦均相同方式啟動如下服務:

mongod --fork --logpath=/opt/data/logs/mongod27018.log -logappend --dbpath=/opt/mdb27018/ --port 27018 --replSet imooc1
mongod --fork --logpath=/opt/data/logs/mongod27019.log -logappend --dbpath=/opt/mdb27019/ --port 27019 --replSet imooc1
mongod --fork --logpath=/opt/data/logs/mongod27020.log -logappend --dbpath=/opt/mdb27020/ --port 27020 --replSet imooc1

在173節點,執行如下命令進入mongod:

mongo 127.0.0.1:27018

在命令行執行如下指令:

cfg = {
    _id: ‘imooc1‘, members: [
        { _id: 0, host: ‘10.156.11.173:27018‘ },
        { _id: 1, host: ‘10.156.11.232:27018‘ }
    ]
}

rs.initiate(cfg)

rs.addArb("10.156.11.233:27018")

另外兩臺電腦的配置類似,此處略。

通過如下命令查看每一個副本集的成員狀態:

re.status()

接下來完成對分片的配置(也就是啟動configsvr),
在清空之前,我要確認我的configsvr的logpath目錄存在,並且log信息是空的:

rm -rf /opt/data/config/*

然後啟動configsvr:

mongod --configsvr --logpath=/opt/data/logs/config.log --logappend /opt/data/config --fork --port 27016

在三臺電腦上都這麽進行啟動configsvr的操作。

接下來啟動mongos,
這一步需要將所有的configsvr的配置都加上,
如下:

mongos --port 27017 --logappend --logpath=/opt/data/logs/mongos.log --configdb 10.156.11.233:27016,10.156.11.232:27016,10.156.11.173:27016 --fork

同樣的,我們可以登陸mongos服務:

mongo 127.0.0.1:27017

這樣我們就順利地把mongos服務啟動起來。

接下來登陸到(233上的)mongos上,把我們的成員節點添加進來:
在命令行下執行mongo進入mongos命令行,然後執行如下命令來進行分片配置操作:

mongos> use admin
mongos> db.runCommand({addshard:"imooc1/10.156.11.173:27018,10.156.11.232:27018",name:"shard1",maxsize:20480});
mongos> db.runCommand({addshard:"imooc2/10.156.11.232:27019,10.156.11.233:27019",name:"shard2",maxsize:20480});
mongos> db.runCommand({addshard:"imooc3/10.156.11.233:27020,10.156.11.173:27020",name:"shard3",maxsize:20480});

創建一個測試庫:

mongos> use myimooc
mongos> db.user.insert({userid:1,name:"zifeiy",email:"[email protected]"})
mongos> db.runCommand({ enablesharding:"zifeiy"})
mongos> db.runCommand({"shardcollection":"zifeiy.user","key":{email:1}});

MongoDB集群之分片技術應用 —— 學習筆記