mongo实战2——第11章 可复制集群

MongoDB可以把数据从一个节点复制到其它节点,并在修改时同步数据,这就是复制集群。复制集群中每个mongdb的节点存储的数据是一样的。
注意:虽然可复制集群中数据是冗余的,但是它无法取代数据备份机制。备份是过去某个时间点的数据库快照,可复制集群通常是最新的。有时候数据量太大,可能备份很困难。但通常备份都是必须的,即使运行了可复制集群也需要启动备份。可以使用备份节点实现。

复制的应用场景

  1. 可以使数据冗余,可以确保从节点与主节点的数据同步。主从节点可以位于不同的数据中心。
  2. 复制是异步的,网络延迟不会影响主节点的性能。
  3. 复制节点可以设置延迟同步数据,防止用户无意的删除数据
  4. 用来在从节点上进行数据备份,而不是在主节点备份数据,可以缓解主节点的压力。
  5. 可以在从节点上构建索引,之后切换主从节点,减小构建索引的压力
  6. 复制模式可以缓解系统的读压力。

复制不能解决的问题

  1. 现有的硬件无法处理工作负荷,如数据集超过内存大小,复制集群不能解决这个问题,因为复制后单节点的数据量并没有减少。
  2. 写入读取的比例超过50%,不适合部署复制集群。因为每个主节点的写入都会同步到从节点,如果从节点的写入数据较多,会影响从节点的读取和写入性能。可能会造成从节点的读写延迟
  3. 应用程序要求数据的读取一致性。因为同步是有延迟的,主从节点的数据并不能保持强一致性。

安装

可复制集群的最小化安装需要3个mongod节点,如果只有两个节点,一但主节点宕机,就无法进行投票表决,选举新的主节点。
部署方式有两种
1. 三个实例都为存储数据的服务器
2. 两个数据存储服务器+一个裁判服务器,裁判服务器不存储数据,只参与主节点的选举。
mongodb,复制集群,3数据节点
mongodb,复制集群,2数据节点+裁判节点

安装详细步骤

环境准备:
centos7.2;
mongo3.6;
安装方式为:2个数据节点+1裁判节点

  1. 创建数据文件
mkdir -p /data/node1
mkdir -p /data/node2
mkdir -p /data/arbiter
  1. 创建节点配置文件
vim ~/repl_node1.cnf
dbpath=/data/node1/
logpath=/data/node1/mongo.log
logappend=true
fork=true
port=40000

vim ~/repl_node2.cnf
dbpath=/data/node2/
logpath=/data/node2/mongo.log
logappend=true
fork=true
port=40001

vim repl_arbiter.cnf
dbpath=/data/arbiter/
logpath=/data/control/mongo.log
logappend=true
fork=true
port=40002
  1. 启动mongod实例
mongod --replSet myapp -f ~/repl_node1.cnf
mongod --replSet myapp -f ~/repl_node2.cnf 
mongod --replSet myapp -f ~/repl_arbiter.cnf 
  1. 集群配置
连接非裁判节点
mongo --port 40000

执行 rs.initiate() 初始化集群
输出
{
	"info2" : "no configuration specified. Using a default configuration for the set",
	"me" : "localhost:40000",
	"ok" : 1,
	"operationTime" : Timestamp(1562984114, 1),
	"$clusterTime" : {
		"clusterTime" : Timestamp(1562984114, 1),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	}
}
此时执行rs.status() 可以看到当前集群中已经有一个节点了
 rs.status()
{
	"set" : "myapp",
	"date" : ISODate("2019-07-13T02:17:58.831Z"),
	"myState" : 1,
	"term" : NumberLong(1),
	"syncingTo" : "",
	"syncSourceHost" : "",
	"syncSourceId" : -1,
	"heartbeatIntervalMillis" : NumberLong(2000),
	"optimes" : {
		"lastCommittedOpTime" : {
			"ts" : Timestamp(1562984276, 1),
			"t" : NumberLong(1)
		},
		"readConcernMajorityOpTime" : {
			"ts" : Timestamp(1562984276, 1),
			"t" : NumberLong(1)
		},
		"appliedOpTime" : {
			"ts" : Timestamp(1562984276, 1),
			"t" : NumberLong(1)
		},
		"durableOpTime" : {
			"ts" : Timestamp(1562984276, 1),
			"t" : NumberLong(1)
		}
	},
	"members" : [
		{
			"_id" : 0,
			"name" : "localhost:40000",
			"health" : 1,
			"state" : 1,
			"stateStr" : "PRIMARY",
			"uptime" : 614,
			"optime" : {
				"ts" : Timestamp(1562984276, 1),
				"t" : NumberLong(1)
			},
			"optimeDate" : ISODate("2019-07-13T02:17:56Z"),
			"syncingTo" : "",
			"syncSourceHost" : "",
			"syncSourceId" : -1,
			"infoMessage" : "",
			"electionTime" : Timestamp(1562984114, 2),
			"electionDate" : ISODate("2019-07-13T02:15:14Z"),
			"configVersion" : 1,
			"self" : true,
			"lastHeartbeatMessage" : ""
		}
	],
	"ok" : 1,
	"operationTime" : Timestamp(1562984276, 1),
	"$clusterTime" : {
		"clusterTime" : Timestamp(1562984276, 1),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	}
}

