Mongodb4.0集群搭建:分片+副本集

前言:项目近期面临技术转型,本人负责搭建mongodb分片+副本集高可用集群,经过几天的踩坑填坑,摸爬滚打终于成功搭建,俗话说好记性不如烂笔头,所以有必要记录下搭建过程,欢迎大家参考转载,本文只记录了搭建过程,其工作原理还需自行学习。


一 概念介绍

MongoDB分片简述:
高数据量和吞吐量的数据库应用会对单机的性能造成较大压力,大的查询量会将单机的 CPU 耗尽,大的数据量对单机的存储压力较大,最终会耗尽系统的内存而将压力转移到磁盘 IO 上。
MongoDB 分片是使用多个服务器存储数据的方法,以支持巨大的数据存储和对数据进行操作。分片技术可以满足 MongoDB 数据量大量增长的需求,当一台 MongoDB 服务器不足以存储海量数据或不足以提供可接受的读写吞吐量时,我们就可以通过在多台服务器上分割数据,使得数据库系统能存储和处理更多的数据。

MongoDB分片优势:
分片为应对高吞吐量与大数据量提供了方法:
使用分片减少了每个分片需要处理的请求数,因此,通过水平扩展,群集可以提高自己的存储容量。比如,当插入一条数据时,应用只需要访问存储这条数据的分片。
使用分片减少了每个分片村存储的数据。
分片的优势在于提供类似线性增长的架构,提高数据可用性,提高大型数据库查询服务器的性能。当MongoDB单点数据库服务器存储成为瓶颈、单点数据库服务器的性能成为瓶颈或需要部署大型应用以充分利用内存时,可以使用分片技术。

MongoDB副本集简述:
副本集(Replica Set)是一组MongoDB实例组成的集群,由一个主(Primary)服务器和多个备份(Secondary)服务器构成。通过Replication,将数据的更新由Primary推送到其他实例上,在一定的延迟之后,每个MongoDB实例维护相同的数据集副本。通过维护冗余的数据库副本,能够实现数据的异地备份,读写分离和自动故障转移。

MongoDB副本集好处:
一切自动化。首先,复制集模式本身做了大量的管理工作,自动管理从节点,确保数据不会不一致。 主节点挂掉后,会自动判断集群中的服务器并进行故障转移,推举新的主节点。 一个复制集集群支持1-7台服务器,在一个复制集中各个服务器数据保持完全一致。

MongoDB分片+副本集群集的组成:
Shard:分片服务器,用于存储实际的数据块,实际生产环境中一个shard server 角色可以由几台服务器组成一个Peplica Set 承担,防止主机单点故障。
Config Server:配置服务器,存储了整个分片群集的配置信息,其中包括chunk信息。
Routers:前端路由,客户端由此接入,且让整个群集看上去像单一数据库,前端应用可以透明使用。
Replica Set:副本集,创建一个Replica Set包含三个成员,Primary 主节点,一个复制集有且仅有一台服务器处于Primary状态,只有主节点才对外提供读写服务;Secondary 备用节点,复制集允许有多台Secondary,每个备用节点的数据与主节点的数据是完全同步的。Recovering 恢复中,当复制集中某台服务器挂掉或者掉线后数据无法同步,重新恢复服务后从其他成员复制数据,这时就处于恢复过程,数据同步后,该节点又回到备用状态;Arbiter 仲裁节点,该类节点可以不用单独存在,如果配置为仲裁节点,就主要负责在复本集中监控其他节点状态,投票选出主节点。该节点将不会用于存放数据。

系统环境
系统:CentOS 7.4 x86_64
软件版本:4.0

架构简介
集群含有两个shard;shard由replica set组成,replica set含有3个实例;mongodb config含有3个实例。如图所示:
Mongodb4.0高可用集群搭建:分片+副本集

说明:演示环境只搭建了一台mongos路由服务器,建议生产环境搭建mongos路由服务器集群。

配置说明

IP地址 路由服务器(Routers) 配置服务器(Config Server) 分片服务器(Shard1) 分片服务器(Shard2)
30.23.8.180 Port:27017 备份节点 Port:27001 主节点 Port:27002 仲裁节点
30.23.8.182 Port:27017 备份节点 Port:27001 副本节点 Port:27002 主节点
30.23.8.189 Port:27018 Port:27017 主节点 Port:27001 仲裁节点 Port:27002 副本节点

