MongoDB Sharding Cluster分片集群

QQ图片20200506140312.png

  • 10个实例: 端口号为38017-38026
  • configserver:3台构成的复制集(1主两从,不支持arbiter)38018-38020(复制集名字configsvr)
  • sh1:38021-23(1主两从,其中一个节点为arbiter,复制集名字sh1)
  • sh2:38024-26(1主两从,其中一个节点为arbiter,复制集名字sh2)

配置过程

  • 以下操作均在mangod用户操作,无需修改目录权限

目录创建

#shard复制集配置
mkdir -p /mongodb/38021/conf  /mongodb/38021/log  /mongodb/38021/data
mkdir -p /mongodb/38022/conf  /mongodb/38022/log  /mongodb/38022/data
mkdir -p /mongodb/38023/conf  /mongodb/38023/log  /mongodb/38023/data
mkdir -p /mongodb/38024/conf  /mongodb/38024/log  /mongodb/38024/data
mkdir -p /mongodb/38025/conf  /mongodb/38025/log  /mongodb/38025/data
mkdir -p /mongodb/38026/conf  /mongodb/38026/log  /mongodb/38026/data

修改配置文件

#sh1
cat > /mongodb/38021/conf/mongodb.conf<<EOF
systemLog:
  destination: file
  path: /mongodb/38021/log/mongodb.log
  logAppend: true
storage:
  journal:
    enabled: true
  dbPath: /mongodb/38021/data
  directoryPerDB: true
  #engine: wiredTiger
  wiredTiger:
    engineConfig:
      cacheSizeGB: 1
      directoryForIndexes: true
    collectionConfig:
      blockCompressor: zlib
    indexConfig:
      prefixCompression: true
net:
  bindIp: 10.0.0.51,127.0.0.1
  port: 38021
replication:
  oplogSizeMB: 2048
  replSetName: sh1
sharding:
  clusterRole: shardsvr
processManagement: 
  fork: true
EOF
cp  /mongodb/38021/conf/mongodb.conf  /mongodb/38022/conf/
cp  /mongodb/38021/conf/mongodb.conf  /mongodb/38023/conf/
sed 's#38021#38022#g' /mongodb/38022/conf/mongodb.conf -i
sed 's#38021#38023#g' /mongodb/38023/conf/mongodb.conf -i

#sh2
cat > /mongodb/38024/conf/mongodb.conf<<EOF
systemLog:
  destination: file
  path: /mongodb/38024/log/mongodb.log
  logAppend: true
storage:
  journal:
    enabled: true
  dbPath: /mongodb/38024/data
  directoryPerDB: true
  wiredTiger:
    engineConfig:
      cacheSizeGB: 1
      directoryForIndexes: true
    collectionConfig:
      blockCompressor: zlib
    indexConfig:
      prefixCompression: true
net:
  bindIp: 10.0.0.51,127.0.0.1
  port: 38024
replication:
  oplogSizeMB: 2048
  replSetName: sh2
sharding:
  clusterRole: shardsvr
processManagement: 
  fork: true
EOF

cp  /mongodb/38024/conf/mongodb.conf  /mongodb/38025/conf/
cp  /mongodb/38024/conf/mongodb.conf  /mongodb/38026/conf/
sed 's#38024#38025#g' /mongodb/38025/conf/mongodb.conf -i
sed 's#38024#38026#g' /mongodb/38026/conf/mongodb.conf -i

启动所有节点

mongod -f  /mongodb/38021/conf/mongodb.conf
mongod -f  /mongodb/38022/conf/mongodb.conf
mongod -f  /mongodb/38023/conf/mongodb.conf
mongod -f  /mongodb/38024/conf/mongodb.conf
mongod -f  /mongodb/38025/conf/mongodb.conf
mongod -f  /mongodb/38026/conf/mongodb.conf

搭建复制集

  • sh1
mongo --port 38021 admin

config = {_id: 'sh1', members: [
  {_id: 0, host: '10.0.0.51:38021'},
  {_id: 1, host: '10.0.0.51:38022'},
  {_id: 2, host: '10.0.0.51:38023',"arbiterOnly":true}]
}
rs.initiate(config)
  • sh2
mongo --port 38024 admin

config = {_id: 'sh2', members: [
  {_id: 0, host: '10.0.0.51:38024'},
  {_id: 1, host: '10.0.0.51:38025'},
  {_id: 2, host: '10.0.0.51:38026',"arbiterOnly":true}]
}
rs.initiate(config)

config节点

创建目录

