MongoDB分片(Sharding)技術
分片(sharding)是MongoDB用來將大型集合分割到不同服務器(或者說一個集群)上所采用的方法。盡管分片起源于關系型數據庫分區,但MongoDB分片完全又是另一回事。
和MySQL分區方案相比,MongoDB的最大區別在于它幾乎能自動完成所有事情,只要告訴MongoDB要分配數據,它就能自動維護數據在不同服務器之間的均衡。
1 分片的目的
高數據量和吞吐量的數據庫應用會對單機的性能造成較大壓力,大的查詢量會將單機的CPU耗盡,大的數據量對單機的存儲壓力較大,最終會耗盡系統的內存而將壓力轉移到磁盤IO上。
為了解決這些問題,有兩個基本的方法: 垂直擴展和水平擴展。
垂直擴展:增加更多的CPU和存儲資源來擴展容量。
水平擴展:將數據集分布在多個服務器上。水平擴展即分片。
2 分片設計思想
分片為應對高吞吐量與大數據量提供了方法。使用分片減少了每個分片需要處理的請求數,因此,通過水平擴展,集群可以提高自己的存儲容量和吞吐量。舉例來說,當插入一條數據時,應用只需要訪問存儲這條數據的分片.
使用分片減少了每個分片存儲的數據。
例如,如果數據庫1tb的數據集,并有4個分片,然后每個分片可能僅持有256 GB的數據。如果有40個分片,那么每個切分可能只有25GB的數據。
Docker部署
架構設計:
三臺主機啟動相同的進程,mongos 、config server、shard server
Rancher 部署
每個主機按照計劃添加標簽:
mongos=true
shard2=true
shard3=true
shard1=true
config=true
host網絡模式,端口務必不能被占用
新建服務:
粘貼以下內容:
compose
version: '2'
services:
shard2:
image: mongo:4.0.1-xenial
stdin_open: true
network_mode: host
volumes:
- /data/shard2:/data/db
tty: true
command:
- /usr/bin/mongod
- --shardsvr
- --replSet
- shard2
- --port
- '27002'
- --bind_ip_all
- --dbpath
- /data/db
- --logpath
- /data/db/shard2.log
- --oplogSize
- '10'
labels:
io.rancher.scheduler.affinity:host_label: shard2=true
io.rancher.container.pull_image: always
io.rancher.scheduler.global: 'true'
mongos:
image: mongo:4.0.1-xenial
stdin_open: true
network_mode: host
volumes:
- /data/mongos:/data/db
tty: true
command:
- mongos
- --configdb
- myset/172.20.101.132:27000,172.20.101.133:27000,172.20.101.134:27000
- --port
- '27017'
- --bind_ip_all
labels:
io.rancher.scheduler.affinity:host_label: mongos=true
io.rancher.container.pull_image: always
io.rancher.scheduler.global: 'true'
shard3:
image: mongo:4.0.1-xenial
stdin_open: true
network_mode: host
volumes:
- /data/shard3:/data/db
tty: true
command:
- /usr/bin/mongod
- --shardsvr
- --replSet
- shard3
- --port
- '27003'
- --bind_ip_all
- --dbpath
- /data/db
- --logpath
- /data/db/shard3.log
- --oplogSize
- '10'
labels:
io.rancher.scheduler.affinity:host_label: shard3=true
io.rancher.container.pull_image: always
io.rancher.scheduler.global: 'true'
shard1:
image: mongo:4.0.1-xenial
stdin_open: true
network_mode: host
volumes:
- /data/shard1:/data/db
tty: true
command:
- /usr/bin/mongod
- --shardsvr
- --replSet
- shard1
- --port
- '27001'
- --bind_ip_all
- --dbpath
- /data/db
- --logpath
- /data/db/shard1.log
- --oplogSize
- '10'
labels:
io.rancher.scheduler.affinity:host_label: shard1=true
io.rancher.container.pull_image: always
io.rancher.scheduler.global: 'true'
config:
image: mongo:4.0.1-xenial
stdin_open: true
network_mode: host
volumes:
- /data/config:/data/db
tty: true
command:
- /usr/bin/mongod
- --configsvr
- --replSet
- myset
- --bind_ip_all
- --dbpath
- /data/db
- --port
- '27000'
- --logpath
- /data/db/config.log
labels:
io.rancher.scheduler.affinity:host_label: config=true
io.rancher.container.pull_image: always
io.rancher.scheduler.global: 'true'
rancher-compose:
rancher-compose
version: '2'
services:
mongos:
start_on_create: true
shard2:
start_on_create: true
shard3:
start_on_create: true
shard1:
start_on_create: true
config:
start_on_create: true
1、登錄某一個宿主機鏈接shard1:
127.0.0.1:27001/admin
config = { _id:"shard1", members:[
{_id:0,host:"172.20.101.132:27001"},
{_id:1,host:"172.20.101.133:27001"},
{_id:2,host:"172.20.101.134:27001"}
]
}
rs.initiate(config)
2、鏈接shard2
127.0.0.1:27002/admin
config = { _id:"shard2", members:[
{_id:0,host:"172.20.101.132:27002"},
{_id:1,host:"172.20.101.133:27002"},
{_id:2,host:"172.20.101.134:27002"}
]
}
rs.initiate(config)
3、鏈接shard3
127.0.0.1:27003/admin
config = { _id:"shard3", members:[
{_id:0,host:"172.20.101.132:27003"},
{_id:1,host:"172.20.101.133:27003"},
{_id:2,host:"172.20.101.134:27003"}
]
}
rs.initiate(config)
4、鏈接config服務:
config = {_id: 'myset', members: [
{_id: 0, host: '172.20.101.132:27000'},
{_id: 1, host: '172.20.101.133:27000'},
{_id: 2, host: '172.20.101.134:27000'}]
}
rs.initiate(config)
5、登錄mongos:
mongo 127.0.0.1:27017/admin #登錄mongos,增加節點
db.runCommand( { addshard : "shard1/172.20.101.132:27001,172.20.101.133:27001,172.20.101.134:27001",name:"shard1"});
db.runCommand( { addshard : "shard2/172.20.101.132:27002,172.20.101.133:27002,172.20.101.134:27002",name:"shard2"});
db.runCommand( { addshard : "shard3/172.20.101.132:27003,172.20.101.133:27003,172.20.101.134:27003",name:"shard3"});
6、查看集群狀態
sh.status()
主機安裝
一、安裝
1、
cat >/etc/yum.repos.d/mongodb-org-4.0.repo<<EOF
[mongodb-org-4.0]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/4.0/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-4.0.asc
EOF
yum install -y mongodb-org-4.0.1 mongodb-org-server-4.0.1 mongodb-org-shell-4.0.1 mongodb-org-mongos-4.0.1 mongodb-org-tools-4.0.1
2、
建立目錄 mongos目錄、config server目錄、share目錄
mkdir -p /data/mongodb/{shard1,shard2,shard3,mongos,config,shard1/data,shard1/log,shard2/data,shard2/log,shard3/data,shard3/log,mongos/log,config/log,config/data}
chown mongod.mongod /data/mongodb/ -R
3、
需要啟動5個進程所以要規劃5個組件對應的端口號,由于一個機器需要同時部署 mongos、config server 、shard1、shard2、shard3
mongos:27017
config server:27000
shard1、shard2、shard3 : 27001 27002 27003
4、啟動各進程
#mongos
mongos --configdb myset/172.20.101.132:27000,172.20.101.133:27000,172.20.101.134:27000 --port 27017 --logpath /data/mongodb/mongos/mongos.log --fork
#config
mongod --configsvr --replSet myset --bind_ip_all --dbpath /data/mongodb/config/data --port 27000 --logpath /data/mongodb/config/log/config.log --fork
#shard1 #shard2 #shard3
mongod --shardsvr --replSet shard1 --bind_ip_all --port 27001 --dbpath /data/mongodb/shard1/data --logpath /data/mongodb/shard1/log/shard1.log --fork --oplogSize 10
mongod --shardsvr --replSet shard2 --bind_ip_all --port 27002 --dbpath /data/mongodb/shard2/data --logpath /data/mongodb/shard2/log/shard2.log --fork --oplogSize 10
mongod --shardsvr --replSet shard3 --bind_ip_all --port 27003 --dbpath /data/mongodb/shard3/data --logpath /data/mongodb/shard3/log/shard3.log --fork --oplogSize 10
5、設置副本集
連接 shard1:mongo 127.0.0.1:27001/admin/
config = { _id:"shard1", members:[
{_id:0,host:"172.20.101.132:27001"},
{_id:1,host:"172.20.101.133:27001"},
{_id:2,host:"172.20.101.134:27001",arbiterOnly:true}
]
}
rs.initiate(config)
連接 shard2:mongo 127.0.0.1:27001/admin
config = { _id:"shard2", members:[
{_id:0,host:"172.20.101.132:27002"},
{_id:1,host:"172.20.101.133:27002"},
{_id:2,host:"172.20.101.134:27002",arbiterOnly:true}
]
}
rs.initiate(config)
連接 shard3:mongo 127.0.0.1:27001/admin
config = { _id:"shard3", members:[
{_id:0,host:"172.20.101.132:27003"},
{_id:1,host:"172.20.101.133:27003"},
{_id:2,host:"172.20.101.134:27003",arbiterOnly:true}
]
}
config server 副本
config = {_id: 'myset', members: [
{_id: 0, host: '172.20.101.132:27000'},
{_id: 1, host: '172.20.101.133:27000'},
{_id: 2, host: '172.20.101.134:27000'}]
}
rs.initiate(config)
6、mongo 127.0.0.1:27017/admin #登錄mongos,增加節點
db.runCommand( { addshard : "shard1/172.20.101.132:27001,172.20.101.133:27001,172.20.101.134:27001",name:"shard1"});
db.runCommand( { addshard : "shard2/172.20.101.132:27002,172.20.101.133:27002,172.20.101.134:27002",name:"shard2"});
db.runCommand( { addshard : "shard3/172.20.101.132:27003,172.20.101.133:27003,172.20.101.134:27003",name:"shard3"});
致辭,部署完成。
測試:
1、殺掉第二個節點所有進程
可讀寫,沒有任何影響
2、繼續殺掉第一個主節點
只剩第三個節點,第三個節點依然是SECONDARY,節點不可寫。重啟節點2后,節點3變為主節點,功能恢復,繼續啟動第一個節點,第幾節點變為SECONDARY
3、如果節點太長時間沒有建立連接,啟動后會變成recovery狀態,操作:關掉進程,刪除數據文件,重啟即可。
4、添加刪除shard 節點:
rs.remove("172.20.101.134:27002");
rs.add("172.20.101.134:27002");
5、添加刪除shard分片,需要在主節點操作,查找主節點,鏈接mongos:mongo ip:27017/admin,sh.status()即可找到主節點
db.runCommand( { addshard : "shard4/172.20.101.125:27004,172.20.101.133:27004",name:"shard4"});
db.runCommand( { removeshard : "shard4/172.20.101.125:27004,172.20.101.133:27004",name:"shard4"});
常用操作:
1、用戶相關
db.auth('admin','ptmind') #登錄認證
創建用戶附權限
db.createUser({user:'datadeck', pwd:'ptmind', roles:['userAdminAnyDatabase']});
db.createUser({user:'datadeck', pwd:'ptmind', roles:['root']});
2、增刪改查:
新建并選擇數據庫
use nettest
新增并寫入數據
db.testtable.insert({'k':'3','c':'4'})
查看表
show collections
查看表內數據
db.testtable.find().pretty()
添加刪除shard 節點:
rs.remove("172.20.101.134:27002");
rs.add("172.20.101.134:27002");
添加刪除shard分片,需要在主節點操作,查找主節點,鏈接mongos:mongo ip:27017/admin,sh.status()即可找到主節點
db.runCommand( { addshard : "shard4/172.20.101.125:27004,172.20.101.133:27004",name:"shard4"});
db.runCommand( { removeshard : "shard4/172.20.101.125:27004,172.20.101.133:27004",name:"shard4"});
3、集群狀態
查看副本集命令:
db.runCommand( { listshards : 1 } )
查看狀態:
sh.status();
激活數據庫分片功能
語法:( { enablesharding : "數據庫名稱" } )
mongos> db.runCommand( { enablesharding : "test" } )
指定分片建對集合分片,范圍片鍵–創建索引
查看shard狀態,登錄某個shard節點
rs.status()
4、備份恢復
a、mongodump 導出為二進制bson文件
mongodump -h dbhost -d dbname -o dbdirectory(目錄)
備份單個collection
mongodump --db test --collection collection
備份單個庫
mongodump -h 127.0.0.1:27017/admin -d db_distribution_test_YYJOTVSUQI -o /var/tmp/db_distribution_test_YYJOTVSUQI.mongodb
備份整個庫去掉表明即可
mongorestore恢復數據默認是追加,如打算先刪除后導入,可以加上--drop參數,不過添加--drop參數后,會將數據庫數據清空后再導入,如果數據庫備份后又新加入了數據,也會將新加的數據刪除,它不像mysql有一個存在的判斷。
mongorestore -h <hostname><:port> -d dbname <path>
b、mongoexport
-h,--host :代表遠程連接的數據庫地址,默認連接本地Mongo數據庫;
--port:代表遠程連接的數據庫的端口,默認連接的遠程端口27017;
-u,--username:代表連接遠程數據庫的賬號,如果設置數據庫的認證,需要指定用戶賬號;
-p,--password:代表連接數據庫的賬號對應的密碼;
-d,--db:代表連接的數據庫;
-c,--collection:代表連接數據庫中的集合;
-f, --fields:代表集合中的字段,可以根據設置選擇導出的字段;
--type:代表導出輸出的文件類型,包括csv和json文件;
-o, --out:代表導出的文件名;
-q, --query:代表查詢條件;
--skip:跳過指定數量的數據;
--limit:讀取指定數量的數據記錄;
--sort:對數據進行排序,可以通過參數指定排序的字段,并使用 1 和 -1 來指定排序的方式,其中 1 為升序排列,而-1是用于降序排列,如sort({KEY:1})。
mongoimport 簡介,通過幫助先了解下mongoimport的功能參數
關鍵參數說明:
h,--host :代表遠程連接的數據庫地址,默認連接本地Mongo數據庫;
--port:代表遠程連接的數據庫的端口,默認連接的遠程端口27017;
-u,--username:代表連接遠程數據庫的賬號,如果設置數據庫的認證,需要指定用戶賬號;
-p,--password:代表連接數據庫的賬號對應的密碼;
-d,--db:代表連接的數據庫;
-c,--collection:代表連接數據庫中的集合;
-f, --fields:代表導入集合中的字段;
--type:代表導入的文件類型,包括csv和json,tsv文件,默認json格式;
--file:導入的文件名稱
--headerline:導入csv文件時,指明第一行是列名,不需要導入;
實例演示:
#首先查看集合中的數據 > db.bike_bak.find() { "_id" : ObjectId("59e8c27804390e04a063159d"), "lat" : 39.9571954199, "bikeId" : "pgdAVg", "current_time" : "2017-10-19 23:19:19", "source" : "ofo", "lng" : 116.3926501736 } #刪除集合中的數據 > db.bike_bak.remove({"bikeId" : "pgdAVg"}) WriteResult({ "nRemoved" : 1 }) #查看集合是否包含數據 > db.bike_bak.find() > #導入數據 [root@iZ2ze4b308vd83fulq9n7iZ ~]# mongoimport --port 27030 -u sa -p Expressin@0618 -d mapdb -c bike_bak --type=json --file bike.csv 2017-10-25T11:59:51.020+0800 connected to: localhost:27030
2017-10-25T11:59:51.030+0800 imported 1 document #檢查數據是否導入成功 > db.bike_bak.find() { "_id" : ObjectId("59e8c27804390e04a063159d"), "bikeId" : "pgdAVg", "current_time" : "2017-10-19 23:19:19", "lat" : 39.9571954199, "lng" : 116.3926501736, "source" : "ofo" }
[root@iZ2ze4b308vd83fulq9n7iZ ~]# mongoimport --help Usage: mongoimport <options> <file>
注意:
當查詢時同時使用sort,skip,limit,無論位置先后,最先執行順序 sort再skip再limit。
實例:
首先查看下數據庫中的數據一共多少條,通過的命令的方式查看下我們要導出的數據信息
db.bike.find().count() 16878865
db.bike.find({"source":"ofo"}).limit(1) { "_id" : ObjectId("59e8c27804390e04a063159d"), "lat" : 39.9571954199, "bikeId" : "pgdAVg", "current_time" : "2017-10-19 23:19:19", "source" : "ofo", "lng" : 116.3926501736 } >
如何通過mongoexport導出"bikeId" : "pgdAVg"的數據,我導出了json和csv兩種類型的數據;
#導出類型為json,數據庫:mapdb,集合:bike 字段:bikeId,lat,lng,current_time,source ,條件為source字段為ofo第一條數據 mongoexport --port 27030 -u sa -p Expressin@0618 -d mapdb -c bike -f bikeId,lat,lng,current_time,source --type=json -o bike.csv --query='{"source":"ofo"}' --limit=1 #導出類型為csv,數據庫:mapdb,集合:bike 字段:bikeId,lat,lng,current_time,source ,條件為source字段為ofo第一條數據 mongoexport --port 27030 -u sa -p Expressin@0618 -d mapdb -c bike -f bikeId,lat,lng,current_time,source --type=csv -o bike.csv --query='{"source":"ofo"}' --limit=1
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。