二 安装过程
安装mongodb环境(三台物理服务器安装及配置相同)
1、下载解压MongoDB

wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-4.0.0.tgz
tar zxvf mongodb-linux-x86_64-4.0.0.tgz -C /opt
mv /opt/mongodb-linux-x86_64-4.0.0/ /usr/local/mongodb

2、创建路由、配置、分片服务器的数据存放目录及日志管理
提示:路由服务器不存储数据,因此不需要创建数据存储目录,日志文件创建完成还需给予权限。

mkdir -p /data/mongodb/config
mkdir -p /data/mongodb/shard{1,2}
mkdir -p /data/mongodb/logs
touch /data/mongodb/logs/shard{1,2}.log
touch /data/mongodb/logs/mongos.log
touch /data/mongodb/logs/config.log
chmod 777 /data/mongodb/logs/*.log

3、创建管理用户,修改目录权限

useradd -M -s /sbin/nologin mongo
chown -R mongo:mongo /usr/local/mongodb
chown -R mongo:mongo /data/mongodb

4、添加环境变量,便于使用

echo 'export MONGODB_HOME=/usr/local/mongodb' >> /etc/profile
echo 'export PATH=$PATH:$MONGODB_HOME/bin' >> /etc/profile
source /etc/profile

5、系统参数优化

ulimit -n 25000  //可以打开的最大文件数量
ulimit -u 25000  //用户最大可用的进程数
sysctl -w vm.zone_reclaim_mode=0 //内存不足时,从其他节点分配内存
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag 

//注意这些优化都是临时的,重启失效

开启所有需要使用的端口,
如:firewall-cmd --zone=public --add-port=27018/tcp --permanent
重启防火墙:service firewalld restart
查看端口是否被占用 : lsof -i:27002

部署配置服务器(三台物理服务器配置步骤相同)
1、写入配置文件,我们可以用scp命令把配置文件发到其他两台物理服务器

vim config.conf
dbpath=/data/mongodb/config //数据文件存放位置
logpath=/data/logs/config.log  //日志文件
port=27017  //端口号
bind_ip=30.23.8.189
logappend=true
fork=true
maxConns=5000 
replSet=configs //复制集名称
configsvr=true  //设置参数为true
// 将配置文件 scp 到另外两台机器上,并改对应的bind_ip
scp /usr/local/mongodb/bin/config.conf root@30.23.8.180:/usr/local/mongodb/bin
scp /usr/local/mongodb/bin/config.conf root@30.23.8.182:/usr/local/mongodb/bin

//在每台机器上启动config实例
mongod -f config.conf

2、配置config服务器的复制集(任意一台物理机上操作即可)

mongo --host 30.23.8.189 --port 27017
config={_id:"configs",members:[{_id:0,host:"30.23.8.189:27017"},{_id:1,host:"30.23.8.180:27017"},{_id:2,host:"30.23.8.182:27017"}]}  //创建复制集
rs.initiate(config)        //初始化复制集
或者
rs.initiate()  //设置本机30.23.8.189为主节点
rs.add('30.23.8.180:27017')   //添加备份机
rs.add('30.23.8.182:27017')   //添加备份机
rs.status() //查看状态

部署分片服务器(三台物理服务器配置步骤相同)
1.编辑三台机器的shard1.conf,shard2.conf配置文件,端口分别为27001和27002,设置shardsvr=true

vim shard1.conf
dbpath=/data/mongodb/shard1
logpath=/data/logs/shard1.log
port=27001
logappend=true
fork=true
maxConns=5000 
bind_ip=30.23.8.180
shardsvr=true
replSet=shard1
mongod -f shard1.conf //启动分片服务器
vim shard2.conf
dbpath=/data/mongodb/shard2
logpath=/data/logs/shard2.log
port=27002
logappend=true
fork=true
maxConns=5000 
bind_ip=30.23.8.180
shardsvr=true
replSet=shard2
mongod -f shard2.conf //启动分片服务器

#另外两台配置实例配置文件相同,仅bind_ip要改,只需配置完成后启动即可

  1. 配置shard1、shard2服务器的复制集(这里需要注意的是,预先被设为仲裁节点的服务器上创建复制集会报错。)
    shard1复制集配置:
    mongo --host 30.23.8.180 --port 27001
    rs.initiate()  //设置本机30.23.8.180为主节点
    rs.add('30.23.8.182:27001')   //添加备份机
    rs.addArb('30.23.8.189:27001')   //添加仲裁节点
    rs.status() //查看状态

    shard2复制集配置:

    mongo --host 30.23.8.182 --port 27002
    rs.initiate()  //设置本机30.23.8.182为主节点
    rs.add('30.23.8.189:27002')   //添加备份机
    rs.addArb('30.23.8.180:27002')  //添加仲裁节点
    rs.status() //查看状态

    部署路由服务器
    1.创建配置文件,注意,路由服务器不需要存储数据目录

    vim mongos.conf
    logpath=/data/mongodb/logs/mongos.log
    logappend = true
    port = 27018
    bind_ip=30.23.8.189
    fork = true
    configdb = configs/30.23.8.189:27017,30.23.8.182:27017,30.23.8.180:27017
    maxConns=20000
    #启动mongos实例
    mongs -f mongos.conf

    #注意,这边启动mongos实例用的是mongos命令
    启动分片功能

    mongo --host 30.23.8.189 --port 27018  
    mongos> use gateway
    mongos> sh.addShard("shard1/30.23.8.180:27001,30.23.8.182:27001,30.23.8.189:27001")
    mongos> sh.addShard("shard2/30.23.8.182:27002,30.23.8.189:27002,30.23.8.180:27002")
    mongos> sh.status()    //查看群集状态
    #此处为添加两台分片服务器,后续添加的也会均匀分配分片数据

    实现分片功能
    设置分片chunk大小

    mongos> use config
    mongos> db.settings.save({"_id":"chunksize","value":1})
    #设置块大小为1M是方便实验,不然需要插入海量数据

    模拟写入数据

    mongos> use school
    mongos> show collections
    mongos> for(i=1;i<=50000;i++){db.user.insert({"id":i,"name":"jack"+i})}
    #在school库的user表中循环写入五万条数据

    启动数据库分片

    mongos>sh.enableSharding("school")
    #我们可以自定义需要分片的库或表

    为school库中的user集合创建索引,然后对表进行分片

    mongos> db.user.createIndex({"id":1})
    #以"id"作为索引
    mongos> sh.shardCollection("school.user",{"id":1})
    #根据"id"对user表进行分片
    mongos> sh.status()
    #查看分片情况
    mongos> sh.help()
    #查看分片相关的命令

安全认证设置
默认的mongodb是不设置认证的。只要ip和端口正确就能连接,这样是不安全的。mongodb官网上也说,为了能保障mongodb的安全有以下几种方式:
1、使用新的端口,默认的27017端口如果一旦知道了ip就能连接上,不×××全,不推荐。
2、设置mongodb的网络环境,最好将mongodb部署到公司服务器内网,这样外网是访问不到的。公司内部访问使用***等。
3、开启安全认证。认证要同时设置服务器之间的内部认证方式,同时要设置客户端连接到集群的账号密码认证方式,推荐。

开启安全认证,对副本集执行访问控制需要配置两个方面:
1、副本集和共享集群的各个节点成员之间使用内部身份验证,可以使用密钥文件或x.509证书。本文介绍的也是使用密钥文件。原理就是,集群中每一个实例彼此连接的时候都检验彼此使用的证书的内容是否相同。只有证书相同的实例彼此才可以访问
2、使用客户端连接到mongodb集群时,开启访问授权。对于集群外部的访问。如通过可视化客户端,或者通过代码连接的时候,需要开启授权。

  1. 生成密钥文件
    openssl rand -base64 756 > /data/mongodb/testKeyFile.file
    chmod 400 /data/mongodb/testKeyFile.file

    第一条命令是生成密钥文件,第二条命令是使用chmod更改文件权限,为文件所有者提供读权限

  2. 将密钥复制到集群中的每台机器的指定位置
    scp /data/mongodb/testKeyFile.file root@30.23.8.180:/data/mongodb/
  3. 创建一个管理员账户和密码,并将集群中的所有mongod和mongos全部关闭
    use admin
    db.createUser({user:"admin",pwd:"123456",roles:["root"]})
    db.auth("admin","123456") //授权
    killall mongod
    killall mongos
    提示:删除每个mongod实例存储数据存储路径下面的mongod.lock(如果后面启动不报错可以不处理)
  4. 修改config server,shard1,shard2配置文件,增加如下参数:

    keyFile=/data/mongodb/testKeyFile.file
    auth=true
  5. 修改mongos配置文件,增加如下参数:
    keyFile=/data/mongodb/testKeyFile.file
  6. 重启config server,shard1,shard2和mongos所有的配置文件
  7. 测试连接
    mongo mongodb://10.25.72.128:8001 -u admin -p 123456
  8. 为指定数据库创建账户
    use admin
    db.createUser({user: "root", pwd: "123456", roles: [{ role: "dbAdmin", db: "gateway_new" }, { role: "readWrite", db: "gateway_new" }]})
    db.auth("root","123456") //授权
    mongo mongodb://10.25.72.128:8001/gateway_new -u root -p 123456 
    //测试连接指定数据库

三 附录
配置文件附件
config.conf:

dbpath=/data/mongodb/config
logpath=/data/mongodb/logs/config.log
port=27017
bind_ip=30.23.8.189
logappend=true
fork=true
maxConns=5000 
replSet=configs
configsvr=true
keyFile=/data/mongodb/testKeyFile.file
auth=true

mongos.conf:

logpath=/data/mongodb/logs/mongos.log
logappend=true
port=27018
fork=true
bind_ip=30.23.8.189
configdb = configs/30.23.8.189:27017,30.23.8.182:27017,30.23.8.180:27017
maxConns=20000
keyFile=/data/mongodb/testKeyFile.file

shard1.conf:

dbpath=/data/mongodb/shard1
logpath=/data/mongodb/logs/shard1.log
port=27001
bind_ip=30.23.8.189
logappend=true
fork=true
maxConns=5000
replSet=shard1
shardsvr=true
keyFile=/data/mongodb/testKeyFile.file
auth=true

shard2.conf:

dbpath=/data/mongodb/shard2
logpath=/data/mongodb/logs/shard2.log
port=27002
bind_ip=30.23.8.189
logappend=true
fork=true
maxConns=5000
replSet=shard2
shardsvr=true
keyFile=/data/mongodb/testKeyFile.file
auth=true

参数说明

dbpath:数据存放目录
logpath:日志存放路径 logappend:以追加的方式记录日志
replSet:replica set 的名字
port:mongodb 进程所使用的端口号,默认为 27017 fork:以后台方式运行进程
journal:写日志
smallfiles:当提示空间不够时添加此参数
其他参数
pidfilepath:进程文件,方便停止 mongodb directoryperdb:为每一个数据库按照数据库名建立文件夹存放 bind_ip:mongodb 所绑定的 ip 地址
oplogSize:mongodb 操作日志文件的最大大小。单位为 Mb,默认为硬盘剩余 空间的 5%
noprealloc:不预先分配存储
shardsvr:分片
configsvr:配置服务节点
configdb:配置 config 节点到 route 节点

MongoDB role 类型
• 数据库用户角色(Database User Roles)
    read:授予User只读数据的权限
    readWrite:授予User读写数据的权限
• 数据库管理角色(Database Administration Roles):
    dbAdmin:在当前dB中执行管理操作
    dbOwner:在当前DB中执行任意操作
    userAdmin:在当前DB中管理User
• 备份和还原角色(Backup and Restoration Roles):
    backup
    restore
• 跨库角色(All-Database Roles):
    readAnyDatabase:授予在所有数据库上读取数据的权限
    readWriteAnyDatabase:授予在所有数据库上读写数据的权限
    userAdminAnyDatabase:授予在所有数据库上管理User的权限
    dbAdminAnyDatabase:授予管理所有数据库的权限
• 集群管理角色(Cluster Administration Roles):
    clusterAdmin:授予管理集群的最高权限
    clusterManager:授予管理和监控集群的权限,A user with this role can access the config and local databases, which are used in sharding and replication, respectively.
    clusterMonitor:授予监控集群的权限,对监控工具具有readonly的权限
    hostManager:管理Server