Linux搭建MongoDB分片叢集
一、介紹
1、基本介紹
MongoDB部署架構分為單機、複製叢集、分片叢集。單機適合學習用,分片叢集比較複雜且運維難度高。
分片叢集是把大型資料集進行拆分,分片到多個MongoDB節點上,這些節點組成了分片叢集。分片結構如下:
2、詞彙表
Shard:分片,儲存叢集中的一部分資料。可以是單個mongo伺服器,也可以是複製集。生產環境推薦使用複製集。
Config Server:配置伺服器。儲存叢集的元資料,比如叢集的分片資訊。mongos 啟動時會從配置伺服器讀取元資料到記憶體中。配置伺服器必須是複製集。
Routers:mongos 路由。負責接收客戶端請求,並將請求路由到叢集內部對應的分片上。
Shard Key:分片鍵。對於每個需要分片的 collection,通過指定分片鍵進行分片。分片鍵必須是索引欄位或者是組合索引的左字首。
Range分割槽:範圍分割槽演算法。分片鍵必須是數字或者字串型別,根據分片鍵將資料分成不同的 chunk,每個 chunk 互相臨近但不重疊。
Hash分割槽:雜湊分割槽演算法。計算分片鍵的hash值,並以此作為 Range 分割槽。這種方式可以將document更加隨機的分散到不同 chunk 上
二、環境準備
虛擬機器三臺(Centos7.6),分別安裝好MongoDB。
分片叢集中,一共10個節點:2個分片(每個分片是3個複製集), 1個config(3個複製集),1個路由。
服務網格資訊如下:
角色 | IP | Node |
分片0複製集 | 192.168.20.100:27017、192.168.20.101:27017、192.168.20.102:27017 | 1主1從1仲裁 |
分片1複製集 | 192.168.20.100:27018、192.168.20.101:27018、192.168.20.102:27018 | 1主1從1仲裁 |
config複製集 | 192.168.20.100:28018、192.168.20.101:28018、192.168.20.102:28018 | 1主2從 |
mongos節點 | 192.168.20.100:29019 |
三、搭建 Shard
1、在100/101/102機器上,建立目錄:
mkdir -p /usr/local/mongo/share/data/db #分片0的資料儲存路徑
mkdir -p /usr/local/mongo/share/data/db2 #分片1的資料儲存路徑
mkdir -p /usr/local/mongo/share/conf
mkdir -p /usr/local/mongo/share/pids
mkdir -p /usr/local/mongo/share/logs
2、在100/101/102機器上,/usr/local/mongo/share/conf 目錄下,新增分片0複製集的配置檔案:mongo.conf :
#資料儲存路徑
dbpath=/usr/local/mongo/share/data/db/
#日誌儲存路徑
logpath=/usr/local/mongo/share/logs/mongo.log
#程序描述檔案
pidfilepath=/usr/local/mongo/share/pids/mongo.pid
#日誌追加寫入
logappend=true
#複製集名稱
replSet=rs0
bind_ip_all=true
#mongo埠
port=27017
#操作日誌容量
oplogSize=10000
#開啟子程序
fork=true
#代表當前節點是一個shard節點
shardsvr=true
3、在100/101/102機器上,/usr/local/mongo/share/conf 目錄下,新增分片1複製集的配置檔案:mongo2.conf :
#資料儲存路徑
dbpath=/usr/local/mongo/share/data/db2/
#日誌儲存路徑
logpath=/usr/local/mongo/share/logs/mongo2.log
#程序描述檔案
pidfilepath=/usr/local/mongo/share/pids/mongo2.pid
#日誌追加寫入
logappend=true
#複製集名稱
replSet=rs1
bind_ip_all=true
#mongo埠
port=27018
#操作日誌容量
oplogSize=10000
#開啟子程序
fork=true
#代表當前節點是一個shard節點
shardsvr=true
4、在100/101/102機器上,分別啟動 mongod 服務:
#分片0(rs0)
/usr/local/mongo/bin/mongod -f /usr/local/mongo/share/conf/mongo.conf
#分片1(rs1)
/usr/local/mongo/bin/mongod -f /usr/local/mongo/share/conf/mongo2.conf
5、登入複製集:
#分片0(rs0)
/usr/local/mongo/bin/mongo --host 192.168.20.100 --port 27017
#分片1(rs1)
/usr/local/mongo/bin/mongo --host 192.168.20.100 --port 27018
6、初始化複製集:
#分片0(rs0)
rs.initiate({
_id:"rs0",
members:[
{_id:0, host:"192.168.20.100:27017", priority:3},
{_id:1, host:"192.168.20.101:27017", priority:2},
{_id:2, host:"192.168.20.102:27017", arbiterOnly:true}
]
});
#分片1(rs1)
rs.initiate({
_id:"rs1",
members:[
{_id:0, host:"192.168.20.100:27018", priority:3},
{_id:1, host:"192.168.20.101:27018", priority:2},
{_id:2, host:"192.168.20.102:27018", arbiterOnly:true}
]
});
四、搭建Config Server
1、在100/101/102機器上,建立目錄:
mkdir -p /usr/local/mongo/config-server/data/db
mkdir -p /usr/local/mongo/config-server/conf
mkdir -p /usr/local/mongo/config-server/pids
mkdir -p /usr/local/mongo/config-server/logs
2、在100/101/102機器上,/usr/local/mongo/config-server/conf 目錄下,新增複製集的配置檔案:mongo-cfg.conf
dbpath=/usr/local/mongo/config-server/data/db
logpath=/usr/local/mongo/config-server/logs/mongo.log
pidfilepath=/usr/local/mongo/config-server/pids/mongo.pid
logappend=true
replSet=rs_conf
bind_ip_all=true
port=28018
oplogSize=10000
fork=true
#代表當前節點是一個config節點
configsvr=true
3、在100/101/102機器上,分別啟動配置複製集:
/usr/local/mongo/bin/mongod -f /usr/local/mongo/config-server/conf/mongo-cfg.conf
4、登入複製集:
/usr/local/mongo/bin/mongo --host 192.168.20.100 --port 28018
5、初始化複製集:
rs.initiate({
_id:"rs_conf",
configsvr: true,
members:[
{_id:0, host:"192.168.20.100:28018", priority:2},
{_id:1, host:"192.168.20.101:28018", priority:1},
{_id:2, host:"192.168.20.102:28018", priority:1}
]
});
五、搭建Router
本案例只配置了一個Router,生產環境通常配置多個。Router不需要資料目錄(dbpath),只需要提供 config server 資訊
1、在100機器上,建立目錄:
mkdir -p /usr/local/mongo/router/conf
mkdir -p /usr/local/mongo/router/pids
mkdir -p /usr/local/mongo/router/logs
2、在 /usr/local/mongo/router/conf 目錄下,建立 Router 的配置檔案:mongo-router.conf
configdb=rs_conf/192.168.20.100:28018,192.168.20.101:28018,192.168.20.102:28018
logpath=/usr/local/mongo/router/logs/mongos.log
pidfilepath=/usr/local/mongo/router/pids/mongos.pid
port=29019
fork=true
bind_ip_all=true
3、啟動 Router 服務:
/usr/local/mongo/bin/mongos -f /usr/local/mongo/router/conf/mongo-router.conf
4、連線 Router 節點:
/usr/local/mongo/bin/mongo --host 192.168.20.100 --port 29019
5、切換到 admin 庫
use admin
6、新增分片資訊:
#分片0
db.runCommand({addShard: "rs0/192.168.20.100:27017,192.168.20.101:27017,192.168.20.102:27017", name: "share0"});
#分片1
db.runCommand({addShard: "rs1/192.168.20.100:27018,192.168.20.101:27018,192.168.20.102:27018", name: "share1"});
7、檢視分片:
db.runCommand({listshards: 1})
8、檢視分片狀態:
sh.status()
六、測試
1、測試分片--雜湊策略
連線 Router 節點並切換到 admin 庫。對測試庫 xwjdb 開啟分片功能:
sh.enableSharding("xwjdb")
對集合 account 分片,分片鍵為 nickname,分片策略為雜湊:
sh.shardCollection("xwjdb.account", {"nickname": "hashed"})
切換到 xwjdb 庫。向 account 集合中,迴圈插入1000條資料:
use xwjdb
for(var i=1; i<=1000; i++){db.account.insert({_id: i+"", nickname: "xwj"+i})}
分別連線 分片0 和 分片1 節點,並切換到 xwjdb 庫。查詢 account 集合資料條數:
use xwjdb
db.account.count()
分片0的資料是505條,分片2是495條,總數正好是1000條,說明資料分片成功了
結論:基於雜湊策略的分片演算法,資料會均勻的分配到不同的分片節點上
2、測試分片-範圍策略
資料塊(chunk)預設大小是64M,填滿後才會考慮向其它片的資料塊填充資料,因此,為了測試可以將其改小,這裡改為1M:
use config
db.setting.save({"_id": "chunksize", "value": 1})
切換到 admin 庫。對測試庫 testdb 開啟分片功能:
sh.enableSharding("testdb")
對集合 person 分片,分片鍵為主鍵id,分片策略為範圍:
sh.shardCollection("testdb.person",{_id:1});
切換到庫 testdb。向 person 集合中,批量插入4000000條資料(資料少了可能只落在一個分片上):
use testdb
var arr=[]
for(var i=1; i<=4000000; i++){arr.push({"_id":i,"username":"user"+i,"createdate":new Date()})}
db.person.insertMany(arr)
分別連線 分片0 和 分片1 節點,並切換到 testdb 庫。查詢 account 集合資料條數:
use testdb
db.person.count()
七、其它
1、一個集合只能有一個分片鍵
2、庫和集合預設是不分片的,對於不分片的庫或者集合,資料均會儲存在 primary shard上,直到開啟分片才會在叢集中分佈
3、刪除所有資料和日誌資訊(刪除後,所有配置資訊也被刪掉了):
rm -rf /usr/local/mongo/config-server/logs/*
rm -rf /usr/local/mongo/config-server/data/db/*
rm -rf /usr/local/mongo/share/data/db/*
rm -rf /usr/local/mongo/share/data/db2/*
rm -rf /usr/local/mongo/share/logs/*
rm -rf /usr/local/mongo/router/logs/*
4、刪除分片鍵命令:
use config
db.collections.remove( { _id: "testdb.person" } )
db.chunks.remove( { ns: "testdb.person" } )
db.locks.remove( { _id: "testdb.person" } )
use admin
db.adminCommand("flushRouterConfig")
5、查詢chunk大小:
use config
db.setting.find()
八、踩坑
1、config server複製集初始化時,報錯:
問題原因:搭建config server複製集時,不能有仲裁節點(Arbiters),否則初始化失敗
解決辦法:複製集使用一主兩從