MongoDB 集群配置笔记
配置一个含有主从机制、自动分片、去中心化的MongoDB集群
一、配置文件说明
必备的配置项知晓,在命令行启动时只需要指定配置文件地址即可,如:
mongod -port=27017 -f /path/db/conf/mongodb.conf
用这种方式可以减少因命令行启动时参数缺失导致的问题,常用的参数都需要写入配置文件,详细的配置项如下表示:
1.基础参数表
参数名 | 默认值 | 备注 |
---|---|---|
dbpath | /[path] | 数据库路径,不指定则默认在/data/db |
verbose | false | 是否打印详细记录到logpath中,如要启动需指定vvvv参数。默认false |
vvvv | true | 日志级别,vv~vvvvv,v越多越详细 |
port | 27017 | 端口,推荐写到命令行 |
bind_ip | 127.0.0.1 | 绑定的IP,非此IP不可访问。多个用,分隔。绑定的地址并不是客户端的IP而是MongoDB所在的服务器的IP。 |
maxConns | 1000000 | 最大连接数,具体值取决于系统和mongodb版本。 |
objcheck | true | 2.4版后默认为true,开启时保证客户端插入到库中的数据都是有效的,但会降低性能 |
noobjcheck | false | 与objcheck互斥,明示关闭对象校验 |
logappend | true | true表示追加,否则为覆盖 |
syslog | true | 输出到主机的syslog系统而非logpath的路径。syslog与logpath不能一起用 |
pidfilepath | /[path] | 指定PID文件位置 |
keyFile | /[path] | 身份验证的密钥信息文件 |
fork | true | 后台运行,默认true |
auth | false | 开启身份验证,启动时应增加账号、密码、目标库。如:mongo -utest -ppwd test,表示test用户用pwd密码登录test库。默认false |
noauth | true | 不认证用户 |
cpu | false | true会强制每4秒记录一次CPU利用率和IO等待并写到日志 |
dbpath | /[path] | 指定数据库位置,必要项 |
dialog | 0 | 输出错误日志到dialog.*文件,0=关闭、1=写操作、2=读操作、3=读写、7=写+部分读 |
directoryperdb | false | 如果开启则将数据存到不同的磁盘上以提高读写速度,需要在第一次启动前就要确认此值。否则一旦改变会导致数据丢失(改回去可恢复)。 |
journal | 64bit=true,32bit=false | 是否启用确保一致性的操作日志 |
nojournal | true | 关闭操作日志,64位系统需要强制开启 |
journalCommitInterval | 100 | 写刷新间隔,默认100毫秒。数值越小越影响IO,取值范围2-300. |
ipv6 | false | 开启ipv6支持,默认false |
jsonp | false | 是否允许jsonp方位http接口 |
nohttpinterface | false | 是否禁止http接口,即28017端口服务。默认比port大1000 |
noprealloc | false | 如果是写频繁的系统开启的话会提升性能。开启时会在后台提前分配一定空间(0填充)来降低动态分配导致的低效率问题,但启动时会慢点。 |
noscripting | false | 关闭脚本引擎,默认false |
notablescan | false | 禁止全表扫描,开启时会提示”table scans not allow” |
nssize | 16 | 块大小,16M(默认)-2G |
profile | 0 | 数据库分析等级。0=关、1=慢操作、2=所有操作 |
slowms | 200 | 慢查询的时间,默认200ms |
quota | false | 是否限制库文件数 |
quotaFiles | 8 | quota开启时,此值表示最大库文件数 |
rest | false | 开启RESTful API。开启时将启用一个比port大1000端口的服务,可以查询数据。 |
repair | false | 默认false,修复数据库。此值应该在命令行明示,修复是需要关闭journal。 |
repairpath | _tmp | 修复路径,默认在dbpath下 |
smallfiles | false | 启用小文件模式,开启时最大为512M的块文件。太小会影响IO。默认false |
sysinfo | false | 开启时启动mongod会显示系统信息而不是启动mongodb,应该在命令行用 |
traceExceptions | false | 启动内部诊断,默认false |
quiet | false | 安静模式,命令行用。默认false |
2.复制项(Replication)
参数名 | 默认值 | 备注 |
---|---|---|
replSet | – | 命令行参数,启用时表示要复制副本集。副本名[/主机地址:端口] |
fastsync | false | 副本集下设置true将通过快照同步 |
replIndexPrefetch | all | 默认all、none、id_only,只能在副本集(replSet)中使用。默认情况下,secondary副本集的成员将加载所有索引到内存中(从OPLOG之前的操作有关的)。您可以修改此行为,使secondary只会加载_id索引。指定id或none,防止mongod的任何索引加载到内存。 |
3.主从复制(Replica set options)
参数名 | 默认值 | 备注 |
---|---|---|
master | true | 表示此节点为master,应该命令行用 |
slave | true | 表示此节点为slave,应该在命令行用,需要指定source |
source | host:port | 从节点是,表示其主节点,即从此节点复制数据 |
only | xxx | 只复制此指定数据库,默认空 |
slavedelay | 0 | 用于从库,指定其与主库复制数据的间隔,秒计。默认0 |
autoresync | false | 从库配置,true表示自动同步,如落后主超过10秒则强制同步。 |
4.分片(Shard options)
参数名 | 默认值 | 备注 |
---|---|---|
configsvr | false | 表示此节点为配置库,默认端口27019,默认目录/data/configdb。应该在命令行使用 |
shardsvr | false | 表示为分片节点,默认端口27018 |
二、主从配置流程(Master & Slave)
主从配置有如下优点:
大数据量,可以通过廉价服务器存储大量的数据,轻松摆脱传统mysql单表存储量级限制。
高扩展性,Nosql去掉了关系数据库的关系型特性,很容易横向扩展,摆脱了以往老是纵向扩展的诟病。
高性能,Nosql通过简单的key-value方式获取数据,非常快速。还有NoSQL的Cache是记录级的,是一种细粒度的Cache,所以NoSQL在这个层面上来说就要性能高很多。
灵活的数据模型,NoSQL无需事先为要存储的数据建立字段,随时可以存储自定义的数据格式。而在关系数据库里,增删字段是一件非常麻烦的事情。如果是非常大数据量的表,增加字段简直就是一个噩梦。
高可用,NoSQL在不太影响性能的情况,就可以方便的实现高可用的架构。比如mongodb通过mongos、mongo分片就可以快速配置出高可用配置。
此处在明文写到命令行参数,这样便于确认进程。假设目录放到了 /data/db/ 下
- 启动进程
# master的mongod.conf配置
master=true
logpath=/data/db/mongodbMaster/logs/mongod.log
logappend=true
fork=true
port=27017
dbpath=/data/db/mongodbMaster/data/
pidfilepath=/data/db/mongodbMaster/conf/mongod.pid
bind_ip=127.0.0.1
noauth=true
directoryperdb=true
# 主节点增加master参数
mongod -f /data/db/mongodbMaster/conf/mongod.conf --master --port=27017
# slave的mongod.conf配置
slave=true
source=127.0.0.1:27017
logpath=/data/db/mongodbSlave/logs/mongod.log
logappend=true
fork=true
port=27018
dbpath=/data/db/mongodbMaster/data/
pidfilepath=/data/db/mongodbSlave/conf/mongod.pid
bind_ip=127.0.0.1
noauth=true
directoryperdb=true
# slave 增加slave参数外,还需要指定source
mongod -f /data/db/mongodbSlave/conf/mongod.conf --slave --source 127.0.0.1:27017
登录到slave后输入 db.printReplicationInfo();查看
> db.printReplicationInfo();
this is a slave, printing slave replication info.
source: 127.0.0.1:27017
syncedTo: Fri Mar 09 2018 08:41:41 GMT-0800 (PST)
3 secs (0 hrs) behind the freshest member (no primary available at the moment)
>
- 初始化集群
登录任意主机执行如下配置
use admin
config = {
"_id":"bsbgpsrs",
"members":[
{"_id":0,"host":"192.168.198.224:27017"},
{"_id":1,"host":"192.168.198.225:27017"},
{"_id":2,"host":"192.168.198.226:27017",arbiterOnly:true}
]
}
rs.initiate(config); # 初始化配置
- 通过实例查看主从是否可用
# master上插入数据
use test
db.test.insert({"name":"master1"});
直接在从库上查看数据时会报错
show dbs;
2018-03-09T07:45:34.493-0800 E QUERY [thread1] Error: listCollections failed: {
"ok" : 0,
"errmsg" : "not master and slaveOk=false",
"code" : 13435,
"codeName" : "NotMasterNoSlaveOk"
} ...
db.mydata.insert({"name":"im slave"});
WriteResult({ "writeError" : { "code" : 10107, "errmsg" : "not master" } })
==原因 mongoDB默认由master读取数据,因此不能直接从slave读取数据。需要设置slave状态==
# 查询前执行此操作即可
db.getMongo().setSlaveOk();
# 执行查询
use test
db.test.find();
{ "_id" : ObjectId("5aa2abeb37bdc4baca1798a0"), "name" : "master1" }
可以看到从库上已经有了数据
- 主从切换试验
如果有必要增加以下参数来设置同步规则
--slavedelay 10 #延时复制 单位为秒
--autoresync #自动重新同步
--only #复制指定的数据库,默认复制所有的库
--oplogSize #主节点的oplog日志大小,单位为M,建议设大点(更改oplog大小时,只需停主库,删除local.*,然后加--oplogSize=* 重新启动即可,*代表大小)
如果不能同步,可以手动试下
db.runCommand({"resync":1})
在slave上执行如下命令可以查看状态
db.runCommand({"isMaster":1})
{
"ismaster" : false,
"maxBsonObjectSize" : 16777216,
"maxMessageSizeBytes" : 48000000,
"maxWriteBatchSize" : 1000,
"localTime" : ISODate("2018-03-09T16:58:32.845Z"),
"maxWireVersion" : 5,
"minWireVersion" : 0,
"readOnly" : false,
"ok" : 1
}
查看从服指向的主服状态(数据源)
> use local
switched to db local
> db.sources.find();
{ "_id" : ObjectId("5aa2b9250eedef392722326e"), "host" : "127.0.0.1:27017", "source" : "main", "syncedTo" : Timestamp(1520614901, 1) }
# 动态增加一个
db.sources.insert({"host": "10.0.0.11:27001"});
# 移除它
db.sources.remove({"host": "10.0.0.11:27001"});
查看主从复制状态
db.printReplicationInfo();
==后记:目前这种方式还不能实现自动主挂切从==
Replica Set集群模式
多机热备构成的集群的解决了其中一台挂掉后,系统自动切换到另一台从而保证服务可用。根据需求预先设定最少3台机器:
- 主节点:承担所有CRUD操作
- 备节点:承担查询的任务,主节点不可用时切换成主节点
- 仲裁节点:无业务任务,仅承担投票选举主节点的功能
准备三份配置,简单如下:
- 配置并启动集群
# 主及节点
dbpath=/data/db/mongodbMaster/data
logpath=/data/db/mongodbMaster/logs/mongod.log
port=27017
fork=true
#这里指定了备机的位置
replSet=mtest/127.0.0.1:27018
# 备节点
dbpath=/data/db/mongodbSlave/data
logpath=/data/db/mongodbSlave/logs/mongod.log
port=27018
fork=true
#这里指定了主机的位置
replSet=mtest/127.0.0.1:27017
# 仲裁节点
dbpath=/data/db/mongodbArbiter/data
logpath=/data/db/mongodbArbiter/logs/mongod.log
port=27018
fork=true
#这里指定了主机的位置
replSet=mtest/127.0.0.1:27017
- 配置关系节点,用mongo连接到任意节点后执行如下命令
cfg={
_id:"mtest",
members:[
{
_id:0,
host:'127.0.0.1:27017',priority:2
}, {
_id:1,
host:'127.0.0.1:27018',priority:1
}, {
_id:2,host:'127.0.0.1:27019',arbiterOnly:true}
] };
rs.initiate(cfg);
# priority:优先级,越高越先成为主节点。0时不会参选
# arbiterOnly: true表示仲裁节点
# 执行成功时返回
{ "ok" : 1 }
# 如果其中备份节点有数据会造成启动失败并提示
{
"ok" : 0,
"errmsg" : "'127.0.0.1:27018' has data already, cannot initiate set.",
"code" : 110,
"codeName" : "CannotInitializeNodeWithData"
}
# 此时删掉备份节点的data再次执行即可
注意,一旦配置成功你会发现提示符变成了 mtest:PRIMARY>,对应的27018节点为mtest:SECONDARY> 、27019节点为mtest:ARBITER>
# 查询状态
rs.status();
{
"set" : "mtest",
"date" : ISODate("2018-03-09T18:25:20.896Z"),
"myState" : 1,
"term" : NumberLong(1),
"heartbeatIntervalMillis" : NumberLong(2000),
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1520619920, 1),
"t" : NumberLong(1)
},
"appliedOpTime" : {
"ts" : Timestamp(1520619920, 1),
"t" : NumberLong(1)
},
"durableOpTime" : {
"ts" : Timestamp(1520619920, 1),
"t" : NumberLong(1)
}
},
"members" : [
{
"_id" : 0,
"name" : "127.0.0.1:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 2491,
"optime" : {
"ts" : Timestamp(1520619920, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2018-03-09T18:25:20Z"),
"electionTime" : Timestamp(1520619569, 1),
"electionDate" : ISODate("2018-03-09T18:19:29Z"),
"configVersion" : 1,
"self" : true
},
{
"_id" : 1,
"name" : "127.0.0.1:27018",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 362,
"optime" : {
"ts" : Timestamp(1520619910, 1),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Timestamp(1520619910, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2018-03-09T18:25:10Z"),
"optimeDurableDate" : ISODate("2018-03-09T18:25:10Z"),
"lastHeartbeat" : ISODate("2018-03-09T18:25:19.307Z"),
"lastHeartbeatRecv" : ISODate("2018-03-09T18:25:19.607Z"),
"pingMs" : NumberLong(0),
"syncingTo" : "127.0.0.1:27017",
"configVersion" : 1
},
{
"_id" : 2,
"name" : "127.0.0.1:27019",
"health" : 1,
"state" : 7,
"stateStr" : "ARBITER",
"uptime" : 362,
"lastHeartbeat" : ISODate("2018-03-09T18:25:19.307Z"),
"lastHeartbeatRecv" : ISODate("2018-03-09T18:25:20.234Z"),
"pingMs" : NumberLong(0),
"configVersion" : 1
}
],
"ok" : 1
}
注意看,member中的项目有个stateStr字段表示节点角色,其值为
- PRIMARY: 表示主节点
- SECONDARY: 表示从节点
- ARBITER: 表示仲裁节点
接下来杀掉主服,看看备份节点是否会自动切换到主节点
kill -9 PRIMARY_PID
来到从节点执行
rs.status();
# 可以看到提示符变成 mtest:PRIMARY>
#
...
{
"_id" : 1,
"name" : "127.0.0.1:27018",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 922,
"optime" : {
"ts" : Timestamp(1520620472, 1),
"t" : NumberLong(2)
},
"optimeDate" : ISODate("2018-03-09T18:34:32Z"),
"infoMessage" : "could not find member to sync from",
"electionTime" : Timestamp(1520620450, 1),
"electionDate" : ISODate("2018-03-09T18:34:10Z"),
"configVersion" : 1,
"self" : true
},
...
# 在从节点执行如下命令即可实现从节点的读取
db.getMongo().setSlaveOk();
# Arbiter上执行查询时会返回
Error: error: {
"ok" : 0,
"errmsg" : "node is not in primary or recovering state",
"code" : 13436,
"codeName" : "NotMasterOrSecondary"
}
# 即便是setSlaveOk()了也不成
如果后原主机27017恢复后仍然会是PRIMARY节点。
Replica 模式总结
- PRIMARY只有一个,它负责读写。只有它挂掉时才会选举新的PRIMARY。
- SECONDARY在成为PRIMARY时会异步复制Oplog中的记录,这会导致数据并不是最新的
- ARBITER只会投票并无数据需求,配置可以低点
- priority=0时表示此节点仅作备份节点
- 为了分担PRIMARY的读压力应该开启从SECONDARY读的,开启slave读的另一种办法是
# 修改/root/.mongorc.js,并加入
rs.slaveOk();
注意这个文件是隐藏的需要用ls -a查看,此方法仅适用于命令行