负载均衡及高可用一直是我们线上服务架构所关注的重点,本文内容,将介绍如何在 Docker 环境下实现 MongoDB 的副本集及分片。
在 MongoDB 中,副本集是一组实现了复制功能的服务器,其中一个是主服务器(Primary),用于处理客户端请求;其余为备份服务器(Secondary),用于保存主服务器的副本。如果主服务器出现故障,备份服务器将推举出其中一个成员为主服务器,继续响应请求。分片(Sharding)是将数据拆分并分散存放在不同机器上,这样不需要功能强大的大型计算机就可以存储更多的数据,处理更大的负载。MongoDB 的分片机制允许你创建一个包含许多台机器的集群,将数据子集分散在集群中,每个分片维护着一个数据集合的子集。与单机服务器和副本集相比,集群架构可以使应用程序具有更大的数据处理能力。
副本集是让多台服务器都拥有同样的数据副本,每一台服务器都是其他服务器的镜像,而每一个分片都拥有和其他分片不同的数据子集。
分片的目标之一是创建一个拥有5台、500台甚至更多机器的集群,整个集群对应用程序来说就像是一台单机服务器。为了对应用程序隐藏数据库架构的细节,在分片之前要先执行 mongos 进行一次路由过程。这个路由服务器维护着一个“内容列表”,指明了每个分片包含哪些数据内容。应用程序只需要连接到路由服务器,就可以像使用单机服务器一样进行正常的请求了。
那么是不是在业务刚起步时就进行分片呢?不然。分片不止会增加部署的操作复杂度,还要求做出设计决策,而该决策以后很难再更改,所以不必太早分片,但也不宜在系统运行太久之后分片,因为在一个过载的系统上不停服进行分片是非常困难的。可以参考以下四点来决定何时分片:
需要增加可用RAM
增加可用磁盘空间
减轻单台服务器的负载
处理单个 mongod 无法承受的吞吐量
MongoDB 集群包含三个组件:配置服务器、mongos 服务器、mongod 服务器。配置服务器相当于集群的大脑,保存着集群和分片的元数据:集群中有哪些分片、分片的是哪些集合以及数据块的分布等。mongos 需要从配置服务器获取信息,因此配置服务器应先于任何 mongos 进程启动。配置服务器是独立的 mongod 进程,所以可以像启动 mongod 一样启动配置服务器,但在 MongoDB3.4 及以后的版本,配置服务器必须部署为副本集的形式。
准备环境
一:初始化宿主机系统
1.安装程序包
yum -y install docker vim net-tools psmisc sysstat telnet wget lsof lrzsz
systemctl enable docker
setenforce 0
vim /etc/sysconfig/selinux 修改Selinux为关闭状态
vim /etc/security/limits.conf 修改文件句柄数
2.禁止内存过度分配
echo 1 > /proc/sys/vm/overcommit_memory
vim /boot/grub2/grub.cfg
numa=off
3.禁用zone_reclaim_mode
cat /proc/sys/vm/zone_reclaim_mode
0
4.块设备预读大小
blockdev --report
blockdev --setra 16 /dev/sdb1
5.禁用大内存页面
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
6.修改文件描述符限制
nofile 64000
nproc 64000
7.时钟同步
*/2 * * * * ntpdate 1.sg.pool.ntp.org
8.禁用atime,默认relatime
vim /etc/fstab
UUID=ef6ba050-6cdc-416a-9380-c14304d0d206 / xfs defaults,noatime 0 0
noatime,nodiratime
9.创建所需目录
mkdir -p /data/db/rs{1..3}
mkdir -p /data/db/conf{1..3}
mkdir -p /data/logs/rs{1..3}
chown -R mongo.mongo /data
二:构建镜像
1.Download Base Image centos7.3
docker pull docker.io/centos
2.start centos
docker run -d -it --name centos7 docker.io/centos /bin/bash
docker run exec -it centos7 bash
useradd mongo
usermod mongo -u 1021
groupmod -g 1021 mongo
mkdir -p /data/db
mkdir -p /data/logs
chown -R mongo.mongo /data
ln -s /usr/lib64/libsasl2.so.3 /usr/lib64/libsasl2.so.2
ln -s /home/mongo/mongodb/bin/* /usr/bin/
su - mongo
mongo --hlep
yum install -y crontabs
su - root
/usr/sbin/crond
3.docker commit centos 7 centos7
4.docker build -t mongod3.2.11 .
cat Dockerfile
####mongod####
FROM centos7
MAINTAINER Weiwendi
USER mongo
ENTRYPOINT ["/usr/bin/mongod"]
5.docker build -t mongos3.2.11 .
cat Dockerfile
####mongos####
FROM centos7
MAINTAINER Weiwendi
USER mongo
ENTRYPOINT ["/usr/bin/mongos"]
分发配置文件
ConfigDB
-------------------------------------------------------------------
port = 37019
pidfilepath = /data/mongodb/configdb/data/mongod.pid
fork = true
configsvr = true
dbpath = /data/mongodb/configdb/data
logpath = /data/mongodb/configdb/logs/mongod.log
logappend = true
logRotate = rename
journal = true
directoryperdb = true
nohttpinterface = true
quiet = true
auth = true
keyFile = /data/mongodb/key/mongodb-keyfile
profile = 1
slowms = 2000
storageEngine = wiredTiger
wiredTigerDirectoryForIndexes = true
wiredTigerCacheSizeGB = 100
replSet = cfgdb
mongos
-------------------------------------------------------------------
port = 47017
pidfilepath = /data/mongodb/mongos/data/mongos.pid
fork = true
configdb = cfgdb/192.168.17.128:37019,192.168.17.129:37019,192.168.17.131:37019
logpath = /data/mongodb/mongos/logs/mongos.log
logappend = true
logRotate = rename
quiet = true
keyFile = /data/mongodb/mongodb-keyfile
mongod
-----------------------------------------------------------------
port = 27017
pidfilepath = /data/logs/mongod.pid
fork = true
dbpath = /data/db
logpath = /data/logs/rs1.log
logappend = true
logRotate = rename
journal = true
directoryperdb = true
nohttpinterface = true
quiet = true
auth = true
keyFile = /data/mongodb/key/mongodb-keyfile
profile = 1
slowms = 2000
storageEngine = wiredTiger
wiredTigerDirectoryForIndexes = true
wiredTigerCollectionBlockCompressor = snappy
wiredTigerJournalCompressor = snappy
wiredTigerCacheSizeGB = 60
replSet = rs1
oplogSize = 102400
在三台主机上启动Docker容器
创建副本集
172.31.90.39 (副本集1)
docker run --name rs1_srv1 -p 21117:27017 --restart=always -v /data/db/rs1:/data/db -v /data/logs/rs1:/data/logs -v /data/conf/rs1:/data/conf -v /data/backup:/data/bak -d registry.newborn-town.com:5000/wtmongodb3.2.11 -f /data/conf/mongodb.conf
docker run --name rs1_srv2 -p 21217:27017 --restart=always -v /data/db/rs2:/data/db -v /data/logs/rs2:/data/logs -v /data/conf/rs2:/data/conf -v /data/backup:/data/bak -d registry.newborn-town.com:5000/wtmongodb3.2.11 -f /data/conf/mongodb.conf
docker run --name rs1_srv3 -p 21317:27017 --restart=always -v /data/db/rs3:/data/db -v /data/logs/rs3:/data/logs -v /data/conf/rs3:/data/conf -v /data/backup:/data/bak -d registry.newborn-town.com:5000/wtmongodb3.2.11 -f /data/conf/mongodb.conf
172.31.90.64 (副本集2)
docker run --name rs2_srv1 -p 21117:27017 --restart=always -v /data/db/rs1:/data/db -v /data/logs/rs1:/data/logs -v /data/conf/rs1:/data/conf -v /data/backup:/data/bak -d registry.newborn-town.com:5000/wtmongodb3.2.11 -f /data/conf/mongodb.conf
docker run --name rs2_srv2 -p 21217:27017 --restart=always -v /data/db/rs2:/data/db -v /data/logs/rs2:/data/logs -v /data/conf/rs2:/data/conf -v /data/backup:/data/bak -d registry.newborn-town.com:5000/wtmongodb3.2.11 -f /data/conf/mongodb.conf
docker run --name rs2_srv3 -p 21317:27017 --restart=always -v /data/db/rs3:/data/db -v /data/logs/rs3:/data/logs -v /data/conf/rs3:/data/conf -v /data/backup:/data/bak -d registry.newborn-town.com:5000/wtmongodb3.2.11 -f /data/conf/mongodb.conf
172.31.90.161 (副本集3)
docker run --name rs3_srv1 -p 21117:27017 --restart=always -v /data/db/rs1:/data/db -v /data/logs/rs1:/data/logs -v /data/conf/rs1:/data/conf -v /data/backup:/data/bak -d registry.newborn-town.com:5000/wtmongodb3.2.11 -f /data/conf/mongodb.conf
docker run --name rs3_srv2 -p 21217:27017 --restart=always -v /data/db/rs2:/data/db -v /data/logs/rs2:/data/logs -v /data/conf/rs2:/data/conf -v /data/backup:/data/bak -d registry.newborn-town.com:5000/wtmongodb3.2.11 -f /data/conf/mongodb.conf
docker run --name rs3_srv3 -p 21317:27017 --restart=always -v /data/db/rs3:/data/db -v /data/logs/rs3:/data/logs -v /data/conf/rs3:/data/conf -v /data/backup:/data/bak -d registry.newborn-town.com:5000/wtmongodb3.2.11 -f /data/conf/mongodb.conf
配置服务器
172.31.90.39
docker run --name cfg1 -p 37017:27017 --restart=always -v /data/db/conf1:/data/db -d registry.newborn-town.com:5000/mongod-3.2.10 --storageEngine wiredTiger --smallfiles --configsvr --dbpath /data/db --port 27017
172.31.90.64
docker run --name cfg2 -p 37017:27017 --restart=always -v /data/db/conf2:/data/db -d registry.newborn-town.com:5000/mongod-3.2.10 --storageEngine wiredTiger --smallfiles --configsvr --dbpath /data/db --port 27017
172.31.90.161
docker run --name cfg3 -p 37017:27017 --restart=always -v /data/db/conf3:/data/db -d registry.newborn-town.com:5000/mongod-3.2.10 --storageEngine wiredTiger --smallfiles --configsvr --dbpath /data/db --port 27017
mongos进程
172.31.90.39
docker run --name mongos1 -p 27017:27018 --restart=always -v /data/logs/rs1:/data/logs -d registry.newborn-town.com:5000/mongos-3.2.10 --logpath /data/logs/mongos.log --logappend --configdb 172.31.90.39:37017,172.31.90.64:37017,172.31.90.161:37017 --port 27018
172.31.90.64
docker run --name mongos2 -p 27017:27018 --restart=always -v /data/logs/rs2:/data/logs -d registry.newborn-town.com:5000/mongos-3.2.10 --logpath /data/logs/mongos.log --logappend --configdb 172.31.90.39:37017,172.31.90.64:37017,172.31.90.161:37017 --port 27018
172.31.90.161
docker run --name mongos3 -p 27017:27018 --restart=always -v /data/logs/rs3:/data/logs -d registry.newborn-town.com:5000/mongos-3.2.10 --logpath /data/logs/mongos.log --logappend --configdb 172.31.90.39:37017,172.31.90.64:37017,172.31.90.161:37017 --port 27018
以上启动Docker容器步骤,可以通过docker compose来管理。
设置副本集(在mongodb上执行)
172.31.90.39
mongo --port 21117
use admin
config_rs = {
"_id":"rs1",
"members": [
{"_id":0,"host":"172.31.90.39:21117"},
{"_id":1,"host":"172.31.90.64:21117"},
{"_id":2,"host":"172.31.90.161:21117"}
]
}
rs.initiate(config_rs)
172.31.90.64
mongo --port 21217
use admin
config_rs = {
"_id":"rs2",
"members": [
{"_id":0,"host":"172.31.90.39:21217"},
{"_id":1,"host":"172.31.90.64:21217"},
{"_id":2,"host":"172.31.90.161:21217"}
]
}
rs.initiate(config_rs)
172.31.90.161
mongo --port 21317
use admin
config_rs = {
"_id":"rs3",
"members": [
{"_id":0,"host":"172.31.90.39:21317"},
{"_id":1,"host":"172.31.90.64:21317"},
{"_id":2,"host":"172.31.90.161:21317"}
]
}
rs.initiate(config_rs)
设置分片(mongos上执行)
use admin
sh.addShard("rs1/172.31.90.39:21117,172.31.90.64:21117,172.31.90.161:21117")
sh.addShard("rs2/172.31.90.39:21217,172.31.90.64:21217,172.31.90.161:21217")
sh.addShard("rs3/172.31.90.39:21317,172.31.90.64:21317,172.31.90.161:21317")
sh.enableSharding("kittylive")
use kittylive
db.user.createIndex({user_id:"hashed"})
db.bill.createIndex({bill_id:"hashed"})
db.giftRecord.createIndex({gift_id:"hashed"})
sh.shardCollection("kittylive.user",{"user_id":"hashed"})
sh.shardCollection("kittylive.bill",{"bill_id":"hashed"})
sh.shardCollection("kittylive.giftRecord",{"gift_id":"hashed"})
设置块迁移窗口期
use config
db.settings.update({ _id : "balancer" }, { $set : { activeWindow : { start : "22:00", stop : "02:00" } } }, true )
sh.getBalancerWindow()