1)机器环境
182.48.115.236 master-node(主节点)
182.48.115.237 slave-node1(从节点)
182.48.115.238 slave-node2(从节点)
MongoDB 安装目录: /usr/local/mongodb
MongoDB 数据库目录: /usr/local/mongodb/data
MongoDB 日志目录: /usr/local/mongodb/log/mongo .log
MongoDB 配置文件: /usr/local/mongodb/mongodb .conf
mongodb安装可以参考:http: //www .cnblogs.com /kevingrace/p/5752382 .html
对以上三台服务器部署Mongodb的副本集功能,定义副本集名称为:hqmongodb
关闭三台服务器的iptables防火墙和selinux
2)确保三台副本集服务器上的配置文件完全相同(即三台机器的mongodb.conf配置一样,除了配置文件中绑定的ip不一样)。下面操作在三台节点机上都要执行:
编写配置文件
[[email protected] ~] # cat /usr/local/mongodb/mongodb.conf
port=27017
bind_ip = 182.48.115.236 // 这个最好配置成本机的ip地址。否则后面进行副本集初始化的时候可能会失败!
dbpath= /usr/local/mongodb/data
logpath= /usr/local/mongodb/log/mongo .log
pidfilepath= /usr/local/mongodb/mongo .pid
fork= true
logappend= true
shardsvr= true
directoryperdb= true
#auth=true
#keyFile =/usr/local/mongodb/keyfile
replSet =hqmongodb
编写启动脚本(各个节点需要将脚本中的ip改为本机自己的ip地址)
[[email protected] ~] # cat /usr/local/mongodb/mongodb.conf
port=27017
dbpath= /usr/local/mongodb/data
logpath= /usr/local/mongodb/log/mongo .log
pidfilepath= /usr/local/mongodb/mongo .pid
fork= true
logappend= true
shardsvr= true
directoryperdb= true
#auth=true
#keyFile =/usr/local/mongodb/keyfile
replSet =hqmongodb
[[email protected] ~] # cat /etc/init.d/mongodb
#!/bin/sh
# chkconfig: - 64 36
# description:mongod
case $1 in
start)
/usr/local/mongodb/bin/mongod --maxConns 20000 --config /usr/local/mongodb/mongodb .conf
;;
stop)
/usr/local/mongodb/bin/mongo 182.48.115.236:27017 /admin -- eval "db.shutdownServer()"
#/usr/local/mongodb/bin/mongo 182.48.115.236:27017/admin --eval "db.auth(‘system‘, ‘123456‘);db.shutdownServer()"
;;
status)
/usr/local/mongodb/bin/mongo 182.48.115.236:27017 /admin -- eval "db.stats()"
#/usr/local/mongodb/bin/mongo 182.48.115.236:27017/admin --eval "db.auth(‘system‘, ‘123456‘);db.stats()"
;; esac
启动mongodb
[[email protected] ~] # ulimit -SHn 655350
[[email protected] ~] # /etc/init.d/mongodb start
about to fork child process, waiting until server is ready for connections.
forked process: 28211
child process started successfully, parent exiting
[[email protected] ~] # ps -ef|grep mongodb
root 28211 1 2 00:30 ? 00:00:00 /usr/local/mongodb/bin/mongod --maxConns 20000 --config /usr/local/mongodb/mongodb .conf
root 28237 27994 0 00:30 pts /2 00:00:00 grep mongodb
[[email protected] ~] # lsof -i:27017
COMMAND PID USER FD TYPE DEVICE SIZE /OFF NODE NAME
mongod 28211 root 7u IPv4 684206 0t0 TCP *:27017 (LISTEN)
------------------------------------------------------------------
如果启动mongodb的时候报错如下:
about to fork child process, waiting until server is ready for connections.
forked process: 14229
ERROR: child process failed, exited with error number 100
这算是一个Mongod 启动的一个常见错误,非法关闭的时候,lock 文件没有干掉,第二次启动的时候检查到有lock 文件的时候,就报这个错误了。
解决方法:进入mongod启动时指定的data目录下删除lock文件,然后执行 "./mongod --repair" 就行了。即
# rm -rf /usr/local/mongodb/data/mongod.lock //由于我的测试环境下没有数据,我将data数据目录下的文件全部清空,然后--repair
# /usr/local/mongodb/bin/mongod --repair
然后再启动mongodb就ok了!
------------------------------------------------------------------
3)对master-node主节点进行配置(182.48.115.236) // 其实,刚开始这三个节点中的任何一个都可以用来初始化为开始的主节点。这里选择以master-node为主节点
[[email protected] ~] # mongo 182.48.115.236:27017 //登陆到mongodb数据库中执行下面命令操作。由于配置文件中绑定了ip,所以要用这个绑定的ip登陆
....
3.1)初始化副本集,设置本机为主节点 PRIMARY
> rs.initiate()
{
"info2" : "no configuration specified. Using a default configuration for the set" ,
"me" : "182.48.115.236:27017" ,
"ok" : 1
}
hqmongodb:OTHER> rs.conf()
{
"_id" : "hqmongodb" ,
"version" : 1,
"protocolVersion" : NumberLong(1),
"members" : [
{
"_id" : 0,
"host" : "182.48.115.236:27017" ,
"arbiterOnly" : false ,
"buildIndexes" : true ,
"hidden" : false ,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
}
],
"settings" : {
"chainingAllowed" : true ,
"heartbeatIntervalMillis" : 2000,
"heartbeatTimeoutSecs" : 10,
"electionTimeoutMillis" : 10000,
"catchUpTimeoutMillis" : 2000,
"getLastErrorModes" : {
},
"getLastErrorDefaults" : {
"w" : 1,
"wtimeout" : 0
},
"replicaSetId" : ObjectId( "5932f142a55dc83eca86ea86" )
}
}
3.2)添加副本集从节点。(发现在执行上面的两个命令后,前缀已经改成 "hqmongodb:PRIMARY" 了,即已经将其自己设置为主节点 PRIMARY了)
hqmongodb:PRIMARY> rs.add( "182.48.115.237:27017" )
{ "ok" : 1 }
hqmongodb:PRIMARY> rs.add( "182.48.115.238:27017" )
{ "ok" : 1 }
3.3)设置节点优先级
hqmongodb:PRIMARY> cfg = rs.conf() // 查看节点顺序
{
"_id" : "hqmongodb" ,
"version" : 3,
"protocolVersion" : NumberLong(1),
"members" : [
{
"_id" : 0,
"host" : "182.48.115.236:27017" ,
"arbiterOnly" : false ,
"buildIndexes" : true ,
"hidden" : false ,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 1,
"host" : "182.48.115.237:27017" ,
"arbiterOnly" : false ,
"buildIndexes" : true ,
"hidden" : false ,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 2,
"host" : "182.48.115.238:27017" ,
"arbiterOnly" : false ,
"buildIndexes" : true ,
"hidden" : false ,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
}
],
"settings" : {
"chainingAllowed" : true ,
"heartbeatIntervalMillis" : 2000,
"heartbeatTimeoutSecs" : 10,
"electionTimeoutMillis" : 10000,
"catchUpTimeoutMillis" : 2000,
"getLastErrorModes" : {
},
"getLastErrorDefaults" : {
"w" : 1,
"wtimeout" : 0
},
"replicaSetId" : ObjectId( "5932f142a55dc83eca86ea86" )
}
}
hqmongodb:PRIMARY> cfg.members[0].priority = 1
1
hqmongodb:PRIMARY> cfg.members[1].priority = 1
1
hqmongodb:PRIMARY> cfg.members[2].priority = 2 // 设置_ID 为 2 的节点为主节点。即当当前主节点发生故障时,该节点就会转变为主节点接管服务
2
hqmongodb:PRIMARY> rs.reconfig(cfg) // 使配置生效
{ "ok" : 1 }
说明:
MongoDB副本集通过设置priority 决定优先级,默认优先级为1,priority值是0到100之间的数字,数字越大优先级越高,priority=0,则此节点永远不能成为主节点 primay。
cfg.members[0].priority =1 参数,中括号里的数字是执行rs.conf()查看到的节点顺序, 第一个节点是0,第二个节点是 1,第三个节点是 2,以此类推。优先级最高的那个
被设置为主节点。
4)分别对两台从节点进行配置
slave-node1节点操作(182.48.115.237)
[[email protected] ~] # mongo 182.48.115.237:27017
.....
hqmongodb:SECONDARY> db.getMongo().setSlaveOk() // 设置从节点为只读.注意从节点的前缀现在是SECONDARY。看清楚才设置
slave-node2节点操作(182.48.115.238)
[[email protected] ~] # mongo 182.48.115.238:27017
......
hqmongodb:SECONDARY> db.getMongo().setSlaveOk() // 从节点的前缀是SECONDARY,看清楚才设置。执行这个,否则后续从节点同步数据时会报错: "errmsg" : "not master and slaveOk=false" ,
5)设置数据库账号,开启登录验证(这一步可以直接跳过,即不开启登陆验证,只是为了安全着想)
5.1)设置数据库账号
在master-node主节点服务器182.48.115.236上面操作
[[email protected] ] # mongo 182.48.115.236:27017
......
-------------------------------------------------
如果执行命令后出现报错: "errmsg" : "not master and slaveOk=false" ,
这是正常的,因为SECONDARY是不允许读写的,如果非要解决,方法如下:
> rs.slaveOk(); // 执行这个命令然后,再执行其它命令就不会出现这个报错了
-------------------------------------------------
hqmongodb:PRIMARY> show dbs
local 0.000GB
hqmongodb:PRIMARY> use admin //mongodb3 .0没有admin数据库了,需要手动创建。admin库下添加的账号才是管理员账号
switched to db admin
hqmongodb:PRIMARY> show collections
#添加两个管理员账号,一个系统管理员:system 一个数据库管理员:administrator
#先添加系统管理员账号,用来管理用户
hqmongodb:PRIMARY> db.createUser({user: "system" , pwd : "123456" ,roles:[{role: "root" ,db: "admin" }]})
Successfully added user: {
"user" : "system" ,
"roles" : [
{
"role" : "root" ,
"db" : "admin"
}
]
}
hqmongodb:PRIMARY> db.auth( ‘system‘ , ‘123456‘ ) // 添加管理员用户认证,认证之后才能管理所有数据库
1
#添加数据库管理员,用来管理所有数据库
hqmongodb:PRIMARY> db.createUser({user: ‘administrator‘ , pwd : ‘123456‘ , roles:[{ role: "userAdminAnyDatabase" , db: "admin" }]});
Successfully added user: {
"user" : "administrator" ,
"roles" : [
{
"role" : "userAdminAnyDatabase" ,
"db" : "admin"
}
]
}
hqmongodb:PRIMARY> db.auth( ‘administrator‘ , ‘123456‘ ) // 添加管理员用户认证,认证之后才能管理所有数据库
1
hqmongodb:PRIMARY> db
admin
hqmongodb:PRIMARY> show collections
system. users
system.version
hqmongodb:PRIMARY> db.system. users . find ()
{ "_id" : "admin.system" , "user" : "system" , "db" : "admin" , "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "uTGH9NI6fVUFXd2u7vu3Pw==" , "storedKey" : "qJBR7dlqj3IgnWpVbbqBsqo6ECs=" , "serverKey" : "pTQhfZohNh760BED7Zn1Vbety4k=" } }, "roles" : [ { "role" : "root" , "db" : "admin" } ] }
{ "_id" : "admin.administrator" , "user" : "administrator" , "db" : "admin" , "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "zJ3IIgYCe4IjZm0twWnK2Q==" , "storedKey" : "2UCFc7KK1k5e4BgWbkTKGeuOVB4=" , "serverKey" : "eYHK/pBpf8ntrER1A8fiI+GikBY=" } }, "roles" : [ { "role" : "userAdminAnyDatabase" , "db" : "admin" } ] }
退出,用刚才创建的账号进行登录
[[email protected] ~] # mongo 182.48.115.236:27017 -u system -p 123456 --authenticationDatabase admin
[[email protected] ~] # mongo 182.48.115.236:27017 -u administrator -p 123456 --authenticationDatabase admin
5.2)开启登录验证
在master-node主节点服务器182.48.115.236上面操作
[[email protected] ~] # cd /usr/local/mongodb/ //切换到mongodb主目录
[[email protected] mongodb] # openssl rand -base64 21 > keyfile //创建一个 keyfile(使用 openssl 生成 21 位 base64 加密的字符串)
[[email protected] mongodb] # chmod 600 /usr/local/mongodb/keyfile
[[email protected] mongodb] # cat /usr/local/mongodb/keyfile //查看刚才生成的字符串,做记录,后面要用到
RavtXslz /WTDwwW2JiNvK4OBVKxU
注意:上面的数字 21,最好是 3 的倍数,否则生成的字符串可能含有非法字符,认证失败。
5.3)设置配置文件
分别在所有节点上面操作(即三个节点的配置文件上都要修改)
[[email protected] ~] # vim /usr/local/mongodb/mongodb.conf //添加下面两行内容
......
auth= true
keyFile = /usr/local/mongodb/keyfile
启动脚本使用下面的代码(注释原来的,启用之前注释掉的)
[[email protected] ~] # cat /etc/init.d/mongodb
#!/bin/sh
# chkconfig: - 64 36
# description:mongod
case $1 in
start)
/usr/local/mongodb/bin/mongod --maxConns 20000 --config /usr/local/mongodb/mongodb .conf
;;
stop)
#/usr/local/mongodb/bin/mongo 182.48.115.236:27017/admin --eval "db.shutdownServer()"
/usr/local/mongodb/bin/mongo 182.48.115.236:27017 /admin -- eval "db.auth(‘system‘, ‘123456‘);db.shutdownServer()"
;;
status)
#/usr/local/mongodb/bin/mongo 182.48.115.236:27017/admin --eval "db.stats()"
/usr/local/mongodb/bin/mongo 182.48.115.236:27017 /admin -- eval "db.auth(‘system‘, ‘123456‘);db.stats()"
;; esac
5.4)设置权限验证文件
先进入master-node主节点服务器182.48.115.236,查看
[[email protected] ~] # cat /usr/local/mongodb/keyfile
RavtXslz /WTDwwW2JiNvK4OBVKxU // 查看刚才生成的字符串,做记录
再分别进入两台从节点服务器182.48.115.237 /238
[[email protected] ~] # vim /usr/local/mongodb/keyfile //将主节点生成的权限验证字符码复制到从节点的权限验证文件里
RavtXslz /WTDwwW2JiNvK4OBVKxU
[[email protected] ~] # chmod 600 /usr/local/mongodb/keyfile
[[email protected] ~] # vim /usr/local/mongodb/keyfile
[[email protected] ~] # cat /usr/local/mongodb/keyfile
RavtXslz /WTDwwW2JiNvK4OBVKxU
[[email protected] ~] # chmod 600 /usr/local/mongodb/keyfile
6)验证副本集
分别重启三台副本集服务器(三台节点都要重启)
[[email protected] ~] # ps -ef|grep mongodb
root 28964 1 1 02:22 ? 00:00:31 /usr/local/mongodb/bin/mongod --maxConns 20000 --config /usr/local/mongodb/mongodb .conf
root 29453 28911 0 03:04 pts /0 00:00:00 grep mongodb
[[email protected] ~] # kill -9 28964
[[email protected] ~] # /etc/init.d/mongodb start
about to fork child process, waiting until server is ready for connections.
forked process: 29457
child process started successfully, parent exiting
[[email protected] ~] # lsof -i:27017
COMMAND PID USER FD TYPE DEVICE SIZE /OFF NODE NAME
mongod 29457 root 7u IPv4 701471 0t0 TCP slave-node1:27017 (LISTEN)
mongod 29457 root 29u IPv4 701526 0t0 TCP slave-node1:27017->master-node:39819 (ESTABLISHED)
mongod 29457 root 30u IPv4 701573 0t0 TCP slave-node1:27017->master-node:39837 (ESTABLISHED)
mongod 29457 root 31u IPv4 701530 0t0 TCP slave-node1:36768->master-node:27017 (ESTABLISHED)
mongod 29457 root 32u IPv4 701549 0t0 TCP slave-node1:36786->master-node:27017 (ESTABLISHED)
mongod 29457 root 33u IPv4 701574 0t0 TCP slave-node1:27017->master-node:39838 (ESTABLISHED)
然后登陆mongodb
[[email protected] ~] # mongo 182.48.115.236:27017 -u system -p 123456 --authenticationDatabase admin
.......
hqmongodb:PRIMARY> rs.status() // 副本集状态查看.也可以省略上面添加登陆验证的步骤,不做验证,直接查看集群状态。集群状态中可以看出哪个节点目前是主节点
{
"set" : "hqmongodb" ,
"date" : ISODate( "2017-06-03T19:06:59.708Z" ),
"myState" : 1,
"term" : NumberLong(2),
"heartbeatIntervalMillis" : NumberLong(2000),
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1496516810, 1),
"t" : NumberLong(2)
},
"appliedOpTime" : {
"ts" : Timestamp(1496516810, 1),
"t" : NumberLong(2)
},
"durableOpTime" : {
"ts" : Timestamp(1496516810, 1),
"t" : NumberLong(2)
}
},
"members" : [
{
"_id" : 0,
"name" : "182.48.115.236:27017" ,
"health" : 1,
"state" : 1, //state 的值为1的节点就是主节点
"stateStr" : "PRIMARY" , // 主节点PRIMARY标记
"uptime" : 138,
"optime" : {
"ts" : Timestamp(1496516810, 1),
"t" : NumberLong(2)
},
"optimeDate" : ISODate( "2017-06-03T19:06:50Z" ),
"infoMessage" : "could not find member to sync from" ,
"electionTime" : Timestamp(1496516709, 1),
"electionDate" : ISODate( "2017-06-03T19:05:09Z" ),
"configVersion" : 4,
"self" : true
},
{
"_id" : 1,
"name" : "182.48.115.237:27017" ,
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY" ,
"uptime" : 116,
"optime" : {
"ts" : Timestamp(1496516810, 1),
"t" : NumberLong(2)
},
"optimeDurable" : {
"ts" : Timestamp(1496516810, 1),
"t" : NumberLong(2)
},
"optimeDate" : ISODate( "2017-06-03T19:06:50Z" ),
"optimeDurableDate" : ISODate( "2017-06-03T19:06:50Z" ),
"lastHeartbeat" : ISODate( "2017-06-03T19:06:59.533Z" ),
"lastHeartbeatRecv" : ISODate( "2017-06-03T19:06:59.013Z" ),
"pingMs" : NumberLong(0),
"syncingTo" : "182.48.115.236:27017" ,
"configVersion" : 4
},
{
"_id" : 2,
"name" : "182.48.115.238:27017" ,
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY" ,
"uptime" : 189,
"optime" : {
"ts" : Timestamp(1496516810, 1),
"t" : NumberLong(2)
},
"optimeDurable" : {
"ts" : Timestamp(1496516810, 1),
"t" : NumberLong(2)
},
"optimeDate" : ISODate( "2017-06-03T19:06:50Z" ),
"optimeDurableDate" : ISODate( "2017-06-03T19:06:50Z" ),
"lastHeartbeat" : ISODate( "2017-06-03T19:06:59.533Z" ),
"lastHeartbeatRecv" : ISODate( "2017-06-03T19:06:59.013Z" ),
"pingMs" : NumberLong(0),
"syncingTo" : "182.48.115.236:27017" ,
"configVersion" : 4
},
],
"ok" : 1
}
注意上面命令结果中的state,如果这个值为 1,说明是主控节点(master);如果是2,说明是从属节点slave。在上面显示的当前主节点写入数据,到从节点上查看发现数据会同步。
当主节点出现故障的时候,在两个从节点上会选举出一个新的主节点,故障恢复之后,之前的主节点会变为从节点。从上面集群状态中开看出,当前主节点是master-node,那么关闭它的mongodb,再次查看集群状态,就会发现主节点变为之前设置的slave-node2,即182.48.115.238了!
至此,Linux 下 MongoDB 副本集部署完成。
-------------------------------------------------------------------------------------------
添加数据,来需要验证的--------------------
1)主从服务器数据是否同步,从服务器没有读写权限
a:向主服务器写入数据 ok 后台自动同步到从服务器,从服务器有数据
b:向从服务器写入数据 false 从服务器不能写
c:主服务器读取数据 ok
d:从服务器读取数据 false 从服务器不能读
2)关闭主服务器,从服务器是否能顶替
mongo 的命令行执行 rs.status() 发现 PRIMARY 替换了主机了
3)关闭的服务器,再恢复,以及主从切换
a:直接启动关闭的服务,rs.status()中会发现,原来挂掉的主服务器重启后变成从服务器了
b:额外删除新的服务器 rs.remove( "localhost:9933" ); rs.status()
c:额外增加新的服务器 rs.add({_id:0,host: "localhost:9933" ,priority:1});
d:让新增的成为主服务器 rs.stepDown(),注意之前的 priority 投票
4)从服务器读写
db.getMongo().setSlaveOk();
db.getMongo().slaveOk(); // 从库只读,没有写权限,这个方法 java 里面不推荐了
db.setReadPreference(ReadPreference.secondaryPreferred()); // 在 复 制 集 中 优 先 读
secondary,如果 secondary 访问不了的时候就从 master 中读
db.setReadPreference(ReadPreference.secondary()); // 只 从 secondary 中 读 , 如 果
secondary 访问不了的时候就不能进行查询
日志查看---------------------------
MongoDB 的 Replica Set 架构是通过一个日志来存储写操作的,这个日志就叫做”oplog”,
它存在于” local ”数据库中,oplog 的大小是可以通过 mongod 的参数”—oplogSize”来改变
oplog 的日志大小。
> use local
switched to db local
> db.oplog.rs. find ()
{ "ts" : { "t" : 1342511269000, "i" : 1 }, "h" : NumberLong(0), "op" : "n" , "ns" : "" , "o" :
{ "msg" : "initiating set" } }
字段说明:
ts: 某个操作的时间戳
op : 操作类型,如下:
i: insert
d: delete
u: update
ns: 命名空间,也就是操作的 collection name
-------------------------------------------------------------------------------------------
其它注意细节:
rs.remove( "ip:port" ); // 删除副本
单服务器,启动时添加--auth 参数开启验证。
副本集服务器,开启--auth 参数的同时,必须指定 keyfile 参数,节点之间的通讯基于该 keyfile,key 长度必须在 6 到 1024 个字符之间,
最好为 3 的倍数,不能含有非法字符。
重新设置副本集
rs.stepDown()
cfg = rs.conf()
cfg.members[n].host= ‘new_host_name:prot‘
rs.reconfig(cfg)
副本集所有节点服务器总数必须为奇数,服务器数量为偶数的时候,需要添加一个仲裁节 点,仲裁节点不参与数副本集,只有选举权。
rs.addArb( "182.48.115.239:27017" ) #添加仲裁节点
|