在添加其他两个节点
rs.add("localhost:40001")
rs.addArb("localhost:40002")

集群信息查看

rs.isMaster() 查看集群的摘要信息
 rs.status() 查看集群的详细信息

开启从节点读取

集群启动后,从节点默认是不允许读取的,因为数据的同步可能比较慢。需要在从节点上执行
rs.slaveOk() 开启从节点的读取。

复制集的工作原理

可复制集依赖两个机制,oplog和heatbeat
oplog实现数据的复制功能
hearbeat 监控集群状态并触发灾备

oplog

  1. oplog是一个盖子集合,存储在每个复制节点的local数据库里,记录了所有数据的变化
  2. 当有数据写入到主节点的数据,都会写入到主节点的oplog中
  3. 数据复制到某个从节点后,也会写入到从节点的oplog中。
查看oplog数据
在主节点插入数据
use school
switched to db school
myapp:PRIMARY> db.students.insert({name:'zhangsan',age:16,sex:'man'})

查看oplog
db.oplog.rs.find({op:'i'}).pretty()
{
	"ts" : Timestamp(1562985810, 3),  文档时间戳 :1970开始的秒数 + 计数器3
	"t" : NumberLong(1),
	"h" : NumberLong("-7265383297214975045"),
	"v" : 2,
	"op" : "i",						表示日志的操作类型 i 表示insert 
	"ns" : "school.students",  命名空间:当前操作的 数据库.集合
	"ui" : UUID("5e9fc652-9276-4a1a-b21b-b7b7f2a0f122"),
	"wall" : ISODate("2019-07-13T02:43:30.381Z"),
	"o" : {   //文档信息 
		"_id" : ObjectId("5d294552d0a0923c139d2149"),
		"name" : "zhangsan",
		"age" : 16,
		"sex" : "man"
	}
}

当一条命令修改了多个文档的时候,会产生多个oplog日志。这是为了保证服务器间数据的幂等性。

查看oplog状态信息
db.getReplicationInfo()
{
	"logSizeMB" : 1342.1103515625,
	"usedMB" : 0.04,
	"timeDiff" : 2662,
	"timeDiffHours" : 0.74,
	"tFirst" : "Sat Jul 13 2019 10:15:14 GMT+0800 (CST)",
	"tLast" : "Sat Jul 13 2019 10:59:36 GMT+0800 (CST)",
	"now" : "Sat Jul 13 2019 10:59:45 GMT+0800 (CST)"
}

从节点复制数据的步骤

  1. 查看自己oplog里最新记录的时间戳
  2. 查询主节点oplog中所有大于自己时间戳的记录。
  3. 写入数据,并添加每个操作日志到自己的oplog中。
    这意味着,到主节点故障,提升任意节点为主节点时,都会有一个oplog,供其他节点同步数据。实现了可复制集群的故障恢复功能
停止复制

如果从节点无法在主节点oplog找到同步的日志记录点,就会永久停止复制。
由于oplog是一个盖子集合,如果从节点离线一段时间,主节点的oplog可能无法存储这段时间所有的日志。如果启动复制会导致部分数据的丢失。
唯一的解决方案就是重新同步主节点的所有数据。
可以通过监控主从延迟和设置oplog的大小来避免这种问题的发生。

oplog大小设置

在mongo3.0中,操作步骤为,停止mongod实例,然后作为独立节点启动,修改oplog大小,重新启动成员。

心跳和故障转移

集群的心跳便于实现选举和灾备。默认每个节点会每隔2s ping一次其他节点。可以通过rs.status 查看每个节点最新的心跳状态 1表示正常,0表示无应答。

  1. 当某个从节点失去响应,集群中大部分节点正常,集群不会做出改变,只是简单的等待从节点恢复
  2. 如果主节点故障,大多数节点正常,此时会选举一个从节点作为主节点
  3. 如果从节点和裁判节点故障,只有一个主节点存在,此时主节点会降级为从节点。
    场景:如果出现网络分区,导致主节点与其他节点心跳失败。但其他节点仍然在线,并且互相心跳正常,其他节点就会选取一个新的主节点对外提供服务。如果原来的主节点不降级,就会有两个主节点对外提供服务。