mkdir -p /mongodb/38018/conf  /mongodb/38018/log  /mongodb/38018/data
mkdir -p /mongodb/38019/conf  /mongodb/38019/log  /mongodb/38019/data
mkdir -p /mongodb/38020/conf  /mongodb/38020/log  /mongodb/38020/data

修改配置文件

cat > /mongodb/38018/conf/mongodb.conf <<EOF
systemLog:
  destination: file
  path: /mongodb/38018/log/mongodb.conf
  logAppend: true
storage:
  journal:
    enabled: true
  dbPath: /mongodb/38018/data
  directoryPerDB: true
  #engine: wiredTiger
  wiredTiger:
    engineConfig:
      cacheSizeGB: 1
      directoryForIndexes: true
    collectionConfig:
      blockCompressor: zlib
    indexConfig:
      prefixCompression: true
net:
  bindIp: 10.0.0.51,127.0.0.1
  port: 38018
replication:
  oplogSizeMB: 2048
  replSetName: configReplSet
sharding:
  clusterRole: configsvr
processManagement:
  fork: true
EOF

cp /mongodb/38018/conf/mongodb.conf /mongodb/38019/conf/
cp /mongodb/38018/conf/mongodb.conf /mongodb/38020/conf/
sed 's#38018#38019#g' /mongodb/38019/conf/mongodb.conf -i
sed 's#38018#38020#g' /mongodb/38020/conf/mongodb.conf -i

启动所有节点

mongod -f /mongodb/38018/conf/mongodb.conf
mongod -f /mongodb/38019/conf/mongodb.conf
mongod -f /mongodb/38020/conf/mongodb.conf

搭建复制集

  • configserver可以是一个节点,官方建议复制集.configserver不能有arbiter
  • 新版本中,要求必须是复制集.mongodb3.4之后,虽然要求config server为replica set,但是不支持arbiter
mongo --port 38018 admin

config = {_id: 'configReplSet', members: [
  {_id: 0, host: '10.0.0.51:38018'},
  {_id: 1, host: '10.0.0.51:38019'},
  {_id: 2, host: '10.0.0.51:38020'}]
}
rs.initiate(config)

mongos节点

创建目录

mkdir -p /mongodb/38017/conf /mongodb/38017/log

修改配置文件

cat >/mongodb/38017/conf/mongos.conf<<EOF
systemLog:
  destination: file
  path: /mongodb/38017/log/mongos.log
  logAppend: true
net:
  bindIp: 10.0.0.51,127.0.0.1
  port: 38017
sharding:
  configDB: configReplSet/10.0.0.51:38018,10.0.0.51:38019,10.0.0.51:38020
processManagement:
  fork: true
EOF

启动mongos

mongos -f /mongodb/38017/conf/mongos.conf

分片集群

  • 连接到mongs的admin数据库,添加分片
#mongod用户操作
mongo 10.0.0.51:38017/admin

db.runCommand( { addshard : "sh1/10.0.0.51:38021,10.0.0.51:38022,10.0.0.51:38023",name:"shard1"} )
db.runCommand( { addshard : "sh2/10.0.0.51:38024,10.0.0.51:38025,10.0.0.51:38026",name:"shard2"} )

#列出分片
sh.status()
db.runCommand( { listshards : 1 } )

使用分片集群

RANGE分片配置测试

  • 激活数据库分片功能
#登录
mongo --port 38017 admin

#激活数据库分片功能
db.runCommand( { enablesharding : "test" } )
  • 分片验证
-- 创建索引
use test
db.vast.ensureIndex( { id: 1 } )

-- 开启分片
use admin
db.runCommand( { shardcollection : "test.vast",key : {id: 1} } )

-- 集合分片验证
use test
for(i=1;i<1000000;i++){ db.vast.insert({"id":i,"name":"shenzheng","age":70,"date":new Date()}); }
db.vast.stats()

-- 分片结果测试
-- 当数据量达到一定的量时(默认64MB),会将一半的数据迁移到另一个节点
-- shard1
mongo --port 38021
db.vast.count();

-- shard2:
mongo --port 38024
db.vast.count();

Hash分片配置测试

  • 激活数据库分片功能
#登录
mongo --port 38017 admin

#激活数据库分片功能
db.runCommand( { enablesharding : "test2" } )
  • 分片验证
-- 创建索引
use test2
db.vast.ensureIndex( { id: "hashed" } )

-- 开启分片
use admin
sh.shardCollection( "test2.vast", { id: "hashed" } )

-- 集合分片验证
use test2
for(i=1;i<100000;i++){ db.vast.insert({"id":i,"name":"shenzheng","age":70,"date":new Date()}); }

