搭建Mongodb高可用分片集群
一、规划
- 服务器:
IP:192.168.1.101/192.168.1.102/192.168.1.103
高可用的mongodb集群各个组件的数量,mongos 3个,config server 3个,数据分3片 shard server 3个,每个shard 有1个副本1个仲裁也就是 3 * 2 = 6 个,总共需要部署15个实例。 - 安装包:
# wget http://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.4.1.tgz
- 端口:
mongos:20000
路由服务器:数据库集群请求的入口,所有的请求都通过mongos进行协调,mongos自己就是一个请求分发中心,它负责把对应的数据请求请求转发到对应的shard服务器上。在生产环境通常有多mongos作为请求的入口,防止其中一个挂掉所有的mongodb请求都没有办法操作。
config server:21000
配置服务器:存储所有数据库元信息(路由、分片)的配置。mongos本身没有物理存储分片服务器和数据路由信息,只是缓存在内存里,配置服务器则实际存储这些数据。mongos第一次启动或者关掉重启就会从 config server 加载配置信息,以后如果配置服务器信息变化会通知到所有的 mongos 更新自己的状态,这样 mongos 就能继续准确路由。在生产环境通常有多个 config server 配置服务器,因为它存储了分片路由的元数据,这个可不能丢失!就算挂掉其中一台,只要还有存货, mongodb集群就不会挂掉。
shard1:22001
shard2:22002
shard3:22003
分片服务:用于存储实际的数据块,解决数据库存储空间、硬盘的读写、网络的IO、CPU和内存的瓶颈。
在生产环境中一个shard server角色可由几台机器组成一个relica set承担,防止主机单点故障。在mongodb集群只要设置好了分片规则,通过mongos操作数据库就能自动把对应的数据操作请求转发到对应的分片机器上。在生产环境中分片的片键可要好好设置,这个影响到了怎么把数据均匀分到多个分片机器上,不要出现其中一台机器分了1T,其他机器没有分到的情况,这样还不如不分片!
replica set:
副本集:在高可用性的分片架构还需要对于每一个分片构建 replica set 副本集保证分片的可靠性。生产环境通常是 2个副本 + 1个仲裁。 - 目录结构:
主程序
# mkdir -p /usr/local/webserver/mongodb/
配置/日志/数据
# mkdir -p /data/mongodb/conf/
# mkdir -p /data/mongodb/log/
# mkdir -p /data/mongodb/data/config/
# mkdir -p /data/mongodb/data/shard1/
# mkdir -p /data/mongodb/data/shard2/
# mkdir -p /data/mongodb/data/shard3/
二、安装部署
- 解压安装包并移到主程序目录及环境设置
# tar xvzf mongodb-linux-x86_64-3.4.1.tgz
# mv mongodb-linux-x86_64-3.4.1/* /usr/local/webserver/mongodb/
# rmdir mongodb-linux-x86_64-3.4.1
# echo "never" > /sys/kernel/mm/transparent_hugepage/enabled
# echo "never" > /sys/kernel/mm/transparent_hugepage/defrag
# cat /sys/kernel/mm/transparent_hugepage/enabled
# cat /sys/kernel/mm/transparent_hugepage/defrag
# vi /etc/rc.d/rc.local #####永久关闭
if test -f /sys/kernel/mm/transparent_hugepage/enabled; then
echo never > /sys/kernel/mm/transparent_hugepage/enabled
fi
if test -f /sys/kernel/mm/transparent_hugepage/defrag; then
echo never > /sys/kernel/mm/transparent_hugepage/defrag
fi
# chmod +x /etc/rc.d/rc.local #####增加可执行权限
# systemctl stop firewalld.service #####停止firewall
# systemctl disable firewalld.service #####禁止firewall开机启动
# useradd mongo
# passwd mongo #####密码设置为mongo
# chown -R mongo.mongo /data/mongodb/
# su - mongo
# echo "export PATH=$PATH:/usr/local/webserver/mongodb/bin" >> ~/.bash_profile
# echo "export LANG=en_US.UTF-8" >> ~/.bash_profile
# source ~/.bash_profile
- 编辑配置文件
# openssl rand -base64 753 > /data/mongodb/conf/mongo.key
# chmod 600 /data/mongodb/conf/mongo.key
# vi /data/mongodb/conf/mongos.conf #第一次配置时不设置安全验证配置 /data/mongodb/conf_init/mongos.conf
systemLog:
destination: file
path: "/data/mongodb/log/mongos.log"
logAppend: true
processManagement:
fork: true
net:
port: 20000
############## 注意:第一次配置时不能加该参数 ##############
# security:
# keyFile: "/data/mongodb/conf/mongo.key"
####################################################
sharding:
configDB: rsconf/192.168.1.101:21000,192.168.1.102:21000,192.168.1.103:21000
# vi /data/mongodb/conf/config.conf #第一次配置时不设置安全验证配置 /data/mongodb/conf_init/config.conf
systemLog:
destination: file
path: "/data/mongodb/log/config.log"
logAppend: true
processManagement:
fork: true
net:
port: 21000
############## 注意:第一次配置时不能加该参数 ##############
# security:
# keyFile: "/data/mongodb/conf/mongo.key"
# authorization: enabled
####################################################
storage:
dbPath: "/data/mongodb/data/config"
directoryPerDB: true
engine: wiredTiger
wiredTiger:
engineConfig:
directoryForIndexes: true
replication:
replSetName: rsconf
sharding:
clusterRole: configsvr
# vi /data/mongodb/conf/shard1.conf #第一次配置时不设置安全验证配置 /data/mongodb/conf_init/shard1.conf
systemLog:
destination: file
path: "/data/mongodb/log/shard1.log"
logAppend: true
processManagement:
fork: true
net:
port: 22001
############## 注意:第一次配置时不能加该参数 ##############
# security:
# keyFile: "/data/mongodb/conf/mongo.key"
# authorization: enabled
####################################################
storage:
dbPath: "/data/mongodb/data/shard1"
directoryPerDB: true
engine: wiredTiger
wiredTiger:
engineConfig:
directoryForIndexes: true
replication:
replSetName: shard1
sharding:
clusterRole: shardsvr
operationProfiling:
slowOpThresholdMs: 200
mode: all
# vi /data/mongodb/conf/shard2.conf #第一次配置时不设置安全验证配置 /data/mongodb/conf_init/shard2.conf
systemLog:
destination: file
path: "/data/mongodb/log/shard2.log"
logAppend: true
processManagement:
fork: true
net:
port: 22002
############## 注意:第一次配置时不能加该参数 ##############
# security:
# keyFile: "/data/mongodb/conf/mongo.key"
# authorization: enabled
####################################################
storage:
dbPath: "/data/mongodb/data/shard2"
directoryPerDB: true
engine: wiredTiger
wiredTiger:
engineConfig:
directoryForIndexes: true
replication:
replSetName: shard2
sharding:
clusterRole: shardsvr
operationProfiling:
slowOpThresholdMs: 200
mode: all
# vi /data/mongodb/conf/shard3.conf #第一次配置时不设置安全验证配置 /data/mongodb/conf_init/shard3.conf
systemLog:
destination: file
path: "/data/mongodb/log/shard3.log"
logAppend: true
processManagement:
fork: true
net:
port: 22003
############## 注意:第一次配置时不能加该参数 ##############
# security:
# keyFile: "/data/mongodb/conf/mongo.key"
# authorization: enabled
####################################################
storage:
dbPath: "/data/mongodb/data/shard3"
directoryPerDB: true
engine: wiredTiger
wiredTiger:
engineConfig:
directoryForIndexes: true
replication:
replSetName: shard3
sharding:
clusterRole: shardsvr
operationProfiling:
slowOpThresholdMs: 200
mode: all
同步配置文件到其他服务器
# scp /data/mongodb/conf/* 192.168.1.102:/data/mongodb/conf/
# scp /data/mongodb/conf/* 192.168.1.103:/data/mongodb/conf/
- 启动服务(注意顺序)
3.1 转到mongo用户
# su - mongo
3.2 启动分片(全部服务器)
# /usr/local/webserver/mongodb/bin/mongod -f /data/mongodb/conf/shard1.conf
# /usr/local/webserver/mongodb/bin/mongod -f /data/mongodb/conf/shard2.conf
# /usr/local/webserver/mongodb/bin/mongod -f /data/mongodb/conf/shard3.conf
初始化replica set,用mongo连接其中一个非仲裁机器IP的mongod,执行:
# /usr/local/webserver/mongodb/bin/mongo 192.168.1.101:22001/admin
> config = {_id: 'shard1', members: [
{_id: 0, host: '192.168.1.101:22001'},
{_id: 1, host: '192.168.1.102:22001'},
{_id: 2, host: '192.168.1.103:22001',arbiterOnly:true}
]};
> rs.initiate(config);
> rs.status();
> exit;
# /usr/local/webserver/mongodb/bin/mongo 192.168.1.102:22002/admin
> config = {_id: 'shard2', members: [
{_id: 0, host: '192.168.1.101:22002',arbiterOnly:true},
{_id: 1, host: '192.168.1.102:22002'},
{_id: 2, host: '192.168.1.103:22002'}
]};
> rs.initiate(config);
> rs.status();
> exit;
# /usr/local/webserver/mongodb/bin/mongo 192.168.1.103:22003/admin
> config = {_id: 'shard3', members: [
{_id: 0, host: '192.168.1.103:22003'},
{_id: 1, host: '192.168.1.102:22003',arbiterOnly:true},
{_id: 2, host: '192.168.1.101:22003'}
]};
> rs.initiate(config);
> rs.status();
> exit;
3.3 启动config server(全部服务器)
# /usr/local/webserver/mongodb/bin/mongod -f /data/mongodb/conf/config.conf
初始化config server,用mongo连接其中一个mongod,执行:
# /usr/local/webserver/mongodb/bin/mongo 192.168.1.101:21000/admin
> config = {_id: 'rsconf', members: [
{_id: 0, host: '192.168.1.101:21000'},
{_id: 1, host: '192.168.1.102:21000'},
{_id: 2, host: '192.168.1.103:21000'}
]};
> rs.initiate(config);
> rs.status();
> exit;
3.4 启动mongos(全部服务器)
# /usr/local/webserver/mongodb/bin/mongos -f /data/mongodb/conf/mongos.conf
连接到其中一台mongs,并切换到admin
# /usr/local/webserver/mongodb/bin/mongo 192.168.1.101:20000/admin
mongos> db.runCommand({addshard:"shard1/192.168.1.101:22001,192.168.1.102:22001,192.168.1.103:22001"});
mongos> db.runCommand({addshard:"shard2/192.168.1.101:22002,192.168.1.102:22002,192.168.1.103:22002"});
mongos> db.runCommand({addshard:"shard3/192.168.1.101:22003,192.168.1.102:22003,192.168.1.103:22003"});
mongos> db.runCommand( { listshards : 1 } );
每个分片副本集的仲裁节点不会在上面结果中列出来。
# 添加用户
mongos> db.createUser({user:"admin",pwd:"123456",roles:["root"]});
mongos> db.system.users.find();
mongos> exit;
3.5 关闭所有mongo服务(全部服务器)
# pkill -15 mongos && pkill -15 mongod
# ps aux | grep mongo
3.6 恢复配置文件安全认证部分的配置(全部服务器)
############## 注意:第一次配置时不能加该参数 ##############
# security:
# keyFile: "/data/mongodb/conf/mongo.key"
# authorization: enabled
####################################################
改为
############## 注意:第一次配置时不能加该参数 ##############
security:
keyFile: "/data/mongodb/conf/mongo.key"
authorization: enabled
####################################################
3.7 重启前面所有mongo服务(注意顺序)
# /usr/local/webserver/mongodb/bin/mongod -f /data/mongodb/conf/config.conf
# /usr/local/webserver/mongodb/bin/mongos -f /data/mongodb/conf/mongos.conf
# /usr/local/webserver/mongodb/bin/mongod -f /data/mongodb/conf/shard1.conf
# /usr/local/webserver/mongodb/bin/mongod -f /data/mongodb/conf/shard2.conf
# /usr/local/webserver/mongodb/bin/mongod -f /data/mongodb/conf/shard3.conf
# ps aux | grep mongo
- 测试
连接在mongos上,准备让指定的数据库、指定的集合分片生效
# /usr/local/webserver/mongodb/bin/mongo 192.168.1.101:20000/admin
mongos> db.auth("admin","123456");
mongos> db.runCommand({enablesharding : "testdb"}); #指定testdb分片生效
mongos> db.runCommand({shardcollection : "testdb.test", key : {_id: 1}}); #指定数据库里需要分片的集合和片键
或
mongos> sh.enableSharding("db");
mongos> sh.shardCollection("db.table", { "keyname" : 1 });
我们设置testdb的 test 表需要分片,根据 _id 自动分片到 shard1 ,shard2,shard3 上面去。
要这样设置是因为不是所有mongodb 的数据库和表都需要分片!
mongos> use testdb; #使用testdb
mongos> for (var i = 1; i <= 100000; i++) db.test.save({"_id" : i, "username" : "username"+i, "password" : "password"+i}); #插入测试数据
mongos> db.test.stats(); #查看分片count情况
三、关闭MongoDB
第一种:使用 kill -15 pid 命令关闭MongoDB服务
# pkill -15 mongos && pkill -15 mongod
第二种:登录到MongoDB控制台,use admin,执行db.shutdownServer()
四、添加分片(全部服务器)
================ start ====================
# su - mongo
# mkdir -p /data/mongodb/data/shard4
# vi /data/mongodb/conf/shard4.conf #第一次配置时不设置安全验证配置 /data/mongodb/conf_init/shard4.conf
systemLog:
destination: file
path: "/data/mongodb/log/shard4.log"
logAppend: true
processManagement:
fork: true
net:
port: 22004
############## 注意:第一次配置时不能加该参数 ##############
security:
keyFile: "/data/mongodb/conf/mongo.key"
authorization: enabled
####################################################
storage:
dbPath: "/data/mongodb/data/shard4"
directoryPerDB: true
engine: wiredTiger
wiredTiger:
engineConfig:
directoryForIndexes: true
replication:
replSetName: shard4
sharding:
clusterRole: shardsvr
operationProfiling:
slowOpThresholdMs: 200
mode: all
# /usr/local/webserver/mongodb/bin/mongod -f /data/mongodb/conf_init/shard4.conf
初始化replica set,用mongo连接其中一个非仲裁机器IP的mongod,执行:
# /usr/local/webserver/mongodb/bin/mongo 192.168.1.101:22004/admin
> config = {_id: 'shard4', members: [
{_id: 0, host: '192.168.1.101:22004'},
{_id: 1, host: '192.168.1.102:22004',arbiterOnly:true},
{_id: 2, host: '192.168.1.103:22004'}
]};
> rs.initiate(config);
> rs.status();
> exit;
重启全部服务器 shard4 分片
# ps axu | grep -v 'grep' | grep shard4 |awk '{system("kill -15 "$2)}'
# /usr/local/webserver/mongodb/bin/mongod -f /data/mongodb/conf/shard4.conf
连接其中一台mongos并添加分片
# /usr/local/webserver/mongodb/bin/mongo 192.168.1.101:20000/admin -uadmin -p123456
mongos> db.runCommand({addshard:"shard4/192.168.1.101:22004,192.168.1.102:22004,192.168.1.103:22004"});
mongos> db.runCommand( { listshards : 1 } );
mongos> exit;
重启分部服务(全部服务器)
# pkill -15 mongos && pkill -15 mongod
# /usr/local/webserver/mongodb/bin/mongod -f /data/mongodb/conf/config.conf
# /usr/local/webserver/mongodb/bin/mongos -f /data/mongodb/conf/mongos.conf
# /usr/local/webserver/mongodb/bin/mongod -f /data/mongodb/conf/shard1.conf
# /usr/local/webserver/mongodb/bin/mongod -f /data/mongodb/conf/shard2.conf
# /usr/local/webserver/mongodb/bin/mongod -f /data/mongodb/conf/shard3.conf
# /usr/local/webserver/mongodb/bin/mongod -f /data/mongodb/conf/shard4.conf
# ps aux | grep mongo
================= end ===================
修改数据库基片
mongos> db.runCommand({moveprimary : "testdb", "to" : "shard1/192.168.1.101:22001,192.168.1.102:22001"});
移除分片
mongos> db.runCommand({removeshard : "shard4/192.168.1.101:22004,192.168.1.103:22004"});
其他命令
————————————————————
查看数据库状态
db.stats()
查看表状态
db.tableName.stats()
查看所有分片信息状态
db.printShardingStatus();
删除分片,删除分片命令执行后,mongos将不再写入该分片数据,同时会将数据迁移到其他分片,这个过程需要一段时间,此时查看db.printShardingStatus();,该分片状态为"draining" : true。
但是由于bug,会一直处于此状态下。需要在人工确定已无数据在此分片后,在mongos中进入config数据库执行db.shards.remove({draining:true}),删除掉该分片。
db.runCommand({removeshard : "shard1/192.168.1.123:30001,192.168.1.124:30001,192.168.1.125:30001"});
使Primary降为Secondary,每一个分片,都是一组副本集,1主2从,设置时自动选举,如果不符合写入压力分散的需求,可以将该主库降级,2个从属会随机选择一个重新为主。
rs.stepDown()