提交和回滚

当向主节点写入数据时,这些写入操作不会被提交,知道它们被复制给大多数节点。

回滚场景:
假设我们在主节点插入了一些数据,但是由于某种原因,这些数据没有同步到从节点。这时主节点宕机,从节点提升为主节点,这时我们向新的主节点写入数据。这时原来的主节点重新上线,成为集群中的从节点,从现有的主节点同步数据。当旧的主节点有一些写入数据在新的主节点的oplog中不存在时,就会触发回滚。
在回滚时,所有没有复制给大多数节点的写入操作都会被取消。

回滚日志:
这些还原的写操作存储在相关节点数据目录的子目录里,对于每个回滚的写入集合,都会创建一个单独的BSON文件,文件名包含回滚的时间。如果需要恢复回滚数据可以使用bsondump 和mongorestore来操作。

通过设置写关注点,可以减少复制集群的回滚的发生。

集群配置

集群的json文档初始化方式

声明config json对象
config={_id:'myapp',members:[]}
config.members.push({_id:0,host:'localhost:40000'})
config.members.push({_id:1,host:'localhost:40001'})
config.members.push({_id:2,host:'localhost:40002',arbiterOnly:true})
结果:
config
{
	"_id" : "myapp",
	"members" : [
		{
			"_id" : 0,
			"host" : "localhost:40000"
		},
		{
			"_id" : 1,
			"host" : "localhost:40001"
		},
		{
			"_id" : 2,
			"host" : "localhost:40002",
			"arbiterOnly" : true
		}
	]
}

rs.initiate(config) 将配置的config对象传递给初始化函数,

成员参数说明

参数说明
_id唯一的自增整数,用来表示成员id,这个id从0开始,而且必须是递增的
host存储主机的名字和端口,冒号分割
arbiterOnlyboolean值,表示这个成员是否是裁判
priority指定此节点被选为主节点的优先级,优先级越高,被选为主节点的概率越大,如果为0,表示此节点永远不会被选为主节点
votes默认情况下,所有的节点都有一次投票机会,votes可以允许某个节点投多票
hiddenboolean值,当为true时,用isMaster查询时不会显示此节点,可以和buildIndexes一起使用,必须和slaveDelay一起使用
buildIndexesboolean值,默认为true,用来决定此成员是否构建索引,只有当前节点不会为主节点时才会设置为false,备份节点不需要构建索引
slaveDelay从节点与主节点同步的延迟时间,只有不是主节点的实例上使用,防止用户操作错误。丢失数据
tags标签,包含键值对的集合文档,通常用来区分数据中心,及节点机房位置

集群的全集参数

config
{
	"_id" : "myapp",
	"members" : [...],
	settings:{
		getLastErrorDefaults:{
				w:2,
				wtimeout:500
		},
		getLastErrorModes:{
			
		}
	}
}
参数说明
getLastErrorDefaults当客户端无参数调用getLastError时,返回的默认值
getLastErrorDefaults为getLastError命令定义了额外模式的文档

部署策略

在生产环境中建议部署方式:

  1. 两个复制节点+1个裁判节点,由于裁判节点不占用资源,可以和应用部署在同一个服务器上,这种部署方式可以满足大部分服务
  2. 3个复制节点,此种方式提高了应用的 稳定性,当一个复制节点宕机,还有两个节点可以对外提供服务。可以将节点部署在两个数据中心,达到异地灾备的目的。

写关注点

mongo默认的写关注点为1,及只要数据写到主节点就会提交,为了减少集群的回滚,在写入数据时,可以动态的指定操作的写关注点。也可以在集群中配置默认的写关注点,较大的写关注点,会影响集群的写入性能。

总结

  1. 在部署生产环境时,应该部署复制集群,否则就需要频繁的备份数据
  2. 复制集群至少需要3个节点,其中一个可以是裁判节点
  3. 数据在复制到大多数节点的时候,才会提交。在故障的场景中,如果大多数节点正常,集群可以正常对外服务。没有达到大多数节点的写请求会被放入数据的回滚目录下,必须手动处理
  4. 如果从节点宕机一段时间,并且这段时间的写入数据没有写入主节点的oplog,这是就需要手动恢复从节点的数据。
  5. 驱动的写关注点可以控制写入请求写入多少个节点后才返回,可以增加应用的持久性,但是降低了写入性能
  6. 可以设置集群的读偏好,分散集群主节点的读取压力。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值