随着内部产品业务的搭建,单机的mongo已经无法满足生产需求,对于单机迁移、损坏等问题,简单的单机数据备份已经无法满足,因为采用了集群方式来满足容灾以及数据快速恢复等功能,下面我就来讲讲如何搭建集群来避免这些问题。
准备工作
机器信息: 3 台机器
mongo1 mongo2 mongo3
环境: CentOS 6.5
采用策略
Mongo有三种集群方式 1.Replica Set副本 2.Sharding分片 3.Master-slave主备
比较常用的为1,2两种方式, 在日后的篇章中将详细介绍两者的区别。
当前我们采用的是 Replica Set 搭建方式。这是官方教程,我们会跟着官方教程,以及对官方未说明的一些信息进行补充。https://docs.mongodb.com/manual/tutorial/deploy-replica-set/#overview
简述
副本集是一组维护相同数据集的 mongo 实例。副本集包含多个数据节点和一个仲裁节点。在数据承载节点中,只能含有一个主节点,其他节点被视为复制节点。
复制节点复制主节点的 oplog 并将操作应用于其数据集,使得复制节点成为主节点的一个镜像。如果主节点停止时候,在复制节点中将会选出新的主节点。
自动故障转移,当主节点与集合中的其他成员通信的时间超过配置的electionTimeoutMillis期间(默认为10秒)时,符合条件的复制节点将会被选举成新主节点。群集尝试完成新主节点的选举并恢复正常操作。
写操作,默认情况下,客户端从主节点读取, 但是,客户端可以设置从复制节点读取。
特性
优势
1.提供容错功能,在主节点故障时,复制节点代替主节点
2.数据的快速恢复
3.增加节点可提高读能力
4.快速横向扩展
劣势
1.所有写操作都从主节点进行,增加节点无法提高写能力
2.每个节点都是完整备份,数据冗余
基础搭建
分别在 3 台机器安装 mongo
用户权限
mongo1
代码语言:javascript复制cd ~
wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.4.6.tgz
tar zxvf mongodb-linux-x86_64-3.4.6.tgz
mv mongodb-linux-x86_64-3.4.6 mongodb
cd mongodb
mkdir data
mkdir data/db
mkdir data/logs
touch data/mongodb.log
cd data
在这里我们采用配置文件的方式启动,先不配置验证,等设置完用户组后,再进行, 为了安全考虑,我们将修改默认端口,分别使用 8410,8411,8412。 [your replSet name]
改成你自己 replSet 的名字, 例如 rs0
(自己取)
vim mongodb.conf
代码语言:javascript复制#端口号
port = 8410
#集群名字
replSet = [your replSet name]
#数据目录(自己刚才设置的位置)
dbpath = ~/mongodb/data/db
#日志目录(自己刚才设置的位置))
logpath = ~/mongodb/data/logs/mongodb.log
#设置后台运行
fork = true
#日志输出方式
logappend = true
#开启认证
#auth = true
#安全文件地址
#keyFile = ~/mongodb/data/keyFile
启动mongo
代码语言:javascript复制cd ..
./bin/mongod --config ~/mongodb/data/mongodb.conf
mongo2,mongo3 同 mongo1。只需要修改端口, 其他都与 mongo1 一样的步骤。
mongo2
mongodb.conf
代码语言:javascript复制...
port = 8411
...
mongo3
mongodb.conf
代码语言:javascript复制...
port = 8412
...
在三台机器都启动好后,我们来到 mongo1 机器。
连接 mongodb
代码语言:javascript复制./bin/mongo 127.0.0.1:8410
配置集群(mongo1为你的机器地址)
代码语言:javascript复制cfg = {"_id" : "[your replSet name]", "members" : [{"_id" : 0,"host" : "mongo1:8410"}]}
rs.initiate(cfg);
效果如图:
1567682388618.jpg
运行 rs.status()
查看状态。
health: 1 代表正常 0 代表异常, stateStr 为描述主节点或者复制节点。
1567682478469.jpg
现在我们已经添加了一个主节点了,接下来继续添加剩余的两个节点。
1567682673974.jpg
运行 rs.status()
查看状态。
1567682754525.jpg
到现在我们已经完成了我们的集群搭建。
接下来我们就要来验证下我们的数据同步问题。
继续保持在主节点连接状态。
创建一条测试数据。
1567683075113.jpg
退出我们的主节点连接,连接复制节点。
代码语言:javascript复制 ./bin/mongo mongo2:8411
1567683192236.jpg
发现我们并不能直接查看
原因是: mongodb默认是从主节点读写数据的。
我们对复制节点进行进行设置。
代码语言:javascript复制db.getMongo().setSlaveOk();
db.test.find();
// { "_id" : ObjectId("5d70f1f19384bf8d850e2042"), "test" : "123" }
数据已经从主节点同步过来了。
模拟宕机 mongo 故障
我们将主节点停止。(也可以直接kill,但是推荐安全退出)
代码语言:javascript复制./bin/mongo 127.0.0.1:8410
use admin
db.shutdownServer()
登录我们的复制mongo2来进行查看,确认是否成功迁移了 mongo 。
来到mongo2
代码语言:javascript复制./bin/mongo 127.0.0.1:8411
rs.status();
1567683538699.jpg
可以看到通过选举,mongo2 成功成为主节点。
重启 mongo1 , 连接实例
代码语言:javascript复制cd ~
./bin/mongod --config /opt/meituan/mongodb/data/mongodb.conf
./bin/mongo 127.0.0.1:8410
rs.status();
1567683684469.jpg
原来的 mongo1 成功地成为了 mongo 2 的复制节点。
mongoose 连接测试
代码语言:javascript复制const mongoose = require("mongoose");
const uri =
"mongodb://mongo1:8410,mongo2:8411,mongo3:8412/test?authSource=admin";
const opts = {
poolSize: 5,
auto_reconnect: true,
useNewUrlParser: true,
keepAlive: 300000,
replicaSet: "banmars",
readPreference: "secondaryPreferred"
};
global.db = mongoose.createConnection(uri, opts);
mongoose.connection = global.db;
db.on("error", function(err) {
console.error(err);
});
db.on("open", function() {
console.log("dbopen");
});
到此我们的 mongo 集群已经搭建并且测试完成,然后就拿着集群兴高采烈地去进行使用,但是发现,因为集群到现在没有设置任何安全认证,任意用户可以进行登录修改数据。这可是个大隐患,你的库随时都有被删除的风险。。。这可不好交代,所以我们接下来讲解如何搭建一个安全的 mongodb 环境。
安全验证
首先来到主节点(mongo2,刚才测试的时候 mongo2 成为主节点了)
创建管理员用户 (权限说明(https://blog.csdn.net/WI_232995/article/details/78881408))
管理员用户,用来添加用户以及授权
代码语言:javascript复制use admin
db.createUser( {
user: "root",
pwd: "root",
roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
});
集群管理用户,用来查看集群状态
代码语言:javascript复制db.createUser(
{
"user" : "cluster",
"pwd" : "cluster",
roles: [ { "role" : "clusterAdmin", "db" : "admin" } ]
}
)
https://docs.mongodb.com/manual/tutorial/deploy-replica-set-with-keyfile-access-control/#deploy-repl-set-with-auth 查看官网我们可以看到 mongo 采用的是 keyFile 的方式
由于一开始我没有采用这个方式,直接采用 auth=true 的方式,导致一直报以下的错误。
代码语言:javascript复制Error in heartbeat request to X.X.X.X:8410; Unauthorized: not authorized on admin to execute command
生成 keyFile
代码语言:javascript复制cd ~
cd mongodb
openssl rand -base64 756 > data/keyFile
chmod 400 data/keyFile
vim data/mongodb.conf
代码语言:javascript复制#端口号
port = 8410
#集群名字
replSet = [your replSet name]
#数据目录(自己刚才设置的位置)
dbpath = ~/mongodb/data/db
#日志目录(自己刚才设置的位置))
logpath = ~/mongodb/data/logs/mongodb.log
#设置后台运行
fork = true
#日志输出方式
logappend = true
#开启认证
auth = true
#安全文件地址
keyFile = ~/mongodb/data/keyFile
将 auth 开启, 指定 keyFile 路径。
将 mongo1 停止,再重启。
代码语言:javascript复制./bin/mongo 127.0.0.1:8410
use admin
db.shutdownServer()
./bin/mongod --config ~/mongodb/data/mongodb.conf
将 mongo1中的 keyFile 文件拷贝到 mongo2 以及 mongo3.
这里我采用的是 rsync 方式。
所以我们还得配置 ssh。(你也可以采用其他方式,我这里为了后续同步方便采用了 ssh )
mongo1
代码语言:javascript复制cd ~/.ssh
ssh-keygen
一路回车...
cat id_rsa.pub
复制内容
mongo2
代码语言:javascript复制cd ~/.ssh/
vim authorized_keys
将刚才复制的添加最后。
mongo3 同 mongo2
mongo1
代码语言:javascript复制cd ~/mongodb
rsync -Cavzt ./data/keyFile mongodb02:~/mongodb/data/
rsync -Cavzt ./data/keyFile mongodb03:~/mongodb/data/
分别到mongo2,mongo3,
编辑配置文件
代码语言:javascript复制...
#开启认证
auth = true
#安全文件地址
keyFile = ~/mongodb/data/keyFile
...
重启 mongo2,mongo3 上的 mongo实例
来到 mongo1
代码语言:javascript复制./bin/mongo 127.0.0.1:8410
1567686047066.jpg
我们看到通过不验证的方式登录已经无法查看信息了。
下面我们用认证方式来进行登录。
代码语言:javascript复制./bin/mongo 127.0.0.1:8410 -u "root" -p "root" --authenticationDatabase "admin"
1567686155667.jpg
通过认证方式登录已经正常使用了。
退出登录,使用集群管理员登录。
代码语言:javascript复制./bin/mongo 127.0.0.1:8410 -u "cluster" -p "cluster" --authenticationDatabase "admin"
代码语言:javascript复制rs.status();
1567686701852.jpg
三台机器已经都正常运行了。
还记得我们一开始创建的 test 集合吗。
我们给它创建一个用户来进行管理。
代码语言:javascript复制db.createUser(
{
"user" : "test",
"pwd" : "test",
roles: [ { "role" : "read", "db" : "test" }, { "role" : "readWrite", "db" : "test" } ]
}
)
mongoose 测试
代码语言:javascript复制const mongoose = require("mongoose");
const uri =
"mongodb://test:test@10.48.172.11:8410,10.48.181.145:8411,10.48.144.74:8412/test?authSource=admin";
const opts = {
poolSize: 5,
auto_reconnect: true,
useNewUrlParser: true,
keepAlive: 300000,
replicaSet: "banmars",
readPreference: "secondaryPreferred"
};
global.db = mongoose.createConnection(uri, opts);
mongoose.connection = global.db;
db.on("error", function(err) {
console.error(err);
});
db.on("open", function() {
console.log("dbopen");
const Schema = mongoose.Schema;
const TestSchema = new Schema({
name: {type: String, default: ""},
});
var Test = mongoose.model("test", TestSchema);
const testModal = new Test({ name: "123" });
testModal.save(function (err, test) {
if (err) return console.error(err);
console.log('success');
});
});
最终效果
1568188107165.jpg
到此,真正地结束了本教程,我们可以愉快地拿着集群去交代了。。。
下期预告
MongoDB系列二: Sharded Cluster 集群搭建实战
参考
https://blog.csdn.net/WI_232995/article/details/78881408
https://docs.mongodb.com/manual/tutorial/deploy-replica-set/#deploy-a-replica-set
更多请关注
友情链接:https://blog.qiufengh.com/blog/
长按二维码,可以关注我哟
万水千山总是情,点个小赞行不行