前言
相较于mysql,mongodb的集群方案要明朗的很多(现在无法直视mysql了),目前只有两种成熟的集群方式,都是由官方提供的:
高可用方案-复制集
高性能方案-分片集
下面我们就介绍下这两种集群方案并根据项目需求进行选型。
集群方案介绍
高可用方案-复制集
它与mysql的主从差不多,但是增加了故障迁移,自动选举的机制。
primary就是我们平常意义上的主节点,可以接受读和写请求;
secondary是从节点,默认情况下只提供数据备份的功能(也可以设置为可读用来接收读请求,做读写分离),一个集群可以拥有一个或多个secondary节点;
arbiter是仲裁节点,其内部没有数据,只是参与primary的选举。当你受制于其他原因,集群只有偶数个节点的时候,就可以引入一个arbiter节点,它很轻量级。
高性能方案-分片集
由于在复制集中,primary只能有一个也就是写请求还是处於单点的状态,虽然可以故障迁移,但整个集群仅仅是高可用状态,受制於单primary不能横向扩展。mongodb为了解决横向扩展的问题,提供了一套分片集群方式。
每个shard都包含了分片集群中的一部分数据,每一个shard都是以一个复制集的形式存在的。
mongos提供了客户端与mongodb集群之间交互的接口,客户端通过操作mongos来与mongodb分片集群交互。
config server里面包含了整个集群的元数据和配置信息,config server地位非常重要,所以需要使用复制集方式部署。
本系统落地方案分析
我对于mongodb的理解是它是一个对传统mysql的补充,它存储结构更加灵活,在海量数据的存储,处理方面比mysql更有优势。即使官方一直希望mongodb可以代替传统mysql,特别在4.0支持了跨集合的事务之后其功能与传统关系型数据库相差无几,但我还是对mongodb代替mysql持怀疑意见,因为没有听说mongodb在互联网行业的传统数据库领域有大规模成功案例。对于一个架构来说稳定性是非常重要的一环,对于强关联数据和强事务数据我还是选择使用mysql,引入mongodb主要是想用来存储物联网设备产生的监控数据和系统产生的日志数据,其他数据可以供开发时自由发挥。
由于mongodb官网提供了完善的高可用,可扩展集群方案,所以我们就不用像mysql那样,将数据库进行物理拆分。这边选择使用分片集群,我们将其打造成为一个大集群,供整个系统使用。
1.分片集群部署结构
这里使用11台机器部署一个生产环境sharding集群,网上清一色都是三台机器的部署方案,每台机器上都部署一个shard1实例,一个shard2实例,一个shard3实例,一个config server实例和一个mongos实例,这样做确实可以做到高可用,哪台机器挂了都可以保证集群正常运行,因为三台机器每一台都有一套完整的sharding运行环境。这样做的好处就行可以节省服务器,但我并不推荐这样部署,不管是生产还是测试,如果真的缺乏服务器可以使用副本集来代替分片集。原因是每一台机器都拥有集群全量的数据,并没有做到数据的分片存储,虽然可以部署多个mongos实例增加写节点个数,但在百分之80的场景下还不如三个节点的副本集来的实际。希望大家还是不要被其他帖子误导。
地址 | 描述 | 端口 |
---|---|---|
192.168.43.130 | mongos节点-1 | 27017 |
192.168.43.131 | mongos节点-2 | 27017 |
192.168.43.132 | config server节点-1 | 27017 |
192.168.43.133 | config server节点-2 | 27017 |
192.168.43.134 | config server节点-3 | 27017 |
192.168.43.135 | shard1节点-1 | 27017 |
192.168.43.136 | shard1节点-2 | 27017 |
192.168.43.137 | shard1节点-3 | 27017 |
192.168.43.138 | shard2节点-1 | 27017 |
192.168.43.139 | shard2节点-2 | 27017 |
192.168.43.140 | shard2节点-3 | 27017 |
2.部署前的准备
下载mongodb4.2的tar包(推荐官网下载,但官网有时打不开,可以使用百度云:),并上传到11台机器上,每台机器只需上传一份即可。在每台机器上都解压mongodb-linux-x86_64-rhel70-4.2.7.tgz,在解压出来的文件夹下面创建data目录,conf目录和log目录,用于存放数据文件,配置文件和日志文件。创建完成后本目录结构如下:
*:别忘记将每台机器上的27017端口都开放出来
3.生成keyfile
在192.168.43.130机器上使用如下命令生成keyfile文件
sudo openssl rand -base64 741 >> /root/software/mongodb/keyfile.key --生成keyfile文件,/root/software/mongodb/keyfile.key为生成keyfile文件的路径和文件名。
sudo chmod 600 /root/software/mongodb/keyfile.key --为生成的keyfile文件赋予600权限,如果不赋予600权限在集群启动的时候会提示keyfile文件权限过大。
然后将此文件拷贝到所有机器上,每台机器都需要使用这个文件。一定要复制到每台机器上,保证11台机器上的keyfile文件是一模一样的。keyfile文件在每台机器上的路径不要求相同,只要自己知道在哪就可以,但强烈建议放到mongodb的根目录下。
4.部署config server
mongodb在3.4之后要求config server必须以副本集的形式存在,所以先我们在三台机器上搭建一个config server副本集。
在192.168.43.132;192.168.43.133;192.168.43.134三台机器上都做如下操作:
进入mongodb安装目录的conf文件夹,创建config.conf文件,文件内容如下:
systemLog:
destination: file
#日志文件的存储路径,这里要指定要一个具体的文件,mongodb在启动时会自动创建这个文件
path: /root/mongodb-cluster/log/config-server.log
logAppend: true
storage:
journal:
enabled: true
#数据文件的存储路径,这里指定一个文件夹即可
dbPath: /root/mongodb-cluster/data/
# 是否一个库一个文件夹
directoryPerDB: true
net:
#这里可以配置ip白名单,可以按需配置,当前配置代表允许所有ip访问(ipv4或ipv6)
bindIpAll: true
#mongodb监听端口
port: 27017
replication:
oplogSizeMB: 2048
# 配置节点所属的复制集名字,后面创建复制集的时候会靠这个名字找到复制集的成员
replSetName: configRepSet
sharding:
# 代表当前节点在sharding集群中是config server的角色
clusterRole: configsvr
processManagement:
# mongodb启动之后是在后台运行,不占用控制台
fork: true
security:
#开启身份认证,后面会讲解
authorization: enabled
#密钥文件,用于集群内部认证。这里指定第三部生成keyfile文件的路径
keyFile: /root/mongodb-cluster/keyFile.key
执行命令
mongod --config /root/mongodb-cluster/config.conf
上面是启动mongodb的命令,--config后面的参数是配置文件的路径,让mongodb按照配置文件配置的内容启动。
三台机器都做完上面的操作之后,随便找一台机器使用
mongo --host:localhost:27017
连接上刚刚启动的mongodb,连接成功后出现如下界面
在当前界面输入:
rs.initiate({
_id: "configRepSet",
members: [
{ _id : 0, host : "192.168.43.132:27017" },
{ _id : 1, host : "192.168.43.133:27017" },
{ _id : 2, host : "192.168.43.134:27017" }
]
}
);
这段代码告诉mongodb,开始初始化副本集。_id属性的值为副本集名称,也就是在config.conf配置文件中replSetName属性的值。member中_id的值为序号,这里不需要改动,从0排下来即可。member中host的值为三个config server实例的ip和端口号。
执行完后出现如下字样代表副本集构建成功,可以使用rs.status()查看config server副本集的状态。
5.部署shard分片1
官方推荐,每一个分片都需要以副本集的形式部署,以提高其可用性。所以其操作与4中部署config server副本集是一样的,这里简单略过。只贴出分片1的配置文件shard-1.conf
systemLog:
destination: file
path: "/root/mongodb-cluster/log/shard-1.log" #注意修改路径
logAppend: true
storage:
journal:
enabled: true
dbPath: "/root/mongodb-cluster/data" #注意修改路径
processManagement:
fork: true
net:
bindIpAll: true
port: 27017 #注意修改端口
setParameter:
enableLocalhostAuthBypass: true
replication:
# 配置节点所属的复制集名字,后面创建复制集的时候会靠这个名字找到复制集的成员
replSetName: shardRepSet1
sharding:
# 代表当前节点在sharding集群中是分片的角色
clusterRole: shardsvr
security:
#开启权限认证,后面会讲
authorization: enabled
keyFile: /root/mongodb-cluster/keyFile.key #密钥文件,用于集群内部认证
6.部署shard分片2
步骤同5相同,只不过再创建一个分片副本集而已
6.部署mongos
mongos可以根据集群所要承载的流量情况部署一个或多个,我们这里先部署两个,后期可以根据压测情况调整。
在192.168.43.130;192.168.43.131下分别执行如下步骤:
进入mongodb安装目录的conf文件夹,创建mongos.conf文件,文件内容如下:
systemLog:
destination: file
path: /root/mongodb-cluster/log/mongos.log
logAppend: true
processManagement:
fork: true
net:
bindIpAll: true
port: 27017
setParameter:
enableLocalhostAuthBypass: true
sharding:
# config server副本集的地址,mongos需要从config server取集群的元数据,所以需要指定地址
configDB: configRepSet/192.168.43.132:27017,192.168.43.133:27017,192.168.43.134:27017
security:
authorization: enabled
keyFile: /root/mongodb-cluster/keyFile.key #密钥文件,用于集群内部认证
执行命令
mongod --config /root/mongodb-cluster/mongos.conf
上面是启动mongodb的命令,--config后面的参数是配置文件的路径,让mongodb按照配置文件配置的内容启动。
启动成功后mongos就部署成功了(mongos不需要副本集,其本身是一个无状态的可横向扩展的轻量级组件)。
7.配置集群的权限
还记得上面配置文件中的这段配置吗?
security:
authorization: enabled
keyFile: /root/mongodb-cluster/keyFile.key #密钥文件,用于集群内部认证
它是用来给我们的mongodb添加权限认证的。mongodb的权限认证分为内部认证和外部认证,内部认证是指集群间各个组件通信的权限认证,外部认证是指外部的客户端访问集群组件时的认证。
内部认证:
内部认证有两种方式,可以任选其一:keyfile和x.509。本系统就是使用的keyfile,网上有朋友说正式环境官方推荐x.509,不过我觉得都差不多,我大体看了下官网没找到相关说法,可能是我没找仔细,也可能在最新版4.2的文档中已经没有这句话了,总之使用keyfile也不会有问题。内部认证只要我们在配置文件内配置好了之后就无需认为干预了,mongodb会自动做权限认证,对用户是透明的。
外部认证:
外部认证就是我们平时说的登陆的账号密码,如果开启了权限认证也就是authorization:为enabled时,外部的客户端想要连接到mongodb就需要使用用户名和密码。我们这里着重说sharding-cluster的外部权限认证。
*:mongodb的用户是在数据库下面的,每个数据库会有不同的用户,而不是像mysql那样用户下面有一个个的数据库,用户还可以被授予不同的角色。对于角色的介绍,推荐一篇博文,写的非常详细https://www.cnblogs.com/dbabd/p/10811523.html
下面我们来配置集群的权限认证。内部认证我们已经在配置的时候配置过了,所以我们直接来配置外部认证。我们选择为每一台mongodb实例配置一个root用户用来管理,在mongos上根据需要额外配置普通用户,让程序员增删改查使用。
为shard1设置用户:
由于之前我们已经启动了shard1复制集,所以我们需要找到复制集的主节点,在主节点上设置用户(从节点不接受写请求)。这里我的主节点是192.168.43.135这台,在这台机器上使用
mongo --host localhost:27017 --连接config server
use admin ---切换数据库
db.createUser( ---创建用户
{
user: "admin",
pwd: "123456",
roles: [ { role: "root", db: "admin" } ]
}
)
我们创建的用户为admin,角色为root,是超级数据库管理员(用户是在数据库下面的,root角色的用户只能到admin库下面创建)。
由于副本集是可以自动同步的,我们在主节点上创建用户后,主节点会把改动同步到从库节点,所以,从节点也会自动拥有admin用户。
为shard2设置用户:
与上面步骤相同,也开一个名叫admin的root用户
为mongos设置用户:
mongos的用户比较特殊,其本身不存储数据,也就没有用户数据。它鉴别用户权限是要去config server中获取用户信息的(真实情况是mongos内部会有用户信息的缓存,只要config server中用户信息变动就会刷新mongos的缓存)。所以我们为mongos设置用户其实就是为config server设置用户。设置用户的步骤为:
mongos --port 27017 --连接mongos,连接mongos要用mongos命令,而不是mongo
use admin ---切换数据库
db.createUser( ---创建用户
{
user: "admin",
pwd: "123456",
roles: [ { role: "root", db: "admin" } ]
}
)
当前节点配置完后,config server集群的用户也配置完了,当用户信息更改时,又会通知所有的mongos刷新缓存,所以这一下子mongos和config server的用户都配置完毕了。
但是在生产环境中我不推荐暴露root用户,我们可以再创建一个拥有readWrite角色的用户,让程序员们使用这个用户连接sharding集群。
8.开启分片集
刚才我们仅仅是搭建了一个config server副本集,一个shard1副本集,一个shard1副本集,两个mongos节点,但还有将集群合并起来。下面我们就开始合并的操作。
连接任意的mongos执行如下命令:
转到admin库,需要使用admin库中的用户信息登陆
use admin
算是登陆吧
db.auth("admin","123456")
添加分片1到集群中
sh.addShard( "shardRepSet1/192.168.43.135:27017,192.168.43.136:27017,192.168.43.137:27017")
sh.addShard( "shardRepSet1/192.168.43.138:27017,192.168.43.139:27017,192.168.43.140:27017")
*:sharding集群并不是所有的数据都会分片存储,只有指定数据库为分片数据库,并且指定分片数据库的某个集合为分片集合之后,存入这个集合的数据才会分片存储。如果不做任何配置的数据库和集合是不会分片的,其数据会全部存储在主分片中,可以直接当成是存储在副本集中,不用考虑分片的相关问题。
指定springboot数据库为分片数据库:
sh.enableSharding("springboot")
指定springboot库的user集合为分片集合并且指定分片键为id,使用hash分片:
sh.shardCollection("springboot.user", { _id : "hashed" } )
设置完成后当前user集合就是一个分片集合了,存入user集合的数据会自动分片存储。
至此,sharding集群构建完毕。如有疏漏出错的地方还望指出,我会及时修改。