mongodb分片集群搭建
前阵子心血来潮,学习如何搭建 mongodb 服务。
也借此次机会,将搭建流程,所遇问题做点小记录。
本次搭建均在 linux 服务器上进行。
如有错误,欢迎指出。
以下链接为本文借鉴之源,各位也可以去看看。(ps:写的比我好多了)
一、mongodb介绍
1) mongodb 特点
① 面向集合存储
② 数据结构自由
③ 支持动态查询
④ 支持索引
⑤ 可高效的二进制数据存储(可存大型对象,像视频等文件)
⑥ 文件格式为Bson(一种Json的扩展)
总结:就是一个很牛的No Sql数据库,也符合数据库系统的要求。
2) 单机劣势
① 读写并发度低
②无数据灾备。一旦挂了,使用的服务崩溃。数据无备份,服务器搞事情,数据全没了。比删库跑路还刺激,还不可控。
总结:总要给自己一点搭分片集群的理由
3) 保证高可用方式
① 复制集 or 副本集 (ps:二者是一样的东西)
② 分片集群,本文着重介绍分片集群,但文中也有涉及复制集部分。
一切请看下回分解 开玩笑开玩笑,先别走
4)分片组件介绍
集群主要组件有mongos、config server、shard、replica set
① mongos 路由服务器:
集群请求入口,本质上是个请求分发中心,将对应请求转发到对应shard分片服务器上。常规会配置多个 mongos 路由服务器,确保高可用。
② config server 配置服务器:
用于存储数据元信息(路由,分片)的配置。
mongos 路由服务器本身没有物理存储分片服务器和数据路由信息,只缓存在内存中。
而配置服务器则实际存储这部分信息,数据。
在 mongos 路由服务器启动时,就从 config server 配置服务器中加载该配置。
而 config server 配置服务器中任何配置信息发生变化,都会通知 mongos 更新状态。
(ps:个人认为这是分片集群核心)
③ shard 分片:
将库拆分,根据片键将数据拆分存储。
其基本思想:将集合分块,分散到若干片中,每个片只负责总数据的一部分,最终通过均衡器保证各分片数据量均衡。
④ replica set 副本集/复制集:
数据的冗余备份机制,配置子节点作为从服务器,用于存储数据副本,提高高可用。
⑤ Arbiter 仲裁者:
复制集中实例之一。使用最小的资源,且无硬件要求。应部署在与主从服务不同的服务器上。
其作用是确保该复制集中 primay 主服务器关闭时,可从各 secondary 从服务器中,选举出新的 primary 主服务器。
primary 主服务器 与 secondary 从服务器集合,也可自行选举新 primary 主服务器。
但当复制集中主从数量为偶数时,自行选举机制将会失效,此时就需要Arbiter仲裁者介入了。
二、环境准备
为了后续部署集群环境顺利,在这里就提前把所需的相关配置文件等准备好
1) 服务器列表
生产环境分三台服务器部署,本文贪图演示方便,只用了一台机器做伪集群 (ps:切记偷懒行为不可取)
2) 端口分配
1.4章节中提及到,分片集群的重要组件
这里提前把架构图、端口分配等信息,准备好
① shard 分片复制集两个,每个复制集以1 primary 主服务,1个 secondary 从服务,1个 Arbiter 仲裁者服务组成
② config server 配置服务三个
③ mongos 路由服务三个
④ 架构图、端口分配(ps:略粗糙,请见怪莫怪,如果糊了可以来这看:sbimg.cn/image/2UMXk)
3) dbpath目录
用于存储 mongodb 实例数据,在配置文件中需指定数据目录。
各服务中,除了mongos路由服务外,都要进行物理存储,因此都要指定存储目录。
根据端口与职能进行分配(我本机 mongodb 目录为 /usr/local/mongodb):
# db 用于存储 分片 数据 # 复制集 rs1 端口为27017的数据目录 mkdir -p /usr/local/mongodb/data/db/rs1_27017 # 复制集 rs1 端口为27018的数据目录 mkdir -p /usr/local/mongodb/data/db/rs1_27018 # 复制集 rs1 端口为27019的数据目录 mkdir -p /usr/local/mongodb/data/db/rs1_27019 # 复制集 rs2 端口为27020的数据目录 mkdir -p /usr/local/mongodb/data/db/rs2_27020 # 复制集 rs2 端口为27021的数据目录 mkdir -p /usr/local/mongodb/data/db/rs2_27021 # 复制集 rs2 端口为27022的数据目录 mkdir -p /usr/local/mongodb/data/db/rs2_27022 # configs 用于存储 配置服务 数据 # 配置服务 27023 服务数据目录 mkdir -p /usr/local/mongodb/data/configs/27023 # 配置服务 27024 服务数据目录 mkdir -p /usr/local/mongodb/data/configs/27024 # 配置服务 27025 服务数据目录 mkdir -p /usr/local/mongodb/data/configs/27025 # mongos 路由服务 不需要物理存储数据,因此无须准备数据目录本步骤已完成,建议用记事本记录下这几个目录信息,后续配置服务时需要用到
4) logpath目录
用于存储 mongodb 日志数据,在配置文件中需指定日志数据目录。
各服务都需配置。
根据端口与职能进行分配(mongodb目录为 /usr/local/mongodb ):
# db 用于存储 分片 日志数据 # 复制集 rs1 端口为27017的日志目录 mkdir -p /usr/local/mongodb/logs/db/rs1_27017 # 复制集 rs1 端口为27018的日志目录 mkdir -p /usr/local/mongodb/logs/db/rs1_27018 # 复制集 rs1 端口为27019的日志目录 mkdir -p /usr/local/mongodb/logs/db/rs1_27019 # 复制集 rs2 端口为27020的日志目录 mkdir -p /usr/local/mongodb/logs/db/rs2_27020 # 复制集 rs2 端口为27021的日志目录 mkdir -p /usr/local/mongodb/logs/db/rs2_27021 # 复制集 rs2 端口为27022的日志目录 mkdir -p /usr/local/mongodb/logs/db/rs2_27022 # configs 用于存储 配置服务 日志数据 # 配置服务 27023 服务日志目录 mkdir -p /usr/local/mongodb/logs/configs/27023 # 配置服务 27024 服务日志目录 mkdir -p /usr/local/mongodb/logs/configs/27024 # 配置服务 27025 服务日志目录 mkdir -p /usr/local/mongodb/logs/configs/27025 # router 用于存储 路由服务 日志数据 # 路由服务 27026 服务日志目录 mkdir -p /usr/local/mongodb/logs/router/27026 # 路由服务 27027 服务日志目录 mkdir -p /usr/local/mongodb/logs/router/27027 # 路由服务 27028 服务日志目录 mkdir -p /usr/local/mongodb/logs/router/27028本步骤已完成,建议用记事本记录下这几个目录信息,后续配置服务时需要用到
5) keyFile文件
副本集成员间的内部认证机制所需文件。
开启 keyfile 身份验证后,副本集中的每个 mongod 实例都使用 keyfile 的内容作为共享密码,只有具有正确的秘钥文件的 mongod 实例或者 mongos 实例才可以连接到副本集。
切记:密钥文件的内容必须在6到1024个字符之间,并且在unix/linux系统中文件所有者必须有对文件至少有读的权限.
① 生成秘钥文件
写入随机的756位二进制码到 /usr/local/mongodb/etc/KeyFile.file 文件中(ps:文件不存在会自动创建)
openssl rand -base64 756 > /usr/local/mongodb/etc/KeyFile.file② 修改秘钥文件权限
修改 KeyFile权限为只读
chmod 400 /usr/local/mongodb/etc/KeyFile.fileKeyfiles是安全的最小格式,非常适合测试和开发环境。对于生产环境,推荐使用
x.509 certificates。
6) 服务配置文件
本处创建配置文件目录与文件,用作后续配置可直接使用
# 创建配置文件目录 mkdir -p /usr/local/mongodb/etc # 进入配置目录 cd /usr/local/mongodb/etc # 复制集 rs1: primary、secondary、arbiter配置文件 touch rs1_27017_primary.conf touch rs1_27018_secondary.conf touch rs1_27019_arbiter.conf # 复制集 rs2: primary、secondary、arbiter配置文件 touch rs2_27020_primary.conf touch rs2_27021_secondary.conf touch rs2_27022_arbiter.conf # 复制集 configs:config server 配置文件 touch configs_27023.conf touch configs_27024.conf touch configs_27025.conf # mongos 路由服务 配置文件 touch router_27026.conf touch router_27027.conf touch router_27028.conf
7) 环境配置
建议把环境变量配置好,方便后续命令使用
① 修改 profile 文件
vi /etc/profilePATH变量 添加 mongodb 的 bin 目录路径
export MONGODB_HOME=/usr/local/mongodb export PATH=$MONGODB_HOME/bin:$PATH② 重新加载 profile 文件
source /etc/profile③ 校验
# 查看mongod的指令提示列表,可正常调用,则表明配置生效 mongod --help
三、配置服务复制集搭建
根据服务启动顺序,先从配置服务开始搭建
1)配置文件解析
以下配置可作用于 configs_27023.conf、configs_27024.conf、configs_27025.conf,此处以 configs_27023.conf 为例
# 监听端口(27023,27024,27025),根据不同配置文件,更改该端口 port=27023 # 数据存储目录(27023,27024,27025),根据不同配置文件,更改该目录 dbpath = /usr/local/mongodb/data/configs/27023 # 日志存储文件地址(27023,27024,27025),根据不同配置文件,更改该目录 logpath = /usr/local/mongodb/logs/configs/27023/congigsrv.log # 日志文件是否以日期划分(每日一个) logappend=true # 是否后台运行 fork=true # 声明这是个配置服务集群 configsvr=true # 复制集名称 replSet=configs本处只提供27023配置样本,另外两个需自行修改
2) 启动
config server 配置服务实例和 mongod 分片实例的启动方式一致,使用 mongod 命令启动。
mongos 路由服务实例启动则用 mongos 命令进行。
该步骤,需要将三台 配置服务 都启动完成
# mongod -f 启动时,加载指定的配置文件 mongod -f /usr/local/mongodb/etc/configs_27023.conf mongod -f /usr/local/mongodb/etc/configs_27024.conf mongod -f /usr/local/mongodb/etc/configs_27025.conf
3)初始化复制集
① 登陆其中一台配置服务
mongo -port 27023② 初始化 primary 服务
登录后键入:
use admin rs.initiate() rs.status()③ 添加 secondary 服务
congfig server 复制集不需要 Arbiter 仲裁者,因此 27024 与 27025 都作为复制集中的从服务使用
# 添加 secondary 节点,此处ip未必填写为localhost,可参照rs.status()中name属性 rs.add('localhost:27024') rs.add('localhost:27025')(ps:配置服务复制集已搭建完毕)
四、分片服务器复制集搭建
1) 配置文件解析
复制集 rs1 配置,以27017为例(27018与27019自行配置)
# 以下配置已在config server介绍过了 port=27017 dbpath=/usr/local/mongodb/data/db/rs1_27017 logpath=/usr/local/mongodb/logs/db/rs1_27017/27017.log logappend=true fork=true replSet=rs1 # 声明这是一个分片复制集 shardsvr = true复制集 rs2 配置,以27020为例(27021与27022自行配置)
port=27020 dbpath=/usr/local/mongodb/data/db/rs2_27020 logpath=/usr/local/mongodb/logs/db/rs2_27020/27020.log logappend=true fork=true replSet=rs2 # 声明这是一个分片复制集 shardsvr = true
2) 启动
本处以 rs1 复制集搭建为案例,rs2复制集自行搭建
mongod -f /usr/local/mongodb/etc/rs1_27017_primary.conf mongod -f /usr/local/mongodb/etc/rs1_27018_secondary.conf mongod -f /usr/local/mongodb/etc/rs1_27019_arbiter.conf
3) 初始化复制集
① 登陆其中一台配置服务
mongo -port 27017② 初始化 primary 服务
登录后键入:
use admin rs.initiate() rs.status()③ 添加 secondary 服务
# 添加 secondary 节点,此处ip未必填写为localhost,可参照rs.status()中name属性 rs.add('localhost:27018')④ 添加 Arbiter 服务
# 添加 arbiter 节点 rs.addArb('localhost:27019')(ps:shard 服务复制集已搭建完毕)
五、路由服务搭建
1) 配置文件解析
以27026为例
# 路由服务没有物理存储数据信息,因此无须配置dbpath logpath = /usr/local/mongodb/logs/router/27026/mongos.log logappend = true port = 27026 #bind_ip=0.0.0.0 开放任意访问,分片集群入口为路由服务,要想外网可以访问该端口,此处必须放开注释,或者指定对应ip fork = true # configs 为 配置服务的复制集名称,必须一一对应 configdb = configs/localhost:27025,localhost:27024,localhost:27023
2) 启动
以27026为例
mongos -f /usr/local/mongodb/router_27026.conf mongos -f /usr/local/mongodb/router_27027.conf mongos -f /usr/local/mongodb/router_27028.conf
3) 串联分片服务
配置中,已将路由服务与配置服务绑定,但路由与分片服务未进行绑定
① 登录其中一台路由服务,以27026为例
mongo -port 27026② 串联分片
sh.addShard("rs1/localhost:27017,localhost:27018,localhost:27019") sh.addShard("rs2/localhost:27020,localhost:27021,localhost:27022") # 查看集群状态 sh.status()搭建完成啦,分片集群搭建基本完成,大家可以开始愉快的造bug了
完成此步后,分片集群基本搭建完毕,以下步骤是开启鉴权操作。
感兴趣的朋友可以继续观看呦
六、配置用户
目前集群在 bind_ip 配置允许的ip内,谁都可以访问。
这样显然是不合理的,应该限制对应用户才可使用,且每个用户可操作权限也不同。
1)连接路由
连接至其中一台路由,进行用户配置。
创建用户后,该数据会通过 config server 配置服务进行数据共享。
mongo -port 27026
2)创建用户
① 使用 admin 库。切记:创建用户时,一定要连接 admin 库,否则新用户会被新增至 test 库中!!!。
use admin② 创建超级用户(黑帮老大,任我行)
db.createUser({ 'user':'xxxx', 'pwd':'xxx', 'roles':[{'role':'root','db':'admin'}] })③ 分析命令
此处借鉴:Mongodb设置用户权限(整理版)
user:用户名
pwd:密码
roles:指定用户的角色,可以用一个空数组给新用户设定空角色;
db:指定该用户的数据库,admin 是用于权限控制的数据库
在 roles 字段,可以指定内置角色和用户定义的角色。role 里的角色可以选
Built-In Roles(内置角色):
1.数据库用户角色:read、readWrite;
2.数据库管理角色:dbAdmin、dbOwner、vuserAdmin;
3.集群管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManager;
4.备份恢复角色:backup、restore;
5.所有数据库角色:readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase;
6.超级用户角色:root;
7.内部角色:__system;
// 这里还有几个角色间接或直接提供了系统超级用户的访问(dbOwner 、userAdmin、userAdminAnyDatabase)
具体角色的功能:
Read:允许用户读取指定数据库
readWrite:允许用户读写指定数据库
dbAdmin:允许用户在指定数据库中执行管理函数,如索引创建、删除,查看统计或访问 system.profile
userAdmin:允许用户向 system.users 集合写入,可以找指定数据库里创建、删除和管理用户
clusterAdmin:只在 admin 数据库中可用,赋予用户所有分片和复制集相关函数的管理权限。
readAnyDatabase:只在 admin 数据库中可用,赋予用户所有数据库的读权限
readWriteAnyDatabase:只在 admin 数据库中可用,赋予用户所有数据库的读写权限
userAdminAnyDatabase:只在 admin 数据库中可用,赋予用户所有数据库的 userAdmin 权限
dbAdminAnyDatabase:只在 admin 数据库中可用,赋予用户所有数据库的 dbAdmin 权限。
root:只在 admin 数据库中可用。超级账号,超级权限
④ 检验用户
show users # 创建成功则返回如下信息. # 如果_id 显示为 test.root,则说明创建用户时,未选中admin库。 { "_id" : "admin.root", "userId" : UUID("05a5a272-ea28-438b-b4fc-f81e48c1c968"), "user" : "root", "db" : "admin", "roles" : [ { "role" : "root", "db" : "admin" } ] }
七、开启鉴权
1) 关闭所有服务
① 方案一:逐台关闭1(该方案中,路由服务/配置服务/分片服务都可用)
# 1.登录服务 mongo -port 27017 # 2.选中 admin use admin # 3.登录账号,此步骤在开启鉴权前可省略 db.auth('user','pwd') # 4.关闭服务 db.shutdownServer()该方案需要逐台进入关闭,略麻烦
② 方案二:逐台关闭2(该方案中,只适用于配置服务/分片服务)
# 1.指定对应配置文件关闭对应服务,其原理是关闭对dbpath的使用 mongod --shutdown -f /usr/local/mongodb/etc/rs1_27017_primary.conf\ # 2.路由服务要用 mongos 命令,但 mongos 只是一个路由节点,没有物理存储结构,只用内存进行部分数据映射。 # 因此路由服务也无需配置 dbpath,也就没提供 --shutdown 命令③ 方案三:全部关闭
# 关闭所有路由节点 killall mongos # 关闭所有mongod实例 killall mongodmongod 实例不建议使用此方式
非正常关闭时,dbpath 中会有 lock 文件遗留,有几率导致无法重新启动。所以 mongod 实例不建议使用这种方式
但 mongos 建议用这种方式,方便且快捷。也不用担心 dbpath 中 lock 文件导致的不能启动问题。( mongos 没有dbpath)
④ 方案四:取各种方案的优点
配置服务/分片服务使用方案二关闭。
路由服务使用方案三关闭。
# 方案二 mongod --shutdown -f rs1_27017_primary.conf mongod --shutdown -f rs1_27018_secondary.conf mongod --shutdown -f rs1_27019_arbiter.conf mongod --shutdown -f rs2_27020_primary.conf mongod --shutdown -f rs2_27021_secondary.conf mongod --shutdown -f rs2_27022_arbiter.conf mongod --shutdown -f configs_27023.conf mongod --shutdown -f configs_27024.conf mongod --shutdown -f configs_27025.conf # 方案三 killall mongos
2) 更改配置文件
官方推荐x509证书(但我还不会)
集群中妹妹一个实例,彼此连接的时候,都校验对方使用的证书是否相同
① shard 与 config server 的所有配置文件中添加
# 开启用户鉴权,需要登录对应用户,才可使用用户角色允许的操作。(比如我们新建的超级用户,拥有全部权限) auth=true # 副本集成员间的 内部认证机制 所需文件,指向2.5章节中准备的验证文件。 # 只用拥有相同秘钥的 mongod 或 mongos 实例可连接复制集 keyFile=/usr/local/mongodb/etc/KeyFile.file② mongos 路由服务配置文件中添加
keyFile=/usr/local/mongodb/etc/KeyFile.file # 如果需要允许外网访问,记住加上 bind_ip=0.0.0.0 配置
八、重启集群
1)启动顺序
启动顺序应该是: config server 配置服务 ——》 shard 分片服务 ——》 mongos 路由服务
2)重启
使用命令启动所有服务。(每次启动都要输入这么多人,有点繁琐。文章结尾将部分快捷操作分享给大家,有兴趣的朋友可以看看)
重启时,一定要先启动配置服务。
如果还有异常,一定原因是服务非正常关闭,dbpath中有lock文件存在,启动时检索到该文件,就抛出异常。
大家遇到问题可以,百度编程
因为遇到的异常情况很多,本处就不贴优秀范文了。
mongod -f configs_27023.conf mongod -f configs_27024.conf mongod -f configs_27025.conf mongod -f rs1_27017_primary.conf mongod -f rs1_27018_secondary.conf mongod -f rs1_27019_arbiter.conf mongod -f rs2_27020_primary.conf mongod -f rs2_27021_secondary.conf mongod -f rs2_27022_arbiter.conf mongos -f router_27026.conf mongos -f router_27027.conf mongos -f router_27028.conf
3)测试集群
# 登录路由 mongo -port 27026 # 选择admin库 use admin # 提示需要登录 show users # 提示登录成功,则集群搭建完毕 db.auth('user','pwd')完成以上操作,一个基本集群就搭建完成了。
大家可以继续深入了解 mongodb 的特性,也祝愿朋友们造Bug开心。
九、小分享
在实验搭建的途中,发现部分操作有点繁琐。
决定写这篇文章时,就想着能不能把一些小Tips分享给大家。
希望对大家有帮助。
1)mongodb 启动、关闭命令
前几章中,有看到过关闭和启动 mongodb 示例的情况。
当时在想这也太麻烦了。
我的做法是,把相应的指令放在sh文件中,用时直接调用即可。
① sh命令创建
我的sh文件,也是放在etc目录下
# 创建 sh 脚本文件 touch xxxx.sh # 编辑 sh 文件 vi xxx.sh # sh文件开头写入下面这行文本,标记是bash命令 #!/bin/bash # 写入想要的linux 指令 # esc :wq 保存退出 # 声明该文件有可执行权限 chmod 700 xxxx.sh # 之后运行该sh文件直接通过 sh xxxx.sh # 或者 ./xxxx.sh② 关闭脚本
# 创建 sh 脚本文件 touch shutdownAllServer.sh # 编辑 sh 文件 vi shutdownAllServer.sh # sh文件开头写入下面这行文本,标记是bash命令 #!/bin/bash mongod -f configs_27023.conf mongod -f configs_27024.conf mongod -f configs_27025.conf mongod -f rs1_27017_primary.conf mongod -f rs1_27018_secondary.conf mongod -f rs1_27019_arbiter.conf mongod -f rs2_27020_primary.conf mongod -f rs2_27021_secondary.conf mongod -f rs2_27022_arbiter.conf mongos -f router_27026.conf mongos -f router_27027.conf mongos -f router_27028.conf # esc :wq 保存退出 # 声明该文件有可执行权限 chmod 700 shutdownAllServer.sh③ 启动脚本
# 创建 sh 脚本文件 touch startAllServer.sh # 编辑 sh 文件 vi startAllServer.sh # sh文件开头写入下面这行文本,标记是bash命令 #!/bin/bash mongod -f configs_27023.conf mongod -f configs_27024.conf mongod -f configs_27025.conf mongod -f rs1_27017_primary.conf mongod -f rs1_27018_secondary.conf mongod -f rs1_27019_arbiter.conf mongod -f rs2_27020_primary.conf mongod -f rs2_27021_secondary.conf mongod -f rs2_27022_arbiter.conf mongos -f router_27026.conf mongos -f router_27027.conf mongos -f router_27028.conf # 声明该文件有可执行权限 chmod 700 startAllServer.sh本处请注意,该脚本只考虑了所有服务在一台服务器上的情况。
因此,应该在有 mongodb 实例的服务器都应创建一个对应的sh文件。
本处分享的未必是最优方案,大家有好的建议,欢迎教导。
2)目录跳转快捷方式
由于我使用 Xshell 连接我的阿里云服务器。
会有偶尔断开的情况,每次重新登录上服务器,都要键入层层的目录。
程序员嘛,就是为了更快捷的生活。而提供偷懒的更优方案。
本处分享的是如何创建 “目录的快捷方式”。
① 新增 sh 文件
# 进入用户家目录 cd # 创建sh文件 touch intoMongodb.sh # 键入sh内容 vi intoMongodb.sh # sh内容 #!/bin/bash cd /usr/local/mongodb/etc # 保存② 试验
./intoMongodb.sh键入命令后,发现目录压根没变化。
这时是不是想着,这人不是在坑我吧。
先别急,有了bug就要耐心修复。
③ 分析原因
sh 文件中的 linux 命令,的的确确是执行。
为什么没有效果呢?
这是因为,sh 命令是一个后台操作。相当于起了个线程,跳转到 mongodb 目录。
等线程结束后,并没有影响主线程的状态
④ 优化方案
# 更改intoMongodb文件,这一步仅仅是想要调用美观,没有.sh的小尾巴 mv intoMongodb.sh intoMongodb # 使用 .或者source调用,指明用父bash来执行 . intoMongodb source intoMongodb # 目录发生更改
以上就是文章的全部内容。
原本想要拆开几篇来发的,但感觉分开又不成体系。所以篇幅略长,大家多多包涵。
这是我首次写文,有很多没考虑的地方。大家多多指导。
特别是知识点,文章中知识点/理论可能和大家的有出入,或不对。欢迎大家指出。
感谢各平台中,技术分享的各位朋友。本文编写时,内容借鉴处有很多,有许多重复处,大家海涵(也可联系,进行文章修改或删除)。
也感谢大家抽空看这篇文章。
最后,祝大家每日欢乐写bug,技术水平日益提升。