-- 分片结果测试
-- 当数据量录入时,会平均分配到各个节点
-- shard1
mongo --port 38021
use test2
db.vast.count();

-- shard2
mongo --port 38024
use test2
db.vast.count();

管理性操作

  • db.runCommand({ isdbgrid : 1}) : 当前库下,判断是否Shard集群
  • db.runCommand({ listshards : 1}) : use admin,列出所有分片信息
  • db.databases.find( { "partitioned": true } ) : use config,列出开启分片的数据库
  • db.databases.find() : use config,列出开启分片的数据库
  • db.collections.find().pretty() : use config,查看分片的片键
  • db.printShardingStatus() : 查看分片的详细信息
  • sh.status() : 查看分片的详细信息
  • sh.getBalancerState() : 确认blance是否在工作
  • db.runCommand( { removeShard: "shard2" } ) : 删除shard2节点(谨慎操作,删除操作一定会立即触发blancer,发生数据迁移)

balancer操作

mongos的一个重要功能,自动巡查所有shard节点上的chunk的情况,自动做chunk迁移

  • balancer什么时候工作
  1. 自动运行,会检测系统不繁忙的时候做迁移
  2. 在做节点删除的时候,立即开始迁移工作
  3. balancer只能在预设定的时间窗口内运行
  • 有需要时可以关闭和开启blancer(备份的时候)
-- 开启blancer
sh.stopBalancer()
-- 关闭blancer
sh.startBalancer()

自定义 自动平衡进行的时间段

-- 登录
mongo --port 38017 admin

use config
-- 开启Balancer工作
sh.setBalancerState( true )
-- 设置3点到5点进行自动平衡
db.settings.update({ _id : "balancer" }, { $set : { activeWindow : { start : "3:00", stop : "5:00" } } }, true )

-- 查看结果
sh.getBalancerWindow()
sh.status()

关于集合的balancer

  • sh.disableBalancing("students.grades") : 关闭某个集合的balancer
  • sh.enableBalancing("students.grades") : 打开某个集合的balancer

备份恢复

  • mongoexport/mongoimport : 导入/导出的是JSON格式或者CSV格式,用于异构平台迁移(mysql <--> mongodb),同平台跨大版本(mongodb2 -> mongodb3)
  • mongodump/mongorestore : 导入/导出的是BSON格式,用于日常备份恢复时使用

JSON可读性强但体积较大,BSON则是二进制文件,体积小但对人类几乎没有可读性.在一些mongodb版本之间,BSON格式可能会随版本不同而有所不同,所以不同版本之间用mongodump/mongorestore可能不会成功,具体要看版本之间的兼容性.当无法使用BSON进行跨版本的数据迁移的时候,使用JSON格式即mongoexport/mongoimport是一个可选项.跨版本的mongodump/mongorestore个人并不推荐,实在要做请先检查文档看两个版本是否兼容(大部分时候是的)JSON虽然具有较好的跨版本通用性,但其只保留了数据部分,不保留索引,账户等其他基础信息,使用时应该注意

导出工具mongoexport

Mongodb中的mongoexport工具可以把一个collection导出成JSON格式或CSV格式的文件.可以通过参数指定导出的数据项,也可以根据指定的条件导出数据

  • mongoexport --help : 查看帮助
  • -h : 指明数据库宿主机的IP
  • -u : 指明数据库的用户名
  • -p : 指明数据库的密码
  • -d : 指明数据库的名字
  • -c : 指明collection的名字
  • -f : 指明要导出列
  • -o : 指明到导出的文件名
  • -q : 指明导出数据的过滤条件
  • --authenticationDatabase admin : 验证库信息

单表备份

#单表备份至json格式
#备份文件的名字可以自定义,默认导出了JSON格式的数据
mongoexport -uroot -p123456 --port 27017 --authenticationDatabase admin -d 1997sty -c log -o /mongodb/log.json

#单表备份至csv格式
#如果我们需要导出CSV格式的数据,则需要使用 --type=csv 参数
mongoexport -uroot -p123456 --port 27017 --authenticationDatabase admin -d 1997sty -c log --type=csv -f uid,name,age,date -o /mongodb/log.csv

导入工具mongoimport

