文章目录
- 资源分享
- 1 MongoDB副本集-Replica Sets
- 2 分片集群-Sharded Cluster
- 3 安全认证
- 常用命令
🙊 前言:本文章为瑞_系列专栏之《MongoDB》的集群和安全整合篇。由于博主是从B站黑马程序员的《MongoDB》学习其相关知识,所以本系列专栏主要是针对该课程进行笔记总结和拓展,文中的部分原理及图解等也是来源于黑马提供的资料,特此注明。本文仅供大家交流、学习及研究使用,禁止用于商业用途,违者必究!
资源分享
已配置完成的Linux版本MongoDB服务
的某度网盘链接如下,需要自取
链接:https://pan.baidu.com/s/1g6wxeRSmQRsiBo6LuIJewg?pwd=l129
提取码:l129
MongoDB环境所需资源
的某度网盘链接如下,需要自取
链接:https://pan.baidu.com/s/1l_e0wUmHgZf8F42wYFUjnw?pwd=8s3b
提取码:8s3b
article
的完整源码的某度网盘链接如下,需要自取
链接:https://pan.baidu.com/s/1t9oFhTKIaaPYg6_Obhvhow?pwd=efas
提取码:efas
1 MongoDB副本集-Replica Sets
1.1 简介
瑞:副本集的作用就是,当一台服务器挂了,可以无缝切换另一台服务,类似 MySQL 的主从复制
MongoDB 中的副本集(Replica Set)是一组维护相同数据集的 MongoDB 服务。 副本集可提供冗余和高可用性,是所有生产部署的基础。
副本集类似于有自动故障恢复功能的主从集群。通俗的讲就是用多台机器进行同一数据的异步同步,从而使多台机器拥有同一数据的多个副本,并且当主库当掉时在不需要用户干预的情况下自动切换其他备份服务器做主库。而且还可以利用副本服务器做只读服务器,实现读写分离,提高负载。
1️⃣ 冗余和数据可用性
复制提供冗余并提高数据可用性。 通过在不同数据库服务器上提供多个数据副本,复制可提供一定级别的容错功能,以防止丢失单个数据库服务器。
在某些情况下,复制可以提供增加的读取性能,因为客户端可以将读取操作发送到不同的服务上, 在不同数据中心维护数据副本可以增加分布式应用程序的数据位置和可用性。 您还可以为专用目的维护其他副本,例如灾难恢复,报告或备份。
2️⃣ MongoDB 中的复制
副本集是一组维护相同数据集的 MongoDB 实例。 副本集包含多个数据承载节点和可选的一个仲裁节点。在承载数据的节点中,一个且仅一个成员被视为主节点,而其他节点被视为次要(从)节点。
主节点接收所有写操作。 副本集只能有一个主要能够确认具有{w:“most”}
写入关注的写入;虽然在某些情况下,另一个 MongoDB 实例可能暂时认为自己也是主要的。主要记录其操作日志中的数据集的所有更改,即 oplog。
辅助(副本)节点复制主节点的 oplog 并将操作应用于其数据集,以使辅助节点的数据集反映主节点的数据集。 如果主要人员不在,则符合条件的中学将举行选举以选出新的主要人员。
3️⃣ 主从复制和副本集区别
主从集群和副本集最大的区别就是副本集没有固定的“主节点”;整个集群会选出一个“主节点”,当其挂掉后,又在剩下的从节点中选中其他节点为“主节点”,副本集总有一个活跃点(主、primary)和一个或多个备份节点(从、secondary)
1.2 副本集的三个角色
副本集有两种类型三种角色
两种类型
- 主节点(Primary)类型:数据操作的主要连接点,可读写。
- 次要(辅助、从)节点(Secondaries)类型:数据冗余备份节点,可以读或选举。
三种角色
- 主要成员(Primary):主要接收所有写操作。就是主节点。
- 副本成员(Replicate):从主节点通过复制操作以维护相同的数据集,即备份数据,不可写操作,但可以读操作(但需要配置)。是默认的一种从节点类型。
- 仲裁者(Arbiter):不保留任何数据的副本,只具有投票选举作用。当然也可以将仲裁服务器维护为副本集的一部分,即副本成员同时也可以是仲裁者。也是一种从节点类型。
【关于仲裁者的额外说明】
您可以将额外的mongod实例添加到副本集作为仲裁者。 仲裁者不维护数据集。 仲裁者的目的是通过响应其他副本集成员的心跳和选举请求来维护副本集中的仲裁。 因为它们不存储数据集,所以仲裁器可以是提供副本集仲裁功能的好方法,其资源成本比具有数据集的全功能副本集成员更便宜。
如果您的副本集具有偶数个成员,请添加仲裁者以获得主要选举中的“大多数”投票。 仲裁者不需要专用硬件。
仲裁者将永远是仲裁者,而主要人员可能会退出并成为次要人员,而次要人员可能成为选举期间的主要人员。
如果你的副本 + 主节点的个数是偶数,建议加一个仲裁者,形成奇数,容易满足大多数的投票。
如果你的副本 + 主节点的个数是奇数,可以不加仲裁者。
1.3 副本集架构目标
需要 3 个 MongoDB 服务:一主一副本一仲裁
- 副本集名称:
myrs
节点名 | 端口号 |
---|---|
主节点 Primary | 27017 |
副本节点 Secondary | 27018 |
仲裁节点 Arbiter | 27019 |
1.4 副本集的创建
瑞:MongoDB 在 Linux 系统中的安装请参考《瑞_MongoDB(笔记超详细,有这一篇就够了)》
1.4.1 创建主节点
1️⃣ 建立存放数据和日志的目录
#-----------myrs
# 主节点 27017
mkdir -p /usr/local/mongodb/replica_sets/myrs_27017/log \ &
mkdir -p /usr/local/mongodb/replica_sets/myrs_27017/data/db
2️⃣ 新建或修改配置文件
vi /usr/local/mongodb/replica_sets/myrs_27017/mongod.conf
瑞:指令使用:按
a
切换到输入状态,将下面配置文件内容复制过去,然后按esc
输入:wq
保存文件并退出
myrs_27017
配置文件可以参考如下,主要修改服务实例绑定的 IP
【注意】
1️⃣ 注意子级配置要使用空格隔开,不能使用Tab,建议直接复制粘贴不要自己输入
2️⃣bindIp: localhost,192.168.133.131
中后面的IP 192.168.133.131
你可能无法绑定,这是博主的虚拟机IP,记得替换为你自己的IP,如果使用的是云服务器,需要绑定的是局域网IP,特别注意不是公网IP是局域网IP,如果您只希望从本地访问,可以直接改为bindIp: localhost
,注意前面有一个空格
systemLog:
# MongoDB发送所有日志输出的目标指定为文件
destination: file
# mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
path: "/usr/local/mongodb/replica_sets/myrs_27017/log/mongod.log"
# 当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
logAppend: true
storage:
# mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
dbPath: "/usr/local/mongodb/replica_sets/myrs_27017/data/db"
journal:
# 启用或禁用持久性日志以确保数据文件保持有效和可恢复。
enabled: true
processManagement:
# 启用在后台运行mongos或mongod进程的守护进程模式。
fork: true
# 指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
pidFilePath: "/usr/local/mongodb/replica_sets/myrs_27017/log/mongod.pid"
net:
# 服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
# bindIpAll: true
# 服务实例绑定的IP
bindIp: localhost,192.168.133.131
# bindIp
# 绑定的端口
port: 27017
replication:
# 副本集的名称
replSetName: myrs
3️⃣ 启动主节点服务,如下图出现 started successfully 则说明安装配置成功!
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/replica_sets/myrs_27017/mongod.conf
[root@localhost ~]# /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/replica_sets/myrs_27017/mongod.conf
about to fork child process, waiting until server is ready for connections.
forked process: 100346
child process started successfully, parent exiting
瑞:如果执行启动节点服务后看到如下图类似的错误,那是因为之前单节点配置的 27017 端口服务的单节点 MongoDB 服务占用了端口号,将其杀死后再尝试启动
1.4.2 创建副本节点
瑞:和主节点创建类似,主要修改端口号为 27018、路径为 myrs_27018
1️⃣ 建立存放数据和日志的目录
#-----------myrs
# 副本节点 27018
mkdir -p /usr/local/mongodb/replica_sets/myrs_27018/log \ &
mkdir -p /usr/local/mongodb/replica_sets/myrs_27018/data/db
2️⃣ 新建或修改配置文件
vi /usr/local/mongodb/replica_sets/myrs_27018/mongod.conf
myrs_27018
配置文件可以参考如下,主要修改服务实例绑定的 IP,注意路径需要修改为 myrs_27018
systemLog:
# MongoDB发送所有日志输出的目标指定为文件
destination: file
# mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
path: "/usr/local/mongodb/replica_sets/myrs_27018/log/mongod.log"
# 当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
logAppend: true
storage:
# mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
dbPath: "/usr/local/mongodb/replica_sets/myrs_27018/data/db"
journal:
# 启用或禁用持久性日志以确保数据文件保持有效和可恢复。
enabled: true
processManagement:
# 启用在后台运行mongos或mongod进程的守护进程模式。
fork: true
# 指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
pidFilePath: "/usr/local/mongodb/replica_sets/myrs_27018/log/mongod.pid"
net:
# 服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
# bindIpAll: true
# 服务实例绑定的IP
bindIp: localhost,192.168.133.131
# bindIp
# 绑定的端口
port: 27018
replication:
# 副本集的名称
replSetName: myrs
3️⃣ 启动副本节点服务,如下图出现 started successfully 则说明安装配置成功!
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/replica_sets/myrs_27018/mongod.conf
1.4.3 创建仲裁节点
瑞:和副本节点创建类似,主要修改端口号为 27019、路径为 myrs_27019
1️⃣ 建立存放数据和日志的目录
#-----------myrs
# 仲裁节点 27019
mkdir -p /usr/local/mongodb/replica_sets/myrs_27019/log \ &
mkdir -p /usr/local/mongodb/replica_sets/myrs_27019/data/db
2️⃣ 新建或修改配置文件
vi /usr/local/mongodb/replica_sets/myrs_27019/mongod.conf
myrs_27019
配置文件可以参考如下,主要修改服务实例绑定的 IP,注意路径需要修改为 myrs_27019
systemLog:
# MongoDB发送所有日志输出的目标指定为文件
destination: file
# mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
path: "/usr/local/mongodb/replica_sets/myrs_27019/log/mongod.log"
# 当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
logAppend: true
storage:
# mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
dbPath: "/usr/local/mongodb/replica_sets/myrs_27019/data/db"
journal:
# 启用或禁用持久性日志以确保数据文件保持有效和可恢复。
enabled: true
processManagement:
# 启用在后台运行mongos或mongod进程的守护进程模式。
fork: true
# 指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
pidFilePath: "/usr/local/mongodb/replica_sets/myrs_27019/log/mongod.pid"
net:
# 服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
# bindIpAll: true
# 服务实例绑定的IP
bindIp: localhost,192.168.133.131
# bindIp
# 绑定的端口
port: 27019
replication:
# 副本集的名称
replSetName: myrs
3️⃣ 启动仲裁节点服务,如下图出现 started successfully 则说明安装配置成功!
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/replica_sets/myrs_27019/mongod.conf
执行ps -ef | grep mongo
命令查看三个节点(27017-主、27018-从、27019-仲裁)是否成功运行
1.4.4 初始化配置副本集和主节点
使用客户端命令连接任意一个节点,建议尽量连接主节点(27017节点)
/usr/local/mongodb/bin/mongo --host=192.168.133.131 --port=27017
连接上之后,很多命令无法使用,比如show dbs
等,必须初始化副本集才行
准备初始化新的副本集,语法如下
rs.initiate(configuration)
configuration
选项
Parameter | Type | Description |
---|---|---|
configuration | document | Optional. A document that specifies configuration for the new replica set. If a configuration is not specified, MongoDB uses a default replica set configuration. |
【示例】使用默认的配置来初始化副本集,即无参
rs.initiate()
【执行结果】
> rs.initiate()
{
"info2" : "no configuration specified. Using a default configuration for the set",
"me" : "192.168.133.131:27017",
"ok" : 1,
"operationTime" : Timestamp(1714162636, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1714162636, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
myrs:SECONDARY>
myrs:PRIMARY>
【说明】
- “ok”的值为1,说明创建成功。
- 命令行提示符发生变化,变成了一个从节点角色
myrs:SECONDARY
,此时默认不能读写。稍等片刻后回车,就会变成主节点myrs:PRIMARY
。
1.4.5 查看副本集的配置内容 rs.conf()
【语法】返回包含当前副本集配置的文档
rs.conf(configuration)
【提示】
-
rs.config()
是该方法的别名 -
configuration:可选,如果没有配置,则使用默认主节点配置。
【示例】在 27017 上执行副本集中当前节点的默认节点配置
[root@localhost ~]# /usr/local/mongodb/bin/mongo --host=192.168.133.131 --port=27017
MongoDB shell version v4.0.10
connecting to: mongodb://192.168.133.131:27017/?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("348dbc74-2c56-4738-bf77-7a15778b858a") }
MongoDB server version: 4.0.10
Server has startup warnings:
2024-04-27T03:44:14.615+0800 I CONTROL [initandlisten]
2024-04-27T03:44:14.615+0800 I CONTROL [initandlisten] ** WARNING: Access control is not enabled for the database.
2024-04-27T03:44:14.616+0800 I CONTROL [initandlisten] ** Read and write access to data and configuration is unrestricted.
2024-04-27T03:44:14.616+0800 I CONTROL [initandlisten] ** WARNING: You are running this process as the root user, which is not recommended.
2024-04-27T03:44:14.616+0800 I CONTROL [initandlisten]
2024-04-27T03:44:14.616+0800 I CONTROL [initandlisten]
2024-04-27T03:44:14.616+0800 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.
2024-04-27T03:44:14.616+0800 I CONTROL [initandlisten] ** We suggest setting it to 'never'
2024-04-27T03:44:14.617+0800 I CONTROL [initandlisten]
2024-04-27T03:44:14.617+0800 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.
2024-04-27T03:44:14.617+0800 I CONTROL [initandlisten] ** We suggest setting it to 'never'
2024-04-27T03:44:14.617+0800 I CONTROL [initandlisten]
myrs:PRIMARY>
myrs:PRIMARY> rs.conf()
{
"_id" : "myrs",
"version" : 1,
"protocolVersion" : NumberLong(1),
"writeConcernMajorityJournalDefault" : true,
"members" : [
{
"_id" : 0,
"host" : "192.168.133.131:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
}
],
"settings" : {
"chainingAllowed" : true,
"heartbeatIntervalMillis" : 2000,
"heartbeatTimeoutSecs" : 10,
"electionTimeoutMillis" : 10000,
"catchUpTimeoutMillis" : -1,
"catchUpTakeoverDelayMillis" : 30000,
"getLastErrorModes" : {
},
"getLastErrorDefaults" : {
"w" : 1,
"wtimeout" : 0
},
"replicaSetId" : ObjectId("662c0bcc58de9a52944397dd")
}
}
myrs:PRIMARY>
【说明】
1️⃣ "_id" : "myrs"
:副本集的配置数据存储的主键值,默认就是副本集的名字
2️⃣ "members"
:副本集成员数组,此时只有一个:"host" : "192.168.133.131:27017"
,该成员不是仲裁节点:"arbiterOnly" : false
,优先级(权重值):"priority" : 1,
3️⃣ "settings"
:副本集的参数配置。
提示:副本集配置的查看命令,本质是查询的是
system.replset
的表中的数据
myrs:PRIMARY> use local
switched to db local
myrs:PRIMARY> show collections
oplog.rs
replset.election
replset.minvalid
replset.oplogTruncateAfterPoint
startup_log
system.replset
system.rollback.id
myrs:PRIMARY> db.system.replset.find()
{ "_id" : "myrs", "version" : 1, "protocolVersion" : NumberLong(1), "writeConcernMajorityJournalDefault" : true, "members" : [ { "_id" : 0, "host" : "192.168.133.131:27017", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 1, "tags" : { }, "slaveDelay" : NumberLong(0), "votes" : 1 } ], "settings" : { "chainingAllowed" : true, "heartbeatIntervalMillis" : 2000, "heartbeatTimeoutSecs" : 10, "electionTimeoutMillis" : 10000, "catchUpTimeoutMillis" : -1, "catchUpTakeoverDelayMillis" : 30000, "getLastErrorModes" : { }, "getLastErrorDefaults" : { "w" : 1, "wtimeout" : 0 }, "replicaSetId" : ObjectId("662c0bcc58de9a52944397dd") } }
myrs:PRIMARY>
1.4.6 查看副本集状态
【说明】
返回包含状态信息的文档。此输出使用从副本集的其他成员发送的心跳包中获得的数据反映副本集的当前状态。
【语法】
rs.status()
【示例】在 27017 上查看副本集状态
myrs:PRIMARY> rs.status()
{
"set" : "myrs",
"date" : ISODate("2024-04-27T04:06:13.904Z"),
"myState" : 1,
"term" : NumberLong(1),
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"heartbeatIntervalMillis" : NumberLong(2000),
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1714190767, 1),
"t" : NumberLong(1)
},
"readConcernMajorityOpTime" : {
"ts" : Timestamp(1714190767, 1),
"t" : NumberLong(1)
},
"appliedOpTime" : {
"ts" : Timestamp(1714190767, 1),
"t" : NumberLong(1)
},
"durableOpTime" : {
"ts" : Timestamp(1714190767, 1),
"t" : NumberLong(1)
}
},
"lastStableCheckpointTimestamp" : Timestamp(1714190717, 1),
"members" : [
{
"_id" : 0,
"name" : "192.168.133.131:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 30119,
"optime" : {
"ts" : Timestamp(1714190767, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2024-04-27T04:06:07Z"),
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"electionTime" : Timestamp(1714162636, 2),
"electionDate" : ISODate("2024-04-26T20:17:16Z"),
"configVersion" : 1,
"self" : true,
"lastHeartbeatMessage" : ""
}
],
"ok" : 1,
"operationTime" : Timestamp(1714190767, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1714190767, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
myrs:PRIMARY>
【说明】
1️⃣ "set" : "myrs"
:副本集的名字
2️⃣ "myState" : 1
:说明状态正常
3️⃣ "members"
:副本集成员数组,此时只有一个:"name" : "192.168.133.131:27017"
,该成员的角色是"stateStr" : "PRIMARY",
该节点是健康的:"health" : 1
1.4.7 添加副本从节点
在主节点添加从节点,将其他成员加入到副本集
【语法】
rs.add(host, arbiterOnly)
【选项】
Parameter | Type | Description |
---|---|---|
host | string or document | 要添加到副本集的新成员。 指定为字符串或配置文档:1)如果是一个字符串,则需要指定新成员的主机名和可选的端口号;2)如果是一个文档,请指定在members数组中找到的副本集成员配置文档。 您必须在成员配置文档中指定主机字段。有关文档配置字段的说明,详见下方文档:“主机成员的配置文档” |
arbiterOnly | boolean | 可选。 仅在<host> 值为字符串时适用。 如果为true,则添加的主机是仲裁者。 |
主机成员的配置文档
{
_id: <int>,
host: <string>, // required
arbiterOnly: <boolean>,
buildIndexes: <boolean>,
hidden: <boolean>,
priority: <number>,
tags: <document>,
slaveDelay: <int>,
votes: <number>
}
【示例】将 27018 的副本节点添加到副本集中
myrs:PRIMARY> rs.add("192.168.133.131:27018")
{
"ok" : 1,
"operationTime" : Timestamp(1714191413, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1714191413, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
【说明】
"ok" : 1
:说明添加成功。
查看副本集状态⬇️
myrs:PRIMARY> rs.status()
{
"set" : "myrs",
"date" : ISODate("2024-04-27T09:26:12.954Z"),
"myState" : 1,
"term" : NumberLong(1),
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"heartbeatIntervalMillis" : NumberLong(2000),
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1714209971, 1),
"t" : NumberLong(1)
},
"readConcernMajorityOpTime" : {
"ts" : Timestamp(1714209971, 1),
"t" : NumberLong(1)
},
"appliedOpTime" : {
"ts" : Timestamp(1714209971, 1),
"t" : NumberLong(1)
},
"durableOpTime" : {
"ts" : Timestamp(1714209971, 1),
"t" : NumberLong(1)
}
},
"lastStableCheckpointTimestamp" : Timestamp(1714209931, 1),
"members" : [
{
"_id" : 0,
"name" : "192.168.133.131:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 49318,
"optime" : {
"ts" : Timestamp(1714209971, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2024-04-27T09:26:11Z"),
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"electionTime" : Timestamp(1714162636, 2),
"electionDate" : ISODate("2024-04-26T20:17:16Z"),
"configVersion" : 2,
"self" : true,
"lastHeartbeatMessage" : ""
},
{
"_id" : 1,
"name" : "192.168.133.131:27018",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 18559,
"optime" : {
"ts" : Timestamp(1714209961, 1),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Timestamp(1714209961, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2024-04-27T09:26:01Z"),
"optimeDurableDate" : ISODate("2024-04-27T09:26:01Z"),
"lastHeartbeat" : ISODate("2024-04-27T09:26:10.955Z"),
"lastHeartbeatRecv" : ISODate("2024-04-27T09:26:11.477Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncingTo" : "192.168.133.131:27017",
"syncSourceHost" : "192.168.133.131:27017",
"syncSourceId" : 0,
"infoMessage" : "",
"configVersion" : 2
}
],
"ok" : 1,
"operationTime" : Timestamp(1714209971, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1714209971, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
myrs:PRIMARY>
【说明】
"name" : "192.168.133.131:27018"
是第二个节点的名字,其角色是"stateStr" : "SECONDARY"
1.4.8 添加仲裁从节点
添加一个仲裁节点到副本集
【语法】
rs.addArb(host)
【示例】将 27019 的仲裁节点添加到副本集中
myrs:PRIMARY> rs.addArb("192.168.133.131:27019")
{
"ok" : 1,
"operationTime" : Timestamp(1714210263, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1714210263, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
myrs:PRIMARY>
【说明】
"ok" : 1
:说明添加成功。
查看副本集状态⬇️
myrs:PRIMARY> rs.status()
{
"set" : "myrs",
"date" : ISODate("2024-04-27T09:32:59.430Z"),
"myState" : 1,
"term" : NumberLong(1),
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"heartbeatIntervalMillis" : NumberLong(2000),
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1714210371, 1),
"t" : NumberLong(1)
},
"readConcernMajorityOpTime" : {
"ts" : Timestamp(1714210371, 1),
"t" : NumberLong(1)
},
"appliedOpTime" : {
"ts" : Timestamp(1714210371, 1),
"t" : NumberLong(1)
},
"durableOpTime" : {
"ts" : Timestamp(1714210371, 1),
"t" : NumberLong(1)
}
},
"lastStableCheckpointTimestamp" : Timestamp(1714210351, 1),
"members" : [
{
"_id" : 0,
"name" : "192.168.133.131:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 49725,
"optime" : {
"ts" : Timestamp(1714210371, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2024-04-27T09:32:51Z"),
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"electionTime" : Timestamp(1714162636, 2),
"electionDate" : ISODate("2024-04-26T20:17:16Z"),
"configVersion" : 3,
"self" : true,
"lastHeartbeatMessage" : ""
},
{
"_id" : 1,
"name" : "192.168.133.131:27018",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 18966,
"optime" : {
"ts" : Timestamp(1714210371, 1),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Timestamp(1714210371, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2024-04-27T09:32:51Z"),
"optimeDurableDate" : ISODate("2024-04-27T09:32:51Z"),
"lastHeartbeat" : ISODate("2024-04-27T09:32:57.812Z"),
"lastHeartbeatRecv" : ISODate("2024-04-27T09:32:57.852Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncingTo" : "192.168.133.131:27017",
"syncSourceHost" : "192.168.133.131:27017",
"syncSourceId" : 0,
"infoMessage" : "",
"configVersion" : 3
},
{
"_id" : 2,
"name" : "192.168.133.131:27019",
"health" : 1,
"state" : 7,
"stateStr" : "ARBITER",
"uptime" : 115,
"lastHeartbeat" : ISODate("2024-04-27T09:32:57.813Z"),
"lastHeartbeatRecv" : ISODate("2024-04-27T09:32:57.812Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"configVersion" : 3
}
],
"ok" : 1,
"operationTime" : Timestamp(1714210371, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1714210371, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
myrs:PRIMARY>
【说明】
"name" : "192.168.133.131:27019"
是第三个节点的名字,其角色是"stateStr" : "ARBITER"
1.5 副本集的数据读写操作
目标:测试三个不同角色的节点的数据读写情况
1.5.1 主节点
登录主节点 27017,写入和读取数据,主节点登录显示myrs:PRIMARY
[root@localhost ~]# /usr/local/mongodb/bin/mongo --host=192.168.133.131 --port=27017
MongoDB shell version v4.0.10
connecting to: mongodb://192.168.133.131:27017/?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("b2ea6714-0239-4933-8ec7-f5cc07943945") }
MongoDB server version: 4.0.10
Server has startup warnings:
2024-04-27T03:44:14.615+0800 I CONTROL [initandlisten]
2024-04-27T03:44:14.615+0800 I CONTROL [initandlisten] ** WARNING: Access control is not enabled for the database.
2024-04-27T03:44:14.616+0800 I CONTROL [initandlisten] ** Read and write access to data and configuration is unrestricted.
2024-04-27T03:44:14.616+0800 I CONTROL [initandlisten] ** WARNING: You are running this process as the root user, which is not recommended.
2024-04-27T03:44:14.616+0800 I CONTROL [initandlisten]
2024-04-27T03:44:14.616+0800 I CONTROL [initandlisten]
2024-04-27T03:44:14.616+0800 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.
2024-04-27T03:44:14.616+0800 I CONTROL [initandlisten] ** We suggest setting it to 'never'
2024-04-27T03:44:14.617+0800 I CONTROL [initandlisten]
2024-04-27T03:44:14.617+0800 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.
2024-04-27T03:44:14.617+0800 I CONTROL [initandlisten] ** We suggest setting it to 'never'
2024-04-27T03:44:14.617+0800 I CONTROL [initandlisten]
myrs:PRIMARY>
myrs:PRIMARY> use articledb
switched to db articledb
myrs:PRIMARY> db
articledb
myrs:PRIMARY> db.comment.insert({"articleid":"100000","content":"今天天气真好,阳光明媚","userid":"1001","nickname":"Rose","createdatetime":new Date()})
WriteResult({ "nInserted" : 1 })
myrs:PRIMARY> db.comment.find()
{ "_id" : ObjectId("662cc809a9bdac5c093423f0"), "articleid" : "100000", "content" : "今天天气真好,阳光明媚", "userid" : "1001", "nickname" : "Rose", "createdatetime" : ISODate("2024-04-27T09:40:25.542Z") }
myrs:PRIMARY>
1.5.2 从节点
登录从节点 27018,可读不可写,从节点登录显示myrs:SECONDARY
[root@localhost ~]# /usr/local/mongodb/bin/mongo --host=192.168.133.131 --port=27018
MongoDB shell version v4.0.10
connecting to: mongodb://192.168.133.131:27018/?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("dfb736cd-ff9a-4799-9fae-5d6e6bf09d0f") }
MongoDB server version: 4.0.10
Server has startup warnings:
2024-04-27T04:05:24.394+0800 I CONTROL [initandlisten]
2024-04-27T04:05:24.395+0800 I CONTROL [initandlisten] ** WARNING: Access control is not enabled for the database.
2024-04-27T04:05:24.395+0800 I CONTROL [initandlisten] ** Read and write access to data and configuration is unrestricted.
2024-04-27T04:05:24.395+0800 I CONTROL [initandlisten] ** WARNING: You are running this process as the root user, which is not recommended.
2024-04-27T04:05:24.395+0800 I CONTROL [initandlisten]
2024-04-27T04:05:24.395+0800 I CONTROL [initandlisten]
2024-04-27T04:05:24.395+0800 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.
2024-04-27T04:05:24.395+0800 I CONTROL [initandlisten] ** We suggest setting it to 'never'
2024-04-27T04:05:24.395+0800 I CONTROL [initandlisten]
2024-04-27T04:05:24.395+0800 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.
2024-04-27T04:05:24.395+0800 I CONTROL [initandlisten] ** We suggest setting it to 'never'
2024-04-27T04:05:24.395+0800 I CONTROL [initandlisten]
myrs:SECONDARY> show dbs
2024-04-27T17:46:07.113+0800 E QUERY [js] Error: listDatabases failed:{
"operationTime" : Timestamp(1714211161, 1),
"ok" : 0,
"errmsg" : "not master and slaveOk=false",
"code" : 13435,
"codeName" : "NotMasterNoSlaveOk",
"$clusterTime" : {
"clusterTime" : Timestamp(1714211161, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:139:1
shellHelper.show@src/mongo/shell/utils.js:882:13
shellHelper@src/mongo/shell/utils.js:766:15
@(shellhelp2):1:1
myrs:SECONDARY>
发现,不能读取集合的数据。因为当前从节点只是一个备份,不是奴隶节点,无法读取数据,写当然更不行。
因为默认情况下,从节点是没有读写权限的,可以增加读的权限,但需要进行设置
设置从节点读操作权限 ★
【说明】
设置为奴隶节点,允许在从成员上运行读的操作
【语法】
rs.slaveOk()
#或
rs.slaveOk(true)
【提示】
该命令是db.getMongo().setSlaveOk()
的简化命令。注意:运行该命令不会有任何提示。
【示例】在 27018 上设置作为奴隶节点权限,具备读权限
myrs:SECONDARY> rs.slaveOk()
此时,再尝试执行查询命令,如上图所示运行成功!但仍然不允许插入,如下
myrs:SECONDARY> rs.slaveOk()
myrs:SECONDARY> show dbs;
admin 0.000GB
articledb 0.000GB
config 0.000GB
local 0.000GB
myrs:SECONDARY> use articledb
switched to db articledb
myrs:SECONDARY> show collections
comment
myrs:SECONDARY> db.comment.find()
{ "_id" : ObjectId("662cc809a9bdac5c093423f0"), "articleid" : "100000", "content" : "今天天气真好,阳光明媚", "userid" : "1001", "nickname" : "Rose", "createdatetime" : ISODate("2024-04-27T09:40:25.542Z") }
myrs:SECONDARY> db.comment.insert({"_id":"1","articleid":"100001","content":"我们不应该把清晨浪费在手机上,健康很重要,k一杯温水幸福你我他。","userid":"1002","nickname":"相忘于江湖","createdatetime":new Date("2019-08-05T22:08:15.522Z"),"likenum":NumberInt(1000),"state":"1"})
WriteCommandError({
"operationTime" : Timestamp(1714211791, 1),
"ok" : 0,
"errmsg" : "not master",
"code" : 10107,
"codeName" : "NotMaster",
"$clusterTime" : {
"clusterTime" : Timestamp(1714211791, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
})
myrs:SECONDARY>
现在实现了读写分离,让主插入数据,让从来读取数据
取消从节点读操作权限 ★
如果要取消作为奴隶节点的读权限,执行rs.slaveOk(false)
myrs:SECONDARY> rs.slaveOk(false)
myrs:SECONDARY>
myrs:SECONDARY> db.comment.find()
Error: error: {
"operationTime" : Timestamp(1714214782, 1),
"ok" : 0,
"errmsg" : "not master and slaveOk=false",
"code" : 13435,
"codeName" : "NotMasterNoSlaveOk",
"$clusterTime" : {
"clusterTime" : Timestamp(1714214782, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
瑞:注意要打开从节点的读操作权限,后续章节需要使用
1.5.3 仲裁者节点
登录仲裁者节点 27019,不存放任何业务数据,只存放一些配置信息,可以登录查看,仲裁者节点登录显示myrs:ARBITER
[root@localhost ~]# /usr/local/mongodb/bin/mongo --host=192.168.133.131 --port=27019
MongoDB shell version v4.0.10
connecting to: mongodb://192.168.133.131:27019/?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("42494802-82eb-4f5a-b067-ace9585cb495") }
MongoDB server version: 4.0.10
Server has startup warnings:
2024-04-27T04:10:35.141+0800 I CONTROL [initandlisten]
2024-04-27T04:10:35.141+0800 I CONTROL [initandlisten] ** WARNING: Access control is not enabled for the database.
2024-04-27T04:10:35.141+0800 I CONTROL [initandlisten] ** Read and write access to data and configuration is unrestricted.
2024-04-27T04:10:35.141+0800 I CONTROL [initandlisten] ** WARNING: You are running this process as the root user, which is not recommended.
2024-04-27T04:10:35.141+0800 I CONTROL [initandlisten]
2024-04-27T04:10:35.142+0800 I CONTROL [initandlisten]
2024-04-27T04:10:35.142+0800 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.
2024-04-27T04:10:35.142+0800 I CONTROL [initandlisten] ** We suggest setting it to 'never'
2024-04-27T04:10:35.142+0800 I CONTROL [initandlisten]
2024-04-27T04:10:35.142+0800 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.
2024-04-27T04:10:35.142+0800 I CONTROL [initandlisten] ** We suggest setting it to 'never'
2024-04-27T04:10:35.142+0800 I CONTROL [initandlisten]
myrs:ARBITER> rs.slaveOk()
myrs:ARBITER> show dbs
local 0.000GB
myrs:ARBITER> use local
switched to db local
myrs:ARBITER> show collections
replset.minvalid
replset.oplogTruncateAfterPoint
startup_log
system.replset
system.rollback.id
myrs:ARBITER>
发现仲裁节点,只存放local
库,即副本集配置等数据。
1.6 主节点的选举原则
1.6.1 选举原则
MongoDB在副本集中,会自动进行主节点的选举,主节点选举的触发条件⬇️
1️⃣ 主节点故障
2️⃣ 主节点网络不可达(默认心跳信息为10秒)
3️⃣ 人工干预(rs.stepDown(600))
一旦触发选举,就要根据一定规则来选主节点。
选举规则是根据票数来决定谁获胜⬇️
- 规则一:票数最高,且获得了“大多数”成员的投票支持的节点获胜。
“大多数”的定义为:假设复制集内投票成员数量为N,则大多数为 N/2 + 1。例如:3个投票成员,则大多数的值是2。当复制集内存活成员数量不足大多数时,整个复制集将无法选举出Primary,复制集将无法提供写服务,处于只读状态。 - 规则二:若票数相同,且都获得了“大多数”成员的投票支持的,数据新的节点获胜。
数据的新旧是通过操作日志oplog来对比的。
瑞:对于规则一,假设在副本集中有一主一副本一仲裁的三个成员,假设主节点和仲裁节点故障,此时的副本节点也不会被选举为主节点,虽然此时副本节点有自身的 1 票,但是 N 为 2 ,所以不满足选举主节点的原则。
1.6.2 优先级
在获得票数的时候,优先级(priority)参数影响重大。
可以通过设置优先级(priority)来设置额外票数。优先级即权重,取值为 0-1000,相当于可额外增加 0-1000 的票数,优先级的值越大,就越可能获得多数成员的投票(votes)数。指定较高的值可使成员更有资格成为主要成员,更低的值可使成员更不符合条件。
默认情况下,优先级的值是 1
如下,在主节点myrs:PRIMARY
中执行rs.conf()
查看配置信息
myrs:PRIMARY> rs.conf()
{
"_id" : "myrs",
"version" : 3,
"protocolVersion" : NumberLong(1),
"writeConcernMajorityJournalDefault" : true,
"members" : [
{
"_id" : 0,
"host" : "192.168.133.131:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 1,
"host" : "192.168.133.131:27018",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 2,
"host" : "192.168.133.131:27019",
"arbiterOnly" : true,
"buildIndexes" : true,
"hidden" : false,
"priority" : 0,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
}
],
"settings" : {
"chainingAllowed" : true,
"heartbeatIntervalMillis" : 2000,
"heartbeatTimeoutSecs" : 10,
"electionTimeoutMillis" : 10000,
"catchUpTimeoutMillis" : -1,
"catchUpTakeoverDelayMillis" : 30000,
"getLastErrorModes" : {
},
"getLastErrorDefaults" : {
"w" : 1,
"wtimeout" : 0
},
"replicaSetId" : ObjectId("662c0bcc58de9a52944397dd")
}
}
myrs:PRIMARY>
可以看出,主节点和副本节点的优先级各为"priority" : 1
,即,默认可以认为都已经有了一票。但选举节点,优先级是 0(要注意的是,官方说了选举节点的优先级必须是 0,不能是别的值。即不具备选举权,但具有投票权)
1.6.3 修改优先级
瑞:可以跟着命令测试,但请记得修改回去,后续要用
【示例】提升从节点的优先级(进入从节点 27018 即myrs:SECONDARY>
)
1️⃣ 将配置导入 cfg 变量
myrs:SECONDARY> cfg=rs.conf()
2️⃣ 然后修改值(ID号默认从0开始)
myrs:SECONDARY> cfg.members[1].priority=2
2
3️⃣ 重新加载配置
myrs:SECONDARY> rs.reconfig(cfg)
{ "ok" : 1 }
稍等片刻就会重新开始选举。记得测试完修改回去。
1.7 故障测试
1.7.1 副本节点故障测试
瑞:主节点、仲裁节点均不受影响,副本节点恢复后仍然可以正常作为副本节点
1️⃣ 通过ps -ef | grep mongo
找到副本节点 27018 的进程ID,博主为 101461,如下图所示
2️⃣ 执行kill -2 101461
模拟副本节点故障
3️⃣ 进入主节点 27017 即myrs:PRIMARY
/usr/local/mongodb/bin/mongo --host=192.168.133.131 --port=27017
4️⃣ 执行查询命令db.comment.find()
,发现主节点并未受到影响,证明查看没问题。
myrs:PRIMARY> db.comment.find()
{ "_id" : ObjectId("662cc809a9bdac5c093423f0"), "articleid" : "100000", "content" : "今天天气真好,阳光明媚", "userid" : "1001", "nickname" : "Rose", "createdatetime" : ISODate("2024-04-27T09:40:25.542Z") }
因为主节点还存活,所以没有触发投票选举
5️⃣ 主节点写入数据测试,发现主节点并未受到影响,证明写入没问题。
db.comment.insert({"_id":"1","articleid":"100001","content":"我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我他。","userid":"1002","nickname":"相忘于江湖","createdatetime":new Date("2019-08-05T22:08:15.522Z"),"likenum":NumberInt(1000),"state":"1"})
6️⃣ 查看从节点情况,在之前登录的从节点窗口中按回车,会发现从节点确实是挂掉了不能执行任何操作,结果如下
myrs:SECONDARY>
2024-04-27T20:27:46.756+0800 I NETWORK [js] trying reconnect to 192.168.133.131:27018 failed
2024-04-27T20:27:46.757+0800 I NETWORK [js] reconnect 192.168.133.131:27018 failed failed
7️⃣ 重启副本节点服务
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/replica_sets/myrs_27018/mongod.conf
8️⃣ 副本节点依次执行以下命令,会发现,主节点写入的数据,会自动同步给从节点
[root@localhost ~]# /usr/local/mongodb/bin/mongo --host=192.168.133.131 --port=27018
MongoDB shell version v4.0.10
connecting to: mongodb://192.168.133.131:27018/?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("f5a0d72f-0be3-49b5-adcd-6c89cabfea1a") }
MongoDB server version: 4.0.10
Server has startup warnings:
2024-04-27T20:39:33.792+0800 I CONTROL [initandlisten]
2024-04-27T20:39:33.793+0800 I CONTROL [initandlisten] ** WARNING: Access control is not enabled for the database.
2024-04-27T20:39:33.793+0800 I CONTROL [initandlisten] ** Read and write access to data and configuration is unrestricted.
2024-04-27T20:39:33.793+0800 I CONTROL [initandlisten] ** WARNING: You are running this process as the root user, which is not recommended.
2024-04-27T20:39:33.793+0800 I CONTROL [initandlisten]
2024-04-27T20:39:33.796+0800 I CONTROL [initandlisten]
2024-04-27T20:39:33.796+0800 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.
2024-04-27T20:39:33.796+0800 I CONTROL [initandlisten] ** We suggest setting it to 'never'
2024-04-27T20:39:33.796+0800 I CONTROL [initandlisten]
2024-04-27T20:39:33.796+0800 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.
2024-04-27T20:39:33.796+0800 I CONTROL [initandlisten] ** We suggest setting it to 'never'
2024-04-27T20:39:33.796+0800 I CONTROL [initandlisten]
2024-04-27T20:39:33.867+0800 I REPL [replexec-0]
2024-04-27T20:39:33.867+0800 I REPL [replexec-0] ** WARNING: This replica set uses arbiters, but readConcern:majority is enabled
2024-04-27T20:39:33.867+0800 I REPL [replexec-0] ** for this node. This is not a recommended configuration. Please see
2024-04-27T20:39:33.867+0800 I REPL [replexec-0] ** https://dochub.mongodb.org/core/psa-disable-rc-majority-4.0
2024-04-27T20:39:33.867+0800 I REPL [replexec-0]
myrs:SECONDARY> rs.slaveOk()
myrs:SECONDARY> show dbs
admin 0.000GB
articledb 0.000GB
config 0.000GB
local 0.000GB
myrs:SECONDARY> use articledb
switched to db articledb
myrs:SECONDARY> show collections
comment
myrs:SECONDARY> db.comment.find()
{ "_id" : ObjectId("662cc809a9bdac5c093423f0"), "articleid" : "100000", "content" : "今天天气真好,阳光明媚", "userid" : "1001", "nickname" : "Rose", "createdatetime" : ISODate("2024-04-27T09:40:25.542Z") }
{ "_id" : "1", "articleid" : "100001", "content" : "我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我他。", "userid" : "1002", "nickname" : "相忘于江湖", "createdatetime" : ISODate("2019-08-05T22:08:15.522Z"), "likenum" : 1000, "state" : "1" }
myrs:SECONDARY>
1.7.2 主节点故障测试★
瑞:主节点故障后,副本节点经投票会被选举为新的主节点,如果原主节点之后恢复,则原主节点会变为副本节点
1️⃣ 通过ps -ef | grep mongo
找到主节点 27017 的进程ID,博主为 100346,如下图所示
2️⃣ 执行kill -2 100346
模拟主节点故障,在主节点窗口中回车,确认主节点确实挂了
3️⃣ 回到原本的副本节点 27018 窗口中,不断回车,在杀死主节点进程约 10 秒后,副本节点变为了主节点,如下图所示
从节点和仲裁节点对 27017 的心跳失败,当失败超过10秒,此时因为没有主节点,会自动发起投票。而副本节点只有 27018,因此,候选人只有一个就是 27018,开始投票。
27019 向 27018 投了一票,27018 本身自带一票,因此共两票,超过了“大多数”,又因为 27019 是仲裁节点,没有选举权,27018 不向其投票,其票数是 0
最终结果,27018 成为新的主节点。具备读写功能。
4️⃣ 在 27018 写入数据进行测试
db.comment.insert({"_id":"2","articleid":"100001","content":"我夏天空腹喝凉开水,冬天喝温开水","userid":"1005","nickname":"伊人憔悴","createdatetime":new Date("2019-08-05T23:58:51.485Z"),"likenum":NumberInt(888),"state":"1"})
5️⃣ 再重新启动 27017 节点,发现 27017 变成了从节点,而 27018 仍保持主节点。
# 启动 27017 节点
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/replica_sets/myrs_27017/mongod.conf
# 连接 27017 节点服务
/usr/local/mongodb/bin/mongo --host=192.168.133.131 --port=27017
# 设置 27017 (当前为副本节点)读取权限
rs.slaveOk(true)
# 查询
db.comment.find()
登录 27017 节点,发现 27017 已经是从节点了(由
myrs:PRIMARY
变为myrs:SECONDARY
),数据自动从 27018 同步。从而实现了高可用。
瑞:记得修改回去,把 27018 节点服务杀死,等待 27017被选举为主节点,再重启 27018 节点服务
1.7.3 仲裁节点和主节点故障
瑞:不会选举出新的主节点
1️⃣ 先关掉仲裁节点 27019
ps -ef | grep mongo
kill -2 pid
2️⃣ 再关掉主节点 27017
ps -ef | grep mongo
kill -2 pid
3️⃣ 登录 27018 后,发现,27018 仍然是从节点,副本集中没有主节点了,导致此时,副本集是只读状态,无法写入。
/usr/local/mongodb/bin/mongo --host=192.168.133.131 --port=27018
- 规则一:票数最高,且获得了“大多数”成员的投票支持的节点获胜。
瑞:对于规则一,假设在副本集中有一主一副本一仲裁的三个成员,假设主节点和仲裁节点故障,此时的副本节点也不会被选举为主节点,虽然此时副本节点有自身的 1 票,但是 N 为 2 ,所以不满足选举主节点的原则。
在当前例子中,因为 27018 的票数,没有获得大多数,即没有大于等于2,它只有默认的一票(优先级是1)
如果要触发选举,随便加入一个成员即可,如果只加入 27019 仲裁节点成员,则主节点一定是 27018,因为没得选了,仲裁节点不参与选举,但参与投票。
如果只加入 27017 节点,会发起选举。因为 27017 和 27018 都是两票,则按照谁数据新,谁当主节点。
1.7.4 仲裁节点和从节点故障
瑞:副本集中只剩下主节点的时候,会触发服务降级,主节点会自动降级为副本节点,此时副本集不可写入数据
1️⃣ 先关掉仲裁节点 27019
ps -ef | grep mongo
kill -2 pid
2️⃣ 再关掉副本节点 27018
ps -ef | grep mongo
kill -2 pid
3️⃣ 10 秒后,27017 主节点自动降级为副本节点。(服务降级)
此时副本集不可写数据了,已经故障了。
1.8 Compass连接副本集
瑞:连接副本集的时候要确保副本集中的三个节点服务都处于正常启动状态
【注意】如果使用云服务器,则需要修改配置中的主节点 IP 为公网 IP(虚拟机可忽略此项)执行以下命令即可
# 连接主节点服务
/usr/local/mongodb/bin/mongo --host=192.168.133.131 --port=27017
# 查看配置信息
myrs:PRIMARY> rs.conf()
# 更改IP配置
var config = rs.config();config.members[0].host="公网IP:27017";rs.reconfig(config)
在主节点服务中可以通过执行rs.conf()
命令查看 IP 是否修改成功
使用 Compass 连接副本集,填写IP、副本集名称等信息,本例中副本集名称为myrs
,其余可以使用默认选项,点击CONNECT
选择数据库进行测试
可以自行测试副本集增删改查功能
1.9 SpringDataMongoDB连接副本集
1.9.1 基本语法
【副本集语法】
mongodb://host1,host2,host3/数据库名称?connect=replicaSet&slaveOk=true&replicaSet=副本集名字
【说明】
- connect=replicaSet:自动到副本集中选择读写的主机。如果slaveOK是打开的,则实现了读写分离
- slaveOk=true:开启副本节点读的功能,可实现读写分离。
1.9.2 案例
相关案例代码可参考《瑞_MongoDB_案例-文章评论》
article【瑞_MongoDB_案例-文章评论】
的完整源码的某度网盘链接如下,需要自取
链接:https://pan.baidu.com/s/1FMNAZNkXYm8kSbv18A6RDw?pwd=a7r4
提取码:a7r4
【示例】
连接 replica set 三台服务器 (端口 27017、27018 和 27019),直接连接第一个服务器,无论是 replicaset 一部分或者主服务器或者从服务器,写入操作应用在主服务器 并且分布查询到从服务器。
修改配置文件application.yml
,如下示例
spring:
#数据源配置
data:
mongodb:
# 主机地址
# host: 192.168.133.131
# 数据库
# database: articledb
# 默认端口是27017
# port: 27017
# 方式二:使用uri连接
# uri: mongodb://192.168.133.131:27017/articledb
# 副本集的连接字符串
uri: mongodb://192.168.133.131:27017,192.168.133.131:27018,192.168.133.131:27019/articledb?connect=replicaSet&slaveOk=true&replicaSet=myrs
在CommentServiceTest
测试类中选择一个测试用例,如查询所有数据的方法testFindAll()
进行测试,如下图测试通过即配置成功
【注意】
-
主机必须是副本集中所有的主机,包括主节点、副本节点、仲裁节点。
-
SpringDataMongoDB 自动实现了读写分离。
-
写操作时,只打开主节点连接。
-
读操作时,同时打开主节点和从节点连接,但使用从节点获取数据。
1.9.3 完整语法
【MongoDB客户端连接语法】
mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]
mongodb://
这是固定的格式,必须要指定。username:password@
可选项,如果设置,在连接数据库服务器之后,驱动都会尝试登陆这个数据库host1
必须指定至少一个 host,host1 是这个 URI 唯一要填写的。它指定了要连接服务器的地址。如果要连接复制集,请指定多个主机地址。portX
可选的指定端口,如果不填,默认为 27017/database
如果指定username:password@
,连接并验证登陆指定数据库。若不指定,默认打开 test 数据库。?options
是连接选项。如果不使用/database
,则前面需要加上/
。所有连接选项都是键值对name=value
,键值对之间通过&
或;
(分号)隔开
标准的连接格式包含了多个选项(options),如下⬇️
选项 | 描述 |
---|---|
replicaSet=name | 验证replica set的名称。 Impliesconnect=replicaSet. |
slaveOk=true|false | true:在connect=direct模式下,驱动会连接第一台机器,即使这台服务器不是主。在connect=replicaSet模式下,驱动会发送所有的写请求到主并且把读取操作分布在其他从服务器。false: 在connect=direct模式下,驱动会自动找寻主服务器. 在connect=replicaSet 模式下,驱动仅仅连接主服务器,并且所有的读写命令都连接到主服务器。 |
safe=true|false | true: 在执行更新操作之后,驱动都会发送getLastError命令来确保更新成功。(还要参考 wtimeoutMS).false: 在每次更新之后,驱动不会发送getLastError来确保更新成功。 |
w=n | 驱动添加 { w : n } 到getLastError命令. 应用于safe=true。 |
wtimeoutMS=ms | 驱动添加 { wtimeout : ms } 到 getlasterror 命令. 应用于 safe=true. |
fsync=true|false | true: 驱动添加 { fsync : true } 到 getlasterror 命令.应用于safe=true.false: 驱动不会添加到getLastError命令中。 |
journal=true|false | 如果设置为 true, 同步到 journal (在提交到数据库前写入到实体中).应用于 safe=true |
connectTimeoutMS=ms | 可以打开连接的时间。 |
socketTimeoutMS=ms | 发送和接受sockets的时间。 |
2 分片集群-Sharded Cluster
瑞:副本集的特点是,无论搭建了多少个副本节点,存储的数据都是一样的,这样就会导致数据只能存在一台服务器上。随着业务量的扩大,一台服务器无法存储海量数据,此时就需要分片集群存储。
2.1 分片概念
分片(sharding)是一种跨多台机器分布数据的方法, MongoDB 使用分片来支持具有非常大的数据集和高吞吐量操作的部署。
换句话说:分片(sharding)是指将数据拆分,将其分散存在不同的机器上的过程。有时也用分区(partitioning)来表示这个概念。将数据分散到不同的机器上,不需要功能强大的大型计算机就可以储存更多的数据,处理更多的负载。
具有大型数据集或高吞吐量应用程序的数据库系统可以会挑战单个服务器的容量。例如,高查询率会耗尽服务器的CPU容量。工作集大小大于系统的RAM会强调磁盘驱动器的I/O容量。
有两种解决系统增长的方法:垂直扩展和水平扩展。
-
垂直扩展意味着增加单个服务器的容量,例如使用更强大的CPU,添加更多RAM或增加存储空间量。可用技术的局限性可能会限制单个机器对于给定工作负载而言足够强大。此外,基于云的提供商基于可用的硬件配置具有硬性上限。结果,垂直缩放有实际的最大值。
-
水平扩展意味着划分系统数据集并加载多个服务器,添加其他服务器以根据需要增加容量。虽然单个机器的总体速度或容量可能不高,但每台机器处理整个工作负载的子集,可能提供比单个高速大容量服务器更高的效率。扩展部署容量只需要根据需要添加额外的服务器,这可能比单个机器的高端硬件的总体成本更低。权衡是基础架构和部署维护的复杂性增加。
MongoDB 支持通过分片进行水平扩展
2.2 分片集群包含的组件
MongoDB 分片群集包含以下组件
- 分片(存储):每个分片包含分片数据的子集。 每个分片都可以部署为副本集
- mongos(路由):mongos充当查询路由器,在客户端应用程序和分片集群之间提供接口
- config servers(“调度”的配置):配置服务器存储群集的元数据和配置设置。 从 MongoDB 3.4 开始,必须将配置服务器部署为副本集(CSRS)
下图描述了分片集群中组件的交互
MongoDB 在集合级别对数据进行分片,将集合数据分布在集群中的分片上。
2.3 分片集群架构目标
本文分片集群架构目标:两个分片节点副本集(3 + 3,一主一副本一仲裁)+ 一个配置节点副本集(3,一主二副本)+ 两个路由节点(1 + 1),共 11 (3 + 3 + 3 + 1 + 1)个服务节点
- 分片 1 副本集名称:myshardrs01
- 第一套副本集主节点:27018
- 第一套副本集副本节点:27118
- 第一套副本集仲裁节点:27218
- 分片 2 副本集名称:myshardrs02
- 第二套副本集主节点:27318
- 第二套副本集副本节点:27418
- 第二套副本集仲裁节点:27518
- 配置节点副本集名称:myconfigrs
- 配置节点副本集主节点:27019
- 配置节点副本集的副本节点1:27119
- 配置节点副本集的副本节点2:27219
- 路由节点名称:mymongos
- 路由节点1:27017
- 路由节点2:27117
在搭建的时候,路由节点一定要最后搭建,否则路由会启动失败
2.4 分片(存储)节点副本集的创建
所有的的配置文件都直接放到sharded_cluster
的相应的子目录下面,默认配置文件名字:mongod.conf
瑞:MongoDB 在 Linux 系统中的安装请参考《瑞_MongoDB(笔记超详细,有这一篇就够了)》
在搭建之前,需要把其它 mongo 服务关闭或杀死,防止端口号冲突等问题,可以使用ps -ef | grep mongo
命令检查当前是否有 mongo 服务
2.4.1 第一套分片副本集
- 分片 1 副本集名称:myshardrs01
- 第一套副本集主节点:27018
- 第一套副本集副本节点:27118
- 第一套副本集仲裁节点:27218
2.4.1.1 第一套分片副本集的创建
1️⃣ 建立存放数据和日志的目录
#-----------myshardrs01
mkdir -p /usr/local/mongodb/sharded_cluster/myshardrs01_27018/log \ &
mkdir -p /usr/local/mongodb/sharded_cluster/myshardrs01_27018/data/db \ &
mkdir -p /usr/local/mongodb/sharded_cluster/myshardrs01_27118/log \ &
mkdir -p /usr/local/mongodb/sharded_cluster/myshardrs01_27118/data/db \ &
mkdir -p /usr/local/mongodb/sharded_cluster/myshardrs01_27218/log \ &
mkdir -p /usr/local/mongodb/sharded_cluster/myshardrs01_27218/data/db
2️⃣ 新建或修改配置文件myshardrs01_27018
vi /usr/local/mongodb/sharded_cluster/myshardrs01_27018/mongod.conf
瑞:指令使用:按
a
切换到输入状态,将下面配置文件内容复制过去,然后按esc
输入:wq
保存文件并退出
myshardrs01_27018 配置文件可以参考如下,主要修改服务实例绑定的 IP
【注意】
1️⃣ 注意子级配置要使用空格隔开,不能使用Tab,建议直接复制粘贴不要自己输入
2️⃣bindIp: localhost,192.168.133.131
中后面的IP 192.168.133.131
你可能无法绑定,这是博主的虚拟机IP,记得替换为你自己的IP,如果使用的是云服务器,需要绑定的是局域网IP,特别注意不是公网IP是局域网IP,如果您只希望从本地访问,可以直接改为bindIp: localhost
,注意前面有一个空格
systemLog:
# MongoDB发送所有日志输出的目标指定为文件
destination: file
# mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
path: "/usr/local/mongodb/sharded_cluster/myshardrs01_27018/log/mongod.log"
# 当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
logAppend: true
storage:
# mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
dbPath: "/usr/local/mongodb/sharded_cluster/myshardrs01_27018/data/db"
journal:
# 启用或禁用持久性日志以确保数据文件保持有效和可恢复。
enabled: true
processManagement:
# 启用在后台运行mongos或mongod进程的守护进程模式。
fork: true
# 指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
pidFilePath: "/usr/local/mongodb/sharded_cluster/myshardrs01_27018/log/mongod.pid"
net:
# 服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
# bindIpAll: true
# 服务实例绑定的IP
bindIp: localhost,192.168.133.131
# bindIp
# 绑定的端口
port: 27018
replication:
# 副本集的名称
replSetName: myshardrs01
sharding:
# 分片角色
clusterRole: shardsvr
分片角色说明sharding.clusterRole
Value | Description |
---|---|
configsvr | Start this instance as a config server. The instance starts on port 27019 by default. |
shardsvr | Start this instance as a shard. The instance starts on port 27018 by default. |
【注意】
设置sharding.clusterRole
需要 mongod 实例运行复制。 要将实例部署为副本集成员,请使用 replSetName 设置并指定副本集的名称。
3️⃣ 新建或修改配置文件myshardrs01_27118
vi /usr/local/mongodb/sharded_cluster/myshardrs01_27118/mongod.conf
瑞:指令使用:按
a
切换到输入状态,将下面配置文件内容复制过去,然后按esc
输入:wq
保存文件并退出
myshardrs01_27118 配置文件可以参考如下,主要修改服务实例绑定的 IP
systemLog:
# MongoDB发送所有日志输出的目标指定为文件
destination: file
# mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
path: "/usr/local/mongodb/sharded_cluster/myshardrs01_27118/log/mongod.log"
# 当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
logAppend: true
storage:
# mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
dbPath: "/usr/local/mongodb/sharded_cluster/myshardrs01_27118/data/db"
journal:
# 启用或禁用持久性日志以确保数据文件保持有效和可恢复。
enabled: true
processManagement:
# 启用在后台运行mongos或mongod进程的守护进程模式。
fork: true
# 指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
pidFilePath: "/usr/local/mongodb/sharded_cluster/myshardrs01_27118/log/mongod.pid"
net:
# 服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
# bindIpAll: true
# 服务实例绑定的IP
bindIp: localhost,192.168.133.131
# bindIp
# 绑定的端口
port: 27118
replication:
# 副本集的名称
replSetName: myshardrs01
sharding:
# 分片角色
clusterRole: shardsvr
4️⃣ 新建或修改配置文件myshardrs01_27218
vi /usr/local/mongodb/sharded_cluster/myshardrs01_27218/mongod.conf
瑞:指令使用:按
a
切换到输入状态,将下面配置文件内容复制过去,然后按esc
输入:wq
保存文件并退出
myshardrs01_27218 配置文件可以参考如下,主要修改服务实例绑定的 IP
systemLog:
# MongoDB发送所有日志输出的目标指定为文件
destination: file
# mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
path: "/usr/local/mongodb/sharded_cluster/myshardrs01_27218/log/mongod.log"
# 当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
logAppend: true
storage:
# mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
dbPath: "/usr/local/mongodb/sharded_cluster/myshardrs01_27218/data/db"
journal:
# 启用或禁用持久性日志以确保数据文件保持有效和可恢复。
enabled: true
processManagement:
# 启用在后台运行mongos或mongod进程的守护进程模式。
fork: true
# 指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
pidFilePath: "/usr/local/mongodb/sharded_cluster/myshardrs01_27218/log/mongod.pid"
net:
# 服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
# bindIpAll: true
# 服务实例绑定的IP
bindIp: localhost,192.168.133.131
# bindIp
# 绑定的端口
port: 27218
replication:
# 副本集的名称
replSetName: myshardrs01
sharding:
# 分片角色
clusterRole: shardsvr
启动第一套副本集:一主一副本一仲裁
5️⃣ 依次启动三个 mongod 服务
[root@localhost ~]# /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs01_27018/mongod.conf
about to fork child process, waiting until server is ready for connections.
forked process: 62216
child process started successfully, parent exiting
[root@localhost ~]#
[root@localhost ~]# /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs01_27118/mongod.conf
about to fork child process, waiting until server is ready for connections.
forked process: 62259
child process started successfully, parent exiting
[root@localhost ~]#
[root@localhost ~]# /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs01_27218/mongod.conf
about to fork child process, waiting until server is ready for connections.
forked process: 62293
child process started successfully, parent exiting
如下图出现 started successfully 则说明安装配置成功!
6️⃣ 执行ps -ef |grep mongod
命令,查看服务是否启动
2.4.1.2 第一套分片副本集的初始化
一、初始化副本集和创建主节点
1️⃣ 使用客户端命令连接任意一个节点,但这里尽量要连接主节点(第一套副本集主节点 27018)
/usr/local/mongodb/bin/mongo --host=192.168.133.131 --port=27018
2️⃣ 执行rs.initiate()
初始化副本集命令
> rs.initiate()
{
"info2" : "no configuration specified. Using a default configuration for the set",
"me" : "192.168.133.131:27018",
"ok" : 1,
"operationTime" : Timestamp(1714270977, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1714270977, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
"me" : "bobohost.localdomain:27018",
说明
- “ok”的值为1,说明创建成功。
- 命令行提示符发生变化,变成了一个从节点角色
myrs:SECONDARY
,此时默认不能读写。稍等片刻后回车,就会变成主节点myrs:PRIMARY
。
查看副本集情况(可省略)
myshardrs01:SECONDARY> rs.status()
{
"set" : "myshardrs01",
......
}
二、主节点配置查看
myshardrs01:PRIMARY> rs.conf()
{
"_id" : "myshardrs01",
"version" : 1,
"protocolVersion" : NumberLong(1),
"writeConcernMajorityJournalDefault" : true,
"members" : [
{
"_id" : 0,
"host" : "192.168.133.131:27018",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
}
],
"settings" : {
"chainingAllowed" : true,
"heartbeatIntervalMillis" : 2000,
"heartbeatTimeoutSecs" : 10,
"electionTimeoutMillis" : 10000,
"catchUpTimeoutMillis" : -1,
"catchUpTakeoverDelayMillis" : 30000,
"getLastErrorModes" : {
},
"getLastErrorDefaults" : {
"w" : 1,
"wtimeout" : 0
},
"replicaSetId" : ObjectId("662db3010e3ab11474ee64b5")
}
}
三、添加副本节点
myshardrs01:PRIMARY> rs.add("192.168.133.131:27118")
{
"ok" : 1,
"operationTime" : Timestamp(1714271742, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1714271742, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
四、添加仲裁节点
myshardrs01:PRIMARY> rs.addArb("192.168.133.131:27218")
{
"ok" : 1,
"operationTime" : Timestamp(1714271794, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1714271794, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
2.4.2 第二套分片副本集
- 分片 2 副本集名称:myshardrs02
- 第二套副本集主节点:27318
- 第二套副本集副本节点:27418
- 第二套副本集仲裁节点:27518
瑞:过程和第一套基本一样,只是换个名字、路径和端口。所以部分解释说明以及图片省略。
2.4.2.1 第二套分片副本集的创建
1️⃣ 建立存放数据和日志的目录
#-----------myshardrs02
mkdir -p /usr/local/mongodb/sharded_cluster/myshardrs02_27318/log \ &
mkdir -p /usr/local/mongodb/sharded_cluster/myshardrs02_27318/data/db \ &
mkdir -p /usr/local/mongodb/sharded_cluster/myshardrs02_27418/log \ &
mkdir -p /usr/local/mongodb/sharded_cluster/myshardrs02_27418/data/db \ &
mkdir -p /usr/local/mongodb/sharded_cluster/myshardrs02_27518/log \ &
mkdir -p /usr/local/mongodb/sharded_cluster/myshardrs02_27518/data/db
2️⃣ 新建或修改配置文件myshardrs02_27318
vi /usr/local/mongodb/sharded_cluster/myshardrs02_27318/mongod.conf
瑞:指令使用:按
a
切换到输入状态,将下面配置文件内容复制过去,然后按esc
输入:wq
保存文件并退出
myshardrs02_27318 配置文件可以参考如下,主要修改服务实例绑定的 IP
systemLog:
# MongoDB发送所有日志输出的目标指定为文件
destination: file
# mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
path: "/usr/local/mongodb/sharded_cluster/myshardrs02_27318/log/mongod.log"
# 当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
logAppend: true
storage:
# mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
dbPath: "/usr/local/mongodb/sharded_cluster/myshardrs02_27318/data/db"
journal:
# 启用或禁用持久性日志以确保数据文件保持有效和可恢复。
enabled: true
processManagement:
# 启用在后台运行mongos或mongod进程的守护进程模式。
fork: true
# 指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
pidFilePath: "/usr/local/mongodb/sharded_cluster/myshardrs02_27318/log/mongod.pid"
net:
# 服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
# bindIpAll: true
# 服务实例绑定的IP
bindIp: localhost,192.168.133.131
# bindIp
# 绑定的端口
port: 27318
replication:
# 副本集的名称
replSetName: myshardrs02
sharding:
# 分片角色
clusterRole: shardsvr
3️⃣ 新建或修改配置文件myshardrs02_27418
vi /usr/local/mongodb/sharded_cluster/myshardrs02_27418/mongod.conf
瑞:指令使用:按
a
切换到输入状态,将下面配置文件内容复制过去,然后按esc
输入:wq
保存文件并退出
myshardrs02_27418 配置文件可以参考如下,主要修改服务实例绑定的 IP
systemLog:
# MongoDB发送所有日志输出的目标指定为文件
destination: file
# mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
path: "/usr/local/mongodb/sharded_cluster/myshardrs02_27418/log/mongod.log"
# 当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
logAppend: true
storage:
# mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
dbPath: "/usr/local/mongodb/sharded_cluster/myshardrs02_27418/data/db"
journal:
# 启用或禁用持久性日志以确保数据文件保持有效和可恢复。
enabled: true
processManagement:
# 启用在后台运行mongos或mongod进程的守护进程模式。
fork: true
# 指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
pidFilePath: "/usr/local/mongodb/sharded_cluster/myshardrs02_27418/log/mongod.pid"
net:
# 服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
# bindIpAll: true
# 服务实例绑定的IP
bindIp: localhost,192.168.133.131
# bindIp
# 绑定的端口
port: 27418
replication:
# 副本集的名称
replSetName: myshardrs02
sharding:
# 分片角色
clusterRole: shardsvr
4️⃣ 新建或修改配置文件myshardrs02_27518
vi /usr/local/mongodb/sharded_cluster/myshardrs02_27518/mongod.conf
瑞:指令使用:按
a
切换到输入状态,将下面配置文件内容复制过去,然后按esc
输入:wq
保存文件并退出
myshardrs02_27518 配置文件可以参考如下,主要修改服务实例绑定的 IP
systemLog:
# MongoDB发送所有日志输出的目标指定为文件
destination: file
# mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
path: "/usr/local/mongodb/sharded_cluster/myshardrs02_27518/log/mongod.log"
# 当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
logAppend: true
storage:
# mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
dbPath: "/usr/local/mongodb/sharded_cluster/myshardrs02_27518/data/db"
journal:
# 启用或禁用持久性日志以确保数据文件保持有效和可恢复。
enabled: true
processManagement:
# 启用在后台运行mongos或mongod进程的守护进程模式。
fork: true
# 指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
pidFilePath: "/usr/local/mongodb/sharded_cluster/myshardrs02_27518/log/mongod.pid"
net:
# 服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
# bindIpAll: true
# 服务实例绑定的IP
bindIp: localhost,192.168.133.131
# bindIp
# 绑定的端口
port: 27518
replication:
# 副本集的名称
replSetName: myshardrs02
sharding:
# 分片角色
clusterRole: shardsvr
启动第二套副本集:一主一副本一仲裁
5️⃣ 依次启动三个 mongod 服务
[root@localhost ~]# /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs02_27318/mongod.conf
about to fork child process, waiting until server is ready for connections.
forked process: 63527
child process started successfully, parent exiting
[root@localhost ~]#
[root@localhost ~]# /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs02_27418/mongod.conf
about to fork child process, waiting until server is ready for connections.
forked process: 63566
child process started successfully, parent exiting
[root@localhost ~]#
[root@localhost ~]# /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs02_27518/mongod.conf
about to fork child process, waiting until server is ready for connections.
forked process: 63600
child process started successfully, parent exiting
[root@localhost ~]#
如下图出现 started successfully 则说明安装配置成功!
6️⃣ 执行ps -ef |grep mongod
命令,查看服务是否启动
2.4.2.2 第二套分片副本集的初始化
一、初始化副本集和创建主节点
1️⃣ 使用客户端命令连接任意一个节点,但这里尽量要连接主节点(第二套副本集主节点 27318)
/usr/local/mongodb/bin/mongo --host=192.168.133.131 --port=27318
2️⃣ 执行rs.initiate()
初始化副本集命令
> rs.initiate()
{
"info2" : "no configuration specified. Using a default configuration for the set",
"me" : "192.168.133.131:27318",
"ok" : 1,
"operationTime" : Timestamp(1714272527, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1714272527, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
myshardrs02:SECONDARY>
myshardrs02:PRIMARY>
查看副本集情况(可省略)
myshardrs02:SECONDARY> rs.status()
{
"set" : "myshardrs02",
......
}
二、主节点配置查看
myshardrs02:PRIMARY> rs.conf()
{
"_id" : "myshardrs02",
"version" : 1,
"protocolVersion" : NumberLong(1),
"writeConcernMajorityJournalDefault" : true,
"members" : [
{
"_id" : 0,
"host" : "192.168.133.131:27318",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
}
],
"settings" : {
"chainingAllowed" : true,
"heartbeatIntervalMillis" : 2000,
"heartbeatTimeoutSecs" : 10,
"electionTimeoutMillis" : 10000,
"catchUpTimeoutMillis" : -1,
"catchUpTakeoverDelayMillis" : 30000,
"getLastErrorModes" : {
},
"getLastErrorDefaults" : {
"w" : 1,
"wtimeout" : 0
},
"replicaSetId" : ObjectId("662db90fd5d67c03049def52")
}
}
三、添加副本节点
myshardrs02:PRIMARY> rs.add("192.168.133.131:27418")
{
"ok" : 1,
"operationTime" : Timestamp(1714272619, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1714272619, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
四、添加仲裁节点
myshardrs02:PRIMARY> rs.addArb("192.168.133.131:27518")
{
"ok" : 1,
"operationTime" : Timestamp(1714272637, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1714272637, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
2.5 配置节点副本集的创建
- 配置节点副本集名称:myconfigrs
- 配置节点副本集主节点:27019
- 配置节点副本集的副本节点1:27119
- 配置节点副本集的副本节点2:27219
瑞:过程和第一套基本一样,只是换个名字、路径和端口。所以部分解释说明以及图片省略。
2.5.1 配置节点副本集的创建
1️⃣ 建立存放数据和日志的目录
#-----------configrs
# 建立数据节点data和日志目录
mkdir -p /usr/local/mongodb/sharded_cluster/myconfigrs_27019/log \ &
mkdir -p /usr/local/mongodb/sharded_cluster/myconfigrs_27019/data/db \ &
mkdir -p /usr/local/mongodb/sharded_cluster/myconfigrs_27119/log \ &
mkdir -p /usr/local/mongodb/sharded_cluster/myconfigrs_27119/data/db \ &
mkdir -p /usr/local/mongodb/sharded_cluster/myconfigrs_27219/log \ &
mkdir -p /usr/local/mongodb/sharded_cluster/myconfigrs_27219/data/db
2️⃣ 新建或修改配置文件myconfigrs_27019
vi /usr/local/mongodb/sharded_cluster/myconfigrs_27019/mongod.conf
瑞:指令使用:按
a
切换到输入状态,将下面配置文件内容复制过去,然后按esc
输入:wq
保存文件并退出
myconfigrs_27019 配置文件可以参考如下,主要修改服务实例绑定的 IP
systemLog:
# MongoDB发送所有日志输出的目标指定为文件
destination: file
# mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
path: "/usr/local/mongodb/sharded_cluster/myconfigrs_27019/log/mongod.log"
# 当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
logAppend: true
storage:
# mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
dbPath: "/usr/local/mongodb/sharded_cluster/myconfigrs_27019/data/db"
journal:
# 启用或禁用持久性日志以确保数据文件保持有效和可恢复。
enabled: true
processManagement:
# 启用在后台运行mongos或mongod进程的守护进程模式。
fork: true
# 指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
pidFilePath: "/usr/local/mongodb/sharded_cluster/myconfigrs_27019/log/mongod.pid"
net:
# 服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
# bindIpAll: true
# 服务实例绑定的IP
bindIp: localhost,192.168.133.131
# bindIp
# 绑定的端口
port: 27019
replication:
# 副本集的名称
replSetName: myconfigrs
sharding:
# 分片角色
clusterRole: configsvr
注意:副本集的名称是
myconfigrs
,分片角色是configsvr
3️⃣ 新建或修改配置文件myconfigrs_27119
vi /usr/local/mongodb/sharded_cluster/myconfigrs_27119/mongod.conf
瑞:指令使用:按
a
切换到输入状态,将下面配置文件内容复制过去,然后按esc
输入:wq
保存文件并退出
myconfigrs_27119 配置文件可以参考如下,主要修改服务实例绑定的 IP
systemLog:
# MongoDB发送所有日志输出的目标指定为文件
destination: file
# mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
path: "/usr/local/mongodb/sharded_cluster/myconfigrs_27119/log/mongod.log"
# 当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
logAppend: true
storage:
# mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
dbPath: "/usr/local/mongodb/sharded_cluster/myconfigrs_27119/data/db"
journal:
# 启用或禁用持久性日志以确保数据文件保持有效和可恢复。
enabled: true
processManagement:
# 启用在后台运行mongos或mongod进程的守护进程模式。
fork: true
# 指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
pidFilePath: "/usr/local/mongodb/sharded_cluster/myconfigrs_27119/log/mongod.pid"
net:
# 服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
# bindIpAll: true
# 服务实例绑定的IP
bindIp: localhost,192.168.133.131
# bindIp
# 绑定的端口
port: 27119
replication:
# 副本集的名称
replSetName: myconfigrs
sharding:
# 分片角色
clusterRole: configsvr
注意:副本集的名称是
myconfigrs
,分片角色是configsvr
4️⃣ 新建或修改配置文件myconfigrs_27219
vi /usr/local/mongodb/sharded_cluster/myconfigrs_27219/mongod.conf
瑞:指令使用:按
a
切换到输入状态,将下面配置文件内容复制过去,然后按esc
输入:wq
保存文件并退出
myconfigrs_27219 配置文件可以参考如下,主要修改服务实例绑定的 IP
systemLog:
# MongoDB发送所有日志输出的目标指定为文件
destination: file
# mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
path: "/usr/local/mongodb/sharded_cluster/myconfigrs_27219/log/mongod.log"
# 当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
logAppend: true
storage:
# mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
dbPath: "/usr/local/mongodb/sharded_cluster/myconfigrs_27219/data/db"
journal:
# 启用或禁用持久性日志以确保数据文件保持有效和可恢复。
enabled: true
processManagement:
# 启用在后台运行mongos或mongod进程的守护进程模式。
fork: true
# 指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
pidFilePath: "/usr/local/mongodb/sharded_cluster/myconfigrs_27219/log/mongod.pid"
net:
# 服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
# bindIpAll: true
# 服务实例绑定的IP
bindIp: localhost,192.168.133.131
# bindIp
# 绑定的端口
port: 27219
replication:
# 副本集的名称
replSetName: myconfigrs
sharding:
# 分片角色
clusterRole: configsvr
注意:副本集的名称是
myconfigrs
,分片角色是configsvr
启动配置节点副本集:一主一副本一仲裁
5️⃣ 依次启动三个 mongod 服务
[root@localhost ~]# /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myconfigrs_27019/mongod.conf
about to fork child process, waiting until server is ready for connections.
forked process: 66705
child process started successfully, parent exiting
[root@localhost ~]#
[root@localhost ~]# /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myconfigrs_27119/mongod.conf
about to fork child process, waiting until server is ready for connections.
forked process: 66747
child process started successfully, parent exiting
[root@localhost ~]#
[root@localhost ~]# /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myconfigrs_27219/mongod.conf
about to fork child process, waiting until server is ready for connections.
forked process: 66788
child process started successfully, parent exiting
如下图出现 started successfully 则说明安装配置成功!
6️⃣ 执行ps -ef |grep mongod
命令,查看服务是否启动
2.5.2 配置节点副本集的初始化
一、初始化副本集和创建主节点
1️⃣ 使用客户端命令连接任意一个节点,但这里尽量要连接主节点(配置节点副本集主节点 27019)
/usr/local/mongodb/bin/mongo --host=192.168.133.131 --port=27019
2️⃣ 执行rs.initiate()
初始化副本集命令
> rs.initiate()
{
"info2" : "no configuration specified. Using a default configuration for the set",
"me" : "192.168.133.131:27019",
"ok" : 1,
"operationTime" : Timestamp(1714273653, 1),
"$gleStats" : {
"lastOpTime" : Timestamp(1714273653, 1),
"electionId" : ObjectId("000000000000000000000000")
},
"lastCommittedOpTime" : Timestamp(0, 0),
"$clusterTime" : {
"clusterTime" : Timestamp(1714273653, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
myconfigrs:SECONDARY>
myconfigrs:PRIMARY>
查看副本集情况(可省略)
myconfigrs:SECONDARY> rs.status()
{
"set" : "myconfigrs",
......
}
二、主节点配置查看
myconfigrs:PRIMARY> rs.conf()
{
"_id" : "myconfigrs",
"version" : 1,
"configsvr" : true,
"protocolVersion" : NumberLong(1),
"writeConcernMajorityJournalDefault" : true,
"members" : [
{
"_id" : 0,
"host" : "192.168.133.131:27019",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
}
],
"settings" : {
"chainingAllowed" : true,
"heartbeatIntervalMillis" : 2000,
"heartbeatTimeoutSecs" : 10,
"electionTimeoutMillis" : 10000,
"catchUpTimeoutMillis" : -1,
"catchUpTakeoverDelayMillis" : 30000,
"getLastErrorModes" : {
},
"getLastErrorDefaults" : {
"w" : 1,
"wtimeout" : 0
},
"replicaSetId" : ObjectId("662dbd759e27dba6d8aa678d")
}
}
三、添加两个副本节点
myconfigrs:PRIMARY> rs.add("192.168.133.131:27119")
{
"ok" : 1,
"operationTime" : Timestamp(1714273799, 1),
"$gleStats" : {
"lastOpTime" : {
"ts" : Timestamp(1714273799, 1),
"t" : NumberLong(1)
},
"electionId" : ObjectId("7fffffff0000000000000001")
},
"lastCommittedOpTime" : Timestamp(1714273789, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1714273799, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
myconfigrs:PRIMARY> rs.add("192.168.133.131:27219")
{
"ok" : 1,
"operationTime" : Timestamp(1714273811, 1),
"$gleStats" : {
"lastOpTime" : {
"ts" : Timestamp(1714273811, 1),
"t" : NumberLong(1)
},
"electionId" : ObjectId("7fffffff0000000000000001")
},
"lastCommittedOpTime" : Timestamp(1714273799, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1714273811, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
查看副本集的配置情况
rs.conf()
rs.status()
2.6 路由节点的创建和操作
2.6.1 第一个路由节点的创建和连接
- 路由节点名称:mymongos
- 路由节点1:27017
1️⃣ 建立存放数据和日志的目录
注意:路由节点只需要
log
目录,不需要 data 目录,因为路由节点主要的作用是路由分发,不需要存储具体数据
#-----------mongos01
mkdir -p /usr/local/mongodb/sharded_cluster/mymongos_27017/log
2️⃣ 新建或修改配置文件mymongos_27017
注意:配置文件是
mongos.conf
,不是之前的 mongod.conf
vi /usr/local/mongodb/sharded_cluster/mymongos_27017/mongos.conf
瑞:指令使用:按
a
切换到输入状态,将下面配置文件内容复制过去,然后按esc
输入:wq
保存文件并退出
mymongos_27017 配置文件mongos.conf
可以参考如下,主要修改服务实例绑定的 IP,以及 sharding 部分,即章节《配置节点副本集》中配置节点副本集所配置的 3 个 mongod 服务
systemLog:
# MongoDB发送所有日志输出的目标指定为文件
destination: file
# mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
path: "/usr/local/mongodb/sharded_cluster/mymongos_27017/log/mongod.log"
# 当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
logAppend: true
processManagement:
# 启用在后台运行mongos或mongod进程的守护进程模式。
fork: true
# 指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
pidFilePath: /usr/local/mongodb/sharded_cluster/mymongos_27017/log/mongod.pid"
net:
# 服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
# bindIpAll: true
# 服务实例绑定的IP
bindIp: localhost,192.168.133.131
# bindIp
# 绑定的端口
port: 27017
sharding:
# 指定配置节点副本集
configDB: myconfigrs/192.168.133.131:27019,192.168.133.131:27119,192.168.133.131:27219
3️⃣ 启动 mongos
/usr/local/mongodb/bin/mongos -f /usr/local/mongodb/sharded_cluster/mymongos_27017/mongos.conf
注意:启动的时候是用
mongos
命令,不是之前的 mongod
如下图出现 started successfully 则说明安装配置成功!
4️⃣ 客户端登录 mongos
/usr/local/mongodb/bin/mongo --host 192.168.133.131 --port 27017
此时,写不进去数据,如果写数据会报错,如下示例
[root@localhost ~]# /usr/local/mongodb/bin/mongo --host 192.168.133.131 --port 27017
MongoDB shell version v4.0.10
connecting to: mongodb://192.168.133.131:27017/?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("de3c5a8e-e790-47a2-b230-859ff1117271") }
MongoDB server version: 4.0.10
Server has startup warnings:
2024-04-28T11:59:27.576+0800 I CONTROL [main]
2024-04-28T11:59:27.577+0800 I CONTROL [main] ** WARNING: Access control is not enabled for the database.
2024-04-28T11:59:27.577+0800 I CONTROL [main] ** Read and write access to data and configuration is unrestricted.
2024-04-28T11:59:27.577+0800 I CONTROL [main] ** WARNING: You are running this process as the root user, which is not recommended.
2024-04-28T11:59:27.577+0800 I CONTROL [main]
mongos> show dbs
admin 0.000GB
config 0.000GB
mongos> use aabb
switched to db aabb
mongos> db.aa.insert({aa:"aa"})
WriteCommandError({
"ok" : 0,
"errmsg" : "unable to initialize targeter for write op for collection aabb.aa :: caused by :: Database aabb not found :: caused by :: No shards found",
"code" : 70,
"codeName" : "ShardNotFound",
"operationTime" : Timestamp(1714276977, 2),
"$clusterTime" : {
"clusterTime" : Timestamp(1714276977, 2),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
})
mongos>
原因:通过路由节点操作,现在只是连接了配置节点,还没有连接分片数据节点,因此无法写入业务数据。
附:properties 配置文件参考
logpath=/usr/local/mongodb/sharded_cluster/mymongos_27017/log/mongos.log
logappend=true
bind_ip_all=true
port=27017
fork=true
configdb=myconfigrs/192.168.133.131:27019,192.168.133.131:27119,192.168.133.131:27219
19
2.6.2 在路由节点上进行分片配置操作
2.6.2.1 添加分片
【语法】添加分片
sh.addShard("IP:Port")
1️⃣ 添加第一套分片副本集
mongos> sh.addShard("myshardrs01/192.168.133.131:27018,192.168.133.131:27118,192.168.133.131:27218")
{
"shardAdded" : "myshardrs01",
"ok" : 1,
"operationTime" : Timestamp(1714280144, 5),
"$clusterTime" : {
"clusterTime" : Timestamp(1714280144, 5),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
mongos>
查看分片状态情况,执行sh.status()
mongos> sh.status()
--- Sharding Status ---
sharding version: {
"_id" : 1,
"minCompatibleVersion" : 5,
"currentVersion" : 6,
"clusterId" : ObjectId("662dbd789e27dba6d8aa679c")
}
shards:
{ "_id" : "myshardrs01", "host" : "myshardrs01/192.168.133.131:27018,192.168.133.131:27118", "state" : 1 }
active mongoses:
"4.0.10" : 1
autosplit:
Currently enabled: yes
balancer:
Currently enabled: yes
Currently running: no
Failed balancer rounds in last 5 attempts: 0
Migration Results for the last 24 hours:
No recent migrations
databases:
{ "_id" : "config", "primary" : "config", "partitioned" : true }
mongos>
2️⃣添加第二套分片副本集
mongos> sh.addShard("myshardrs02/192.168.133.131:27318,192.168.133.131:27418,192.168.133.131:27518")
{
"shardAdded" : "myshardrs02",
"ok" : 1,
"operationTime" : Timestamp(1714280437, 4),
"$clusterTime" : {
"clusterTime" : Timestamp(1714280437, 4),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
mongos>
查看分片状态情况,执行sh.status()
mongos> sh.status()
--- Sharding Status ---
sharding version: {
"_id" : 1,
"minCompatibleVersion" : 5,
"currentVersion" : 6,
"clusterId" : ObjectId("662dbd789e27dba6d8aa679c")
}
shards:
{ "_id" : "myshardrs01", "host" : "myshardrs01/192.168.133.131:27018,192.168.133.131:27118", "state" : 1 }
{ "_id" : "myshardrs02", "host" : "myshardrs02/192.168.133.131:27318,192.168.133.131:27418", "state" : 1 }
active mongoses:
"4.0.10" : 1
autosplit:
Currently enabled: yes
balancer:
Currently enabled: yes
Currently running: no
Failed balancer rounds in last 5 attempts: 0
Migration Results for the last 24 hours:
No recent migrations
databases:
{ "_id" : "config", "primary" : "config", "partitioned" : true }
config.system.sessions
shard key: { "_id" : 1 }
unique: false
balancing: true
chunks:
myshardrs01 1
{ "_id" : { "$minKey" : 1 } } -->> { "_id" : { "$maxKey" : 1 } } on : myshardrs01 Timestamp(1, 0)
mongos>
提示:如果添加分片失败,需要先手动移除分片,检查添加分片的信息的正确性后,再次添加分片。
2.6.2.2 移除分片(可跳过)
移除分片参考(了解):
use admin
db.runCommand( { removeShard: "myshardrs02" } )
注意
- 如果只剩下最后一个shard,是无法删除的
- 移除时会自动转移分片数据,需要一个时间过程。
- 完成后,再次执行删除分片命令才能真正删除。
2.6.2.3 数据库开启分片功能
【语法】数据库开启分片功能
sh.enableSharding("数据库名")
【示例】在 mongos 上的 articledb 数据库配置 sharding 开启分片功能
mongos> sh.enableSharding("articledb")
{
"ok" : 1,
"operationTime" : Timestamp(1714282360, 5),
"$clusterTime" : {
"clusterTime" : Timestamp(1714282360, 5),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
mongos>
查看分片状态情况,执行sh.status()
mongos> sh.status()
--- Sharding Status ---
sharding version: {
"_id" : 1,
"minCompatibleVersion" : 5,
"currentVersion" : 6,
"clusterId" : ObjectId("662dbd789e27dba6d8aa679c")
}
shards:
{ "_id" : "myshardrs01", "host" : "myshardrs01/192.168.133.131:27018,192.168.133.131:27118", "state" : 1 }
{ "_id" : "myshardrs02", "host" : "myshardrs02/192.168.133.131:27318,192.168.133.131:27418", "state" : 1 }
active mongoses:
"4.0.10" : 1
autosplit:
Currently enabled: yes
balancer:
Currently enabled: yes
Currently running: no
Failed balancer rounds in last 5 attempts: 0
Migration Results for the last 24 hours:
No recent migrations
databases:
{ "_id" : "articledb", "primary" : "myshardrs02", "partitioned" : true, "version" : { "uuid" : UUID("93ec9185-c1c6-4f73-b1a7-a9bc23ae5aea"), "lastMod" : 1 } }
{ "_id" : "config", "primary" : "config", "partitioned" : true }
config.system.sessions
shard key: { "_id" : 1 }
unique: false
balancing: true
chunks:
myshardrs01 1
{ "_id" : { "$minKey" : 1 } } -->> { "_id" : { "$maxKey" : 1 } } on : myshardrs01 Timestamp(1, 0)
mongos>
2.6.2.4 集合分片
瑞:使用集合分片之前,要确保该集合所在的数据库开启了分片功能。且一个集合的分片策略只能使用一个字段,即一个集合只能指定一个片键
【语法】对集合分片,需要指定集合和分片键
sh.shardCollection(namespace, key, unique)
【参数说明】
Parameter | Type | Description |
---|---|---|
namespace | string | 要(分片)共享的目标集合的命名空间,格式: <database>.<collection> |
key | document | 用作分片键的索引规范文档。shard键决定MongoDB如何在shard之间分发文档。除非集合为空,否则索引必须在shardcollection命令之前存在。如果集合为空,则MongoDB在对集合进行分片之前创建索引,前提是支持分片键的索引不存在。简单的说:由包含字段和该字段的索引遍历方向的文档组成。 |
unique | boolean | 当值为true情况下,片键字段上会限制为确保是唯一索引。哈希策略片键不支持唯一索引。默认是false。 |
对集合进行分片时,你需要选择一个片键(Shard Key) , shard key 是每条记录都必须包含的,且建立了索引的单个字段或复合字段,MongoDB 按照片键将数据划分到不同的数据块中,并将数据块均衡地分布到所有分片中。为了按照片键划分数据块,MongoDB 使用基于哈希的分片方式(随机平均分配)或者基于范围的分片方式(数值大小分配)
用什么字段当片键都可以,如:nickname 作为片键,但一定是必填字段。
【注意】
- 一个集合只能指定一个片键,否则报错。
- 一旦对一个集合分片,分片键和分片值就不可改变。
如:不能给集合选择不同的分片键、不能更新分片键的值。
集合分片规则一:哈希策略
瑞:哈希规则在开发中常用
对于基于哈希的分片,MongoDB计算一个字段的哈希值,并用这个哈希值来创建数据块。
在使用基于哈希分片的系统中,拥有”相近”片键的文档很可能不会存储在同一个数据块中,因此数据的分离性更好一些。
【示例】使用 nickname 作为片键,根据其值的哈希值进行数据分片(前提:确保 articledb 库开启了分片功能)
mongos> sh.shardCollection("articledb.comment",{"nickname":"hashed"})
{
"collectionsharded" : "articledb.comment",
"collectionUUID" : UUID("af0b0af8-c4c9-47ca-adaf-4055b61a7b2b"),
"ok" : 1,
"operationTime" : Timestamp(1714283855, 28),
"$clusterTime" : {
"clusterTime" : Timestamp(1714283855, 28),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
mongos>
查看分片状态情况,执行sh.status()
mongos> sh.status()
--- Sharding Status ---
sharding version: {
"_id" : 1,
"minCompatibleVersion" : 5,
"currentVersion" : 6,
"clusterId" : ObjectId("662dbd789e27dba6d8aa679c")
}
shards:
{ "_id" : "myshardrs01", "host" : "myshardrs01/192.168.133.131:27018,192.168.133.131:27118", "state" : 1 }
{ "_id" : "myshardrs02", "host" : "myshardrs02/192.168.133.131:27318,192.168.133.131:27418", "state" : 1 }
active mongoses:
"4.0.10" : 1
autosplit:
Currently enabled: yes
balancer:
Currently enabled: yes
Currently running: no
Failed balancer rounds in last 5 attempts: 0
Migration Results for the last 24 hours:
No recent migrations
databases:
{ "_id" : "articledb", "primary" : "myshardrs02", "partitioned" : true, "version" : { "uuid" : UUID("93ec9185-c1c6-4f73-b1a7-a9bc23ae5aea"), "lastMod" : 1 } }
articledb.comment
shard key: { "nickname" : "hashed" }
unique: false
balancing: true
chunks:
myshardrs01 2
myshardrs02 2
{ "nickname" : { "$minKey" : 1 } } -->> { "nickname" : NumberLong("-4611686018427387902") } on : myshardrs01 Timestamp(1, 0)
{ "nickname" : NumberLong("-4611686018427387902") } -->> { "nickname" : NumberLong(0) } on : myshardrs01 Timestamp(1, 1)
{ "nickname" : NumberLong(0) } -->> { "nickname" : NumberLong("4611686018427387902") } on : myshardrs02 Timestamp(1, 2)
{ "nickname" : NumberLong("4611686018427387902") } -->> { "nickname" : { "$maxKey" : 1 } } on : myshardrs02 Timestamp(1, 3)
{ "_id" : "config", "primary" : "config", "partitioned" : true }
config.system.sessions
shard key: { "_id" : 1 }
unique: false
balancing: true
chunks:
myshardrs01 1
{ "_id" : { "$minKey" : 1 } } -->> { "_id" : { "$maxKey" : 1 } } on : myshardrs01 Timestamp(1, 0)
mongos>
集合分片规则二:范围策略
对于基于范围的分片,MongoDB 按照片键的范围把数据分成不同部分。假设有一个数字的片键:想象一个从负无穷到正无穷的直线,每一个片键的值都在直线上画了一个点。MongoDB 把这条直线划分为更短的不重叠的片段,并称之为数据块,每个数据块包含了片键在一定范围内的数据。
在使用片键做范围划分的系统中,拥有”相近”片键的文档很可能存储在同一个数据块中,因此也会存储在同一个分片中。
【示例】使用作者年龄字段作为片键,按照点赞数的值进行分片(前提:确保 articledb 库开启了分片功能)
mongos> sh.shardCollection("articledb.author",{"age":1})
{
"collectionsharded" : "articledb.author",
"collectionUUID" : UUID("28fe1cd9-3a33-4b97-9cc6-82b55fffb3ca"),
"ok" : 1,
"operationTime" : Timestamp(1714284678, 13),
"$clusterTime" : {
"clusterTime" : Timestamp(1714284678, 13),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
mongos>
查看分片状态情况,执行sh.status()
mongos> sh.status()
--- Sharding Status ---
sharding version: {
"_id" : 1,
"minCompatibleVersion" : 5,
"currentVersion" : 6,
"clusterId" : ObjectId("662dbd789e27dba6d8aa679c")
}
shards:
{ "_id" : "myshardrs01", "host" : "myshardrs01/192.168.133.131:27018,192.168.133.131:27118", "state" : 1 }
{ "_id" : "myshardrs02", "host" : "myshardrs02/192.168.133.131:27318,192.168.133.131:27418", "state" : 1 }
active mongoses:
"4.0.10" : 1
autosplit:
Currently enabled: yes
balancer:
Currently enabled: yes
Currently running: no
Failed balancer rounds in last 5 attempts: 0
Migration Results for the last 24 hours:
No recent migrations
databases:
{ "_id" : "articledb", "primary" : "myshardrs02", "partitioned" : true, "version" : { "uuid" : UUID("93ec9185-c1c6-4f73-b1a7-a9bc23ae5aea"), "lastMod" : 1 } }
articledb.author
shard key: { "age" : 1 }
unique: false
balancing: true
chunks:
myshardrs02 1
{ "age" : { "$minKey" : 1 } } -->> { "age" : { "$maxKey" : 1 } } on : myshardrs02 Timestamp(1, 0)
articledb.comment
shard key: { "nickname" : "hashed" }
unique: false
balancing: true
chunks:
myshardrs01 2
myshardrs02 2
{ "nickname" : { "$minKey" : 1 } } -->> { "nickname" : NumberLong("-4611686018427387902") } on : myshardrs01 Timestamp(1, 0)
{ "nickname" : NumberLong("-4611686018427387902") } -->> { "nickname" : NumberLong(0) } on : myshardrs01 Timestamp(1, 1)
{ "nickname" : NumberLong(0) } -->> { "nickname" : NumberLong("4611686018427387902") } on : myshardrs02 Timestamp(1, 2)
{ "nickname" : NumberLong("4611686018427387902") } -->> { "nickname" : { "$maxKey" : 1 } } on : myshardrs02 Timestamp(1, 3)
{ "_id" : "config", "primary" : "config", "partitioned" : true }
config.system.sessions
shard key: { "_id" : 1 }
unique: false
balancing: true
chunks:
myshardrs01 1
{ "_id" : { "$minKey" : 1 } } -->> { "_id" : { "$maxKey" : 1 } } on : myshardrs01 Timestamp(1, 0)
mongos>
2.6.3 分片后插入数据测试
瑞:为了直观的看到效果,建议开两个客户端观察分片一和分片二的数据插入变化,加上 mongos 操作命令,共三个窗口
登录 mongos
/usr/local/mongodb/bin/mongo --host 192.168.133.131 --port 27017
分片一
/usr/local/mongodb/bin/mongo --host=192.168.133.131 --port=27018
分片二
/usr/local/mongodb/bin/mongo --host=192.168.133.131 --port=27318
2.6.3.1 哈希策略
1️⃣ 登录 mongs 后,向 articledb 数据库的 comment 集合循环插入 1000 条数据做测试for(var i=1;i<=1000;i++){db.comment.insert({_id:i+"",nickname:"Ray"+i})}
【提示】使用了 js 的语法,因为 mongo 的 shell 是一个 JavaScript 的 shell
【注意】从路由上插入的数据,必须包含片键,否则无法插入
mongos> db
test
mongos> show dbs
admin 0.000GB
articledb 0.000GB
config 0.001GB
mongos> use articledb
switched to db articledb
mongos> for(var i=1;i<=1000;i++){db.comment.insert({_id:i+"",nickname:"Ray"+i})}
WriteResult({ "nInserted" : 1 })
mongos> show collections
author
comment
mongos> db.comment.count()
1000
mongos>
2️⃣ 在分片一中查看,发现有 518 条数据
myshardrs01:PRIMARY> show dbs
admin 0.000GB
articledb 0.000GB
config 0.000GB
local 0.000GB
myshardrs01:PRIMARY> use articledb
switched to db articledb
myshardrs01:PRIMARY> db
articledb
myshardrs01:PRIMARY> db.comment.count()
518
myshardrs01:PRIMARY>
3️⃣ 在分片二中查看,发现有 482 条数据
myshardrs02:PRIMARY> show dbs
admin 0.000GB
articledb 0.000GB
config 0.000GB
local 0.000GB
myshardrs02:PRIMARY> use articledb
switched to db articledb
myshardrs02:PRIMARY> db
articledb
myshardrs02:PRIMARY> db.comment.count()
482
myshardrs02:PRIMARY>
如果有需要,可以使用db.comment.stats()
查看单个集合的完整情况,mongos 执行该命令可以查看该集合的数据分片的情况。
使用sh.status()
查看本库内所有集合的分片信息。
可以看到,1000 条数据近似均匀的分布到了 2 个 shard 上。是根据片键的哈希值分配的。
哈希策略的分配方式非常易于水平扩展:一旦数据存储需要更大空间,可以直接再增加分片即可,同时提升了性能,所以在开发中通常选用哈希分片策略。
2.6.3.2 范围策略
瑞:以下操作一定要记得使用
use 数据库名
命令切换当前操作的数据库
如果数据块(chunk)没有填满,默认的数据块尺寸(chunksize)是64M,填满后才会考虑向其他片的数据块填充数据,因此,为了测试范围策略,可以将其改小,这里改为1M,操作如下(记得测试完改回去)
mongos> use config
mongos> db.settings.save( { _id:"chunksize", value: 1 } )
登录 mongs 后,向 articledb 数据库的 author 集合循环插入 2000 条数据做测试
mongos> use articledb
switched to db articledb
mongos> for(var i=1;i<=2000;i++){db.author.save({"name":"RayRayRayRayRayRayRayRayRayRayRayRayRayRayRayRayRayRayRayRayRayRayRayRayRayRay"+i,"age":NumberInt(i%120)})}
WriteResult({ "nInserted" : 1 })
mongos> db.author.count()
2000
查看分片一和分片二中的数据存储情况
# 分片一
myshardrs01:PRIMARY> use articledb
myshardrs01:PRIMARY> db.author.count()
730
# 分片二
myshardrs02:PRIMARY> use articledb
myshardrs02:PRIMARY> db.author.count()
1270
测试完改回数据块尺寸
mongos> use config
mongos> db.settings.save( { _id:"chunksize", value: 64 } )
注意:要先改小,再设置分片。为了测试,可以先删除集合,重新建立集合的分片策略,再插入数据测试即可。
2.6.3.3 哈希策略和范围策略对比
瑞:当数据不确定的时候,又希望随机分片,此时用哈希策略。确定是类似年龄的这种范围查询,如查找40-60岁的作者,此时用范围策略效率高。由于实际业务往往较为复杂,所以大多数情况下使用哈希策略。
基于范围的分片方式与基于哈希的分片方式性能对比
基于范围的分片方式提供了更高效的范围查询,给定一个片键的范围,分发路由可以很简单地确定哪个数据块存储了请求需要的数据,并将请求转发到相应的分片中。
不过,基于范围的分片会导致数据在不同分片上的不均衡,有时候,带来的消极作用会大于查询性能的积极作用。比如,如果片键所在的字段是线性增长的,一定时间内的所有请求都会落到某个固定的数据块中,最终导致分布在同一个分片中。在这种情况下,一小部分分片承载了集群大部分的数据,系统并不能很好地进行扩展。
与此相比,基于哈希的分片方式以范围查询性能的损失为代价,保证了集群中数据的均衡。哈希值的随机性使数据随机分布在每个数据块中,因此也随机分布在不同分片中。但是也正由于随机性,一个范围查询很难确定应该请求哪些分片,通常为了返回需要的结果,需要请求所有分片。
如无特殊情况,一般推荐使用 Hash Sharding。
而使用_id
作为片键是一个不错的选择,因为它是必有的,你可以使用数据文档_id
的哈希作为片键。
这个方案能够是的读和写都能够平均分布,并且它能够保证每个文档都有不同的片键所以数据块能够很精细。
似乎还是不够完美,因为这样的话对多个文档的查询必将命中所有的分片。虽说如此,这也是一种比较好的方案了。
理想化的 shard key 可以让 documents 均匀地在集群中分布:
显示集群的详细信息
mongos> db.printShardingStatus()
查看均衡器是否工作(需要重新均衡时系统才会自动启动,不用管它)
mongos> sh.isBalancerRunning()
false
查看当前 Balancer 状态
mongos> sh.getBalancerState()
true
2.6.4 再增加一个路由节点
- 路由节点名称:mymongos
- 路由节点2:27117
瑞:过程和添加第一个路由节点基本一样,只是换个名字、路径和端口。所以部分解释说明以及图片省略。
1️⃣ 建立存放数据和日志的目录
#-----------mongos02
mkdir -p /usr/local/mongodb/sharded_cluster/mymongos_27117/log
2️⃣ 新建或修改配置文件mymongos_27117
vi /usr/local/mongodb/sharded_cluster/mymongos_27117/mongos.conf
瑞:指令使用:按
a
切换到输入状态,将下面配置文件内容复制过去,然后按esc
输入:wq
保存文件并退出
mymongos_27117 配置文件mongos.conf
可以参考如下,主要修改服务实例绑定的 IP,以及 sharding 部分,即章节《配置节点副本集》中配置节点副本集所配置的 3 个 mongod 服务
systemLog:
# MongoDB发送所有日志输出的目标指定为文件
destination: file
# mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
path: "/usr/local/mongodb/sharded_cluster/mymongos_27117/log/mongod.log"
# 当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
logAppend: true
processManagement:
# 启用在后台运行mongos或mongod进程的守护进程模式。
fork: true
# 指定用于保存mongos或mongod进程的进程ID的文件位置,其中mongos或mongod将写入其PID
pidFilePath: /usr/local/mongodb/sharded_cluster/mymongos_27117/log/mongod.pid"
net:
# 服务实例绑定所有IP,有副作用,副本集初始化的时候,节点名字会自动设置为本地域名,而不是ip
# bindIpAll: true
# 服务实例绑定的IP
bindIp: localhost,192.168.133.131
# bindIp
# 绑定的端口
port: 27117
sharding:
# 指定配置节点副本集
configDB: myconfigrs/192.168.133.131:27019,192.168.133.131:27119,192.168.133.131:27219
3️⃣ 启动 mongos
/usr/local/mongodb/bin/mongos -f /usr/local/mongodb/sharded_cluster/mymongos_27117/mongos.conf
如下图出现 started successfully 则说明安装配置成功!
4️⃣ 客户端登录 mongos
/usr/local/mongodb/bin/mongo --host 192.168.133.131 --port 27117
使用 mongo 客户端登录 27117,发现,第二个路由无需配置,因为分片配置都保存到了配置服务器中了
2.7 Compass连接分片集群
使用 Compass 连接路由节点的端口,使用路由节点 1 或者 2 都可以,即 27017 和 27117 都一样
可以进行增删改查等操作,无论是路由节点 1 还是节点 2 均可以
瑞:需要注意你的服务器或者虚拟机是否开启了防火墙,如果开启了防火墙则会远程连接失败,需要开放在配置中的 MongoDB 服务端口 27017 以及 27117,命令如下⬇️
# 在public区域(zone)中永久地添加一个TCP端口,如27017
sudo firewall-cmd --zone=public --add-port=27017/tcp --permanent
# 重新加载防火墙配置,让27017端口开放生效
sudo firewall-cmd --reload
# 开放 27117
sudo firewall-cmd --zone=public --add-port=27117/tcp --permanent
sudo firewall-cmd --reload
2.8 SpringDataMongDB连接分片集群
相关案例代码可参考《瑞_MongoDB_案例-文章评论》
article【瑞_MongoDB_案例-文章评论】
的完整源码的某度网盘链接如下,需要自取
链接:https://pan.baidu.com/s/1FMNAZNkXYm8kSbv18A6RDw?pwd=a7r4
提取码:a7r4
Java 客户端常用的是 SpringDataMongoDB,其连接的是 mongs 路由,配置和单机 mongod 的配置是一样的
多个路由的时候的SpringDataMongoDB的客户端配置application.yml
参考如下
spring:
#数据源配置
data:
mongodb:
# 主机地址
# host: 192.168.133.131
# 数据库
# database: articledb
# 默认端口是27017
# port: 27017
# 方式二:使用uri连接
# uri: mongodb://192.168.133.131:27017/articledb
# 副本集的连接字符串
# uri: mongodb://192.168.133.131:27017,192.168.133.131:27018,192.168.133.131:27019/articledb?connect=replicaSet&slaveOk=true&replicaSet=myrs
# 连接路由字符串
uri: mongodb://192.168.133.131:27017,192.168.133.131:27117/articledb
SpringDataMongoDB 自带了负载均衡策略,在写入数据的时候,会选择一个路由写入。所以在真正使用的时候,只需要修改 uri 配置即可,里面的分片之类的配置好就可直接使用。
在CommentServiceTest
测试类中选择一个测试用例,如查询所有数据的方法testFindAll()
进行测试,如下图测试通过即配置成功
2.9 清除所有的节点数据(备用)
如果在搭建分片的时候有操作失败或配置有问题,需要重新来过的,可以进行如下操作 ⬇️
1️⃣ 查询出所有的测试服务节点的进程
[root@localhost ~]# ps -ef |grep mongo
root 62216 1 0 4月28 ? 00:07:14 /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs01_27018/mongod.conf
root 62259 1 0 4月28 ? 00:07:51 /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs01_27118/mongod.conf
root 62293 1 0 4月28 ? 00:04:40 /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs01_27218/mongod.conf
root 63527 1 0 4月28 ? 00:07:32 /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs02_27318/mongod.conf
root 63566 1 0 4月28 ? 00:07:57 /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs02_27418/mongod.conf
root 63600 1 0 4月28 ? 00:04:28 /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs02_27518/mongod.conf
root 66705 1 1 4月28 ? 00:08:14 /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myconfigrs_27019/mongod.conf
root 66747 1 1 4月28 ? 00:08:29 /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myconfigrs_27119/mongod.conf
root 66788 1 1 4月28 ? 00:08:12 /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myconfigrs_27219/mongod.conf
root 69914 1 0 4月28 ? 00:02:00 /usr/local/mongodb/bin/mongos -f /usr/local/mongodb/sharded_cluster/mymongos_27017/mongos.conf
root 109518 1 0 4月28 ? 00:00:07 /usr/local/mongodb/bin/mongos -f /usr/local/mongodb/sharded_cluster/mymongos_27117/mongos.conf
root 112667 112191 0 00:43 pts/0 00:00:00 grep --color=auto mongo
[root@localhost ~]#
2️⃣ 根据上述的进程编号,依次中断进程
kill -2 进程ID
3️⃣ 清除所有的节点的数据(慎用)
rm -rf /usr/local/mongodb/sharded_cluster/myconfigrs_27019/data/db/*.* \ &
rm -rf /usr/local/mongodb/sharded_cluster/myconfigrs_27119/data/db/*.* \ &
rm -rf /usr/local/mongodb/sharded_cluster/myconfigrs_27219/data/db/*.* \ &
rm -rf /usr/local/mongodb/sharded_cluster/myshardrs01_27018/data/db/*.* \ &
rm -rf /usr/local/mongodb/sharded_cluster/myshardrs01_27118/data/db/*.* \ &
rm -rf /usr/local/mongodb/sharded_cluster/myshardrs01_27218/data/db/*.* \ &
rm -rf /usr/local/mongodb/sharded_cluster/myshardrs02_27318/data/db/*.* \ &
rm -rf /usr/local/mongodb/sharded_cluster/myshardrs02_27418/data/db/*.* \ &
rm -rf /usr/local/mongodb/sharded_cluster/myshardrs02_27518/data/db/*.* \ &
rm -rf /usr/local/mongodb/sharded_cluster/mymongos_27017/data/db/*.* \ &
rm -rf /usr/local/mongodb/sharded_cluster/mymongos_27117/data/db/*.*
4️⃣ 依次启动所有节点,不包括路由节点
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs01_27018/mongod.conf
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs01_27118/mongod.conf
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs01_27218/mongod.conf
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs02_27318/mongod.conf
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs02_27418/mongod.conf
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs02_27518/mongod.conf
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myconfigrs_27019/mongod.conf
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myconfigrs_27119/mongod.conf
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myconfigrs_27219/mongod.conf
5️⃣ 对两个数据分片副本集和一个配置副本集进行初始化和相关配置(请参考本篇的前文相关部分)
6️⃣ 检查路由 mongos 的配置,并启动 mongos
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/mymongos_27017/mongos.cfg
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/mymongos_27017/mongos.cfg
7️⃣ mongo 登录 mongos,在其上进行相关操作
/usr/local/mongodb/bin/mongo --host 192.168.133.131 --port 27017
3 安全认证
3.1 MongoDB的用户和角色权限简介
默认情况下,MongoDB 实例启动运行时是没有启用用户访问权限控制的,也就是说,在实例本机服务器上都可以随意连接到实例进行各种操作,MongoDB 不会对连接客户端进行用户验证,这是非常危险的。
MongoDB 官网上说,为了能保障 MongoDB 的安全可以做以下几个步骤⬇️
1️⃣ 使用新的端口,默认的 27017 端口如果一旦知道了 ip 就能连接上,不太安全。
2️⃣ 设置 MongoDB 的网络环境,最好将 MongoDB 部署到公司服务器内网,外网无法访问。公司内部访问使用 vpn 等。
3️⃣ 开启安全认证。认证要同时设置服务器之间的内部认证方式,同时要设置客户端连接到集群的账号密码认证方式。
为了强制开启用户访问控制(用户验证),则需要在 MongoDB 实例启动时使用选项
--auth
或在指定启动配置文件中添加选项auth=true
3.1.1 相关概念
在开始之前先了解一些相关概念
- 启用访问控制
MongoDB使用的是基于角色的访问控制(Role-Based Access Control,RBAC)来管理用户对实例的访问。通过对用户授予一个或多个角色来控制用户访问数据库资源的权限和数据库操作的权限,在对用户分配角色之前,用户无法访问实例。
在实例启动时添加选项--auth
或指定启动配置文件中添加选项auth=true
- 角色
在 MongoDB 中通过角色对用户授予相应数据库资源的操作权限,每个角色当中的权限可以显式指定,也可以通过继承其他角色的权限,或者两都都存在的权限。
- 权限
权限由指定的数据库资源(resource)以及允许在指定资源上进行的操作(action)组成。
1️⃣ 资源(resource)包括:数据库、集合、部分集合和集群;
2️⃣ 操作(action)包括:对资源进行的增、删、改、查(CRUD)操作。
在角色定义时可以包含一个或多个已存在的角色,新创建的角色会继承包含的角色所有的权限。在同一个数据库中,新创建角色可以继承其他角色的权限,在admin
数据库中创建的角色可以继承在其它任意数据库中角色的权限。
3.1.2 角色权限相关命令
关于角色权限的查看,可以通过如下命令查询(了解)
# 查询所有角色权限(仅用户自定义角色)
> db.runCommand({ rolesInfo: 1 })
# 查询所有角色权限(包含内置角色)
> db.runCommand({ rolesInfo: 1, showBuiltinRoles: true })
# 查询当前数据库中的某角色的权限
> db.runCommand({ rolesInfo: "<rolename>" })
# 查询其它数据库中指定的角色权限
> db.runCommand({ rolesInfo: { role: "<rolename>", db: "<database>" } }
# 查询多个角色权限
> db.runCommand(
{
rolesInfo: [
"<rolename>",
{ role: "<rolename>", db: "<database>" },
...
]
}
)
【示例】查看所有内置角色
> db.runCommand({ rolesInfo: 1, showBuiltinRoles: true })
{
"roles" : [
{
"role" : "__queryableBackup",
"db" : "admin",
"isBuiltin" : true,
"roles" : [ ],
"inheritedRoles" : [ ]
},
{
"role" : "__system",
"db" : "admin",
"isBuiltin" : true,
"roles" : [ ],
"inheritedRoles" : [ ]
},
{
"role" : "backup",
"db" : "admin",
"isBuiltin" : true,
"roles" : [ ],
"inheritedRoles" : [ ]
},
{
"role" : "clusterAdmin",
"db" : "admin",
"isBuiltin" : true,
"roles" : [ ],
"inheritedRoles" : [ ]
},
{
"role" : "clusterManager",
"db" : "admin",
"isBuiltin" : true,
"roles" : [ ],
"inheritedRoles" : [ ]
},
{
"role" : "clusterMonitor",
"db" : "admin",
"isBuiltin" : true,
"roles" : [ ],
"inheritedRoles" : [ ]
},
{
"role" : "dbAdmin",
"db" : "admin",
"isBuiltin" : true,
"roles" : [ ],
"inheritedRoles" : [ ]
},
{
"role" : "dbAdminAnyDatabase",
"db" : "admin",
"isBuiltin" : true,
"roles" : [ ],
"inheritedRoles" : [ ]
},
{
"role" : "dbOwner",
"db" : "admin",
"isBuiltin" : true,
"roles" : [ ],
"inheritedRoles" : [ ]
},
{
"role" : "enableSharding",
"db" : "admin",
"isBuiltin" : true,
"roles" : [ ],
"inheritedRoles" : [ ]
},
{
"role" : "hostManager",
"db" : "admin",
"isBuiltin" : true,
"roles" : [ ],
"inheritedRoles" : [ ]
},
{
"role" : "read",
"db" : "admin",
"isBuiltin" : true,
"roles" : [ ],
"inheritedRoles" : [ ]
},
{
"role" : "readAnyDatabase",
"db" : "admin",
"isBuiltin" : true,
"roles" : [ ],
"inheritedRoles" : [ ]
},
{
"role" : "readWrite",
"db" : "admin",
"isBuiltin" : true,
"roles" : [ ],
"inheritedRoles" : [ ]
},
{
"role" : "readWriteAnyDatabase",
"db" : "admin",
"isBuiltin" : true,
"roles" : [ ],
"inheritedRoles" : [ ]
},
{
"role" : "restore",
"db" : "admin",
"isBuiltin" : true,
"roles" : [ ],
"inheritedRoles" : [ ]
},
{
"role" : "root",
"db" : "admin",
"isBuiltin" : true,
"roles" : [ ],
"inheritedRoles" : [ ]
},
{
"role" : "userAdmin",
"db" : "admin",
"isBuiltin" : true,
"roles" : [ ],
"inheritedRoles" : [ ]
},
{
"role" : "userAdminAnyDatabase",
"db" : "admin",
"isBuiltin" : true,
"roles" : [ ],
"inheritedRoles" : [ ]
}
],
"ok" : 1,
"operationTime" : Timestamp(1714337286, 5),
"$clusterTime" : {
"clusterTime" : Timestamp(1714337288, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
3.1.3 常用的内置角色
常用的内置角色
- 数据库用户角色:read、readWrite;
- 所有数据库用户角色:readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase
- 数据库管理角色:dbAdmin、dbOwner、userAdmin;
- 集群管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManager;
- 备份恢复角色:backup、restore;
- 超级用户角色:root
- 内部角色:system
角色说明
角色 | 权限描述 |
---|---|
read | 读取指定数据库中任何数据 |
readWrite | 读写指定数据库中任何数据,包括创建、重命名、删除集合 |
readAnyDatabase | 读取所有数据库中任何数据(除了数据库config和local之外) |
readWriteAnyDatabase | 读写所有数据库中任何数据(除了数据库config和local之外) |
userAdminAnyDatabase | 在指定数据库创建和修改用户(除了数据库config和local之外) |
dbAdminAnyDatabase | 读取任何数据库以及对数据库进行清理、修改、压缩、获取统计信息、执行检查等操作(除了数据库config和local之外) |
dbAdmin | 读取指定数据库以及对数据库进行清理、修改、压缩、获取统计信息、执行检查等操作 |
userAdmin | 在指定数据库创建和修改用户 |
clusterAdmin | 对整个集群或数据库系统进行管理操作 |
backup | 备份MongoDB数据最小的权限 |
restore | 从备份文件中还原恢复MongoDB数据(除了system.profile集合)的权限 |
root | 超级账号,超级权限 |
3.2 单实例环境
目标:对单实例的 MongoDB 服务开启安全认证,这里的单实例指的是未开启副本集或分片的 MongoDB 实例
增加 MongoDB 的单实例的安全认证功能,可以在服务搭建的时候直接添加,也可以在之前搭建好的服务上添加。
本文使用之前搭建好的服务,Linux 安装 MongoDB 服务可参考本系列《瑞_MongoDB的2.4.2 Linux安装MongoDB》,因此,需要先停止之前的服务(如果你是第一次接触本系列文章,则可跳过关闭服务步骤),如下一小节进行关闭操作
3.2.1 关闭已开启的服务(可选)
由于本系列之前文章的操作,运行了多个 MongoDB 服务,现在需要关闭已开启的服务,执行ps -ef | grep mongo
命令查看 mongo 服务,并执行kill -2 PID PID PID
命令杀死 MongoDB 进程,如下图所示
关闭已开启的 mongo 服务有以下两种方式,上例使用的是方式2️⃣,实际操作时建议使用方式1️⃣
方法1️⃣ 通过 mongo 客户端中的 shutdownServer 命令来标准关闭服务
# 客户端登录服务,注意,这里通过localhost登录,如果需要远程登录,必须先登录认证才行
/usr/local/mongodb/bin/mongo --host=192.168.133.131 --port=27017
# 切换到admin库
use admin
# 关闭服务
db.shutdownServer()
显示如下图所示,即成功关闭服务
方法2️⃣ 通过系统的kill命令直接杀死 MongoDB 进程,快速关闭服务(快速,简单,但数据可能会出错)
# 查询 MongoDB 服务进程PID
ps -ef | grep mongod
# 使用 kill -2 或 kill -9 杀死 MongoDB 服务进程(kill -2 会尝试以优雅的方式终止进程,并允许进程执行清理工作;而 kill -9 则会立即停止进程的运行,不考虑进程的优雅结束或释放资源)
kill -2 3028
【补充】
如果一旦数据损坏,可以进行如下操作⬇️
1️⃣ 删除lock文件:rm -f /usr/local/mongodb/single/data/db/*.lock
2️⃣ 修复数据:/usr/local/mongodb/bin/mongod --repair --dbpath=/usr/local/mongodb/single/data/db/
3.2.2 添加用户和权限
单实例环境即 Linux 安装 MongoDB 服务,可参考本系列《瑞_MongoDB的2.4.2 Linux安装MongoDB》
1️⃣ 按照普通无授权认证的配置,来配置服务端的配置文件/usr/local/mongodb/single/mongod.conf
(复用之前的文章)
systemLog:
# MongoDB发送所有日志输出的目标指定为文件
# The path of the log file to which mongod or mongos should send all diagnostic logging information
destination: file
# mongod或mongos应向其发送所有诊断日志记录信息的日志文件的路径
path: "/usr/local/mongodb/single/log/mongod.log"
# 当mongos或mongod实例重新启动时,mongos或mongod会将新条目附加到现有日志文件的末尾。
logAppend: true
storage:
# mongod实例存储其数据的目录。storage.dbPath设置仅适用于mongod。
##The directory where the mongod instance stores its data.Default Value is "/data/db".
dbPath: "/usr/local/mongodb/single/data/db"
journal:
# 启用或禁用持久性日志以确保数据文件保持有效和可恢复。
enabled: true
processManagement:
# 启用在后台运行mongos或mongod进程的守护进程模式。
fork: true
net:
# 服务实例绑定的IP,默认是localhost
bindIp: localhost,192.168.133.131
# bindIp
# 绑定的端口,默认是27017
port: 27017
2️⃣ 按之前未开启认证的方式(不添加--auth
参数)来启动 MongoDB 服务
建议:在操作用户时,启动 mongod 服务时尽量不要开启授权,尽量使用配置文件方式代替参数启动
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/single/mongod.conf
# 或
/usr/local/mongodb/bin/mongod --config /usr/local/mongodb/single/mongod.conf
3️⃣ 使用 Mongo 客户端登录
/usr/local/mongodb/bin/mongo --host=192.168.133.131 --port=27017
4️⃣ 创建两个管理员用户,一个是系统的超级管理员myroot
,一个是 admin 库的管理用户myadmin
# 查看数据库
> show dbs
admin 0.000GB
articledb 0.000GB
config 0.000GB
local 0.000GB
rayTest 0.000GB
# 切换到admin库
> use admin
switched to db admin
# 确认已切换到admin库
> db
admin
# 创建系统超级用户 myroot,设置密码123456,设置角色root
# > db.createUser({user:"myroot",pwd:"123456",roles:[ { "role" : "root", "db" :"admin" } ]})
# 或
> db.createUser({user:"myroot",pwd:"123456",roles:["root"]})
Successfully added user: { "user" : "myroot", "roles" : [ "root" ] }
# 创建专门用来管理admin库的账号myadmin,只用来作为用户权限的管理
> db.createUser({user:"myadmin",pwd:"123456",roles:[{role:"userAdminAnyDatabase",db:"admin"}]})
Successfully added user: {
"user" : "myadmin",
"roles" : [
{
"role" : "userAdminAnyDatabase",
"db" : "admin"
}
]
}
# 查看已经创建了的用户的情况
> db.system.users.find()
{ "_id" : "admin.myroot", "userId" : UUID("ebcc96af-56be-40c4-accc-122fd5c8d0f6"), "user" : "myroot", "db" : "admin", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "pSQvpKqaguK16dOjQh/WUw==", "storedKey" : "NLtcyxvrm6csgvwudvnP3rxvS0g=", "serverKey" : "j0ONQ+1Ny/ZEmEhHkQHo/n4B7X0=" }, "SCRAM-SHA-256" : { "iterationCount" : 15000, "salt" : "JxSQhmOUBLkyg4xuIi4uxqIaPMxzrDOHWRc16A==", "storedKey" : "05U7LHA/43k5AlkMxRp81F9TThdsMgnUE0k+iCGI9tM=", "serverKey" : "Q2iijziAWotJ70bi/a4Njt5FssDu9yXBsz3515LxOQA=" } }, "roles" : [ { "role" : "root", "db" : "admin" } ] }
{ "_id" : "admin.myadmin", "userId" : UUID("653e4032-8b5c-44d3-a0e2-f55474f44472"), "user" : "myadmin", "db" : "admin", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "Cl79GxxPiwF4viOKiwcmBA==", "storedKey" : "EbCqEejCEIUPWiMuYMVFJxfluBc=", "serverKey" : "VVyZc3Q7EyDl/MSW2xPzOjzNluE=" }, "SCRAM-SHA-256" : { "iterationCount" : 15000, "salt" : "/O+Ni20QBWeWYScYlO5Zbp685vHee+e/kCDsHA==", "storedKey" : "9ajUY9VGDn6wduIM8+Wt3r6UZAfr/OIkPDUVoqnEN2Y=", "serverKey" : "EEZOLSJGO4FqdT+WWrn3cS182rcgzfS5VfYgYTG6DAQ=" } }, "roles" : [ { "role" : "userAdminAnyDatabase", "db" : "admin" } ] }
# 删除用户myadmin
> db.dropUser("myadmin")
true
# 确认用户myadmin被删除
> db.system.users.find()
{ "_id" : "admin.myroot", "userId" : UUID("ebcc96af-56be-40c4-accc-122fd5c8d0f6"), "user" : "myroot", "db" : "admin", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "pSQvpKqaguK16dOjQh/WUw==", "storedKey" : "NLtcyxvrm6csgvwudvnP3rxvS0g=", "serverKey" : "j0ONQ+1Ny/ZEmEhHkQHo/n4B7X0=" }, "SCRAM-SHA-256" : { "iterationCount" : 15000, "salt" : "JxSQhmOUBLkyg4xuIi4uxqIaPMxzrDOHWRc16A==", "storedKey" : "05U7LHA/43k5AlkMxRp81F9TThdsMgnUE0k+iCGI9tM=", "serverKey" : "Q2iijziAWotJ70bi/a4Njt5FssDu9yXBsz3515LxOQA=" } }, "roles" : [ { "role" : "root", "db" : "admin" } ] }
>
# 修改密码
> db.changeUserPassword("myroot", "123456")
角色
userAdminAnyDatabase
说明:在指定数据库创建和修改用户(除了数据库 config 和 local 之外)
【提示】
- 本案例创建了两个用户,分别对应超管和专门用来管理用户的角色,事实上,你只需要一个用户即可。如果你对安全要求很高,防止超管泄漏,则不要创建超管用户。
- 和其它数据库(如 MySQL)一样,权限的管理都差不多一样,也是将用户和权限信息保存到数据库对应的表中。MongoDB 存储所有的用户信息在 admin 数据库的集合
system.users
中,保存用户名、密码和数据库信息。 - 如果不指定数据库,则创建的指定的权限的用户在所有的数据库上有效,如
{role:"userAdminAnyDatabase", db:""}
5️⃣ 认证测试,测试添加的用户是否正确
# 切换到admin
> use admin
# 密码故意输错
> db.auth("myroot","ray")
Error: Authentication failed.
0
# 输入正确的密码
> db.auth("myroot","123456")
1
瑞:在一般情况下,不建议直接使用超级管理员用户去操作,因为相当危险,所以一般情况下还会创建一个权限相对小的普通用户,并使用普通用户进行操作某个具体的数据库
6️⃣ 创建普通用户
创建普通用户可以在没有开启认证的时候添加,也可以在开启认证之后添加,但开启认证之后,必须使用有操作 admin 库的用户登录认证后才能操作。底层都是将用户信息保存在了 admin 数据库的集合system.users
中。
# 创建(切换)将来要操作的数据库articledb,如果你没有的话请先创建该数据库
> use articledb
switched to db articledb
# 创建用户,拥有articledb数据库的读写权限readWrite,密码是123456
> db.createUser({user: "ray", pwd: "123456", roles: [{ role: "readWrite", db:"articledb" }]})
Successfully added user: {
"user" : "ray",
"roles" : [
{
"role" : "readWrite",
"db" : "articledb"
}
]
}
# 测试是否可用
> db.auth("ray","123456")
1
提示:如果开启了认证后,登录的客户端的用户必须使用 admin 库的角色,如拥有 root 角色的 myadmin 用户,再通过 myadmin 用户去创建其他角色的用户
3.2.3 服务端开启认证和客户端连接登录
由于服务端启动的时候没有添加开启认证的操作命令,所以当前不用登录用户依然可以直接操作。如果想要登录用户后才能进行操作,则需要进行以下操作
1️⃣ 关闭已经启动的服务。执行ps -ef | grep mongo
命令查看 mongo 服务,并执行kill -2 PID
命令杀死 MongoDB 进程,如下图所示
2️⃣ 以服务端开启认证的方式启动服务
有两种方式开启权限认证启动服务:一种是参数方式,一种是配置文件方式
3.2.3.1 服务端开启认证——参数方式
在启动时指定参数--auth
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/single/mongod.conf --auth
瑞:以参数方式开启认证在开发当中很少使用。因为这种方式必须要每次启动的时候带上参数,如果哪一次忘了,就相当于安全认证不起作用,非常不安全,操作不严谨。
3.2.3.2 服务端开启认证——配置文件方式(推荐)
在mongod.conf
配置文件中加入开启授权认证的配置
使用vi /usr/local/mongodb/single/mongod.conf
编辑配置文件
瑞:指令使用:按
a
切换到输入状态,将下面配置文件内容复制过去,然后按esc
输入:wq
保存文件并退出
添加如下配置
security:
# 开启授权认证
authorization: enabled
启动时可不加--auth
参数
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/single/mongod.conf
此时连接客户端,发现可以正常连接,但无操作权限,如下图执行show dbs
后啥也看不见
/usr/local/mongodb/bin/mongo --host=192.168.133.131 --port=27017
开启认证后再登录,打印的日志会有所减少。相关操作需要认证后才可以执行成功。
开启了认证的情况下的客户端登录,有两种认证方式
1️⃣ 先连接登录,再在 mongo shell 中认证
2️⃣ 登录时直接认证
3.2.4.3 客户端连接登录——先连接再认证
连接客户端
/usr/local/mongodb/bin/mongo --host=192.168.133.131 --port=27017
再在相应的数据库中使用 mongo shell 进行认证
【示例1】使用use admin
数据库进行 myroot 角色(超级管理员)认证
[root@localhost ~]# /usr/local/mongodb/bin/mongo --host=192.168.133.131 --port=27017
MongoDB shell version v4.0.10
connecting to: mongodb://192.168.133.131:27017/?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("98afb9e9-b56c-4f3e-a9df-8f573871e252") }
MongoDB server version: 4.0.10
> show dbs
>
> use admin
switched to db admin
> db.auth("myroot","123456")
1
> show dbs
admin 0.000GB
articledb 0.000GB
config 0.000GB
local 0.000GB
rayTest 0.000GB
> db
admin
> show collections
system.users
system.version
> db.system.users.find()
..输出省略..
【示例2】使用use articledb
数据库进行 ray 角色(普通用户)认证
[root@localhost ~]# /usr/local/mongodb/bin/mongo --host=192.168.133.131 --port=27017
MongoDB shell version v4.0.10
connecting to: mongodb://192.168.133.131:27017/?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("1d248426-e70e-4204-9820-1ac0bca2f2e8") }
MongoDB server version: 4.0.10
> show dbs
>
> use articledb
switched to db articledb
> db.auth("ray","123456")
1
> show collections
comment
> show dbs
articledb 0.000GB
瑞:注意一定要到相应的数据库中进行认证操作,如
use admin
或use articledb
,默认使用 test 数据库,则会报 Error: Authentication failed.
3.2.4.4 客户端连接登录——连接时直接认证
【参数说明】
-u
:用户名-p
:密码--authenticationDatabase
:指定连接到哪个库。当登录是指定用户名密码时,必须指定对应的数据库
【示例1】对 admin 数据库进行登录认证和相关操作
[root@localhost ~]# /usr/local/mongodb/bin/mongo --host=192.168.133.131 --port=27017 --authenticationDatabase admin -u myroot -p 123456
MongoDB shell version v4.0.10
connecting to: mongodb://192.168.133.131:27017/?authSource=admin&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("069db1cb-6450-4a81-8cd4-7da8cc76c16e") }
MongoDB server version: 4.0.10
Server has startup warnings:
2024-07-13T16:16:21.355+0800 I CONTROL [initandlisten] ** WARNING: You are running this process as the root user, which is not recommended.
2024-07-13T16:16:21.355+0800 I CONTROL [initandlisten]
2024-07-13T16:16:21.355+0800 I CONTROL [initandlisten]
2024-07-13T16:16:21.355+0800 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.
2024-07-13T16:16:21.355+0800 I CONTROL [initandlisten] ** We suggest setting it to 'never'
2024-07-13T16:16:21.355+0800 I CONTROL [initandlisten]
2024-07-13T16:16:21.355+0800 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.
2024-07-13T16:16:21.355+0800 I CONTROL [initandlisten] ** We suggest setting it to 'never'
2024-07-13T16:16:21.355+0800 I CONTROL [initandlisten]
> show dbs
admin 0.000GB
articledb 0.000GB
config 0.000GB
local 0.000GB
rayTest 0.000GB
【示例2】对 articledb 数据库进行登录认证和相关操作
[root@localhost ~]# /usr/local/mongodb/bin/mongo --host=192.168.133.131 --port=27017 --authenticationDatabase articledb -u ray -p 123456
MongoDB shell version v4.0.10
connecting to: mongodb://192.168.133.131:27017/?authSource=articledb&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("5583875f-f8bc-4cec-b112-5702df4ce326") }
MongoDB server version: 4.0.10
> show dbs
articledb 0.000GB
>
3.2.4 SpringDataMongoDB连接认证
相关案例代码可参考《瑞_MongoDB_案例-文章评论》
article【瑞_MongoDB_案例-文章评论】
的完整源码的某度网盘链接如下,需要自取
链接:https://pan.baidu.com/s/1FMNAZNkXYm8kSbv18A6RDw?pwd=a7r4
提取码:a7r4
使用用户名和密码连接到 MongoDB 服务器,你必须使用'username:password@hostname/dbname'
格式,username
为用户名,password
为密码
【示例】使用用户 ray 使用密码 123456 连接到 MongoDB 服务上
application.yml
添加配置,可参考如下
spring:
#数据源配置
data:
mongodb:
# 主机地址
# host: 192.168.133.131
# 数据库
# database: articledb
# 默认端口是27017
# port: 27017
# 帐号
# username: ray
# 密码(如果密码是纯数字要加上'')
# password: '123456'
# 方式二:使用uri连接
# uri: mongodb://192.168.133.131:27017/articledb
# 副本集的连接字符串
# uri: mongodb://192.168.133.131:27017,192.168.133.131:27018,192.168.133.131:27019/articledb?connect=replicaSet&slaveOk=true&replicaSet=myrs
# 连接路由字符串
# uri: mongodb://192.168.133.131:27017,192.168.133.131:27117/articledb
# 单机有设置安全认证的情况下,使用字符串连接
uri: mongodb://ray:123456@192.168.133.131:27017/articledb
在CommentServiceTest
测试类中选择一个测试用例,如查询所有数据的方法testFindAll()
进行测试,如下图测试通过即配置成功
使用 Compass 的时候要选择使用用户名密码连接,并输入认证数据库
3.3 副本集环境
对于搭建好的 MongoDB 副本集,为了安全,启动安全认证,使用账号密码登录
瑞:和单实例环境配置基本一致,区别在于要创建和配置 keyfile 密钥文件
3.3.1 前言
本文副本集环境使用之前本系列章节中《瑞_MongoDB_MongoDB副本集》搭建好的,架构如下图所示
对副本集执行访问控制需要配置两个方面
1️⃣ 副本集和共享集群的各个节点成员之间使用内部身份验证,可以使用密钥文件(keyfile)或 x.509 证书。密钥文件比较简单,本文使用密钥文件,官方推荐如果是测试环境可以使用密钥文件,但是正式环境,官方推荐x.509证书。原理就是,集群中每一个实例彼此连接的时候都检验彼此使用的证书的内容是否相同。只有证书相同的实例彼此才可以访问。
2️⃣ 使用客户端连接到 MongoDB 集群时,开启访问授权。对于集群外部的访问。如通过可视化客户端,或者通过代码连接的时候,需要开启授权。
在 keyfile 身份验证中,副本集中的每个 实例都使用 MongoDB 的内容作为共享密码,只有具有正确密钥文件的 mongod 或者 mongos 实例可以连接到副本集。密钥文件的内容必须在 6 到 1024 个字符之间,并且在 unix/linux 系统中文件所有者必须有对文件至少有读的权限。
3.3.2 关闭已开启的副本集服务(可选)
增加副本集的安全认证和服务鉴权功能,可以在副本集搭建的时候直接添加,也可以在之前搭建好的副本集服务上添加。
本文使用之前搭建好的服务,Linux 安装 MongoDB 副本集可参考本系列《瑞_MongoDB_MongoDB副本集》,因此,需要先停止之前的集群服务(如果你是第一次接触本系列文章,则可跳过关闭服务步骤),如下进行关闭操作
由于本系列之前文章的操作,运行了多个 MongoDB 服务,现在需要关闭已开启的服务,执行ps -ef | grep mongo
命令查看 mongo 服务,并执行kill -2 PID PID PID
命令杀死 MongoDB 进程,如下图所示
关闭已开启的 mongo 服务有两种方式,点我跳转回顾,上例使用的是方式2️⃣,实际操作时建议使用方式1️⃣
标准关闭副本集中的服务,建议依次关闭仲裁节点、副本节点、主节点。主要的操作步骤参考如下
# 客户端登录服务,注意,这里通过localhost登录,如果需要远程登录,必须先登录认证才行。
mongo --port 27017
# 告知副本集说本机要下线
rs.stepDown()
# 切换到admin库
use admin
# 关闭服务
db.shutdownServer()
在实际情况中,如果副本集是开启状态,则先分别关闭关闭副本集中的每个 mongod,从次节点开始。直到副本集的所有成员都离线,包括任何仲裁者。主节点必须是最后一个成员关闭以避免潜在的回滚。
3.3.3 通过主节点添加一个管理员帐号
只需要在主节点上添加用户,副本集会自动同步
1️⃣ 分别启动副本集的 3 个节点,组成副本集环境
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/replica_sets/myrs_27017/mongod.conf
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/replica_sets/myrs_27018/mongod.conf
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/replica_sets/myrs_27019/mongod.conf
2️⃣ 登录主节点客户端
/usr/local/mongodb/bin/mongo --host=192.168.133.131 --port=27017
3️⃣ 开启认证之前,创建超管用户:myroot,密码:123456
# 切换到admin库
myrs:PRIMARY> use admin
switched to db admin
# 创建系统超级用户 myroot,设置密码123456,设置角色root
myrs:PRIMARY> db.createUser({user:"myroot",pwd:"123456",roles:["root"]})
Successfully added user: { "user" : "myroot", "roles" : [ "root" ] }
myrs:PRIMARY>
瑞:详细步骤解释详可参考本文单实例环境的添加用户和权限的相关部分
3.3.4 创建副本集认证的key文件
1️⃣ 生成一个 key 文件到当前文件夹中(当前文件夹建议使用副本集目录,如博主为/usr/local/mongodb/replica_sets/
)
可以使用任何方法生成密钥文件。例如,以下操作使用 openssl 生成密码文件,然后使用 chmod 来更改文件权限,仅为文件所有者提供读取权限
# 进入副本集目录
[root@localhost ~]# cd /usr/local/mongodb/replica_sets/
# 使用 openssl 生成密码文件
[root@localhost replica_sets]# openssl rand -base64 90 -out ./mongo.keyfile
# 更改文件权限,仅为文件所有者提供读取权限
[root@localhost replica_sets]# chmod 400 ./mongo.keyfile
# 查看
[root@localhost replica_sets]# ll mongo.keyfile
-r--------. 1 root root 122 7月 13 19:23 mongo.keyfile
【提示】
所有副本集节点都必须要用同一份 keyfile,一般是在一台机器上生成,然后拷贝到其他机器上,且必须有读的权限,否则将来会报错: permissions on /usr/local/mongodb/replica_sets/myrs_27017/mongo.keyfile are too open
2️⃣ 一定要保证 keyfile 密钥文件是一致的,文件位置随便。但是为了方便查找,建议每台机器都放到一个固定的位置,都放到和配置文件一起的目录中。博主将该文件分别拷贝到多个节点目录中
# 进入副本集目录
[root@localhost ~]# cd /usr/local/mongodb/replica_sets/
# 拷贝文件
[root@localhost replica_sets]# cp mongo.keyfile /usr/local/mongodb/replica_sets/myrs_27017
[root@localhost replica_sets]# cp mongo.keyfile /usr/local/mongodb/replica_sets/myrs_27018
[root@localhost replica_sets]# cp mongo.keyfile /usr/local/mongodb/replica_sets/myrs_27019
3.3.5 修改配置文件指定keyfile
分别编辑几个节点服务的mongod.conf
文件,在配置文件中添加相关内容
/usr/local/mongodb/replica_sets/myrs_27017/mongod.conf
security:
# KeyFile鉴权文件
keyFile: /usr/local/mongodb/replica_sets/myrs_27017/mongo.keyfile
# 开启认证方式运行
authorization: enabled
/usr/local/mongodb/replica_sets/myrs_27018/mongod.conf
security:
# KeyFile鉴权文件
keyFile: /usr/local/mongodb/replica_sets/myrs_27018/mongo.keyfile
# 开启认证方式运行
authorization: enabled
/usr/local/mongodb/replica_sets/myrs_27019/mongod.conf
security:
# KeyFile鉴权文件
keyFile: /usr/local/mongodb/replica_sets/myrs_27019/mongo.keyfile
# 开启认证方式运行
authorization: enabled
3.3.6 重新启动副本集
由于之前将副本集开启了,运行了多个 MongoDB 服务,先分别关闭副本集中的每个 MongoDB 服务,从次节点开始。直到副本集的所有成员都离线,包括任何仲裁者。主节点必须是最后一个成员关闭以避免潜在的回滚。
执行ps -ef | grep mongo
命令查看 mongo 服务,并执行kill -2 PID PID PID
命令杀死 MongoDB 进程,建议依次杀死仲裁节点、副本节点、主节点,如下图所示
关闭已开启的 mongo 服务有两种方式,点我跳转回顾,上例使用的是方式2️⃣,实际操作时建议使用方式1️⃣
分别启动副本集的 3 个节点
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/replica_sets/myrs_27017/mongod.conf
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/replica_sets/myrs_27018/mongod.conf
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/replica_sets/myrs_27019/mongod.conf
执行ps -ef |grep mongod
命令查看进程情况
3.3.7 在主节点上添加普通账号
在主节点上添加普通账号,副本节点也会同步复制
# 登录主节点客户端
[root@localhost replica_sets]# /usr/local/mongodb/bin/mongo --host=192.168.133.131 --port=27017
MongoDB shell version v4.0.10
connecting to: mongodb://192.168.133.131:27017/?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("7a32ce4d-6a52-4728-9fdc-8db91477fb35") }
MongoDB server version: 4.0.10
myrs:PRIMARY>
# 无权限操作演示
myrs:PRIMARY> show dbs
myrs:PRIMARY>
# 先用管理员账号登录
# 切换到admin库
myrs:PRIMARY> use admin
switched to db admin
# 管理员账号认证
myrs:PRIMARY> db.auth("myroot","123456")
1
# 认证后有权限操作数据库演示
myrs:PRIMARY> show dbs
admin 0.000GB
articledb 0.000GB
config 0.000GB
local 0.001GB
test 0.000GB
myrs:PRIMARY>
# 切换到要认证的库
myrs:PRIMARY> use articledb
switched to db articledb
# 添加普通用户ray
myrs:PRIMARY> db.createUser({user: "ray", pwd: "123456", roles: ["readWrite"]})
Successfully added user: { "user" : "ray", "roles" : [ "readWrite" ] }
myrs:PRIMARY>
# 切换到admin库
myrs:PRIMARY> use admin
switched to db admin
# 查看普通用户是否添加成功
myrs:PRIMARY> db.system.users.find()
..数据省略..
重新连接,使用普通用户 ray 重新登录,查看数据。也可以使用rs.status()
命令查看副本集是否健康
# 退出连接
myrs:PRIMARY> exit
bye
# 重新连接
[root@localhost replica_sets]# /usr/local/mongodb/bin/mongo --host=192.168.133.131 --port=27017
MongoDB shell version v4.0.10
connecting to: mongodb://192.168.133.131:27017/?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("938dd50a-d18c-4bed-9a50-77cb476f1701") }
MongoDB server version: 4.0.10
# 切换到articledb库
myrs:PRIMARY> use articledb
switched to db articledb
# 登录普通用户
myrs:PRIMARY> db.auth("ray","123456")
1
# 操作演示
myrs:PRIMARY> show dbs
articledb 0.000GB
# 操作演示
myrs:PRIMARY> show collections
comment
# 状态查看
myrs:PRIMARY> rs.status()
{
"operationTime" : Timestamp(1720872863, 1),
"ok" : 0,
"errmsg" : "not authorized on admin to execute command { replSetGetStatus: 1.0, lsid: { id: UUID(\"938dd50a-d18c-4bed-9a50-77cb476f1701\") }, $clusterTime: { clusterTime: Timestamp(1720872843, 1), signature: { hash: BinData(0, 2C2EFBD07CCC7165AD33AF696877C266A7986688), keyId: 7362272470235086849 } }, $db: \"admin\" }",
"code" : 13,
"codeName" : "Unauthorized",
"$clusterTime" : {
"clusterTime" : Timestamp(1720872863, 1),
"signature" : {
"hash" : BinData(0,"n9mWARREOq84pAvEb02WDQ7xTYk="),
"keyId" : NumberLong("7362272470235086849")
}
}
}
myrs:PRIMARY>
3.3.8 SpringDataMongoDB连接副本集
相关案例代码可参考《瑞_MongoDB_案例-文章评论》
article【瑞_MongoDB_案例-文章评论】
的完整源码的某度网盘链接如下,需要自取
链接:https://pan.baidu.com/s/1FMNAZNkXYm8kSbv18A6RDw?pwd=a7r4
提取码:a7r4
使用用户名和密码连接到 MongoDB 服务器,你必须使用'username:password@hostname/dbname'
格式,username
为用户名,password
为密码
【示例】使用用户 ray 使用密码 123456 连接到 MongoDB 服务上
application.yml
添加配置,可参考如下
spring:
#数据源配置
data:
mongodb:
# 主机地址
# host: 192.168.133.131
# 数据库
# database: articledb
# 默认端口是27017
# port: 27017
# 帐号
# username: ray
# 密码(如果密码是纯数字要加上'')
# password: '123456'
# 方式二:使用uri连接
# uri: mongodb://192.168.133.131:27017/articledb
# 副本集的连接字符串
# uri: mongodb://192.168.133.131:27017,192.168.133.131:27018,192.168.133.131:27019/articledb?connect=replicaSet&slaveOk=true&replicaSet=myrs
# 连接路由字符串
# uri: mongodb://192.168.133.131:27017,192.168.133.131:27117/articledb
# 单机有设置安全认证的情况下,使用字符串连接
# uri: mongodb://ray:123456@192.168.133.131:27017/articledb
# 副本集有认证的情况下,字符串连接
uri: mongodb://ray:123456@192.168.133.131:27017,192.168.133.131:27018,192.168.133.131:27019/articledb?connect=replicaSet&slaveOk=true&replicaSet=myrs
在CommentServiceTest
测试类中选择一个测试用例,如查询所有数据的方法testFindAll()
进行测试,如下图测试通过即配置成功
3.4 分片集群环境
瑞:和副本集环境配置基本一致,区别在于有更多的节点服务需要配置
分片集群的服务器环境和架构较为复杂,建议在搭建分片集群的时候,直接加入安全认证和服务器间的鉴权,如果之前有数据,可先将之前的数据备份出来,再还原回去。
本文分片集群环境使用之前本系列章节中《瑞_MongoDB_MongoDB分片集群》搭建好的
3.4.1 关闭已开启的集群服务(可选)
由于本系列之前文章的操作,运行了多个 MongoDB 服务,现在需要关闭已开启的服务,执行ps -ef | grep mongo
命令查看 mongo 服务,并执行kill -2 PID PID PID
命令杀死 MongoDB 进程,如下图所示
关闭已开启的 mongo 服务有两种方式,点我跳转回顾,上例使用的是方式2️⃣,实际操作时建议使用方式1️⃣
标准关闭分片服务器副本集中的服务,建议依次关闭仲裁节点、副本节点、主节点。主要的操作步骤参考如下
# 客户端登录服务,注意,这里通过localhost登录,如果需要远程登录,必须先登录认证才行。
mongo --port 27018
# 告知副本集说本机要下线
rs.stepDown()
# 切换到admin库
use admin
# 关闭服务
db.shutdownServer()
标准关闭配置服务器副本集的服务,建议依次关闭副本节点、主节点。主要的操作步骤参考如下
# 客户端登录服务,注意,这里通过localhost登录,如果需要远程登录,必须先登录认证才行。
mongo --port 27019
# 告知副本集说本机要下线
rs.stepDown()
# 切换到admin库
use admin
# 关闭服务
db.shutdownServer()
标准关闭路由服务器的服务,建议依次关闭两个路由节点。主要的操作步骤参考如下
# 客户端登录服务,注意,这里通过localhost登录,如果需要远程登录,必须先登录认证才行。
mongo --port 27017
# 告知副本集说本机要下线
rs.stepDown()
# 切换到admin库
use admin
# 关闭服务
db.shutdownServer()
3.4.2 创建分片集群认证的key文件
1️⃣ 生成一个 key 文件到当前文件夹中(当前文件夹建议使用分片集群目录,如博主为/usr/local/mongodb/sharded_cluster/
)
可以使用任何方法生成密钥文件。例如,以下操作使用 openssl 生成密码文件,然后使用 chmod 来更改文件权限,仅为文件所有者提供读取权限
# 进入副本集目录
[root@localhost ~]# cd /usr/local/mongodb/sharded_cluster/
# 使用 openssl 生成密码文件
[root@localhost sharded_cluster]# openssl rand -base64 90 -out ./mongo.keyfile
# 更改文件权限,仅为文件所有者提供读取权限
[root@localhost sharded_cluster]# chmod 400 ./mongo.keyfile
# 查看
[root@localhost sharded_cluster]# ll mongo.keyfile
-r--------. 1 root root 122 7月 13 19:23 mongo.keyfile
【提示】
所有分片集群节点都必须要用同一份 keyfile,一般是在一台机器上生成,然后拷贝到其他机器上,且必须有读的权限,否则将来会报错: permissions on /usr/local/mongodb/sharded_cluster/myrs_27017/mongo.keyfile are too open
2️⃣ 一定要保证 keyfile 密钥文件是一致的,文件位置随便。但是为了方便查找,建议每台机器都放到一个固定的位置,都放到和配置文件一起的目录中。博主将该文件分别拷贝到多个节点目录中
# 进入分片集群目录
[root@localhost ~]# cd /usr/local/mongodb/sharded_cluster/
# 拷贝文件
[root@localhost sharded_cluster]# cp mongo.keyfile /usr/local/mongodb/sharded_cluster/myshardrs01_27018/mongo.keyfile
[root@localhost sharded_cluster]# cp mongo.keyfile /usr/local/mongodb/sharded_cluster/myshardrs01_27118/mongo.keyfile
[root@localhost sharded_cluster]# cp mongo.keyfile /usr/local/mongodb/sharded_cluster/myshardrs01_27218/mongo.keyfile
[root@localhost sharded_cluster]# cp mongo.keyfile /usr/local/mongodb/sharded_cluster/myshardrs02_27318/mongo.keyfile
[root@localhost sharded_cluster]# cp mongo.keyfile /usr/local/mongodb/sharded_cluster/myshardrs02_27418/mongo.keyfile
[root@localhost sharded_cluster]# cp mongo.keyfile /usr/local/mongodb/sharded_cluster/myshardrs02_27518/mongo.keyfile
[root@localhost sharded_cluster]# cp mongo.keyfile /usr/local/mongodb/sharded_cluster/myconfigrs_27019/mongo.keyfile
[root@localhost sharded_cluster]# cp mongo.keyfile /usr/local/mongodb/sharded_cluster/myconfigrs_27119/mongo.keyfile
[root@localhost sharded_cluster]# cp mongo.keyfile /usr/local/mongodb/sharded_cluster/myconfigrs_27219/mongo.keyfile
[root@localhost sharded_cluster]# cp mongo.keyfile /usr/local/mongodb/sharded_cluster/mymongos_27017/mongo.keyfile
[root@localhost sharded_cluster]# cp mongo.keyfile /usr/local/mongodb/sharded_cluster/mymongos_27117/mongo.keyfile
3.4.3 修改配置文件指定keyfile
分别编辑几个节点服务的mongod.conf
文件,在配置文件中添加相关内容
1️⃣ /usr/local/mongodb/sharded_cluster/myshardrs01_27018/mongod.conf
security:
# KeyFile鉴权文件
keyFile: /usr/local/mongodb/sharded_cluster/myshardrs01_27018/mongo.keyfile
# 开启认证方式运行
authorization: enabled
2️⃣ /usr/local/mongodb/sharded_cluster/myshardrs01_27118/mongod.conf
security:
# KeyFile鉴权文件
keyFile: /usr/local/mongodb/sharded_cluster/myshardrs01_27118/mongo.keyfile
# 开启认证方式运行
authorization: enabled
3️⃣ /usr/local/mongodb/sharded_cluster/myshardrs01_27218/mongod.conf
security:
# KeyFile鉴权文件
keyFile: /usr/local/mongodb/sharded_cluster/myshardrs01_27218/mongo.keyfile
# 开启认证方式运行
authorization: enabled
4️⃣ /usr/local/mongodb/sharded_cluster/myshardrs02_27318/mongod.conf
security:
# KeyFile鉴权文件
keyFile: /usr/local/mongodb/sharded_cluster/myshardrs02_27318/mongo.keyfile
# 开启认证方式运行
authorization: enabled
5️⃣ /usr/local/mongodb/sharded_cluster/myshardrs02_27418/mongod.conf
security:
# KeyFile鉴权文件
keyFile: /usr/local/mongodb/sharded_cluster/myshardrs02_27418/mongo.keyfile
# 开启认证方式运行
authorization: enabled
6️⃣ /usr/local/mongodb/sharded_cluster/myshardrs02_27518/mongod.conf
security:
# KeyFile鉴权文件
keyFile: /usr/local/mongodb/sharded_cluster/myshardrs02_27518/mongo.keyfile
# 开启认证方式运行
authorization: enabled
7️⃣ /usr/local/mongodb/sharded_cluster/myconfigrs_27019/mongod.conf
security:
# KeyFile鉴权文件
keyFile: /usr/local/mongodb/sharded_cluster/myconfigrs_27019/mongo.keyfile
# 开启认证方式运行
authorization: enabled
8️⃣ /usr/local/mongodb/sharded_cluster/myconfigrs_27119/mongod.conf
security:
# KeyFile鉴权文件
keyFile: /usr/local/mongodb/sharded_cluster/myconfigrs_27119/mongo.keyfile
# 开启认证方式运行
authorization: enabled
9️⃣ /usr/local/mongodb/sharded_cluster/myconfigrs_27219/mongod.conf
security:
# KeyFile鉴权文件
keyFile: /usr/local/mongodb/sharded_cluster/myconfigrs_27219/mongo.keyfile
# 开启认证方式运行
authorization: enabled
1️⃣0️⃣/usr/local/mongodb/sharded_cluster/mymongos_27017/mongod.conf
security:
# KeyFile鉴权文件
keyFile: /usr/local/mongodb/sharded_cluster/mymongos_27017/mongo.keyfile
1️⃣1️⃣/usr/local/mongodb/sharded_cluster/mymongos_27117/mongod.conf
security:
# KeyFile鉴权文件
keyFile: /usr/local/mongodb/sharded_cluster/mymongos_27117/mongo.keyfile
【注意】
- mongos 比 mongod 少了
authorization: enabled
的配置。原因是,副本集加分片的安全认证需要配置两方面的,副本集各个节点之间使用内部身份验证,用于内部各个 mongo 实例的通信,只有相同 keyfile 才能相互访问。所以都要开启keyFile: /usr/local/mongodb/sharded_cluster/路径/mongo.keyfile
- 然而对于所有的 mongod,才是真正的保存数据的分片。mongos 只做路由,不保存数据。所以所有的 mongod 开启访问数据的授权
authorization: enabled
。这样用户只有账号密码正确才能访问到数据。
3.4.4 重新启动节点
启动顺序:必须依次启动配置节点、分片节点、路由节点
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myconfigrs_27019/mongod.conf
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myconfigrs_27119/mongod.conf
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myconfigrs_27219/mongod.conf
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs01_27018/mongod.conf
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs01_27118/mongod.conf
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs01_27218/mongod.conf
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs02_27318/mongod.conf
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs02_27418/mongod.conf
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs02_27518/mongod.conf
/usr/local/mongodb/bin/mongos -f /usr/local/mongodb/sharded_cluster/mymongos_27017/mongos.conf
/usr/local/mongodb/bin/mongos -f /usr/local/mongodb/sharded_cluster/mymongos_27117/mongos.conf
【注意】如果先启动分片节点,会卡住,会提示如下
about to fork child process, waiting until server is ready for connections
解决方案未知(可能是bug)
3.4.5 创建帐号和认证
瑞:和副本集环境不同,必须通过 localhost 登录任意一个 mongos 路由
客户端连接 mongo,通过 localhost 登录任意一个 mongos 路由,例如 27017
/usr/local/mongodb/bin/mongo --port 27017
【提示】此处相当于一个后门,只能在admin下添加用户
创建一个管理员帐号
[root@localhost sharded_cluster]# /usr/local/mongodb/bin/mongo --port 27017
MongoDB shell version v4.0.10
connecting to: mongodb://127.0.0.1:27017/?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("ebb0be23-a29c-45d4-98c8-cc95d70f2b57") }
MongoDB server version: 4.0.10
mongos>
mongos> show dbs
mongos>
mongos> use admin
switched to db admin
mongos> db.createUser({user:"myroot",pwd:"123456",roles:["root"]})
Successfully added user: { "user" : "myroot", "roles" : [ "root" ] }
mongos>
【提示】如果在开启认证之前已经创建了管理员账号,这里可以忽略
创建一个普通权限帐号
[root@localhost sharded_cluster]# /usr/local/mongodb/bin/mongo --port 27017
MongoDB shell version v4.0.10
connecting to: mongodb://127.0.0.1:27017/?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("8d167461-35a2-41ea-b274-113d27922182") }
MongoDB server version: 4.0.10
mongos> show dbs
mongos>
mongos> use admin
switched to db admin
mongos> db.auth("myroot","123456")
1
mongos> show dbs
admin 0.000GB
articledb 0.001GB
config 0.002GB
mongos> use articledb
switched to db articledb
mongos> db.createUser({user: "ray", pwd: "123456", roles: [{ role: "readWrite",db: "articledb" }]})
Successfully added user: {
"user" : "ray",
"roles" : [
{
"role" : "readWrite",
"db" : "articledb"
}
]
}
mongos>
mongos> use articledb
switched to db articledb
mongos> db.auth("ray","123456")
1
mongos>
【提示】
通过 mongos 添加的账号信息,只会保存到配置节点的服务中,具体的数据节点不保存账号信息,因此,分片中的账号信息不涉及到同步问题
mongo 客户端登录 mongos 路由,用管理员帐号登录可查看分片情况
[root@localhost sharded_cluster]# /usr/local/mongodb/bin/mongo --port 27017
MongoDB shell version v4.0.10
connecting to: mongodb://127.0.0.1:27017/?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("f72e4ad8-55d7-4873-b825-6d2a138a6854") }
MongoDB server version: 4.0.10
mongos> use admin
switched to db admin
mongos> db.auth("myroot","123456")
1
mongos> sh.status()
..省略..
退出连接,重新连接服务,使用普通权限帐号访问数据
[root@localhost sharded_cluster]# /usr/local/mongodb/bin/mongo --port 27017
MongoDB shell version v4.0.10
connecting to: mongodb://127.0.0.1:27017/?gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("9fc70806-8a92-4822-bff0-8e27c68e660d") }
MongoDB server version: 4.0.10
mongos> use articledb
switched to db articledb
mongos> db.auth("ray","123456")
1
mongos> show collections
author
comment
mongos> db.comment.count()
1000
mongos>
3.4.6 SpringDataMongoDB连接认证
相关案例代码可参考《瑞_MongoDB_案例-文章评论》
article【瑞_MongoDB_案例-文章评论】
的完整源码的某度网盘链接如下,需要自取
链接:https://pan.baidu.com/s/1FMNAZNkXYm8kSbv18A6RDw?pwd=a7r4
提取码:a7r4
使用用户名和密码连接到 MongoDB 服务器,你必须使用'username:password@hostname/dbname'
格式,username
为用户名,password
为密码
【示例】使用用户 ray 使用密码 123456 连接到 MongoDB 服务上
application.yml
添加配置,可参考如下
spring:
#数据源配置
data:
mongodb:
# 主机地址
# host: 192.168.133.131
# 数据库
# database: articledb
# 默认端口是27017
# port: 27017
# 帐号
# username: ray
# 密码(如果密码是纯数字要加上'')
# password: '123456'
# 方式二:使用uri连接
# uri: mongodb://192.168.133.131:27017/articledb
# 副本集的连接字符串
# uri: mongodb://192.168.133.131:27017,192.168.133.131:27018,192.168.133.131:27019/articledb?connect=replicaSet&slaveOk=true&replicaSet=myrs
# 连接路由字符串
# uri: mongodb://192.168.133.131:27017,192.168.133.131:27117/articledb
# 单机有设置安全认证的情况下,使用字符串连接
# uri: mongodb://ray:123456@192.168.133.131:27017/articledb
# 副本集有认证的情况下,字符串连接
# uri: mongodb://ray:123456@192.168.133.131:27017,192.168.133.131:27018,192.168.133.131:27019/articledb?connect=replicaSet&slaveOk=true&replicaSet=myrs
# 分片集群有认证的情况下,连接路由字符串
uri: mongodb://ray:123456@192.168.133.131:27017,192.168.133.131:27117/articledb
在CommentServiceTest
测试类中选择一个测试用例,如查询所有数据的方法testFindAll()
进行测试,如下图测试通过即配置成功
常用命令
1️⃣ 使用客户端命令连接任意一个节点,以主节点为例(27017节点)
/usr/local/mongodb/bin/mongo --host=192.168.133.131 --port=27017
2️⃣ 启动节点服务,以主节点为例
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/replica_sets/myrs_27017/mongod.conf
3️⃣ 设置从节点读操作权限
rs.slaveOk()
#或
rs.slaveOk(true)
4️⃣ 启动分片副本集节点服务,以 myshardrs01_27018 为例
/usr/local/mongodb/bin/mongod -f /usr/local/mongodb/sharded_cluster/myshardrs01_27018/mongod.conf
如果觉得这篇文章对您有所帮助的话,请动动小手点波关注💗,你的点赞👍收藏⭐️转发🔗评论📝都是对博主最好的支持~