复制概述
复制就是在多台服务器上分布并管理数据库服务器。MongoDB提供了两种复制风格:主从复制和副本集。两种方式都是在一个主节点进行写操作(写入的数据被异步地同步到所有的从节点上),并从节点上读取数据。
所有数据库都对其运行环境中的故障很敏感,而复制提供了一种抵御故障的机制。
主从配置
配置主从复制注意点
- 在数据库集群中要明确的知道谁是主服务器,主服务器只有一台;
- 从服务器要知道自己的数据源也就是对应的主服务器是谁;
- master用来确定主服务器,slave和source来控制从服务器。
机器环境
192.168.160.145 master node
192.168.160.146 slave node
主节点配置
master.conf
#data file directory
dbpath=/home/soft/mongodb/data
# log file directory
logpath=/home/soft/mongodb/logs/mongodb.log
#port
port=26016
#daemon process
fork=true
#log type of output
logappend=true
#pid file
pidfilepath=/home/soft/mongodb/bin/mongo.pid
软链接使命令全局可用
ln -s /home/soft/mongodb/bin/mongod /usr/bin/mongod
ln -s /home/soft/mongodb/bin/mongo /usr/bin/mongo
启动mongodb master
mongod -f master.conf
启动报错
about to fork child process, waiting until server is ready for connections.
forked process: 31619
ERROR: child process failed, exited with error number 1
怀疑是配置文件中数据和日志目录未创建
mkdir /home/soft/mongodb/data
mkdir /home/soft/mongodb/logs
touch /home/soft/mongodb/logs/mongodb.log
创建目录后,再次执行启动命令,启动结果如下:
about to fork child process, waiting until server is ready for connections.
forked process: 31678
child process started successfully, parent exiting
说明启动成功
启动mongo并创建用户
mongo --port=26016
use admin;
db.createUser({user: 'root', pwd:'root', roles:[{role: '__system', db: 'admin'}]});
结果:
Successfully added user: {
"user" : "root",
"roles" : [
{
"role" : "__system",
"db" : "admin"
}
]
}
查看新建用户:
show users;
结果:
{
"_id" : "admin.root",
"user" : "root",
"db" : "admin",
"roles" : [
{
"role" : "__system",
"db" : "admin"
}
]
}
或使用db.system.users.find()查看用户。
slave节点配置步骤同上。
认证配置
生成密钥文件mongo_key
openssl rand -base64 1024 >> mongo_key
chmod 700 mongo_key
修改master.conf并重新启动
#data file directory
dbpath=/home/soft/mongodb/data
# log file directory
logpath=/home/soft/mongodb/logs/mongodb.log
#port
port=26016
#daemon process
fork=true
#log type of output
logappend=true
#pid file
pidfilepath=/home/soft/mongodb/mongodb/bin/mongo.pid
journal=true
# authentication
auth=true
#key file
keyFile=/home/soft/mongodb/mongodb/mongo_key
#master node
master=true
#set oplog size(MB)
oplogSize=1024
关掉mongodb进程时不要使用kill -9 pid,这种方式杀掉进程会导致错误,即使mongod --repair也无法恢复。应使用killall mongod关闭mongodb进程。
启动过程报错
Unable to lock file mongod.lock
2018-11-08T22:46:54.594-0800 I STORAGE [initandlisten] exception in initAndListen: 98 Unable to lock file: /home/soft/mongodb/data/mongod.lock Resource temporarily unavailable. Is a mongod instance already running?, terminating
2018-11-08T22:46:54.594-0800 I NETWORK [initandlisten] shutdown: going to close listening sockets...
2018-11-08T22:46:54.594-0800 I NETWORK [initandlisten] shutdown: going to flush diaglog...
2018-11-08T22:46:54.594-0800 I CONTROL [initandlisten] now exiting
2018-11-08T22:46:54.594-0800 I CONTROL [initandlisten] shutting down with code:100
解决方法:
删除data目录下的mongod.lock
addr already in use
2018-11-08T22:53:30.757-0800 E NETWORK [initandlisten] listen(): bind() failed Address already in use for socket: 0.0.0.0:26016
2018-11-08T22:53:30.757-0800 E NETWORK [initandlisten] addr already in use
解决方法
杀掉mongodb进程,重新启动
若执行上述方法仍报错,可查询占用端口的进程,杀掉即可。
lsof -i:26016
占用端口的进程如下:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
mongod 31678 root 7u IPv4 62742 0t0 TCP *:26016 (LISTEN)
杀掉进程:
kill -9 31678
再次启动,无错误。
修改slave.conf并重新启动
#data file directory
dbpath=/home/soft/mongodb/data
# log file directory
logpath=/home/soft/mongodb/logs/mongodb.log
#port
port=26016
#daemon process
fork=true
#log type of output
logappend=true
#pid file
pidfilepath=/home/soft/mongodb/bin/mongo.pid
# authentication
auth=true
#key file
keyFile=/home/soft/mongodb/mongo_key
#slave node
slave=true
#replication source
source=192.168.160.145:26016
#add global lock when slave have much to replicate
autoresync=true
oplogSize=1024
需配置source指定复制源,slave=true设置为从节点
查看数据库时出错 not master and slaveOk=false
2018-11-08T23:12:26.598-0800 E QUERY [thread1] Error: listDatabases failed:{
"ok" : 0,
"errmsg" : "not master and slaveOk=false",
"code" : 13435,
"codeName" : "NotMasterNoSlaveOk"
}
输入如下命令,重新执行即可:
rs.slaveOk();
测试
在主节点新建数据库,从节点查看是否复制
> show dbs;
admin 0.000GB
datavisual 0.197GB
local 0.000GB
多了datavisual,数据库复制成功.
admin和local中数据不会被复制。
查看日志有如下输出,说明一直在请求主节点进行数据复制。
2018-11-08T23:07:17.297-0800 I REPL [replslave] syncing from host:192.168.160.145:26016
2018-11-08T23:07:18.299-0800 I REPL [replslave] syncing from host:192.168.160.145:26016
2018-11-08T23:07:19.302-0800 I REPL [replslave] syncing from host:192.168.160.145:26016
2018-11-08T23:07:20.303-0800 I REPL [replslave] syncing from host:192.168.160.145:26016
2018-11-08T23:07:22.292-0800 I REPL [replslave] syncing from host:192.168.160.145:26016
2018-11-08T23:07:23.295-0800 I REPL [replslave] syncing from host:192.168.160.145:26016
日志文件一直在写入。
主从架构面临的问题
a. 如果读写都是对主节点的操作,会导致主节点压力过大;
b. 如果主节点挂掉,架构失效;
c. 如果多个从节点从主节点复制数据,主节点压力过大。
主从复制,主节点挂掉后从节点不会自动提升为主节点,需手动配置;可设置从节点读取数据,减轻主节点压力。
其他
关于oplog
oplog是MongoDB复制的关键。oplog是一个固定集合,位于每个复制节点的local数据库里,记录了所有对数据的变更。每次客户端向主节点写入数据,就会自动向主节点的oplog里添加一个条目,其中包含了足够的信息来再现数据。一旦写操作被复制到某个从节点上,从节点的oplog也会保存一条关于写入的记录。每个oplog条目都由一个BSON时间戳进行标识,所有从节点都使用这个时间戳来追踪它们最后应用的条目。
调整复制OPLOG大小
因为oplog是一个固定集合,所以一旦创建就无法重新设置大小,为此要慎重选择初始oplog大小。
默认的oplog大小会随着环境发生变化。在32位系统上,oplog默认是50MB,而在64位系统上,oplog会增大到1GB或空余磁盘空间的5%。对于多数部署环境,空余磁盘空间的5%绰绰有余。对于这种尺寸的oplog,要意识到一旦重写20次,磁盘可能就满了。
因此默认大小并非适用于所有应用程序。如果知道应用程序写入量会很大,在部署之前应该做些测试。配置好复制,然后以生产环境的写入量向主节点发起写操作,像这样对服务器施压起码一小时。完成之后,连接到任意副本集成员上,获取当前复制信息:
db.getReplicationInfo();
一旦了解了每小时会生成多少oplog,就能决定分配多少oplog空间了。你应该为从节点下线八小时做好准备。发生网络故障或类似事件时,要避免任意节点重新同步完整数据,增加oplog大小能为你争取更多事件。
如果要改变默认oplog大小,必须在每个成员节点首次启动时使用mongod的--oplogSize选项,其值的单位是兆。
读扩展
经复制的数据库能很好地适用于读扩展。如果单台服务器无法承担应用程序的读负载,那么可以将查询路由到更多的副本上。大多数驱动都内置了将查询发送到从节点的功能。