centos配置mongodb副本集
那什么是副本集呢?打魔兽世界总说打副本,其实这两个概念差不多一个意思。游戏里的副本是指玩家集中在高峰时间去一个场景打怪,会出现玩家暴多怪物少的情况,游戏开发商为了保证玩家的体验度,就为每一批玩家单独开放一个同样的空间同样的数量的怪物,这一个复制的场景就是一个副本,不管有多少个玩家各自在各自的副本里玩不会互相影响。 mongoDB的副本也是这个,主从模式其实就是一个单副本的应用,没有很好的扩展性和容错性。而副本集具有多个副本保证了容错性,就算一个副本挂掉了还有很多副本存在,并且解决了上面第一个问题“主节点挂掉了,整个集群内会自动切换”。难怪mongoDB官方推荐使用这种模式。我们来看看mongoDB副本集的架构图:
由图可以看到客户端连接到整个副本集,不关心具体哪一台机器是否挂掉。主服务器负责整个副本集的读写,副本集定期同步数据备份,一但主节点挂掉,副本节点就会选举一个新的主服务器,这一切对于应用服务器不需要关心。我们看一下主服务器挂掉后的架构:
副本集中的副本节点在主节点挂掉后通过心跳机制检测到后,就会在集群内发起主节点的选举机制,自动选举一位新的主服务器。看起来很牛X的样子,我们赶紧操作部署一下! 官方推荐的副本集机器数量为至少3个,那我们也按照这个数量配置测试。
上面是对副本集的解释,下面开始操作!
首先先去下载一个mongodb,版本选择随意,选择一个稳定版本就行个人推荐3.X.X的版本。
下载地址https://www.mongodb.org/dl/linux/x86_64-amazon
下载 wget http://downloads.mongodb.org/linux/mongodb-linux-x86_64-amazon3.4.7.tgz
解压 tar -zxvf mongodb-linux-x86_64-amazon3.4.7.tgz
文件相关操作自行脑补。。。
最终文件夹(个人习惯)
/home/mongo/bin //mongo文件夹
/home/mongo/data //mongo数据文件夹
/home/mongo/log //mongo日志文件夹
献上一份启动配置文件
port=27017
replSet=mySet
dbpath=/home/mongo/data/
logpath=/home/mongo/log/mongodb.log
logappend=true
directoryperdb=true
journal=true
fork=true
smallfiles=true
maxConns=20000
参数解释:
dbpath:数据存放目录
logpath:日志存放路径
logappend:以追加的方式记录日志
replSet:replica set的名字
port:mongodb进程所使用的端口号,默认为27017
fork:以后台方式运行进程
journal:写日志
smallfiles:当提示空间不够时添加此参数
其他参数
pidfilepath:进程文件,方便停止mongodb
directoryperdb:为每一个数据库按照数据库名建立文件夹存放
bind_ip:mongodb所绑定的ip地址
oplogSize:mongodb操作日志文件的最大大小。单位为Mb,默认为硬盘剩余空间的5%
noprealloc:不预先分配存储
开始配置:
三台机器 192.168.0.2(主),192.168.0.3(从),192.168.0.4(仲裁)
分别在每台机器上启动mongodb
cd /home/mongo/bin
./mongod -f /home/mongo/mongo.conf
*别说找不到配置文件,在上方都看不到,表示你不适合搞这个。
有这样的提示说明启动成功
全部三个服务全部启动成功之后开始配置主(master),备(slaver),仲裁(arbiter)节点
初始化副本集
在三台机器上任意一台机器登陆mongodb
/home/mongo/bin/mongo
#使用admin数据库
use admin
#定义副本集配置变量,这里的 _id:”repset” 和启动参数“ –replSet” 要保持一样。
cfg={ _id:"mySet", members:[ {_id:0,host:'192.168.0.2:27017',priority:2}, {_id:1,host:'192.168.0.3:27017',priority:1},{_id:2,host:'192.168.0.4:27017',arbiterOnly:true}] };
个人比较喜欢的一种方式,权限类型一下搞定。
#初始化副本集配置
rs.initiate(cfg);
#输出成功
{
"info" : "Config now saved locally. Should come online in about a minute.",
"ok" : 1
}
#查看状态
#查看集群节点的状态
rs.status();
#输出
{
"set" : "mySet",
"date" : ISODate("2017-08-30T08:18:59.820Z"),
"myState" : 2,
"term" : NumberLong(7),
"syncingTo" : "172.18.73.13:27017",
"heartbeatIntervalMillis" : NumberLong(2000),
"members" : [
{
"_id" : 0,
"name" : "192.168.0.2:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 23176,
"optime" : {
"ts" : Timestamp(1504081121, 621),
"t" : NumberLong(7)
},
"optimeDate" : ISODate("2017-08-30T08:18:41Z"),
"lastHeartbeat" : ISODate("2017-08-30T08:18:58.394Z"),
"lastHeartbeatRecv" : ISODate("2017-08-30T08:18:58.394Z"),
"pingMs" : NumberLong(0),
"electionTime" : Timestamp(1504056061, 1),
"electionDate" : ISODate("2017-08-30T01:21:01Z"),
"configVersion" : 1
},
{
"_id" : 1,
"name" : "192.168.0.2:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 23176,
"optime" : {
"ts" : Timestamp(1504081139, 620),
"t" : NumberLong(7)
},
"optimeDate" : ISODate("2017-08-30T08:18:59Z"),
"syncingTo" : "172.18.73.13:27017",
"configVersion" : 1,
"self" : true
},
{
"_id" : 2,
"name" : "192.168.0.3:27017",
"health" : 1,
"state" : 7,
"stateStr" : "ARBITER",
"uptime" : 23176,
"lastHeartbeat" : ISODate("2017-08-30T08:18:58.394Z"),
"lastHeartbeatRecv" : ISODate("2017-08-30T08:18:56.260Z"),
"pingMs" : NumberLong(0),
"configVersion" : 1
}
],
"ok" : 1
}
其他操作
增添节点
添加节点,需要在主节点进行
PRIMARY>>rs.add(hostname:port)
删减节点
删减节点,需要在主节点进行
PRIMARY>rs.remove(hostname:port)
设置副本节点可以读
设置节点可读,需要在副本节点进行
SECONDARY> db.getMongo().setSlaveOk();
设置副本节点优先级
设置优先级,需要在主节点进行。通过修改priority的值来实现(默认的优先级是1(0-100),priority的值设的越大,就优先成为主。如果值是0,那么不能成为primay)
PRIMARY> config=rs.conf()
PRIMARY>config.members[3].priority = 3
PRIMARY> rs.reconfig(config)
注意:members大括号里面的成员和_id是没有关系的,而是rs.conf查出来节点的数值的顺序;
相关资料
节点数量
副本集至少需要两个节点,至多12个节点。其中一个是主节点,其余的都是从节点和仲裁节点。具备投票权的节点至多为7个。从节点越多,复制的压力就越大,备份太多反而增加了网络负载和拖慢了集群性能。
MongoDB官方推荐节点数量为奇数。主要在于副本集常常为分布式,可能位于不同的IDC。如果为偶数,可能出现每个IDC的节点数一样,从而如果网络故障,那么每个IDC里的节点都无法选出主节点,导致全部不可用的情况。比如,节点数为4,分处于2个IDC,现在IDC之间的网络出现故障,每个IDC里的节点都没有大于2,所以副本集没有主节点,变成只读。
从节点的类型
Secondary:标准从节点,可复制,可投票,可被选为主节点
Secondary-Only:不能成为主节点,只能作为从节点,防止一些性能不高的节点成为主节点。设置方法是将其priority = 0
Hidden:这类节点是不能够被客户端制定IP引用,也不能被设置为主节点,但是可以投票,一般用于备份数据。
Delayed:可以指定一个时间延迟从primary节点同步数据。主要用于备份数据,如果实时同步,误删除数据马上同步到从节点,恢复又恢复不了。
示例:
cfg= {
"_id" : ,
" host" : ,
" priority" : 0,
"slaveDelay" : ,
" hidden" : true
}
rs.initiate(cfg);
Non-Voting:没有选举权的secondary节点,纯粹的备份数据节点。设置方法是将其votes = 0。之所以设置这种节点,是照顾副本集最多12个节点,但有投票权的节点最多7个节点的要求。
示例:
PRIMARY>cfg = rs.conf()
PRIMARY>cfg.members[3].votes = 0
PRIMARY>cfg.members[4].votes = 0
PRIMARY>cfg.members[5].votes = 0
PRIMARY>rs.reconfig(cfg)
读写分离
从节点默认情况下不能读取,但可以设置此选项:
SECONDARY> db.getMongo().setSlaveOk();
这样,读取部分可以使用这些开启了读取选项的从节点,从而减轻主节点的负荷。
至于写入,永远只有主节点才可以进行。
最终一致性
数据的写入在主节点进行,将操作记录进日志oplog,从节点定期轮询主节点,获取oplog,然后对自己的数据副本执行这些操作,从而保证从节点的数据与主节点一致,因此有一定时间的滞后是必然的,MongoDB追求的是最终一致性。既然“滞后”不可避免,需要做的就是尽可能减小这种滞后,主要涉及到以下几点:
网络延迟:这是所有分布式系统都存在的问题。我们能做的就是尽可能减小副本集节点之间的网络延迟。
磁盘吞吐量:secondary节点上数据刷入磁盘的速度比primary节点上慢的话会导致secondary节点很难跟上primary节点的节奏。
并发:并发大的情况下,primary节点上的一些耗时操作会阻塞secondary节点的复制操作,导致复制操作跟不上主节点的写入负荷。解决方法是通过设置操作的write concern(参看这里:http://docs.mongodb.org/manual/core/write-concern/#replica-set-write-concern)默认的副本集中写入操作只关心primary节点,但是可以指定写入操作同时传播到其他secondary节点,代价就是严重影响集群的并发性。注意:而且这里还存在一个问题如果,如果写入操作关心的某个节点宕机了,那么操作将会一直被阻塞直到节点恢复。
适当的write concern:我们为了提高集群写操作的吞吐量经常会将writer concern设置为unacknowledged write concern,这导致primary节点的写操作很快而secondary节点复制操作跟不上。解决方法和第三点是类似的就是在性能和一致性之间做权衡。
副本集不可用的应对之道
当节点发生故障,或者因为网络原因失联,造成余下的节点小于等于副本集总节点数的一半,那么整个副本集中都不再存在主节点,原来的主节点会降级成为从节点!此时整个副本集呈现只读状态,也即不再可用。
当出现这种瘫痪情况,目前我还没找到将某个从节点切换为主节点的方法,也许本来就不存在这种方法。因为这和MongoDB的Primary选举策略有关:如果情况不是Secondary宕机,而是网络断开,那么可能出现位于不同IDC的节点各自选取自己为Primary。这样在网络恢复后就需要处理复杂的一致性问题。而且断开的时间越长,时间越复杂。所以MongoDB选择的策略是如果集群中存活节点数量不够,则不选取Primary。
所以
1) 一方面要极力避免出现这种存活节点不够半数的情况,在规划副本集的时候就注意:
设置仲裁节点。
节点总数为奇数,且主节点所在的IDC,拥有超过半数的节点数量
2) 注意对节点的备份,必要时可以对节点进行恢复
也可以按照相同配置建立一个全新的从节点,恢复副本集后,系统会自动同步数据。但猜测数据量比较大的情况下,耗时会比较长,所以平时对从节点进行备份,还是有必要。
使用一段时间后的出现的问题:mongo内存占用量!
监控了下mongo使用 内存使用高达87%,搞的其他线程都跑不了。
这里需要限制下mongo的使用。
后来网上找了下,发现cgroup这个东西可以限制内存使用,于是就去找了相关资料,并自己配置试验了下,发现可以,现在线上系统用这个跑了快一周了,暂时没发现什么问题,内存被限制住了。
cgroup是linux内核的一个功能,用于管理系统各种资源,包括cpu、内存等其他资源,个人只看了下内存的使用。可以直接使用cgroup的相关命令配置,也可以使用预先配置cgconfig服务的相关配置文件来管理。
一、安装:
a、cgroup是linux系统的一个内核组件,只需要安装控制接口程序
yum install -y libcgroup
b、启动cgroup的管理程序
service cgconfig start
查看cgconfig是否启动
service cgconfig status
设置开机启动
chkconfig cgconfig on
二、配置:
a、先看cgconfig配置文件:
[root@mongo1 mongodb]# cat /etc/cgconfig.conf
mount {
cpuset = /cgroup/cpuset;
cpu = /cgroup/cpu;
cpuacct = /cgroup/cpuacct;
memory = /cgroup/memory;
devices = /cgroup/devices;
freezer = /cgroup/freezer;
net_cls = /cgroup/net_cls;
blkio = /cgroup/blkio;
}
group DBLimitedGroup {
memory {
memory.limit_in_bytes = "32212254720" ;
}
}
上面配置文件中,mount{...} 这一部分是安装libcgroup后生成的/etc/cgconfig.conf中默认有的,目的是定义各个子系统的挂载点,可以不用管。
为了限制mongodb,这里定义了一个group名字叫做DBLimitedGroup,这个group中定义了对内存memory进行限制,限制的项为memory.limit_in_bytes ,它的值为32212254720(32212254720/1024/1024/1024=30GB),线上服务器是32G的内存,这里设置限制为30G给mongodb。根据自己的情况设置,数值的单位为 byte字节,比如1G=1*1024*1024*1024=1073741824(byte)
b、然后看cgrules.conf
cat /etc/cgrules.conf
# /etc/cgrules.conf
#The format of this file is described in cgrules.conf(5)
#manual page.
#
# Example:
#<user> <controllers> <destination>
#@student cpu,memory usergroup/student/
#peter cpu test1/
#% memory test2/
# End of file
*:mongod memory DBLimitedGroup/
这个cgrules.conf是配置cgexec命令的默认配置,后面会用到cgexec来执行mongod的程序,"#"开头是注释,不用管,看最后一行。
上面的意思为:
* 所有的用户以及用户组
mongod mongod程序名(进程)
memory 使用memory子系统中的配置
DBLimitedGroup cgroup.conf中自定义的group
全部连在一起就是说,执行cgexec时,如果满足“任何用户任何组执行mongod程序,那么被执行的进程(及mongod进程)将满足memory内存子系统中的DBLimitedGroup中的所有限制”
而DBLimitedGroup中的限制就是,限制内存使用为32G。
这样使用cgroup就限制了指定进程(这里是mongod进程)的(物理)内存使用。
配置完成后重新启动cgconfig
service cgconfig restart
三、运行mongodb
cgexec -g memory:DBLimitedGroup /usr/bin/mongod -f /etc/mongodb/shard11.conf
本文参考:
http://blog.csdn.net/leftfist/article/details/39583585
http://www.lanceyan.com/tech/mongodb/mongodb_repset1.html
http://xiaotong.blog.51cto.com/4312502/1783768