一、介绍
Mongodb 是 NoSql ,属于文档存储,同类型的文档存储还有ES
Mongodb 是介于关系型数据库和非关系性数据库之间,故有强大的关系型数据库功能 ( 查询功能、强一致性、二级索引) 和关系性数据库 ( 灵活模式、扩展性、性能 )
Mongodb 与 Redis 区别:没有固定的行列组织数据结构
表 叫做 集合 数据行 叫做 文档
Mongodb 存档就是文档 ,一个文档就是一个 json,相当于 mysql 的一行中数据
二、部署Mongodb
官网:Download MongoDB Community Server | MongoDB
1、查看操作系统内核版本
# 操作系统内核版本
uname -a
# 操作系统发行版本
cat /etc/redhat-release
2、下载 mongodb_4.0.28
[root@db1 opt]# yun install -y wget
[root@db1 ~]# cd /opt/src
[root@db1 src]# wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-4.0.28.tgz
3、解压目录
# -C 指定解压目录
[root@db1 src]# tar -zxvf mongodb-linux-x86_64-rhel70-4.0.28.tgz -C /opt/
# 修改名字
[root@db1 src]# cd /opt
[root@db1 opt]# mv mongodb-linux-x86_64-rhel70-4.0.28/ mongodb-4.0.28
# 软连接
[root@db1 opt]# ln -s mongodb-4.0.28/ mongodb
4、mongodb主要使用的就是bin目录的二进制文件,加载到环境变量中
[root@db1 mongodb]# ll /opt/mongodb/
drwxr-xr-x 2 root root 70 10月 24 11:32 bin
-rw-r--r-- 1 root root 30608 9月 29 19:18 LICENSE-Community.txt
-rw-r--r-- 1 root root 16726 9月 29 19:18 MPL-2
-rw-r--r-- 1 root root 1977 9月 29 19:18 README
-rw-r--r-- 1 root root 77913 9月 29 19:18 THIRD-PARTY-NOTICES
[root@db1 mongodb]# ll /opt/mongodb/bin/
-rwxr-xr-x 1 root root 15205 9月 29 19:18 install_compass
-rwxr-xr-x 1 root root 58599688 9月 29 20:05 mongo
-rwxr-xr-x 1 root root 110063096 9月 29 20:04 mongod
-rwxr-xr-x 1 root root 76724856 9月 29 20:05 mongos
5、配置环境变量
[root@db1 mongodb]# echo "export PATH=\$PATH:/opt/mongodb/bin/" >> /etc/profile
# 使配置文件生效
[root@db1 mongodb]# source /etc/profile
6、创建 data 目录
[root@db1 opt]# mkdir -p /opt/mongodb/{conf,logs,data}
7、启动mongodb ,验证是否能启动
[root@db1 conf]# mongod --dbpath /opt/mongodb/data/ --logpath /opt/mongodb/logs/mongodb.log --logappend --port 27017 --fork
注:可以添加-bind_ip 0.0.0.0 选项,让所有的用户访问mongodb,可以不加
[root@db1 conf]# ps -ef |grep mongodb
root 2830 1 0 14:19 ? 00:00:03 mongod --dbpath /opt/mongodb/data/ --logpath /opt/mongodb/logs/mongodb.log --logappend --port 27017 --bind_ip 0.0.0.0 --fork
root 3180 2075 0 14:25 pts/2 00:00:00 grep --color=auto mongodb
[root@db1 conf]# ll /opt/mongodb/data/ # 第一次启动生成的初始化文件
总用量 272
-rw------- 1 root root 20480 10月 24 14:19 collection-0--3238775234172203344.wt
-rw------- 1 root root 36864 10月 24 14:20 collection-2--3238775234172203344.wt
-rw------- 1 root root 4096 10月 24 14:07 collection-4--3238775234172203344.wt
drwx------ 2 root root 197 10月 24 14:26 diagnostic.data
-rw------- 1 root root 20480 10月 24 14:19 index-1--3238775234172203344.wt
-rw------- 1 root root 36864 10月 24 14:20 index-3--3238775234172203344.wt
-rw------- 1 root root 4096 10月 24 14:07 index-5--3238775234172203344.wt
-rw------- 1 root root 4096 10月 24 14:20 index-6--3238775234172203344.wt
drwx------ 2 root root 110 10月 24 14:19 journal
-rw------- 1 root root 20480 10月 24 14:19 _mdb_catalog.wt
-rw------- 1 root root 5 10月 24 14:19 mongod.lock
-rw------- 1 root root 36864 10月 24 14:21 sizeStorer.wt
-rw------- 1 root root 114 10月 24 14:06 storage.bson
-rw------- 1 root root 50 10月 24 14:06 WiredTiger
-rw------- 1 root root 4096 10月 24 14:19 WiredTigerHS.wt
-rw------- 1 root root 21 10月 24 14:06 WiredTiger.lock
-rw------- 1 root root 1467 10月 24 14:26 WiredTiger.turtle
-rw------- 1 root root 69632 10月 24 14:26 WiredTiger.wt
[root@db1 conf]# ll /opt/mongodb/logs/
总用量 192
-rw------- 1 root root 90288 10月 24 14:26 mongodb.log
[root@db1 conf]#
8、配置文件
--系统日志有关
systemLog:
destination: file --定义日志
path: "/var/log/mongo/mongod.log" --日志位置
quiet: true --安静输出
logAppend: true --日志以追加模式记录
--数据存储有关
storage: --定义数据存储
journal: --是不是开启redo
enabled
dbPath: "/var/lib/mongo" --数据位置
directoryPerDB: true --设置每个数据库将被保存在一个单独的目录
indexBuildRetry: false --在一个索引创建失败后启动mongod,可以使用storage.indexBuildRetry or --noIndexBuildRetry跳过索引创建来启动
preallocDataFiles: true
nsSize: 16 --设置数据库.ns文件大小(MB)
--进程控制
processManagement:
fork: true --后台守护进程
pidFilePath: "/var/run/mongodb/mongod.pid" --pid文件位置,默认不指定在/data目录下
--网络有关的
net:
bindIp: 192.168.11.52 --监听端口,如果不配置这行就是监听0.0.0.0
port: 27017 --端口号,默认不配置端口号,是27017
http:
enabled: true
RESTInterfaceEnabled: false
--安全认证有关,比mysql更加的安全,有认证库
security:
keyFile: "/var/lib/mongo/mongodb-keyfile"
clusterAuthMode: "keyFile"
authorization: "disabled" --是否打开用户名密码验证
--集群相关的
replication:
oplogSizeMB: 50
replSetName: "repl_test"
secondaryIndexPrefetch: "all"
[root@db1 conf]# cat /opt/mongodb/conf/mongo.conf # 先简单配置
storage:
dbPath: /opt/mongodb/data/
journal:
enabled: true
systemLog:
destination: file
logAppend: true
path: /opt/mongodb/logs/mongodb.log
processManagement:
fork: true
net:
bindIp: 192.168.86.5,127.0.0.1
port: 27017
9、关闭之前启动的mongodb,添加systemcd 管理,并使用自定义配置文件进行启动
# 关闭mongodb
[root@db1 conf]# mongod -f /opt/mongodb/conf/mongo.conf --shutdown
killing process with pid: 3755
# 启动 mongodb
[root@db1 mongodb]# cat /etc/systemd/system/mongod.service
[Unit]
Description=mongodb
After=network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
User=root
Group=root
ExecStart=/opt/mongodb/bin/mongod --config /opt/mongodb/conf/mongo.conf
ExecReload=/bin/kill -s HUP
ExecStop=/opt/mongodb/bin/mongod --config /opt/mongodb/conf/mongo.conf --shutdown
PrivateTmp=true
[root@db1 mongodb]# systemctl daemon-reload
[root@db1 mongodb]# systemctl start mongod.service
10、登陆mongo
[root@db1 mongodb]# mongo
MongoDB shell version v4.0.28
connecting to: mongodb://127.0.0.1:27017/?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("a1d7a2ab-ac77-47d6-bf1c-23e469d9ad2a") }
MongoDB server version: 4.0.28
Server has startup warnings:
2022-10-24T15:42:34.696+0800 I CONTROL [initandlisten]
2022-10-24T15:42:34.696+0800 I CONTROL [initandlisten] ** WARNING: Access control is not enabled for the database.
2022-10-24T15:42:34.696+0800 I CONTROL [initandlisten] ** Read and write access to data and configuration is unrestricted.
2022-10-24T15:42:34.696+0800 I CONTROL [initandlisten] ** WARNING: You are running this process as the root user, which is not recommended.
2022-10-24T15:42:34.696+0800 I CONTROL [initandlisten]
2022-10-24T15:42:34.696+0800 I CONTROL [initandlisten]
2022-10-24T15:42:34.696+0800 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.
2022-10-24T15:42:34.696+0800 I CONTROL [initandlisten] ** We suggest setting it to 'never'
2022-10-24T15:42:34.696+0800 I CONTROL [initandlisten]
2022-10-24T15:42:34.696+0800 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.
2022-10-24T15:42:34.696+0800 I CONTROL [initandlisten] ** We suggest setting it to 'never'
2022-10-24T15:42:34.696+0800 I CONTROL [initandlisten]
---
Enable MongoDB's free cloud-based monitoring service, which will then receive and display
metrics about your deployment (disk utilization, CPU, operation statistics, etc).
The monitoring data will be available on a MongoDB website with a unique URL accessible to you
and anyone you share the URL with. MongoDB may use this information to make product
improvements and to suggest MongoDB products and deployment options to you.
To enable free monitoring, run the following command: db.enableFreeMonitoring()
To permanently disable this reminder, run the following command: db.disableFreeMonitoring()
---
>
[root@db1 data]# ll
总用量 188
drwx------ 4 root root 37 10月 25 06:12 admin
drwx------ 4 root root 37 10月 25 06:12 config
drwx------ 2 root root 216 10月 25 09:13 diagnostic.data
drwx------ 4 root root 37 10月 25 08:47 jerry
drwx------ 2 root root 110 10月 25 09:06 journal #日志
drwx------ 4 root root 37 10月 25 05:54 local
-rw------- 1 root root 36864 10月 25 09:13 _mdb_catalog.wt
-rw------- 1 root root 0 10月 25 09:13 mongod.lock
-rw------- 1 root root 36864 10月 25 09:13 sizeStorer.wt
-rw------- 1 root root 114 10月 25 05:54 storage.bson
-rw------- 1 root root 45 10月 25 05:54 WiredTiger
-rw------- 1 root root 4096 10月 25 09:13 WiredTigerLAS.wt
-rw------- 1 root root 21 10月 25 05:54 WiredTiger.lock
-rw------- 1 root root 1073 10月 25 09:13 WiredTiger.turtle
-rw------- 1 root root 98304 10月 25 09:13 WiredTiger.wt # .wt使用WiredTiger存储引擎存储的
三、命令集合
1、增删改查(库、集合、文档)
只有show databases(show dbs)、 use 库、show tables(show collections); 跟 mysl 一样,其他的都不一样
输入mongo后,提示的信息说的是没有验证之类的,好在mongodb只允许本地登陆
[root@db1 mongodb]# mongo
MongoDB shell version v4.0.28
connecting to: mongodb://127.0.0.1:27017/?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("a1d7a2ab-ac77-47d6-bf1c-23e469d9ad2a") }
MongoDB server version: 4.0.28
Server has startup warnings:
2022-10-24T15:42:34.696+0800 I CONTROL [initandlisten]
2022-10-24T15:42:34.696+0800 I CONTROL [initandlisten] ** WARNING: Access control is not enabled for the database.
2022-10-24T15:42:34.696+0800 I CONTROL [initandlisten] ** Read and write access to data and configuration is unrestricted.
2022-10-24T15:42:34.696+0800 I CONTROL [initandlisten] ** WARNING: You are running this process as the root user, which is not recommended.
2022-10-24T15:42:34.696+0800 I CONTROL [initandlisten]
2022-10-24T15:42:34.696+0800 I CONTROL [initandlisten]
2022-10-24T15:42:34.696+0800 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.
2022-10-24T15:42:34.696+0800 I CONTROL [initandlisten] ** We suggest setting it to 'never'
2022-10-24T15:42:34.696+0800 I CONTROL [initandlisten]
2022-10-24T15:42:34.696+0800 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.
2022-10-24T15:42:34.696+0800 I CONTROL [initandlisten] ** We suggest setting it to 'never'
2022-10-24T15:42:34.696+0800 I CONTROL [initandlisten]
---
Enable MongoDB's free cloud-based monitoring service, which will then receive and display
metrics about your deployment (disk utilization, CPU, operation statistics, etc).
The monitoring data will be available on a MongoDB website with a unique URL accessible to you
and anyone you share the URL with. MongoDB may use this information to make product
improvements and to suggest MongoDB products and deployment options to you.
To enable free monitoring, run the following command: db.enableFreeMonitoring()
To permanently disable this reminder, run the following command: db.disableFreeMonitoring()
---
> show databases;
admin 0.000GB
config 0.000GB
local 0.000GB
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
> use admin
switched to db admin
> show tables;
system.version
>
这三个库是mongodb相关的系统库,不能删除,不能修改
admin 0.000GB # 系统相关的
config 0.000GB # 配置相关的
local 0.000GB # 日志相关的
db 命令,代表你在哪个库下,每次第一次登陆,会进入一个临时库 test 库
> db
test
如何指定库登陆
[root@db1 mongodb]# mongo admin
> db
admin
[root@db1 mongodb]# mongo admin1 # 库不存在直接创建
> db
admin1
创建数据库直接use,如果不存在则创建,存在则切换到
> use dev
switched to db dev
> db
dev
集合(表)中插入数据,给 jerry 表插入一条文档(数据行)
> db.jerry.insert({name:"hello"})
WriteResult({ "nInserted" : 1 })
>
只要数据库中存在表,则 数据库会自动保存
> show databases;
admin 0.000GB
config 0.000GB
dev 0.000GB
local 0.000GB
> use abc
switched to db abc
> show databases;
admin 0.000GB
config 0.000GB
dev 0.000GB
local 0.000GB
>
查集合中的文档 db.集合.find()
> use dev
switched to db dev
> show collections;
jerry
> db.jerry.find()
{ "_id" : ObjectId("635647932670e9afdaddee05"), "name" : "hello" }
> db.jerry.insert({name:"world"})
WriteResult({ "nInserted" : 1 })
> db.jerry.find()
{ "_id" : ObjectId("635647932670e9afdaddee05"), "name" : "hello" }
{ "_id" : ObjectId("6356495d2670e9afdaddee06"), "name" : "world" }
>
help() 函数,帮助文档
> db.help()
table 命令补全
> db.
Display all 103 possibilities? (y or n)
db.adminCommand( db.fsyncUnlock( db.grantPrivilegesToRole( db.revokePrivilegesFromRole(
db.aggregate( db.getCollection( db.grantRolesToRole( db.revokeRolesFromRole(
db.auth( db.getCollectionInfos( db.grantRolesToUser( db.revokeRolesFromUser(
db.changeUserPassword( db.getCollectionNames( db.group( db.runCommand(
db.cloneCollection( db.getFreeMonitoringStatus( db.groupcmd(
createCollection 创建集合
> db.createCollection("zxy")
{ "ok" : 1 }
> show tables;
zxy
> db.zxy.find()
>
修改表名 renameCollection
> db.zxy.renameCollection("biao1")
{ "ok" : 1 }
删除表
> show tables;
zxy
> db.zxy.drop()
true
查看版本
> db.version()
4.0.28
>
[root@db1 ~]# mongo -version
MongoDB shell version v4.0.28
git version: af1a9dc12adcfa83cc19571cb3faba26eeddac92
OpenSSL version: OpenSSL 1.0.1e-fips 11 Feb 2013
allocator: tcmalloc
modules: none
build environment:
distmod: rhel70
distarch: x86_64
target_arch: x86_64
库状态,可以看库占用空间大小
> show databases;
admin 0.000GB
config 0.000GB
dev 0.000GB
local 0.000GB
> use admin
> db.stats()
{
"db" : "admin",
"collections" : 1,
"views" : 0,
"objects" : 1,
"avgObjSize" : 59,
"dataSize" : 59,
"storageSize" : 16384,
"numExtents" : 0,
"indexes" : 1,
"indexSize" : 16384,
"fsUsedSize" : 10771628032,
"fsTotalSize" : 40778076160,
"ok" : 1
}
显示连接的地址
> db.getMongo()
connection to 127.0.0.1:27017
>
删除库 use 库 db.dropDatabase()
> use dev
switched to db dev
> show tables;
jerry
> db.dropDatabase()
{ "dropped" : "dev", "ok" : 1 }
> db
dev
> show databases;
admin 0.000GB
config 0.000GB
local 0.000GB
>
集合操作 db.getCollectionNames()
> use app
switched to db app
> db.createCollection('a')
{ "ok" : 1 }
> db.createCollection('b')
{ "ok" : 1 }
> show collections
a
b
> db.getCollectionNames()
[ "a", "b" ]
pretty() 以 json 格式显示
> db.test.find({"age" : "10", "gender" : "nan"})
{ "_id" : ObjectId("6356d3e931c488f67f74bd3b"), "id" : "102", "name" : "lisi", "age" : "10", "gender" : "nan" }
{ "_id" : ObjectId("6356d43d31c488f67f74bd3c"), "id" : "102", "name" : "liu", "age" : "10", "gender" : "nan" }
> db.test.find({"age" : "10", "gender" : "nan"}).pretty()
{
"_id" : ObjectId("6356d3e931c488f67f74bd3b"),
"id" : "102",
"name" : "lisi",
"age" : "10",
"gender" : "nan"
}
{
"_id" : ObjectId("6356d43d31c488f67f74bd3c"),
"id" : "102",
"name" : "liu",
"age" : "10",
"gender" : "nan"
}
>
删除记录 # 注意删除表中所有数据,会很慢,所以建议删除表,在创建一个空表
> db.test.find()
{ "_id" : ObjectId("6356d25a31c488f67f74bd37"), "name" : "zhang" }
{ "_id" : ObjectId("6356d2c031c488f67f74bd38"), "id" : "101", "name" : "liu", "age" : "10" }
{ "_id" : ObjectId("6356d2ff31c488f67f74bd39"), "name" : "zhang", "age" : "23" }
{ "_id" : ObjectId("6356d3b831c488f67f74bd3a"), "id" : "102", "name" : "lisi", "age" : "10" }
{ "_id" : ObjectId("6356d3e931c488f67f74bd3b"), "id" : "102", "name" : "lisi", "age" : "10", "gender" : "nan" }
{ "_id" : ObjectId("6356d43d31c488f67f74bd3c"), "id" : "102", "name" : "liu", "age" : "10", "gender" : "nan" }
# 删除指定的文档(数据行)
> db.test.remove({"age" : "10", "gender" : "nan"})
WriteResult({ "nRemoved" : 2 })
> db.test.find()
{ "_id" : ObjectId("6356d25a31c488f67f74bd37"), "name" : "zhang" }
{ "_id" : ObjectId("6356d2c031c488f67f74bd38"), "id" : "101", "name" : "liu", "age" : "10" }
{ "_id" : ObjectId("6356d2ff31c488f67f74bd39"), "name" : "zhang", "age" : "23" }
{ "_id" : ObjectId("6356d3b831c488f67f74bd3a"), "id" : "102", "name" : "lisi", "age" : "10" }
# 删除表中所有数据
> db.test.remove({})
WriteResult({ "nRemoved" : 4 })
> db.test.find()
>
去掉集合中,某列重复值后,都存在什么, 查询语句,不影响原值
> db.jihe.find()
{ "_id" : ObjectId("6356da33e3f8ef3a107dc651"), "id" : "101", "name" : "lisi", "age" : "10", "gender" : "nan" }
{ "_id" : ObjectId("6356da42e3f8ef3a107dc652"), "id" : "102", "name" : "zhang", "age" : "12", "gender" : "nan" }
{ "_id" : ObjectId("6356da4fe3f8ef3a107dc653"), "id" : "103", "name" : "wang", "age" : "10", "gender" : "nan" }
{ "_id" : ObjectId("6356db851a1cdc1597160e25"), "id" : "104", "name" : "lisi", "age" : "12", "gender" : "nan" }
> db.jihe.distinct("age") # age去重后,只有10 和 12
[ "10", "12" ]
> db.jihe.distinct("name") # name去重后,只有lisi 和 wang 和 zhang
[ "lisi", "wang", "zhang" ]
>
2、增删改使用
1、给一个新的文档插入数据
> use jerry
switched to db jerry
> db.test.insert({name:"zhang"})
WriteResult({ "nInserted" : 1 })
> db.test.insert({id:"101",name:"liu",age:"10",gender:"nan"})
WriteResult({ "nInserted" : 1 })
> db.test.insert({id:"102",name:"liu",age:"10",gender:"nan"})
WriteResult({ "nInserted" : 1 })
2、指定查询
> db.test.find({"age" : "10", "gender" : "nan"})
{ "_id" : ObjectId("6356d3e931c488f67f74bd3b"), "id" : "102", "name" : "lisi", "age" : "10", "gender" : "nan" }
{ "_id" : ObjectId("6356d43d31c488f67f74bd3c"), "id" : "102", "name" : "liu", "age" : "10", "gender" : "nan" }
>
3、批量插入数据,mongodb支持for循环 (压力测试)
> for(i=0;i<10;i++){db.log.insert({"uid":i,"name":"mongodb","age":6,"date":new
... Date()})}
WriteResult({ "nInserted" : 1 })
> db.log.find()
{ "_id" : ObjectId("6356d64f31c488f67f74bd3d"), "uid" : 0, "name" : "mongodb", "age" : 6, "date" : ISODate("2022-10-24T18:15:43.748Z") }
{ "_id" : ObjectId("6356d64f31c488f67f74bd3e"), "uid" : 1, "name" : "mongodb", "age" : 6, "date" : ISODate("2022-10-24T18:15:43.764Z") }
{ "_id" : ObjectId("6356d64f31c488f67f74bd3f"), "uid" : 2, "name" : "mongodb", "age" : 6, "date" : ISODate("2022-10-24T18:15:43.764Z") }
{ "_id" : ObjectId("6356d64f31c488f67f74bd40"), "uid" : 3, "name" : "mongodb", "age" : 6, "date" : ISODate("2022-10-24T18:15:43.765Z") }
{ "_id" : ObjectId("6356d64f31c488f67f74bd41"), "uid" : 4, "name" : "mongodb", "age" : 6, "date" : ISODate("2022-10-24T18:15:43.765Z") }
{ "_id" : ObjectId("6356d64f31c488f67f74bd42"), "uid" : 5, "name" : "mongodb", "age" : 6, "date" : ISODate("2022-10-24T18:15:43.765Z") }
{ "_id" : ObjectId("6356d64f31c488f67f74bd43"), "uid" : 6, "name" : "mongodb", "age" : 6, "date" : ISODate("2022-10-24T18:15:43.765Z") }
{ "_id" : ObjectId("6356d64f31c488f67f74bd44"), "uid" : 7, "name" : "mongodb", "age" : 6, "date" : ISODate("2022-10-24T18:15:43.766Z") }
{ "_id" : ObjectId("6356d64f31c488f67f74bd45"), "uid" : 8, "name" : "mongodb", "age" : 6, "date" : ISODate("2022-10-24T18:15:43.766Z") }
{ "_id" : ObjectId("6356d64f31c488f67f74bd46"), "uid" : 9, "name" : "mongodb", "age" : 6, "date" : ISODate("2022-10-24T18:15:43.766Z") }
>
4、会自动分页,每页20条,超过提示Type "it" for more,输入it下一页。 使用DBQuery.shellBatchSize= 修改多扫条一页 (修改后真对已经存在、以后创建的)
{ "_id" : ObjectId("6356d6a531c488f67f74bd57"), "uid" : 16, "name" : "mongodb", "age" : 6, "date" : ISODate("2022-10-24T18:17:09.635Z") }
{ "_id" : ObjectId("6356d6a531c488f67f74bd58"), "uid" : 17, "name" : "mongodb", "age" : 6, "date" : ISODate("2022-10-24T18:17:09.635Z") }
{ "_id" : ObjectId("6356d6a531c488f67f74bd59"), "uid" : 18, "name" : "mongodb", "age" : 6, "date" : ISODate("2022-10-24T18:17:09.635Z") }
{ "_id" : ObjectId("6356d6a531c488f67f74bd5a"), "uid" : 19, "name" : "mongodb", "age" : 6, "date" : ISODate("2022-10-24T18:17:09.636Z") }
Type "it" for more
>
> DBQuery.shellBatchSize=30;
3、复制集有关
复制集有关(replication set) rs 比 mysql 主从复制高级太多,比MHA还好用,保证了集群的所有节点的一致性,不会出现不一致问题,有延时,隐藏、投票等等。
分片集群(sharding custer) sh 自动分片,分布式集群
> rs.
rs.add( rs.constructor rs.printReplicationInfo( rs.slaveOk(
rs.addArb( rs.debug rs.printSecondaryReplicationInfo( rs.status(
rs.apply( rs.freeze( rs.printSlaveReplicationInfo( rs.stepDown(
rs.bind( rs.hasOwnProperty( rs.propertyIsEnumerable( rs.syncFrom(
rs.call( rs.hello( rs.prototype rs.toLocaleString(
rs.compareOpTimes( rs.help( rs.reconfig( rs.toString(
rs.conf( rs.initiate( rs.remove( rs.valueOf(
rs.config( rs.isMaster( rs.secondaryOk(
> sh.
sh.addShard( sh.disableBalancing( sh.getShouldAutoSplit( sh.removeShardTag( sh.toLocaleString(
sh.addShardTag( sh.enableAutoSplit( sh.hasOwnProperty( sh.removeTagRange( sh.toString(
sh.addShardToZone( sh.enableBalancing( sh.help( sh.setBalancerState( sh.updateZoneKeyRange(
sh.addTagRange( sh.enableSharding( sh.isBalancerRunning( sh.shardCollection( sh.valueOf(
sh.apply( sh.getActiveMigrations( sh.moveChunk( sh.splitAt( sh.waitForPingChange(
sh.bind( sh.getBalancerState( sh.propertyIsEnumerable( sh.splitFind(
sh.call( sh.getBalancerWindow( sh.prototype sh.startBalancer(
sh.constructor sh.getRecentFailedRounds( sh.removeRangeFromZone( sh.status(
sh.disableAutoSplit( sh.getRecentMigrations( sh.removeShardFromZone( sh.stopBalancer(
> sh.
4、集合存储信息
1、数据压缩比,对比 mysql 高很多
2、注意,命令查看会有延迟,执行totalSize()后,在插入数据,在执行totalSize(),在一小段时间内大小不变
– 查看集合存储信息
app> db.log.stats()
app> db.log.dataSize() //集合中数据的原始大小
app> db.log.totalIndexSize() //集合中索引数据的原始大小
# ***** 集合大小(索引+数据压缩存储之后的大小)单位字节 ,
# 将来数据量比较大的业务,需要关注存储空间占用
app> db.log.totalSize()
app> db.log.storageSize() //集合中数据压缩存储的大小
四、用户管理(运维重要)
1、介绍
mysql:用户、密码、对应的有哪些权限(增删改查)、访问IP限制
mongodb :
1、用户、密码
2、权限( 类似Linux权限定义,Linux是rwx,mongodb 使用角色管理,定义可读可写rw,只读 r-,还有一种 root 权限,把一堆可能性的命令打包成一个角色,进行给用户授权,mysql 8.0 已经存在,比如给 insert 、update 打包给 名字叫 jerry 的角色,然后账户1 和 jerry 的角色绑定,然后账户2 和 jerry 的角色绑定 )、
3、验证库,登录时,必须明确指定验证库才能登录,相当于再一次加了一道锁,账户密码对了,不一定能的登录,还的看验证库。要求你是管理员,执行(mongo -u 用户名 -p 密码 admin)进入admin库。你是开发,执行(mongo -u 用户名 -p 密码 dev)进入dev库,增加了安全的能力。
注意:
验证库,建立用户时use到的库,在使用用户时,要加上验证库才能登陆。
对于管理员用户,必须在admin下创建.
1. 建用户时,use到的库,就是此用户的验证库Linu
2. 登录时,必须明确指定验证库才能登录
3. 通常,管理员用的验证库是admin,普通用户的验证库一般是所管理的库设置为验证库
4. 如果直接登录到数据库,不进行use,默认的验证库是test,不是我们生产建议的
5、mongodb 在 3.4 版本之前,可以不加验证进行远程登录,在之后的版本,不加验证只能在本地
查看帮助文档
[root@db1 ~]# mongo -help
Authentication Options:
-u [ --username ] arg username for authentication
-p [ --password ] arg password for authentication
--authenticationDatabase arg user source (defaults to dbname) # 验证库
--authenticationMechanism arg authentication mechanism
--gssapiServiceName arg (=mongodb) Service name to use when authenticating
using GSSAPI/Kerberos
--gssapiHostName arg Remote host name to use for purpose of
GSSAPI/Kerberos authentication
1、use 到某一个库(db命令查看在那个库),建立用户密码,登录的时候,就必须指定这个库 ( 登录不加库名,默认 test 库 ),尽量不用test库,容易被破解
2、mongodb 会建立两种,第一种 admin 管理员用户库,第二种是谁使用哪个库,就指定哪个库
2、创建管理员用户
默认第一次安装后,配置文件没开验证,直接使用 mongo 回车后,登录的是管理员用户,需要借助此账户创建
[root@db1 ~]# mongo
> use admin
switched to db admin
> db
admin
> db.createUser(
{
user: "root",
pwd: "root123",
roles: [ { role: "root", db: "admin" } ]
}
)
# 回车后
Successfully added user: {
"user" : "root",
"roles" : [
{
"role" : "root",
"db" : "admin"
}
]
}
>
# 注意user: user: "root", 可以不给root名字,用户名字可以随意起,我们是将用户名字跟mongo服
务账号root做了绑定的,root服务账号才是真的root,这样能增加安全性
解释:
db.createUser(
{
user: "<name>", # 用户名
pwd: "<cleartext password>", # 密码
roles: [ { role: "<role>", db: "<database>" } ] # 权限又叫角色,角色类型是<role>,如果是root就是超级管理员.<database> 可以管理的库
}
)
<role>角色类型:
root , readWrite, read(only read)
<database> 可以管理的库:
如果是admin库,所有的管理都需要经过admin库
# 验证用户
> db.auth('root','root123') # 此命令不会保存历史记录,所有通过上下翻越找不到
1 # 1代表sueecss
> db.auth('root','root1234')
Error: Authentication failed.
0
>
3、开启验证功能
[root@db1 ~]# tail -n 2 /opt/mongodb/conf/mongo.conf # 最后两行添加
security:
authorization: enabled
[root@db1 ~]# systemctl restart mongod.service
验证
[root@db1 ~]# mongo # 直接输入mongo,输入命令后会有问题
connecting to: mongodb://127.0.0.1:27017/?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("547a17bc-774e-4cc0-a504-29c1a5c25e7a") }
MongoDB server version: 4.0.28
>
> show databases;
> db
test
> use admin
switched to db admin
> show tables;
Warning: unable to run listCollections, attempting to approximate collection names by parsing connectionStatus
警告:无法运行listCollections,试图通过解析connectionStatus来近似集合名称
[root@db1 ~]# mongo -uroot -proot123 # 此方式是可以进入,走的是本地的登录,增加验证后,可以直接使用
connecting to: mongodb://127.0.0.1:27017/?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("b69aa6c8-c5b4-4739-920c-9bb52202c36f") }
> show databases;
admin 0.000GB
app 0.000GB
config 0.000GB
jerry 0.000GB
local 0.000GB
> use admin
switched to db admin
> show tables;
system.users
system.version
>
[root@db1 ~]# mongo -uroot -proot123 192.168.86.5 # 这种的意思是,使用mongo命令,去连接192.168.86.5的mongo,虽然都在本机,在不加库的时候不好使
MongoDB shell version v4.0.28
connecting to: mongodb://192.168.86.5:27017/test?gssapiServiceName=mongodb
2022-10-25T03:41:48.087+0800 E QUERY [js] Error: Authentication failed. :
connect@src/mongo/shell/mongo.js:356:17
@(connect):2:6
exception: connect failed
[root@db1 ~]#
[root@db1 ~]# mongo -uroot -proot123 192.168.86.5/admin
> show databases;
admin 0.000GB
app 0.000GB
config 0.000GB
jerry 0.000GB
local 0.000GB
>
# 注意,管理员用户必须是roles: [ { role: "root", db: "admin" } ],如下
> use admin
switched to db admin
> db
admin
> db.createUser(
{
user: "jerry",
pwd: "root123",
roles: [ { role: "root", db: "jerry" } ]
}
)
或者
> use jerry
switched to db jerry
> db.createUser(
... {
... user: "jerry",
... pwd: "root123",
... roles: [ { role: "root", db: "jerry" } ]
... }
... )
提示 Error: couldn't add user: No role named root@jerry
# 另外如果没有use到admin账户下,只要roles: [ { role: "root", db: "admin" },发现也可以管理,但是登陆的时候,需要执行你use的那个库,应该是执行db.createUser后,会将信息存在这个库,有没有权限看roles
> use jerry
switched to db jerry
> db
jerry
> db.createUser(
{
user: "jerry4",
pwd: "root123",
roles: [ { role: "root", db: "admin" } ]
}
)
Successfully added user: {
"user" : "jerry4",
"roles" : [
{
"role" : "root",
"db" : "admin"
}
]
}
> show tables;
> db
jerry
> exit
bye
[root@db1 ~]# mongo -ujerry4 -proot123 192.168.86.5/jerry
> show databases;
admin 0.000GB
app 0.000GB
config 0.000GB
jerry 0.000GB
local 0.000GB
> use admin
switched to db admin
> show tables;
system.users
system.version
>
4、创建库管理用户(了解)
只能对库单独的这个库做操作( 查询状态),不能对表做操作
mongo -uroot -proot123 192.168.86.5/admin
use app
db.createUser(
{
user: "app1",
pwd: "app1",
roles: [ { role: "dbAdmin", db: "app" } ]
}
)
db.auth('app1','app1')
登录测试
mongo -uapp1 -papp1 192.168.86.5/app
> db
app
> show databases;
app 0.000GB
> db.stats()
{
"db" : "app",
"collections" : 2,
"views" : 0,
"objects" : 0,
"avgObjSize" : 0,
"dataSize" : 0,
"storageSize" : 8192,
"numExtents" : 0,
"indexes" : 2,
"indexSize" : 8192,
"fsUsedSize" : 10772742144,
"fsTotalSize" : 40778076160,
"ok" : 1
}> show tables;
a
b
> db.a.find()
Error: error: {
"ok" : 0,
"errmsg" : "not authorized on app to execute command { find: \"a\", filter: {}, lsid: { id: UUID(\"97710038-f3e3-4f36-acd1-8a6937298248\") }, $db: \"app\" }",
"code" : 13,
"codeName" : "Unauthorized"
}
5、创建用户多库权限、只读只写
创建一个对 app 库的可读可写,对 test 库的只能读
> use app
> show tables;
biao1
biao2
> use test
> show tables;
biao1
biao2
> db.createUser(
{
user: "app3",
pwd: "app3",
roles: [ { role: "readWrite", db: "app" },{ role: "read", db: "test" } ]
}
)
Successfully added user: {
"user" : "app3",
"roles" : [
{
"role" : "readWrite",
"db" : "app"
},
{
"role" : "read",
"db" : "test"
}
]
}
>
验证
[root@db1 ~]# mongo -uapp3 -papp3 192.168.86.5/test # 为什么是test库,因为最后在test下创建的
> show databases;
app 0.000GB
test 0.000GB
> use app
switched to db app
> show tables;
biao1
biao2
> db.biao1.insert({"name":"nihao"})
WriteResult({ "nInserted" : 1 })
> db.biao1.find()
{ "_id" : ObjectId("6356fa7bcc4502724f1a083a"), "name" : "nihao" }
> use test
switched to db test
> show tables;
biao1
biao2
> db.biao1.insert({"name":"nihao"})
WriteCommandError({
"ok" : 0,
"errmsg" : "not authorized on test to execute command { insert: \"biao1\", ordered: true, lsid: { id: UUID(\"25c3e0c2-01c4-41f9-bfb6-11ca9892b9d7\") }, $db: \"test\" }",
"code" : 13,
"codeName" : "Unauthorized"
})
> db.biao1.find()
>
6、查询mongo下的用户信息
[root@db1 ~]# mongo -uroot -proot123 192.168.86.5/admin
> db
admin
> db.system.users.find().pretty()
{
"_id" : "admin.root", # 验证库.权限
"userId" : UUID("8f56275e-0c78-4465-851f-389685ced05d"),
"user" : "root", # 用户名
"db" : "admin", # 密码
},
"roles" : [ # 权限
{
"role" : "root",
"db" : "admin"
}
]
}
{
"_id" : "admin.jerry",
"userId" : UUID("9ad43321-97c0-4782-b453-933f
7、删除用户
使用 root 身份登录, use 到验证库
# 先查有哪些用户
[root@db1 ~]# mongo -uroot -proot123 192.168.86.5/admin
> db
admin
> db.system.users.find().pretty()
{
"_id" : "app.app1",
"userId" : UUID("ac3dd3bc-f308-4b7d-a6b1-3dcb65636e90"),
"user" : "app1",
"db" : "app",
"credentials" : {
"SCRAM-SHA-1" : {
"iterationCount" : 100
# 删除
[root@db1 ~]# mongo -uroot -proot123 192.168.86.5/admin
> use app
switched to db app
> db.dropUser("app1")
true
>
五、复制集RS集群架构(运维重要)
1、介绍
对比的是 mysql8.0以下主从,复制集很重要,因为 MongoDB 没有单机运行的,都是集群,最简单的集群是RS(复制集),跟主从不一样,跟 mysql 8.0的 mgr 很像
普通复制集架构
1、基本构成是最低3台, 1主2从的结构,3节点
2、自带互相监控 (心跳检测) 投票机制(Raft(MongoDB),还有一种是 Paxos(mysql MGR 用的是变种))
如果发生主库宕机,复制集内部会进行投票选举,选择一个新的主库替代原有主库对外提供服务。同时复制集会自动通知客户端程序,4、主库已经发生切换了,应用就会连接到新的主库。mongodb没有VIP,怎么解决应用透明到的问题,会自动告知应用程序,主节点已经切换了,连接我的新主节点
比如java程序连接mongodb集群(不是分片集群,分片可以连接config servers应) 1、带如下代码,mongodb会自动发现集群中那个是主节点,auto-discovery of the primary // or, to connect to a replica set, with auto-discovery of the primary, supply a seed list of members MongoClient mongoClient = new MongoClient(Arrays.asList(new ServerAddress("localhost", 27017), new ServerAddress("localhost", 27018), new ServerAddress("localhost", 27019))); 2、底层判断的机制,类似momgodb暴露一个api,返回那个是primary。java 获取后只将写入发送给primary。并不是简单的链接节点1不能插入,在连接节点2。因为momgodb默认从库不能插入。 3、java连接那个版本的mongodb,就需要那个版本的mongdb的jar包(驱动),通过驱动获取去连接那个哪个api接口,获取momgodb的primary
5、宕机节点在修复好之后,自动加入集群
3、保证多节点数值一致性
一主一从一个 Arbiter(心跳检测和投票)
1、为什么需要3个节点,因为2节点以防选举失败而脑裂
2、如果多节点一主多从,主给从复制数据压力也大
3、考虑主压力的问题,主只给一个从做复制,另一个不做,这样压力就小了,另一个只是作为他们两个节点之间的选举作用,毕竟有一个宕机后,还有另一台,期间运维人员不可能不去进行修复,修复好后,自动加入集群作为从,所以出现以下架构,另一台只是作为投票4、Arbiter 可以选择配置较低的设备
2、搭建集群(四节点使用多实例)
端口:28017 28018 28019 28020
多套目录:
mkdir -p /mongodb/28017/conf /mongodb/28017/data /mongodb/28017/log
mkdir -p /mongodb/28018/conf /mongodb/28018/data /mongodb/28018/log
mkdir -p /mongodb/28019/conf /mongodb/28019/data /mongodb/28019/log
mkdir -p /mongodb/28020/conf /mongodb/28020/data /mongodb/28020/log
多套配置文件:
/mongodb/28017/conf/mongod.conf
/mongodb/28018/conf/mongod.conf
/mongodb/28019/conf/mongod.conf
/mongodb/28020/conf/mongod.conf
配置文件内容:
cat > /mongodb/28017/conf/mongod.conf <<EOF
systemLog:
destination: file
path: /mongodb/28017/log/mongodb.log
logAppend: true
storage:
journal:
enabled: true
dbPath: /mongodb/28017/data
directoryPerDB: true
#engine: wiredTiger
wiredTiger:
engineConfig:
cacheSizeGB: 1
directoryForIndexes: true
collectionConfig:
blockCompressor: zlib
indexConfig:
prefixCompression: true
processManagement:
fork: true
net:
bindIp: 192.168.86.5,127.0.0.1
port: 28017
replication:
oplogSizeMB: 2048
replSetName: my_repl
EOF
解释:
# 引擎选择,默认是 wiredTiger,和innodb一样,有事务行级锁、自动故障恢复等。4.0 完全实现和mysql 一样
#engine: wiredTiger
wiredTiger:
engineConfig:
cacheSizeGB: 1 # 缓冲区大小, 相当于innodb跟buffer pool功能一样,内存区域,所有数据跟索引的缓冲
# 复制集专用的配置选项
replication:
oplogSizeMB: 2048 # mysql 通过 mysqlbinlog实现主从复制,mongnDB 叫做 oploglog,而且做到了比mysql 高效,表来存储日志,而不是 mysql 落盘在导入SQL层,
# 所以同步极其快。但是他是定容集合,也就是说表的大小是有限制的,最多可以使用2g, 如果不设置,最大不超过总磁盘的5%。既然跟二进制有关,一定跟备份恢复有关
replSetName: my_repl # 复制集名字,随便起,但是主、从的名字一定要一致,配置文件定义好了,在生成集群的时候,起的这个名字也是这个
cp /mongodb/28017/conf/mongod.conf /mongodb/28018/conf/
cp /mongodb/28017/conf/mongod.conf /mongodb/28019/conf/
cp /mongodb/28017/conf/mongod.conf /mongodb/28020/conf/
sed 's#28017#28018#g' /mongodb/28018/conf/mongod.conf -i
sed 's#28017#28019#g' /mongodb/28019/conf/mongod.conf -i
sed 's#28017#28020#g' /mongodb/28020/conf/mongod.conf -i
启动多个实例备用:
mongod -f /mongodb/28017/conf/mongod.conf
mongod -f /mongodb/28018/conf/mongod.conf
mongod -f /mongodb/28019/conf/mongod.conf
mongod -f /mongodb/28020/conf/mongod.conf
查看:
[root@db1 /]# ps -ef |grep mongo
root 2166 1 1 05:54 ? 00:00:00 mongod -f /mongodb/28017/conf/mongod.conf
root 2199 1 2 05:54 ? 00:00:00 mongod -f /mongodb/28018/conf/mongod.conf
root 2232 1 2 05:54 ? 00:00:00 mongod -f /mongodb/28019/conf/mongod.conf
root 2265 1 4 05:54 ? 00:00:01 mongod -f /mongodb/28020/conf/mongod.conf
root 2297 1170 0 05:55 pts/1 00:00:00 grep --color=auto mongo
[root@db1 /]#
3、配置普通复制集(重要)
第一步先定义config ,随意找那台设备,但一般情况下,配置那个机器,后台选择也会选择此节点为主
[root@db1 /]# mongo --port 28017 admin
> db
admin
> config = {_id: 'my_repl', members: [
{_id: 0, host: '192.168.86.5:28017'},
{_id: 1, host: '192.168.86.5:28018'},
{_id: 2, host: '192.168.86.5:28019'}]
}
提示:
{
"_id" : "my_repl",
"members" : [
{
"_id" : 0,
"host" : "192.168.86.5:28017"
},
{
"_id" : 1,
"host" : "192.168.86.5:28018"
},
{
"_id" : 2,
"host" : "192.168.86.5:28019"
}
]
}
解释:
一个配置文件config
给三个成员变量起一个集群名字my_repl
在启动复制集
> rs.initiate(config)
{ "ok" : 1 }
my_repl:SECONDARY> # SECONDARY 代表次级,因为刚刚启动三个节点在PK,过一段时间会选择出谁是主,一般都是那个机器配置,那个为主
my_repl:PRIMARY> # PRIMARY表是主
[root@db1 /]# mongo --port 28018 admin
my_repl:SECONDARY>
4、故障演示
挡掉主节点
[root@db1 /]# mongod -f /mongodb/28017/conf/mongod.conf --shutdown
[root@db1 ~]# mongo --port 28018 admin
my_repl:SECONDARY>
my_repl:PRIMARY>
[root@db1 ~]# mongo --port 28019 admin
my_repl:SECONDARY>
启动被关掉的主节点,自动作为从库
[root@db1 /]# mongod -f /mongodb/28017/conf/mongod.conf
[root@db1 /]# mongo --port 28017 admin
my_repl:SECONDARY>
6、查看复制集状态
my_repl:PRIMARY> rs.status();
{
"set" : "my_repl", # rs集群名字
"date" : ISODate("2022-10-24T22:22:30.364Z"),
...............
"members" : [ # 节点信息
{
"_id" : 0,
"name" : "192.168.86.5:28017", # 节点1
"health" : 1, # 健康状态
"state" : 2,
"stateStr" : "SECONDARY", # 从库还会主库
"uptime" : 121,
"optime" : { # 相当于gtid的号码
"ts" : Timestamp(1666650148, 1),
"t" : NumberLong(2)
},
{
"_id" : 1,
"name" : "192.168.86.5:28018",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 1679,
7、复制集的监控
rs.status(); //查看整体复制集状态
rs.isMaster(); // 查看当前是否是主节点
rs.conf(); //查看复制集配置信息
my_repl:PRIMARY> rs.isMaster()
{
"hosts" : [
"192.168.86.5:28017",
"192.168.86.5:28018",
"192.168.86.5:28019"
],
"setName" : "my_repl",
"setVersion" : 1,
"ismaster" : true,
"secondary" : false,
"primary" : "192.168.86.5:28018", 主节点是谁
"me" : "192.168.86.5:28018", 我是谁
my_repl:PRIMARY> rs.conf()
{
"_id" : "my_repl",
"version" : 1,
"protocolVersion" : NumberLong(1),
"writeConcernMajorityJournalDefault" : true,
"members" : [
{
"_id" : 0,
"host" : "192.168.86.5:28017",
"arbiterOnly" : false, 代表是不是arbiter
8、添加删除节点
rs.remove("ip:port"); // 删除一个节点 在主上操作
rs.add("ip:port"); // 新增从节点
rs.addArb("ip:port"); // 新增仲裁节点
9、配置一主一从一 Arbiter(重要)
一个节点是无法同时在两个复制集以上存在的,mongodb 是不支持级联的。也没有多主的功能。不能参数多节点的复制。mysql 是支持的,比如节点可以作为另一个节点的从,可以作为其他节点的主。
9.1、从头搭建
1、取消刚刚搭建的 28017 28018 28019 主从关系
2、搭建过程跟普通复制集一样,区别是在config中其中一个节点声明Arbiter
mongo -port 28017 admin
config = {_id: 'my_repl', members: [
{_id: 0, host: '192.168.86.5:28017'},
{_id: 1, host: '192.168.86.5:28018'},
{_id: 2, host: '192.168.86.5:28019',"arbiterOnly":true}]
}
rs.initiate(config)
9.2 、将刚刚搭建的普通复制集,转成一主一从一Arbiter
思路:将想要添加Arbiter节点的从集群中删除,重新在添加为Arbiter
my_repl:PRIMARY> rs.remove("192.168.86.5:28019")
{
"ok" : 1, # 代表成功
"operationTime" : Timestamp(1666651545, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1666651545, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
my_repl:PRIMARY> rs.addArb("192.168.86.5:28019")
{
"ok" : 1,
"operationTime" : Timestamp(1666651620, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1666651620, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
my_repl:PRIMARY> rs.conf()
{
"_id" : 2,
"host" : "192.168.86.5:28019",
"arbiterOnly" : true, # 代表是arbiter
10、常见问题
主从复制后,从数据库默认不能读不能插入
1、主从复制后,从数据库默认不能读不能插入,必须需要执行rs.slaveOk(),此时当前的从数据库才能可读可写,其他从节点还是不能读不能插入,在主节点执行rs.slaveOk()也不会让从节点能读能写
my_repl:PRIMARY> use jerry
switched to db jerry
my_repl:PRIMARY> db.t1.insert({"id":101,"name":"nihao"})
WriteResult({ "nInserted" : 1 })
my_repl:PRIMARY> rs.conf()
my_repl:SECONDARY> show databases;
2022-10-25T08:48:15.220+0800 E QUERY [js] Error: listDatabases failed:{
"operationTime" : Timestamp(1666658878, 2),
"ok" : 0,
"errmsg" : "not master and slaveOk=false",
"code" : 13435,
"codeName" : "NotMasterNoSlaveOk",
"$clusterTime" : {
"clusterTime" : Timestamp(1666658878, 2),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:151:1
shellHelper.show@src/mongo/shell/utils.js:882:13
shellHelper@src/mongo/shell/utils.js:766:15
@(shellhelp2):1:1
my_repl:SECONDARY> rs.slaveOk()
WARNING: slaveOk() is deprecated and may be removed in the next major release. Please use secondaryOk() instead.
my_repl:SECONDARY> show databases;
admin 0.000GB
config 0.000GB
jerry 0.000GB
local 0.000GB
my_repl:SECONDARY> show databases;
2、当重启数据库后,或者删除子节点,重新加入,继续变成默认不能读不能写
3、如果就行能读
要想不用每次输入该命令,可以修改如下文件
[root@db1 ~]# find / -name .mongorc.js
/root/.mongorc.js
/home/mongod/.mongorc.js
在文件里面添加一行:rs.slaveOk();
一般这个文件都是空的,直接加上去。保存退出。之后退出mongo在进去就可以了.
[root@db1 ~]# cat /root/.mongorc.js
rs.slaveOk();
重启mongodb
六、特殊从节点-延时从库
延时从库(slaveDelay):
mysql 有过滤、半同步、延时同步节点,mongodb也有延时从库
架构:一主、一从、一Arbiter、一个延时从库,解决逻辑损坏
mysql 是通过SQL线程实现的,mongodb也是。
隐藏节点概念:
隐藏节点中有 hidden:true 概念(不进行读写操作,业务上看不见他),priority : 0 概念(不参与选举、投票、权重是0),隐藏节点 搭配 延时从库,实现了延时从库加到集群中,不需要参与选举、投票等,只是为了做数据备份
1、环境
架构:28017 28018 为主从 28019 为 Arbiter 28020 为隐藏节点的延时从库
my_repl:PRIMARY> rs.conf()
{
"_id" : "my_repl",
"version" : 4,
"protocolVersion" : NumberLong(1),
"writeConcernMajorityJournalDefault" : true,
"members" : [
{
"_id" : 0,
"host" : "192.168.86.5:28017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 1,
"host" : "192.168.86.5:28018",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 2,
"host" : "192.168.86.5:28019",
"arbiterOnly" : true,
"buildIndexes" : true,
"hidden" : false,
"priority" : 0,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 3,
"host" : "192.168.86.5:28020",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false, # hidden
"priority" : 1, # priority
"tags" : {
},
"slaveDelay" : NumberLong(0), # 延时从库
"votes" : 1
}
}
my_repl:PRIMARY>
2、参数配置介绍
启动
cfg=rs.conf() # rs.conf()打印的信息,定义到cfg变量
cfg.members[2].priority=0 # 不进行选主功能,独立
cfg.members[2].hidden=true # 藏起来不参与业务
cfg.members[2].slaveDelay=120 # 延时多久
rs.reconfig(cfg) # 配置生效
取消
cfg=rs.conf()
cfg.members[2].priority=1
cfg.members[2].hidden=false
cfg.members[2].slaveDelay=0
rs.reconfig(cfg)
3、修改对应的参数,启动延时从库
# 注意,将192.168.86.5:28020加入到延时从库中,他的下标是03
my_repl:PRIMARY> rs.conf()
},
{
"_id" : 3,
"host" : "192.168.86.5:28020",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
my_repl:PRIMARY> cfg=rs.conf()
my_repl:PRIMARY> cfg.members[3].priority=0
0
my_repl:PRIMARY> cfg.members[3].hidden=true
true
my_repl:PRIMARY> cfg.members[3].slaveDelay=120
120
my_repl:PRIMARY> rs.reconfig(cfg)
my_repl:PRIMARY> rs.conf()
{
"_id" : 3,
"host" : "192.168.86.5:28020",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : true, # 从 false 变成 true
"priority" : 0, # 从 1 变成 0
"tags" : {
},
"slaveDelay" : NumberLong(120), # 从 0 变成 120
"votes" : 1
七、集群分片
1、介绍
分布式集群架构图,根据颜色,分为三大部分
蓝色部分Mongos,也称之为 router ,在 mysql 架构中,相当于Mycat角色(访问Mycat,Mycat 通过规则决定到底给那个库或者那个表,分库分表),所以所有的连接需要通过Mongos,由Mongos决定给谁,是给 Shard 1 还是 Shard 2。可以随意扩容多个节点
但本身 Mongos 是一个无状态的,没有脑子,他也不清楚来了给谁,甚至不知道后端有多少个节点。所以需要Config Servers来进行配合使用,可以说 Config Servers是 Mongos 秘书,一个插入数据,到达Mongos,Mongos 会问 Config Servers 有几个节点,应该怎么发。所以整个集群都在Config Servers,这个统一配置文件中。Mycat 使用 zookpeer 作为统一存储配置信息(比如路由规则)
绿色的就是分片,一个分片中包含一套主从,所以架构中既有高可用(每个shard中有复制集)、又有分布式分片功能(多个shard),每个Shard中的复制集可以存在Arbiter
思考:架构中什么最重要,Shard 数据最为重要,毕竟是数据。其次是 Config Servers 是配置的中心。所以 Mongodb 也是考虑到了此问题,故一般每个Shard 要做(replica set)复制集,Config Servers也要做复制集。一套复制集也必须要最低有三个节点(防止脑裂),而且不能存在Arbiter,必须独立的主跟从节点
2、规划
shard 节点:
sh1:38021-23 (1主两从,其中一个节点为arbiter,复制集名字sh1)
sh2:38024-26 (1主两从,其中一个节点为arbiter,复制集名字sh2)configService节点:
38018-20 (1主两从,不支持Arbiter)
mongos节点:
38017
生产最低规划: 物理机做多实例
3、环境搭建
搭建两组分片节点
目录创建:
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: 192.168.86.5,127.0.0.1
port: 38021
replication:
oplogSizeMB: 2048
replSetName: sh1 # 复制集名字,自定义
sharding: # sharding相关的
clusterRole: shardsvr # 在sharding集群中角色是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: 192.168.86.5,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
或者 for i in {21..26}; do mongod -f /mongodb/380$i/conf/mongodb.conf;done
构建主从
mongo --port 38021 admin
config = {_id: 'sh1', members: [
{_id: 0, host: '192.168.86.5:38021'},
{_id: 1, host: '192.168.86.5:38022'},
{_id: 2, host: '192.168.86.5:38023',"arbiterOnly":true}]
}
rs.initiate(config)
mongo --port 38024 admin
config = {_id: 'sh2', members: [
{_id: 0, host: '192.168.86.5:38024'},
{_id: 1, host: '192.168.86.5:38025'},
{_id: 2, host: '192.168.86.5:38026',"arbiterOnly":true}]
}
rs.initiate(config)
config节点配置
构建主从(不能是Arbiter)
目录创建:
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: 192.168.86.5,127.0.0.1
port: 38018
replication:
oplogSizeMB: 2048
replSetName: configReplSet # config名字随意,但是要记住,因为mongos要先找到这个复制集,在找到复制集下的每个节点
sharding:
clusterRole: configsvr # 也是不能变,生命是什么角色,是shard还是config
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
mongo --port 38018 admin
config = {_id: 'configReplSet', members: [
{_id: 0, host: '192.168.86.5:38018'},
{_id: 1, host: '192.168.86.5:38019'},
{_id: 2, host: '192.168.86.5:38020'}]
}
rs.initiate(config)
mongos节点配置
创建目录:不用创建数据目录,因为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: 192.168.86.5,127.0.0.1
port: 38017
sharding:
configDB: configReplSet/192.168.86.5:38018,192.168.86.5:38019,192.168.86.5:38020 # 连接config的地址,去configReplSet复制集
processManagement:
fork: true
EOF
启动mongos
mongos -f /mongodb/38017/conf/mongos.conf
mongos的一般的配置都在config
mongos> use config
configReplSet/192.168.86.5:38018,192.168.86.5:38019,192.168.86.5:38020
由于告知了mongos 了config 的复制集,所以一旦 mongos 找不到正在连接的,会自动切换连接另一个,所以 mongos 起不来跟 config 有关,mongos 依赖 config
shard 节点加入集群
目前 shard 还没有加入到集群中,只不过做了主从,生命了 shar d的 name
连接到其中一个mongos(192.168.86.5),做以下配置
1、连接到mongs的admin数据库
[root@db1 ~]# mongo 192.168.86.5:38017/admin
2、添加分片
db.runCommand( { addshard : "sh1/192.168.86.5:38021,192.168.86.5:38022,192.168.86.5:38023",name:"shard1"} )
db.runCommand( { addshard : "sh2/192.168.86.5:38024,192.168.86.5:38025,192.168.86.5:38026",name:"shard2"} )
3、列出分片
db.runCommand( { listshards : 1 } )
4、整体状态查看
sh.status();
mongos> db.runCommand( { listshards : 1 } )
{
"shards" : [
{
"_id" : "shard1",
"host" : "sh1/192.168.86.5:38021,192.168.86.5:38022",
"state" : 1
},
{
"_id" : "shard2",
"host" : "sh2/192.168.86.5:38024,192.168.86.5:38025",
"state" : 1
}
}
mongos> sh.status()
--- Sharding Status ---
sharding version: {
"_id" : 1,
"minCompatibleVersion" : 5,
"currentVersion" : 6,
"clusterId" : ObjectId("635728fb0e818403199da478")
}
shards:
{ "_id" : "shard1", "host" : "sh1/192.168.86.5:38021,192.168.86.5:38022", "state" : 1 }
{ "_id" : "shard2", "host" : "sh2/192.168.86.5:38024,192.168.86.5:38025", "state" : 1 }
# 会发现每个shard中只有另个节点能用,因为另一个是Arbiter,是不需传递数据
此时还没有开启分片,因为还需要对mongodb做优化
4、Mongodb 的默认分片存储过程
会把每一个分片的存储的单元定义为一个chunk的概念,存储的时候,给我们分配一个一个大小方框的chunk,均匀分配chunk,做存储单元,跟mysql的页,每一个chunk是64M,假如说插入一条数据,16Kb的,假如正好分配到了第一个shard1的chunk中,存不满所以不会拆分,但达到64M后,数据会被分裂成2个32M的chunk。默认情况下,只会在一个 shard 中进行分裂,这两个32M的chunk会继续提供 存储,在满后,在分裂。但是另一个shard2 shard3 没用,所以mongos有一个组件均衡器Balancer,会进行shard的chunk检查,不均匀后,会进行网络把一部分的chunk迁移到另外一个 shark节点。这就是mongod的自动分片。可以设置一个chunk的大小,一般设置128M,迁移会很消耗I/O,特别是网络I/O。解决方案加万兆网卡,但是磁盘I/O也占用一些。
5、分片键
跟 Mycat 一样,在一开始就定义好,数据该怎么 分布,由于均匀分布,所以出现 chunk 迁移的情况就会小。根据业务做需求,比如这一列整体 数据查询很大,拆分的时候,尽量 让热点数据均分到不同的节点,查的时候,并发度更高,做分片策略选择的方案,可以修改分片键。经常那那个列做查询,就在那个建立分片键(索引列),如果无法选择,就选择ID这种列。
1、行必须为分片定义分片键
2、基于一个或者多个列创建
3、分片键定义数据空间
4、想象key space 类似一条线上一个点数据
5、一个key rang 是一条线上一段数据
6、我们可以按照分片键进行Range 和 Hash 分片
Range适用于大规模,一般range通常是数字列,一个chunk 是64M,如果 几万条没有达到64M,不会平均法,Hash 会更加 的合理,进行对hash的取模,会得到一个范围数值,进行类似B+树算法
定义分片键后不可变
分片键必须有索引(默认b+树,也支持hash)
分片键大小限制512bytes
分片键用于路由查询
MongoDB不接受已经colletion级分片的colletion上插入五分片间的文档(也不支持空值插入)
6、使用分片键
6.1、RANGE分片配置及测试
test库下的vast大表进行分片,
db.vast.insert({"id":i,"name":"shenzheng","age":70,"date":new Date()}); }
1、激活数据库分片功能
# 进入mongos
mongo --port 38017 admin
mongos> db
admin
# 激活数据库分片功能
mongos> db.runCommand( { enablesharding : "数据库名称" } )
eg:
mongos> db.runCommand( { enablesharding : "test" } )
{
"ok" : 1, # 代表激活成功
"operationTime" : Timestamp(1666672178, 5),
"$clusterTime" : {
"clusterTime" : Timestamp(1666672178, 5),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
mongos>
2、指定分片建对集合分片
eg:范围片键
--创建索引,在表中,发现有ID列,一定以重复率最低的最为索引
--生产一定是看where后的条件,用哪个列多一些,range通常是数字列
--ensureIndex代表创建所以,使用range普通的range索引
--:1 :-1 代表的是range
use test
> db.vast.ensureIndex( { id: 1 } )
3、开启分片
# 开启分片是一个管理性动作,所以需要use回admin
# shardcollection配置分片的表示什么
# test.vast test库下的vast表
# id: 1 使用id这列做分片键,1是从小到大顺序做拆分分布,-1从大到小
use admin
> db.runCommand( { shardcollection : "test.vast",key : {id: 1} } )
4、集合分片验证
mongos> use test
switched to db test
mongos> db
test
mongos> for(i=1;i<1000000;i++){ db.vast.insert({"id":i,"name":"shenzheng","age":70,"date":new Date()}); }
test> db.vast.stats()
注意:测试量不能太少,否则由于是range,如果达不到64M,不会触发均匀分配
5、分片结果测试
# 分别登陆sh1 和 sh2 上的数据行数
shard1:
mongo --port 38021
db.vast.count(); # 查看行数
shard2:
mongo --port 38024
db.vast.count();
6.2、Hash分片例子
jerry库下的vast大表进行分片,
db.vast.insert({"id":i,"name":"shenzheng","age":70,"date":new Date()});
1、激活数据库分片功能
[root@db1 ~]# mongo --port 38017 admin
mongos> db
admin
mongos> db.runCommand( { enablesharding : "jerry" } )
{
"ok" : 1,
"operationTime" : Timestamp(1666674335, 255),
"$clusterTime" : {
"clusterTime" : Timestamp(1666674335, 436),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
2、对于oldboy库下的vast表建立hash索引
mongos> use jerry
mongos> db.vast.ensureIndex( { id: "hashed" } )
3、开启分片
mongos> use admin
mongos> sh.shardCollection( "jerry.vast", { id: "hashed" } )
4、录入10w行数据测试
mongos> use jerry
mongos> for(i=1;i<100000;i++){ db.vast.insert({"id":i,"name":"shenzheng","age":70,"date":new Date()}); }
5、hash分片结果测试,在少量数据下都是均匀的
mongo --port 38021
use jerry
db.vast.count();
mongo --port 38024
use jerry
db.vast.count();
7、查看分片状态命令
判断是否Shard集群
mongos> db.runCommand({ isdbgrid : 1})
{
"isdbgrid" : 1, # 是
"hostname" : "db1",
列出所有分片信息
mongos> use admin
switched to db admin
mongos> db.runCommand({ listshards : 1})
{
"shards" : [
{
"_id" : "shard1",
"host" : "sh1/192.168.86.5:38021,192.168.86.5:38022",
"state" : 1
},
{
"_id" : "shard2",
"host" : "sh2/192.168.86.5:38024,192.168.86.5:38025",
"state" : 1
}
-------------列出开启分片的数据库--------------
mongos> use config
mongos> db.databases.find( { "partitioned": true } )
{ "_id" : "test", "primary" : "shard2", "partitioned" : true, "version" : { "uuid" : UUID("1224f74c-970b-47b4-9cdc-d0b833e48c9d"), "lastMod" : 1 } }
{ "_id" : "jerry", "primary" : "shard1", "partitioned" : true, "version" : { "uuid" : UUID("dcd8a87e-4f43-4401-bde4-d2a093bd1de4"), "lastMod" : 1 } }
mongos>
# 分片主节点primary对于range有用 ,hash没用,因为是两边同时
或者:
mongos> use config
mongos> db.databases.find() //列出所有数据库分片情况
{ "_id" : "test", "primary" : "shard2", "partitioned" : true, "version" : { "uuid" : UUID("1224f74c-970b-47b4-9cdc-d0b833e48c9d"), "lastMod" : 1 } }
{ "_id" : "jerry", "primary" : "shard1", "partitioned" : true, "version" : { "uuid" : UUID("dcd8a87e-4f43-4401-bde4-d2a093bd1de4"), "lastMod" : 1 } }
{ "_id" : "oldboy", "primary" : "shard1", "partitioned" : false, "version" : { "uuid" : UUID("889479d4-9a62-4e1a-a77b-7a8046a3a483"), "lastMod" : 1 } }
mongos>
-------------列出开启分片的数据库--------------
查看分片的片键
config> db.collections.find().pretty()
{
"_id" : "test.vast",
"lastmodEpoch" : ObjectId("58a599f19c898bbfb818b63c"),
"lastmod" : ISODate("1970-02-19T17:02:47.296Z"),
"dropped" : false,
"key" : {
"id" : 1
},
"unique" : false
}
查看分片的详细信息
admin> db.printShardingStatus()
或
admin> sh.status() *****
删除分片节点(谨慎),因为会触发chunk迁移,会把删除的分片节点迁移到另一个节点
删除分片节点(谨慎),因为会触发chunk迁移,会把删除的分片节点迁移到另一个节点
(1)确认blance是否在工作
sh.getBalancerState()
(2)删除shard2节点(谨慎)
mongos> db.runCommand( { removeShard: "shard2" } )
注意:删除操作一定会立即触发blancer。
8、分片的添加
注意:添加新节点都会触发chunk迁移,添加后,会触发数据的均匀
db.runCommand( { addshard : "sh1/192.168.86.5:38021,192.168.86.5:38022,192.168.86.5:38023",name:"shard1"} )
db.runCommand( { addshard : "sh2/192.168.86.5:38024,192.168.86.5:38025,192.168.86.5:38026",name:"shard2"} )
八、balancer操作(运维重要)
介绍:mongos的一个重要功能,自动巡查所有shard节点上的chunk的情况,自动做chunk迁移
什么时候工作?
1、自动运行,会检测系统不繁忙的时候做迁移
2、在做节点删除的时候,立即开始迁移工作
3、balancer只能在预设定的时间窗口内运行(建议) *****
3.1、繁忙的时候不能
3.2、备份的时候不能,chunk迁移,导致数据不一致,恢复的时候没办法恢复
自定义自动平衡进行的时间段
设置凌晨3:00 ~ 5:00
mongos> use config # mongos 的配置一般都在config
mongos> sh.setBalancerState( true ) #设置启动Balance
{
"ok" : 1,
"operationTime" : Timestamp(1666679479, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1666679479, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
db.settings.update({ _id : "balancer" }, { $set : { activeWindow : { start : "3:00", stop : "5:00" } } }, true )
# 查看
mongos> sh.status()
balancer:
Currently enabled: yes
Currently running: no
Balancer active window is set between 3:00 and 5:00 server local time
Failed balancer rounds in last 5 attempts: 0
Migration Results for the last 24 hours:
512 : Success
或者
sh.getBalancerWindow()
关于集合的balancer(了解下)
关闭某个集合的balance
sh.disableBalancing("students.grades")
打开某个集合的balancer
sh.enableBalancing("students.grades")
确定某个集合的balance是开启或者关闭
db.getSiblingDB("config").collections.findOne({_id : "students.grades"}).noBalance;
九、备份恢复 (运维重要)
1、备份恢复工具介绍:
(1)** mongoexport/mongoimport
(2)***** mongodump/mongorestore
2、备份工具区别在哪里?
mongoexport/mongoimport 逻辑备份导入/导出的是JSON格式或者CSV格式,基于
mongodump/mongorestore 物理备份导入/导出的是BSON格式。
JSON可读性强但体积较大,BSON则是二进制文件,体积小但对人类几乎没有可读性
mongoexport/mongoimport 由于可以导出CSV格式,所以可以作为不同数据库之间导入的桥梁
3、在一些mongodb版本之间,BSON格式可能会随版本不同而有所不同,所以不同版本之间用mongoexport/mongoimport。
跨版本的mongodump/mongorestore个人并不推荐,实在要做请先检查文档看两个版本是否兼容(大部分时候是的)
4、JSON虽然具有较好的跨版本通用性,但其只保留了数据部分,不保留索引,账户等其他基础信息。使用时应该注意。
5、应用场景总结:
mongoexport/mongoimport:json csv
1、异构平台迁移 mysql <---> mongodb
2、同平台,跨大版本:mongodb 2 ----> mongodb 3
6、mongodump/mongorestore 日常备份恢复时使用.
1、mongoexport/mongoimport
mongoexport 导出 json
导出工具mongoexport
导入工具mongoimport
mongodb中的mongoexport工具可以把一个collection(表)导出成JSON格式或CSV格式的文件。
可以通过参数指定导出的数据项,也可以根据指定的条件导出数据。注意:由于是json 所以只能对表 就是集合导出,不能对库进行整体导出
(1)版本差异较大
(2)异构平台数据迁移
mongoexport具体用法如下所示:
$ mongoexport --help
参数说明:
-h:指明数据库宿主机的IP
-u:指明数据库的用户名
-p:指明数据库的密码
-d:指明数据库的名字 注意:由于是json 所以只能对表 就是集合导出,不能对库进行整体导出
-c:指明collection的名字
-f:指明要导出那些列 导出是json 或者 csv 默认只导出数据,没有列的名字,所以加上-f 要加上列的信息,如2020-08-19T05:58:26.700+0800 Failed: CSV mode requires a field list
-o:指明到要导出的文件名
-q:指明导出数据的过滤条件 while 哪些不导出
--authenticationDatabase admin 验证库,的必须手工加上
单表备份至json格式
[root@db1 ~]# mkdir /mongodb/backup
[root@db1 ~]# mongo -uroot -proot123
> use jerry
> for(i=1;i<10000;i++){ db.jihe.insert({"id":i,"name":"shenzheng","age":70,"date":new Date()}); }
> db.jihe.count()
10000
>
# 导出jerry 库下的jihe 表
[root@db1 ~]# mongoexport -uroot -proot123 --port 27017 --authenticationDatabase admin -d jerry -c jihe -o /mongodb/jerry_jihe.json
2022-10-25T15:01:40.529+0800 connected to: localhost:27017
2022-10-25T15:01:40.892+0800 exported 10000 records
[root@db1 ~]# head -n 10 /mongodb/jerry_jihe.json
{"_id":{"$oid":"6356da33e3f8ef3a107dc651"},"id":"101","name":"lisi","age":"10","gender":"nan"}
{"_id":{"$oid":"6356da42e3f8ef3a107dc652"},"id":"102","name":"zhang","age":"12","gender":"nan"}
{"_id":{"$oid":"6356da4fe3f8ef3a107dc653"},"id":"103","name":"wang","age":"10","gender":"nan"}
{"_id":{"$oid":"6356db851a1cdc1597160e25"},"id":"104","name":"lisi","age":"12","gender":"nan"}
{"_id":{"$oid":"6356ddee1a1cdc1597160e26"},"id":"108","name":"lisi","age":"12","gender":"nan"}
{"_id":{"$oid":"6357888d897d35cbb4efb3b2"},"id":1.0,"name":"shenzheng","age":70.0,"date":{"$date":"2022-10-25T06:56:13.544Z"}}
{"_id":{"$oid":"6357888d897d35cbb4efb3b3"},"id":2.0,"name":"shenzheng","age":70.0,"date":{"$date":"2022-10-25T06:56:13.608Z"}}
{"_id":{"$oid":"6357888d897d35cbb4efb3b4"},"id":3.0,"name":"shenzheng","age":70.0,"date":{"$date":"2022-10-25T06:56:13.608Z"}}
{"_id":{"$oid":"6357888d897d35cbb4efb3b5"},"id":4.0,"name":"shenzheng","age":70.0,"date":{"$date":"2022-10-25T06:56:13.609Z"}}
{"_id":{"$oid":"6357888d897d35cbb4efb3b6"},"id":5.0,"name":"shenzheng","age":70.0,"date":{"$date":"2022-10-25T06:56:13.609Z"}}
"_id":$oid":"6357888d897d35cbb4efb3b2"} 自己加的主键id,每次插入数据行,自动生成聚集索引列
mongoexport 导出 scv
[root@db1 ~]# mongoexport -uroot -proot123 --port 27017 --authenticationDatabase admin -d jerry -c jihe --type=csv -o /mongodb/jerry_jihe.csv
提示导出csv需要告诉我导出哪些列
# 指定到处-f id,name,age,date这些列
[root@db1 ~]# mongoexport -uroot -proot123 --port 27017 --authenticationDatabase admin -d jerry -c jihe --type=csv -f id,name,age,date -o /mongodb/jerry_jihe.csv
2022-10-25T15:10:03.174+0800 connected to: localhost:27017
2022-10-25T15:10:03.282+0800 exported 10005 records
[root@db1 ~]# head -n 10 /mongodb/jerry_jihe.csv
id,name,age,date # 列明 数据行
1,shenzheng,70,2022-10-25T06:56:13.544Z
2,shenzheng,70,2022-10-25T06:56:13.608Z
3,shenzheng,70,2022-10-25T06:56:13.608Z
4,shenzheng,70,2022-10-25T06:56:13.609Z
mongoimport 导入json
Mongodb中的mongoimport工具可以把一个特定格式文件中的内容导入到指定的collection中。该工具可以导入JSON格式数据,也可以导入CSV格式数据。具体使用如下所示:
$ mongoimport --help
参数说明:
-h:指明数据库宿主机的IP
-u:指明数据库的用户名
-p:指明数据库的密码
-d:指明数据库的名字 # 导入那个库,可以导入其他库
-c:指明collection的名字 # 指定导入到那个表中,可以导入其他库下的任意表
-f:指明要导入那些列 # csv 用
-j, --numInsertionWorkers=<number> number of insert operations to run concurrently (defaults to 1) //并行 开启并发导入 ,看cpu和I/O
[root@db1 ~]# mongoimport -uroot -proot123 --port 27017 --authenticationDatabase admin -d jerry -c jihe1 /mongodb/jerry_jihe.json
2022-10-25T15:24:13.118+0800 connected to: localhost:27017
2022-10-25T15:24:13.369+0800 imported 10000 documents
注:
1、导入原库原表会失败,因为有$oid":"6356da33e3f8ef3a107dc651"限制,必须添加--drop将原有的数据删除
2、可以导入一个没创建的库、或者表中,会自动创建
mongoimport 导入scv
注:
1、导入原库原表会失败,必须添加--drop将原有的数据删除
2、可以导入一个没创建的库、或者表中,会自动创建
情况一:原csv有列名字id,name,age,date,我不能把列名字直接也导入
[root@db1 ~]# head -n 10 /mongodb/jerry_jihe.csv
id,name,age,date
1,shenzheng,70,2022-10-25T06:56:13.544Z
2,shenzheng,70,2022-10-25T06:56:13.608Z
3,shenzheng,70,2022-10-25T06:56:13.608Z
4,shenzheng,70,2022-10-25T06:56:13.609Z
5,shenzheng,70,2022-10-25T06:56:13.609Z
6,shenzheng,70,2022-10-25T06:56:13.609Z
# headerline 第一行不要导入,需要作为列明
[root@db1 ~]# mongoimport -uroot -proot123 --port 27017 --authenticationDatabase admin -d test2 -c log2 --type=csv --headerline --file /mongodb/jerry_jihe.csv
2022-10-25T15:33:58.432+0800 connected to: localhost:27017
2022-10-25T15:33:58.583+0800 imported 10000 documents
情况二:开头没有列名
# 需要-f 指定列信息
[root@db1 ~]# mongoimport -uroot -proot123 --port 27017 --authenticationDatabase admin -d test3 -c log2 --type=csv -f uid,name,age,data --file /mongodb/jerry_jihe.csv
2022-10-25T15:40:48.742+0800 connected to: localhost:27017
2022-10-25T15:40:48.895+0800 imported 10000 documents
mysql 数据迁移 mongodb
mysql 导出的 scv 以空格分隔,mongodb 导出的 scv 以,分隔
mysql> use t100
mysql> select * from t100w limit 100000 into outfile "/tmp/t100w.csv";
mysql> exit
[root@db1 ~]# head -n 10 /tmp/t100w.csv
1 56914 Hd MN89 2019-07-09 16:01:41
2 542219 tx bc45 2019-07-09 16:01:41
3 944336 6i XYPQ 2019-07-09 16:01:41
4 137325 PK 34VW 2019-07-09 16:01:41
5 81318 wz 67KL 2019-07-09 16:01:41
6 574174 LZ wxuv 2019-07-09 16:01:41
[root@db1 ~]# head -n 10 /mongodb/jerry_jihe.csv
1,shenzheng,70,2022-10-25T06:56:13.544Z
2,shenzheng,70,2022-10-25T06:56:13.608Z
3,shenzheng,70,2022-10-25T06:56:13.608Z
4,shenzheng,70,2022-10-25T06:56:13.609Z
5,shenzheng,70,2022-10-25T06:56:13.609Z
6,shenzheng,70,2022-10-25T06:56:13.609Z
7,shenzheng,70,2022-10-25T06:56:13.610Z
8,shenzheng,70,2022-10-25T06:56:13.610Z
mysql 的 fields terminated by ',' 参数将中间到的空格变成逗号
mysql> use t100
mysql> select * from t100w limit 10000 into outfile '/tmp/t100w2.csv' fields terminated by ',';
mysql> exit
[root@db1 ~]# head -n 10 /tmp/t100w2.csv
1,56914,Hd,MN89,2019-07-09 16:01:41
2,542219,tx,bc45,2019-07-09 16:01:41
3,944336,6i,XYPQ,2019-07-09 16:01:41
4,137325,PK,34VW,2019-07-09 16:01:41
5,81318,wz,67KL,2019-07-09 16:01:41
6,574174,LZ,wxuv,2019-07-09 16:01:41
7,146558,ZG,fg23,2019-07-09 16:01:41
8,649971,e4,ABxy,2019-07-09 16:01:41
9,94891,ey,YZ34,2019-07-09 16:01:41
导入到mongodb
[root@db1 ~]# mongoimport -uroot -proot123 --port 27017 --authenticationDatabase admin -d test4 -c log2 --type=csv -f ID,Name,CountryCode,District,Population --file /tmp/t100w.csv
[root@db1 ~]# mongo -uroot -p123 test4
> use test4
switched to db test4
> db.log
db.log2 db.logout(
> db.log2.find()
{ "_id" : ObjectId("635798a53a4e0b8c12657db9"), "ID" : "1\t56914\tHd\tMN89\t2019-07-09 16:01:41" }
2、mongodump和mongorestore
mongodump能够在Mongodb运行时进行备份,它的工作原理是对运行的Mongodb做查询,然后将所有查到的文档写入磁盘。但是存在的问题时使用mongodump产生的备份不一定是数据库的实时快照,如果我们在备份时对数据库进行了写入操作,则备份出来的文件可能不完全和Mongodb实时数据相等。另外在备份时可能会对其它客户端性能产生不利的影响。对单库单表都可以实时备份,对分片备份不太好。支持热备
mongodump 备份
mongodump用法如下:
$ mongodump --help
参数说明:
-h:指明数据库宿主机的IP
-u:指明数据库的用户名
-p:指明数据库的密码
-d:指明数据库的名字
-c:指明collection的名字
-o:指明到要导出的文件名
-q:指明导出数据的过滤条件
-j, --numParallelCollections= number of collections to dump in parallel (4 by default)
--oplog 备份的同时备份oplog 配合复制集以上的集群才会用,单机无用。单机没有oplog或者单节点配置成复制集角色,单机没oplog,只有复制集才有
全库备份,如果有同名目录会覆盖
# 备份的目录中,以数据库名字命名文件夹,文件夹中就是表,两个表一个json 一个bson
mongodump -uroot -proot123 --port 27017 --authenticationDatabase admin -o /mongodb/backup
备份world库,注意会在你指定的目录中生成一个数据库文件夹
mongodump -uroot -proot123 --port 27017 --authenticationDatabase admin -d world -o /mongodb/backup/
备份表
备份oldboy库下的log集合
mongodump -uroot -proot123 --port 27017 --authenticationDatabase admin -d oldboy -c log -o /mongodb/backup/
压缩备份
mongodump -uroot -proot123 --port 27017 --authenticationDatabase admin -d oldguo -o /mongodb/backup/ --gzip
mongodump -uroot -proot123 --port 27017 --authenticationDatabase admin -o /mongodb/backup/ --gzip
mongodump -uroot -proot123 --port 27017 --authenticationDatabase admin -d app -c vast -o /mongodb/backup/ --gzip
mongorestore 恢复
单表恢复
ongorestore -uroot -proot123 --port 27017 --authenticationDatabase admin -d oldguo -c log4 /mongodb/backup/oldguo/log4.bson
单表恢复--gzip 备份的恢复
在语句结尾加 --gzip
ongorestore -uroot -proot123 --port 27017 --authenticationDatabase admin -d oldguo -c log4 --gzip /mongodb/backup/oldguo/log4.bson
--drop表示恢复的时候把之前的集合drop掉(危险)
mongorestore -uroot -proot123 --port 27017 --authenticationDatabase admin -d oldboy --drop /mongodb/backup/oldboy
可以不用加,如果恢复有重复,会自动跳过
3、mongodump和mongorestore高级企业应用(--oplog)
注意:这是 replica set 或者 master/slave 模式专用
--oplog
use oplog for taking a point-in-time snapshot
在replica set中oplog是一个定容集合(capped collection),它的默认大小是磁盘空间的5%(可以通过--oplogSizeMB参数修改).
位于local库的db.oplog.rs,有兴趣可以看看里面到底有些什么内容。
其中记录的是整个mongod实例一段时间内数据库的所有变更(插入/更新/删除)操作。
当空间用完时新记录自动覆盖最老的记录。
其覆盖范围被称作oplog时间窗口。需要注意的是,因为oplog是一个定容集合,
所以时间窗口能覆盖的范围会因为你单位时间内的更新次数不同而变化。
想要查看当前的oplog时间窗口预计值,可以使用以下命令:
把数据进行快照备份,第二能再备份的同时把数据库的变化日志一并保存,假如备份5min,将会把5min内发生新的变化(oplog)一并进行保存
oplog 配合 mongdump 实现热备
主要在主库,数据会更加完整
[root@db1 ~]# mongodump --port 28018 --oplog -o /mongodb/backup/
[root@db1 ~]# ll /mongodb/backup/
总用量 8
drwxr-xr-x 2 root root 69 10月 25 17:17 admin
drwxr-xr-x 2 root root 4096 10月 25 17:17 config
-rw-r--r-- 1 root root 198 10月 25 17:17 oplog.bson # 备份过程中产生新的变化
mongorestore恢复
# 全部恢复,自动读取备份跟oplog.bson,有重复自动跳过
mongorestore --port 28017 --oplogReplay /mongodb/backup/
# 也可以遇到重复的先删除,在导入,建议不加
mongorestore --port 28017 --drop --oplogReplay /mongodb/backup/
4、oplog高级应用(oplog理解为binlog)
背景:每天0点全备,oplog恢复窗口为48小时
某天,上午10点world.city 业务表被误删除。恢复思路:
0、停应用
2、找测试库
3、恢复昨天晚上全备
4、截取全备之后到world.city误删除时间点的oplog,并恢复到测试库
5、将误删除表导出,恢复到生产库
案例:每周天有全量备份,平常有oplog,周一早晨出现删除的操作,如何恢复
思路:先恢复全备份,在周天到周一早晨把oplog的日志截取出来,恢复
问题:怎么截图,日志在表中存的,怎么让oplog备份一起恢复,oplog不能单独恢复,也能必须转成json,用import导入,,挺麻烦的,
如何恢复,找到误操作到的点,--oplogReplay,oplogReplay有幂等性,有重复得不跑了
------ 备份全部数据------
[root@db1 ~]# mongo --port 38021 admin
sh1:PRIMARY> use jerry
sh1:PRIMARY> db.t1.find()
{ "_id" : ObjectId("6357c48055eda30737aaf449"), "id" : "101", "name" : "tom" }
{ "_id" : ObjectId("6357c48955eda30737aaf44a"), "id" : "102", "name" : "hello" }
[root@db1 ~]# mongodump --port 38021 --oplog -o /mongodb/backup/38021/
------ 删库------
sh1:PRIMARY> use jerry
sh1:PRIMARY> sh1:PRIMARY> db.dropDatabase()
------ 获取oplog已经记录多久------
sh1:PRIMARY> rs.printReplicationInfo() 返回oplog的大小,已经运行时间
configured oplog size: 2048MB
log length start to end: 63669secs (17.69hrs) 当oplog写满时可以理解为时间窗口
oplog first event time: Tue Oct 25 2022 07:59:39 GMT+0800 (CST)
oplog last event time: Wed Oct 26 2022 01:40:48 GMT+0800 (CST) 最后一个操作发生的时间
now: Wed Oct 26 2022 01:40:54 GMT+0800 (CST)
sh1:PRIMARY>
# 怎么看这东西
# 默认存满2048MB后自动删除之前的binlog
# oplog first event time 为当前binlog从哪开始记录的,之前的binlog由于满了之后已经删除
# oplog last event time 此命令是你执行mongodump -d local -c oplog.rs 导出oplog 的时间点
# log length start to end 最为重要,这个时间点是变化的,他记录了离你现在保存多久binlog数据
# 配置文件 conf/slave.conf 中的oplogsize
replication:
oplogsizemb: 10240
replsetname: rpset1
------ 获取oplog删除库的oplog号------
sh1:PRIMARY> use local
sh1:PRIMARY> db.oplog.rs.find({"op":"c"}).pretty() # 过滤op=c 最后一条就是删除数据库
{
"ts" : Timestamp(1666697460, 3), # 这个时间点
"t" : NumberLong(10),
"h" : NumberLong("-9018111726918247667"),
"v" : 2,
"op" : "c",
"ns" : "jerry.$cmd",
"wall" : ISODate("2022-10-25T11:31:00.333Z"),
"o" : {
"dropDatabase" : 1
}
}
------ oplog备份数据----
[root@db1 ~]# mongodump --port 38021 -d local -c oplog.rs -o /mongodb/
2022-10-26T01:23:43.226+0800 writing local.oplog.rs to
2022-10-26T01:23:43.361+0800 done dumping local.oplog.rs (25403 documents)
[root@db1 ~]# ll /mongodb/local/
总用量 5064
-rw-r--r-- 1 root root 5180267 10月 26 01:23 oplog.rs.bson
-rw-r--r-- 1 root root 125 10月 26 01:23 oplog.rs.metadata.json
--- 进行oplog 重演------
我们之前备份数据的时候,知道了oplog.bson是备份过程中产生新的变化
mongodump --port 28018 --oplog -o /mongodb/backup/
ll /mongodb/backup/
总用量 8
drwxr-xr-x 2 root root 69 10月 25 17:17 admin
drwxr-xr-x 2 root root 4096 10月 25 17:17 config
-rw-r--r-- 1 root root 198 10月 25 17:17 oplog.bson
#上述也看过oplog记录了从什么时候到什么时候的binlog,这个时间推算是周天之前的,并导出binlog
#我们知道全量备份的时候,/mongodb/backup/oplog.bson 是记录的偏移量,也就是备份到备份完成之间发生的数据差异,其实他就是binlog,在恢复数据的时候,直接恢复全部+差异binlog
#所以我们直接将刚才备份的/mongodb/local/oplog.rs.bson 拷贝到/mongodb/backup/目录下,替代/mongodb/backup/oplog.bson,也就是说,现在的数据是,周天的全库+现在到周天之前的binlog,然后再去除刚才的删库操作,他们之间有重叠的部分,恢复的时候会自动跳过
[root@db1 local]# mv /mongodb/local/oplog.rs.bson /mongodb/backup/38021/
[root@db1 local]# cd /mongodb/backup/38021/
[root@db1 38021]# ll
总用量 5068
drwxr-xr-x 2 root root 69 10月 25 19:17 admin
drwxr-xr-x 2 root root 4096 10月 25 19:17 config
drwxr-xr-x 2 root root 45 10月 25 19:17 jerry
-rw-r--r-- 1 root root 110 10月 25 19:17 oplog.bson
-rw-r--r-- 1 root root 5180267 10月 26 01:23 oplog.rs.bson
[root@db1 38021]# mv oplog.rs.bson oplog.basn
[root@db1 38021]# ll
总用量 5068
drwxr-xr-x 2 root root 69 10月 25 19:17 admin
drwxr-xr-x 2 root root 4096 10月 25 19:17 config
drwxr-xr-x 2 root root 45 10月 25 19:17 jerry
-rw-r--r-- 1 root root 5180267 10月 26 01:23 oplog.basn
-rw-r--r-- 1 root root 110 10月 25 19:17 oplog.bson
-- 进行oplog 重演,跳过删除数据库的操作
sh1:PRIMARY> db.oplog.rs.find({"op":"c"}).pretty()
"ts" : Timestamp(1666697460, 3)
[root@db1 38021]# mongorestore --port 38021 --oplogReplay --oplogLimit "1666697460:3" --drop /mongodb/backup/38021/
[root@db1 38021]# mongo --port 38021
sh1:PRIMARY> show databases;
admin 0.000GB
config 0.000GB
jerry 0.000GB # 查看数据库已经恢复
local 0.001GB
sh1:PRIMARY> use jerry
switched to db jerry
sh1:PRIMARY> show tables;
t1
5、分片集群的备份思路
1、你要备份什么?
config server 数据
shard 节点数据
2、可不可以直接通过mongos 备份,直接就能备份shard 、 config server
可以备份,但一个大表的数据比如100W可能存在一半在shard1(50W)、一半在shard2(50W)等等均匀的,通过mongos备份的数据是一个合计(100W)整表,整表就没有分片策略节点信息,意味着,mongos备份的数据备份的时候只能恢复到单节点,实现不了一半在shard1(50W)、一半在shard2,那违背了集群架构了,集群应该是哪个坏,恢复到哪
3、单独进行备份config server 数据、shard 节点数据
4、单独进行备份有什么困难和问题
一个shard 比如说10点备份整库或者整表,由于表1非常繁忙,导致备份花费了5min,最后数据是10.05分数据
另一个shard 比如说10点备份整库或者整表,可能使用了Range,最大业务的表1没存储过来,业务轻松,花费了2min,最后数据是10.02分数据
就算使用了Hash,也不能绝对的两边数据对等,而且机器的性能也影响备份时间,会导致两个shard 的备份出时间点几乎不一致。
做数据恢复的时候,一个节点是10.05分数据、另一个10.02分数据,对不上,mongos 逻辑上还是一张表,但是物理上不是,而且时间点不一样,肯定丢数据了。
如果此时 chunk迁移,比如10点并发备份config server 数据,期间 shard 进行chunk 迁移还没迁移完毕。而config server 数据备份时候记录的是 chunk迁移前的位置,config server 数据备份时候记录是shard1,备份完config server 后,数据已经迁移到shard 2,恢复config server 数据备份,导致mongos找不到数据
1、 人为控制在备份的时候,避开迁移的时间窗口
2、shard节点之间的数据不在同一时间点。
选业务量较少的时候
3、官网给出一个建议是,在做备份的时候,每一个shard中 摘出一个从节点,统一备份,完事再添加会原节点