MongoDB 7.0 搭建 Sharding 副本集群
本文是在ubuntu 22.03 系统版本上部署的,最低支持mongodb-6.0.4以上,所以这里安装mongodb7.0
1 安装mongo
安装方式有多种,本人是使用的第一种方式,时间也就20分钟吧,能接受。
1.1 方法一:使用apt安装
- S1.导入 MongoDB GPG 公钥,用于验证下载的软件包的完整性,使用以下命令导入公钥
curl -fsSL https://pgp.mongodb.com/server-7.0.asc | sudo gpg -o /usr/share/keyrings/mongodb-server-7.0.gpg --dearmor
具体需要导入的版本号,可以去https://www.mongodb.org/static/pgp 查询
- S2. 创建一个 MongoDB 软件源列表文件,该文件告诉 apt 去哪里下载 MongoDB 软件包。在
/etc/apt/sources.list.d/
目录中创建一个新的文件并将以下行添加到文件中,根据你的需要更改版本号:
echo "deb [ arch=amd64 signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list
- S3. 更新 apt 软件包索引
sudo apt update
- S4. 现在已经配置了 MongoDB 软件源,可以通过
apt
命令安装 MongoDB 或更新到最新版本:
安装最新版本,此命令包含mongodb几乎所有的工具(本文档采用此种方式)
sudo apt install -y mongodb-org
也可以安装指定的版本号,且为各个工具指定统一版本号
sudo apt install mongodb-org=7.0 mongodb-org-server=7.0 mongodb-org-shell=7.0 mongodb-org-mongos=7.0 mongodb-org-tools=7.0
此种方式安装,一是在配置GPG公钥和apt源容易配置错,同时,安装的时候也非常的慢,我没有去找国内的源,后续的朋友可以尝试换个国内的源
成功安装后,最后会有以下各个工具的版本信息:
Preparing to unpack .../6-mongodb-org_7.0.5_amd64.deb ...
Unpacking mongodb-org (7.0.5) ...
Setting up mongodb-mongosh (2.1.1) ...
Setting up mongodb-org-shell (7.0.5) ...
Setting up mongodb-database-tools (100.9.4) ...
Setting up mongodb-org-database-tools-extra (7.0.5) ...
Setting up mongodb-org-database (7.0.5) ...
Setting up mongodb-org-tools (7.0.5) ...
Setting up mongodb-org (7.0.5) ...
Processing triggers for man-db (2.10.2-1) ...
needrestart is being skipped since dpkg has failed
[1]+ Done sudo nohup mongod -f /mongodb/mongod-1.conf (wd: /mongodb/node1)
(wd now: /etc/apt/sources.list.d)
各个工具的介绍如下:
- mongodb-mongosh: Mongosh是MongoDB官方提供的命令行工具,用于连接和操作MongoDB数据库。
- mongodb-org-shell: 这是MongoDB Shell的软件包,它是一个交互式的JavaScript环境,用于执行数据库操作和查询。
- mongodb-database-tools: 这是MongoDB数据库工具的软件包,包括备份、还原、导入和导出等功能。
- mongodb-org-database-tools-extra: 这是附加的MongoDB数据库工具软件包,提供了更多的数据库管理工具。
- mongodb-org-database: 这是MongoDB数据库服务器的软件包,用于启动和管理MongoDB服务器实例。
- mongodb-org-tools: 这是MongoDB工具集的软件包,包含了一些额外的辅助工具。
- S5.启动mongodb
sudo systemctl start mongod.service
连接mongo
mongosh
再使用 show dbs;
查看当前默认的数据库
- S6 设置为开机启动
sudo systemctl enable mongod.service
1.2 方法二:下载包,直接安装
可以从MongoDB 官网下载:https://www.mongodb.com/download-center/community/releases
- S1.选择7.0.5 下面的两个包并下载:
Archive
: mongodb-linux-x86_64-ubuntu2204-7.0.5.tgzServer Package
: mongodb-org-server_7.0.5_amd64.debMongos Package
: mongodb-org-mongos_7.0.5_amd64.deb
Archive
是免安装版本,下载后,解压,里面的bin下面有各种 sh 执行文件
Server Pagekage
是服务器的包
Mongos Package
是分片集群需要安装的包,用于实现分片集群(Sharded Cluster)中的路由功能,因此,如果你需要使用MongoDB分片集群,就需要安装mongos软件包并配置mongos实例。而如果你只是想使用MongoDB数据库,那么只需要安装MongoDB服务器软件包即可
- S2. 安装
进入到下载的文件目录,并执行安装命令
sudo dpkg -i mongodb-org-server_7.0.5_amd64.deb
sudo dpkg -i mongodb-org-mongos_7.0.5_amd64.deb
- S3 mongo-shell 的安装
由于mongodb 从6.0时代开始,不再提供 mongo-shell 的包,需要自己去下载对应的 mongodb-mongosh了。
这里是2.1.1 对应的下载地址:mongodb-mongosh_2.1.1_amd64.deb
其它更多的mongo-shell,参见 https://github.com/mongodb-js/mongosh/releases
下载后,安装如上一样的
MongoDB 7.0 更新了不少的内容,具体参见 https://www.mongodb.com/docs/v7.0/release-notes/7.0/#general-changes
2 部署集群
这里将采用3台服务器,搭建 MongoDB 的 Sharding 集群
服务器\mongo实例 | config | mongos | shard1(主shard) | shard2 | shard3 |
服务器1(192.168.0.4) | 主节点 27016 | 主节点 27017 | 主节点27018 | 仲裁节点27019 | 副节点27020 |
服务器2(192.168.0.5) | 副节点27016 | 副节点27017 | 副节点27018 | 主节点27019 | 仲裁节点27020 |
服务器3(192.168.0.6) | 副节点27016 | 副节点27017 | 仲裁节点27018 | 副节点27019 | 主节点27020 |
分片副本集是可以不用仲裁节点的,但是考虑到仲裁节点不需要考虑读写请求的负载,也不涉及数据同步,只是参与主节点选举并解决平票问题,所占用硬件资源(CPU、Memory)就小很多,这样就能减轻服务器压力,同时也让由三台服务器搭建的集群有不错的高可用性,挂掉任何一台服务器,都能正常运行
S1 在每台机器都创建以下目录
sudo mkdir -p /data/mongodb/config/db
sudo mkdir -p /data/mongodb/config/logs
sudo mkdir -p /data/mongodb/mongos/logs
sudo mkdir -p /data/mongodb/shard1/db
sudo mkdir -p /data/mongodb/shard1/logs
sudo mkdir -p /data/mongodb/shard2/db
sudo mkdir -p /data/mongodb/shard2/logs
sudo mkdir -p /data/mongodb/shard3/db
sudo mkdir -p /data/mongodb/shard3/logs
//最后更改到feizhu到权限
sudo chown -R feizhu:feizhu /data/
S2 再创建各个实例的配置文件
以服务器1 为例
- config 实例的配置文件
sudo vim /data/mongodb/config/mongodb.conf
# 数据库文件位置
dbpath=/data/mongodb/config/db
#日志文件位置
logpath=/data/mongodb/config/logs/mongod.log
# 以追加方式写入日志
logappend=true
# 是否以守护进程方式运行
fork=true
bind_ip=192.168.0.1
port=27016
# 表示是一个配置服务器
configsvr=true
#配置服务器副本集名称
replSet=configsvr
- mongos 实例的配置文件
sudo vim /data/mongodb/mongos/mongodb.conf
# mongos 不需要存储数据,所以不配置此项
#dbpath=/data/mongodb/mongos/db
#日志文件位置
logpath=/data/mongodb/mongos/logs/mongod.log
# 以追加方式写入日志
logappend=true
# 是否以守护进程方式运行
fork=true
bind_ip=0.0.0.0
port=27017
#配置服务器副本集名称
replSet=mongossvr
configdb=configsvr/192.168.0.1:27016,192.168.0.5:27016,192.168.0.6:27016
- Shard1 实例的配置文件
sudo vim /data/mongodb/shard1/mongodb.conf
# 数据库文件位置
dbpath=/data/mongodb/shard1/db
#日志文件位置
logpath=/data/mongodb/shard1/logs/mongod.log
# 以追加方式写入日志
logappend=true
# 是否以守护进程方式运行
fork=true
bind_ip=192.168.0.1
port=27018
#声明开启分片
shardsvr=true
#指定分片shar1的副本集名称
replSet=shard1
- Shard2 实例的配置
shard2 和shard3实例跟shard1基本是一样的,只需要把上面的shard路径和端口写对即可
sudo vim /data/mongodb/shard2/mongodb.conf
# 数据库文件位置
dbpath=/data/mongodb/shard2/db
#日志文件位置
logpath=/data/mongodb/shard2/logs/mongod.log
# 以追加方式写入日志
logappend=true
# 是否以守护进程方式运行
fork=true
bind_ip=192.168.0.1
port=27019
#声明开启分片
shardsvr=true
#指定分片shard2的副本集名称
replSet=shard2
- Shard3 实例的配置
sudo vim /data/mongodb/shard3/mongodb.conf
# 数据库文件位置
dbpath=/data/mongodb/shard3/db
#日志文件位置
logpath=/data/mongodb/shard3/logs/mongod.log
# 以追加方式写入日志
logappend=true
# 是否以守护进程方式运行
fork=true
bind_ip=192.168.0.1
port=27020
#声明开启分片
shardsvr=true
#指定分片shard3的副本集名称
replSet=shard3
最后将/data更改到 feizhu 权限
sudo chown -R feizhu:feizhu /data/
S3 启动 config server
把每台服务器的 config server 实例启动
mongod -f /data/mongodb/config/mongodb.conf
3台服务器的config server都启动后,从任意一台服务器登录到主节点的config server,我们对照上面的实例部署表,服务器1是config的主节点
mongosh --host 192.168.0.1 --port 27016
所以,登录主节点这个config实例,然后初始化
rs.initiate()
初始化后,在回车,我们就发现已经显示 configsvr [direct: primary]
的字样,说明成功了,然后将另外两个副节点加入即可
rs.add("192.168.0.5:27013")
rs.add("192.168.0.6:27013")
最后使用 rs.status()
查看一下结果,很明显3个实例的config副本集就搭建了,接下来就是启动 shard 实例了
S4 启动 shard 实例
启动 shard 实例,以启动 shard1 为例,进入各个服务器,分别启动各自的shard1实例
mongod -f /data/mongodb/shard1/mongodb.conf
然后使用任意服务器登录到shard1主节点,我们希望shard1是以服务器1为主节点,那么就登录到服务器1的shard1实例
mongosh --host 192.168.0.1 --port 27018
登录后,输入以下命令,初始化
rs.initiate()
此时,就是以当前节点为主节点,再加入副节点和仲裁节点
rs.add("192.168.0.5:27018")
rs.addArb("192.168.0.6:27018")
rs.status()
查看状态,发现已经成功了,以此方式,同等启动shard2 和shard3,这里就不过多描述
最后将上面的mongodb目录,复制一份到服务器2和服务器3,将里面的配置文件相应的 bind_id 改成本机的即可
S5 启动 mongos 实例
- 配置 mongos 的配置文件,
sudo vim /data/mongodb/mongos/mongodb.conf
# mongos 不需要存储数据,所以不配置此项
#dbpath=/data/mongodb/mongos/db
#日志文件位置
logpath=/data/mongodb/mongos/logs/mongod.log
# 以追加方式写入日志
logappend=true
# 是否以守护进程方式运行
fork=true
# 允许所有IP 访问
bind_ip=0.0.0.0
port=27017
#配置config server
configdb=configsvr/192.168.0.1:27016,192.168.0.5:27016,192.168.0.6:27016
-
启动 mongos 实例
mongos -f /data/mongodb/mongos/mongodb.config
注意是前面是 mongos 而不是 mongod
因为我们这里是 mongos 集群,所以需要分别在三台服务器上都启动
-
将 3 个shard 加入到分片集群
登录任意一个 mongos 添加各个分片集群
use admin sh.addShard("shard1/192.168.0.1:27018,192.168.0.5:27018,192.168.0.5:27018") sh.addShard("shard2/192.168.0.5:27019,192.168.0.5:27019,192.168.0.6:27019") sh.addShard("shard3/192.168.0.1:27020,192.168.0.5:27020,192.168.0.6:27020")
然而在加入集群的时候报以下错误:
[direct: mongos] admin> sh.addShard("shard3/192.168.0.1:27020,192.168.0.5:27020,192.168.0.6:27020") MongoServerError: Cannot add shard3/192.168.0.1:27020,192.168.0.5:27020,192.168.0.6:27020 as a shard since the implicit default write concern on this shard is set to {w : 1}, because number of arbiters in the shard's configuration caused the number of writable voting members not to be strictly more than the voting majority. Change the shard configuration or set the cluster-wide write concern using the setDefaultRWConcern command and try again.
在 mongos 实例中 我们使用命令
db.adminCommand({ "getDefaultRWConcern": 1 })
可以查看到当前mongos 默认设置的写入安全机制defaultWriteConcern,默认是majority
(多数确认),这是mongodb5.0后开始的默认设置 ,这意味着当进行写操作时,至少要有超过大多数的数据节点确认写操作成功,才会返回成功的响应,目前我们是3个节点,mongo系统定义的一半节点数是 (3+1)/2=2,需要超过2,也就是至少要有3个节点写入成功才行,但是我们设置了一个 仲裁节点,导致3个shard节点中,只有2个可写数据的节点,怎么也不会写成功了,所以导致失败解决方法,将写入安全级别调低,使用以下命令
db.adminCommand({ "setDefaultRWConcern" : 1, "defaultWriteConcern" : { "w" : 1 }})
-
"w" : 1 只要主节点写入成功,就直接返回成功的响应,而不管副节点的同步情况
-
"w" : majority 超过节点半数【(节点数+1)/2】写入成功,才返回成功响应
-
"w" : 0 不等待任何节点确认写操作,只需写入到内存就返回成功,这是最低级别的写安全级别,这个配置可以提供写入性能,但也有一定的风险
-
"w" :
等待指定数量的节点确认写成功
-
S6 创建 database
- 登录到 mongos 集群中,创建 jfj 数据库
use jfj
db.createCollection('test')
db.test.insert({"name":"tom","sex":"1"})
- 创完后,使用
sh.status()
查看,可以看到以下这样一段
{
database: {
_id: 'jfj',
primary: 'shard1',
partitioned: false,
version: {
uuid: UUID('21e70f6b-cd5a-485a-b8d6-baa9430c2d11'),
timestamp: Timestamp({ t: 1705977864, i: 2 }),
lastMod: 1
}
},
collections: {}
}
意思是 jfj 的数据库默认使用的主节点是 shard1,也就是一些不使用分片的集合,会落在 shard1 上,如果想更改database的主shard,可以使用以下命令更改
db.adminCommand( { movePrimary: <databaseName>, to: <newPrimaryShard> } )
// 例如以下命令,会将数据库 jfj 挪到shard2分片副本集上
db.adminCommand( { movePrimary : "jfj", to : "shard2" } )
- 开启分片,并为集合创建片键
use admin
sh.enableSharding("jfj") // mongodb7.0 不需要这一步也可以
#以"name"作为分片键对集合 jfj.test进行分片
sh.shardCollection("jfj.test", {"name" : "hashed"})
至此,shard集群+副本集的mongodb集群就搭建完成了,使用 mongosh --host ip --port
可以连接到mongos进行操作
后面是安全认证的,生产环境的需要配置了
登录到mongos实例,使用以下的这段shell脚本导入数据试试
var users = [];
for (var i = 1; i <= 1000; i++) {
users.push({"id": i, "name": "jiangfj" + i});
}
db.users.insertMany(users);
3 安全认证及用户权限
MongoDB 社区版本的安全认证只支持 keyfile(SCRAM) 和 x.509 CA 数字证书(公私钥),我们这里就采用 keyfile的方式,也就是密钥的意思,稍微简单一些
安全认证包括两方面:
-
集群内部认证 (Internal Authentication)
-
用于集群内的各个组件(mongos, config server, shard)之间相互访问认证
-
也就是所有的 mongos 进程和 mongod 进程之间相互访问认证
-
内部认证通过 keyfile 密钥文件实现,即所有的 monogs/mongod 公用同一个keyfile文件来相互认证
-
如果集群外随便来一个 mongod 进程,如果没有相同的 keyfile,想加入集群,是不可能的
-
-
外部用户访问集群 mongos 所需的用户认证 (User Access Controls)
- 用于外部客户端访问 mongos 时,所需的用户认证,我们配置用户名+密码的方式
S1 生成keyfile
首先在服务器上生成一个 keyfile 密钥文件,将其填充为随机的 512 字节数据,可以根据需要调整文件名和大小
openssl rand -base64 512 > ./keyfile
Keyfile 的内容
feizhuguOI1434VBHZcv8m+VafAe8041IkkaZt7Ag8vytW21qkRtYkZX7b4z4SBdp
ELYVMd7wf3HKdTH85ehehZa2fuALkld9sDF3HZSDZ5cKF4t2H9d0u8r8EQmEk8RU
pNopBCTMvwPMn9ve0coMvUrSiERNTYOLxSB7hSmUNleau9E6xAriyEIw7vYUEoSJ
SPahSYn6JqrQax4tX014lT957m3tSPMnvSjgsvbTX6YsD1t25TlWimDdrnpCEk+X
oRtDIg7HGJdxX4twY8dK0IQcyouw/twE9VugTMsbdk8DCvNI6qWoTVK37zHotGLF
k/QnXkF1KXdpmN9axj+Lo0ObJ86feizhuDlAo8XQIfRR5kENAzRdvPgRGliusnWxN
CuxD2qkR9UmtBze95Ztrb+zgioEhRe8O8Go1XXYzJhZz+yC6RoFELr2XZlallpFm
+5m9pK2RgHV38lQeQcVh72py+1ukwE5F46Em801PF8JIQ50mjnq4UL512824+DOv
TE+A/2SEdjLxUau9HuiSQ1R2zocyXIV1DCGcCqYq1qD/o1BH1STd8md+UCDMdAWY
E91kQUnf9ygiLxHCFAZUwYKlWzYfIX+UvMBp/sxyjwFldV33fCYXkRUKjE3ZlLvh
6bPrELnjy27YMSgoCGXaeP2+XaW5ZtzwJMGMBLfeizhu=
为了确保文件的安全性,设置只有 feizhu 用户可读写
chmod 600 keyfile
将上面的 keyfile 文件复制到每个实例的目录中,或者复制到每台服务器上去,一台服务器都走同一个keyfile文件即可
S2 添加超级管理员用户
连接任意一个 mongos 创建超级管理员 root
use admin;
db.createUser({user:"root",pwd:'password',roles:[{"role":"root","db":"admin"}]});
在
mongos
上添加的用户,用户信息实际保存在config server
上,mongos
本身不存储任何数据,包括用户信息
同时,
mongos
上创建的用户,也不会自动添加到各个shard
分片服务器上的,不管是主节点还是副节点都没有
所以,为了以后方便维护shard
各个分片集群,分别登录到每个分片服务器的primary
节点,添加 root 用户
use admin
db.createUser({user:"root",pwd:'password',roles:[{"role":"root","db":"admin"}]});
如果前期没有为各个shard副本集上创建root用户,但是后续又想用,就需要关闭config 实例和shard实例,在改配置文件,去掉安全认证的配置,在重启config和shard实例,在创建用户,完之后在改回来,特别麻烦,所以先创建好root,后续想干什么都行
S3 配置 mongodb.conf
配置各个 mongod 实例的 mongodb.conf 文件,在最后加上安全认证的配置
#auth
auth=true
keyFile=/data/mongodb/keyfile
配置各个 mongos 实例的 mongodb.conf 文件
keyFile=/data/mongodb/keyfile
mongos 不需要 auth=true
S4 重启实例
停止集群所有 mongod 和 mongos 的进程
最后,按照如下顺序启动所有程序
1 config 集群 > 2 shard 集群 > 3 mongos 集群
在启动shard的时候,至少需要config2个节点起来,也就是config集群可用才行
重启完之后,可以登录任一mongos实例
mongosh -u root -p password 192.168.0.1:27017/admin
S5 创建 jfj 数据库的用户权限
使用管理员账号登录到mongos,创建一个 jfj 的只读用户
use jfj
db.createUser({user:"feizhu",pwd:'password',roles:[{"role":"readWrite","db":"jfj"}]});
连接试试
mongosh -u feizhu -p password 192.168.0.1:27017/jfj
至此,整个shard集群就搭建好了~!~
4 其它
4.卸载MongoDB
1.停止MongoDB
sudo service mongod stop
//或者
sudo systemctl stop mongod.service
// 或者直接kill
集群的话就需要进去实例里面执行一下命令,或者直接kill
use admin
db.shutdownServer()
2.删除包
sudo apt-get purge mongodb-org*
3.删除数据目录
- 删除MongoDB数据库和日志文件