Mongodb中的mongoimport工具可以把一个特定格式文件中的内容导入到指定的collection中.该工具可以导入JSON格式数据,也可以导入CSV格式数据.具体使用如下所示

  • mongoimport --help : 查看帮助
  • -h : 指明数据库宿主机的IP
  • -u : 指明数据库的用户名
  • -p : 指明数据库的密码
  • -d : 指明数据库的名字
  • -c : 指明collection的名字
  • -f : 指明要导入列
  • --headerline : 指明第一行是列名,不需要导入
  • -j : 要运行的插入操作数(并发操作,提升效率,默认为1)
  • --numInsertionWorkers= : 要运行的插入操作数(并发操作,提升效率,默认为1)

单表恢复

#恢复json格式表数据到log1
mongoimport -uroot -p123456 --port 27017 --authenticationDatabase admin -d 1997sty -c log1 /mongodb/log.json

#如果要导入CSV格式文件中的内容,则需要通过--type参数指定导入格式
#恢复csv格式的文件到log2
mongoimport -uroot -p123456 --port 27017 --authenticationDatabase admin -d 1997sty -c log2 --type=csv --headerline --file /mongodb/log.csv

#恢复csv格式的文件到log3
mongoimport -uroot -p123456 --port 27017 --authenticationDatabase admin -d 1997sty -c log3 --type=csv -f id,name,age,date --file /mongodb/log1.csv

异构平台迁移案例

mysql数据库下city表进行导出,导入到mongodb

  • mysql开启安全路径
#插入信息后重启数据库
vi /etc/my.cnf

secure-file-priv=/tmp
  • 导出mysql的city表数据到/tmp目录下
select * from world.city into outfile '/tmp/city.csv' fields terminated by ',';
  • 处理备份文件
#根据表结构添加第一行列名信息
vim /tmp/city.csv

ID,Name,CountryCode,District,Population
  • 在mongodb中导入备份
mongoimport -uroot -p123456 --port 27017 --authenticationDatabase admin -d world -c city --type=csv --headerline --file  /tmp/city1.csv
  • 验证数据
#登录后查看结果
use world
db.city.find();

mysql多表大量迁移

#mysql单表导出
select * from world.city into outfile '/tmp/world_city.csv' fields terminated by ',';

#mysql多表导出
#使用infomation_schema.columns + information_schema.tables组合拼凑出所有表的导出语句
select concat("select * from ",table_schema,".",table_name ," into outfile '/tmp/",table_schema,"_",table_name,".csv' fields terminated by ',';") from information_schema.tables where table_schema ='world';

mysql导出csv

select * from test_info   
into outfile '/tmp/test.csv'   
fields terminated by ','    ------字段间以,号分隔
optionally enclosed by '"'   ------字段用"号括起
escaped by '"'           ------字段中使用的转义符为"
lines terminated by '\r\n';  ------行以\r\n结束

mysql导入csv

load data infile '/tmp/test.csv'
into table test_info
fields terminated by ','
optionally enclosed by '"'
escaped by '"'
lines terminated by '\r\n';

导出工具mongodump和导入工具mongorestore

mongodump能够在Mongodb运行时进行备份,它的工作原理是对运行的Mongodb做查询,然后将所有查到的文档写入磁盘.但是存在的问题时使用mongodump产生的备份不一定是数据库的实时快照,如果我们在备份时对数据库进行了写入操作,则备份出来的文件可能不完全和Mongodb实时数据相等.另外在备份时可能会对其它客户端性能产生不利的影响

  • mongodump --help : 查看帮助
  • -h : 指明数据库宿主机的IP
  • -u : 指明数据库的用户名
  • -p : 指明数据库的密码
  • -d : 指明数据库的名字
  • -c : 指明collection的名字
  • -o : 指明到要导出的文件名
  • -q : 指明导出数据的过滤条件
  • -j : 要并行转储的集合数(并发操作,提升效率,默认为4)
  • --numParallelCollections= : 要并行转储的集合数(并发操作,提升效率,默认为4)
  • --oplog : 备份的同时备份oplog
#全库备份
mongodump -uroot -p123456 --port 27017 --authenticationDatabase admin -o /mongodb/backup

#备份world库
mongodump -uroot -p123456 --port 27017 --authenticationDatabase admin -d world -o /mongodb/backup/

#备份1997sty库下的log集合
mongodump -uroot -p123456 --port 27017 --authenticationDatabase admin -d 1997sty -c log -o /mongodb/backup/

#压缩备份
mongodump -uroot -p123456 --port 27017 --authenticationDatabase admin -o /mongodb/backup/ --gzip
mongodump -uroot -p123456 --port 27017 --authenticationDatabase admin -d 1997sty -o /mongodb/backup/ --gzip
mongodump -uroot -p123456 --port 27017 --authenticationDatabase admin -d 1997sty -c log -o /mongodb/backup/ --gzip

