Mongodb 运维讲解

一、介绍

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中 摘出一个从节点,统一备份,完事再添加会原节点

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值