导入工具mongorestore应用

#恢复world库
mongorestore -uroot -p123456 --port 27017 --authenticationDatabase admin -d world /mongodb/backup/world

#恢复1997sty库下的t1集合
mongorestore -uroot -p123456 --port 27017 --authenticationDatabase admin -d 1997sty -c t1 /mongodb/backup/1997sty/log.bson

# --drop表示恢复的时候把之前的集合drop掉(危险)
mongorestore -uroot -p123456 --port 27017 --authenticationDatabase admin -d 1997sty --drop /mongodb/backup/1997sty

mongodump和mongorestore高级企业应用(--oplog)

  • --oplog : 使用oplog拍摄时间点快照
  • 这是replica set或者master/slave模式专用
  • 在replica set中oplog是一个定容集合(capped collection),它的默认大小是磁盘空间的5%(可以通过--oplogSizeMB参数修改)
  • 位于local库的db.oplog.rs,有兴趣可以看看里面到底有些什么内容
  • 其中记录的是整个mongod实例一段时间内数据库的所有变更(插入/更新/删除)操作
  • 当空间用完时新记录自动覆盖最老的记录
  • 其覆盖范围被称作oplog时间窗口.需要注意的是,因为oplog是一个定容集合,所以时间窗口能覆盖的范围会因为你单位时间内的更新次数不同而变化
  • 想要查看当前的oplog时间窗口预计值,可以使用rs.printReplicationInfo()命令
#查看oplog内容
use local
db.oplog.rs.find().pretty()

-- op参数
-- i insert
-- u update
-- d delete
-- c db cmd


test:PRIMARY> rs.printReplicationInfo()
configured oplog size:   2048MB <--集合大小
log length start to end: 281479secs (78.19hrs) <--预计窗口覆盖时间
oplog first event time:  Mon May 04 2020 12:45:30 GMT+0800 (CST)
oplog last event time:   Thu May 07 2020 18:56:49 GMT+0800 (CST)
now:                     Thu May 07 2020 18:56:51 GMT+0800 (CST)

oplog企业级应用

oplog 配合mongodump实现热备

#作用 --oplog 会记录备份过程中的数据变化.会以oplog.bson保存下来
mongodump --port 28017 --oplog -o /mongodb/backup

#恢复
mongorestore --port 28017 --oplogReplay /mongodb/backup

故障恢复模拟

  1. 停应用
  2. 找测试库
  3. 恢复昨天晚上全备
  4. 截取全备之后找到误删除时间点的oplog,并恢复到测试库
  5. 将误删除表导出,恢复到生产库

模拟数据

#登录数据库
mongo --port 28017 admin

-- 进入sty1997库,生成测试数据

use sty1997
for(var i = 1 ;i < 20; i++) {
 db.t1.insert({a: i});
}

对数据进行全量备份

#mongod用户下,备份数据
#--oplog功能:在备份同时,将备份过程中产生的日志进行备份
#文件必须存放在/mongodb/backup下,自动命令为oplog.bson
mongodump --port 28017 --oplog -o /mongodb/backup

添加增量数据

for(var i = 21 ;i < 40; i++) {
 db.t1.insert({a: i});
}

删除t1表

use sty1997
db.t1.drop()

找到误操作时间点

use local
db.oplog.rs.find({op:"c"}).pretty()
{
        "ts" : Timestamp(1588852870, 2),
        "t" : NumberLong(1),
        "h" : NumberLong("5637878556167102522"),
        "v" : 2,
        "op" : "c",
        "ns" : "sty1997.$cmd",
        "ui" : UUID("4973c701-f243-41ac-a3a1-3239f9b774c7"),
        "wall" : ISODate("2020-05-07T12:01:10.683Z"),
        "o" : {
                "drop" : "t1"
        }
}

备份现有的oplog.rs表

mongodump --port 28017 -d local -c oplog.rs -o /mongodb/backup

处理oplog.bson文件

#替换原有oplog.bson文件
cp /mongodb/backup/local/oplog.rs.bson /mongodb/backup/oplog.bson
#删除local目录
rm -rf /mongodb/backup/local/

恢复数据

mongorestore --port 28017 --oplogReplay --oplogLimit "1588852870:2" --drop /mongodb/backup/

分片集群的备份思路

你要备份什么

  • config server
  • shard 节点

备份有什么困难和问题

  • chunk迁移的问题,人为控制在备份的时候,避开迁移的时间窗口
  • shard节点之间的数据不在同一时间点,选业务量较少的时候,可以在备份时将从节点移除,备份完成后再加入,保证数据一致性