Redis Cluster Cron调度

返回目录

说明

  1. clusterCron 每秒执行10次
  2. clusterCron 内置了一个iteration计数器。每一次运行clusterCron,iteration都加1。当 iteration % 10 == 0的时候,就会随机选取一个节点,给它发送PING。而由于clusterCron每秒执行10次,所以实际上每秒才会PING一次随机节点。

过程

c 复制代码
++iteration		/* 每次运行clusterCron都加一 */
if 配置的cluster-announce-hostname发生了变化:
	更新myself的hostname
计算handshakeTimeout = max(cluster-node-timeout, 3000)
statsPfailNodes = 0	 /* 重新计算timeout的node数 */
遍历cluster节点字典中的每个node:
	对于node的inbound link和outbound link:
		1. 检查它们的发送buffer能否收缩,从而节省内存
		2. 如果配置的cluster-link-sendbuf-limit != 0,检查它们的发送buffer
	   	  (可能经过1的收缩)是否超过了限制,若是则释放掉相应的link
		3. 更新统计它们对内存的使用量
	跳过myself
	跳过处于NOADDR的node  /* 没有地址,没法建立连接 */
	if node处于PFAIL状态:
		++statsPfailNodes  /* 计算timeout节点数 */
	if node处于handshake && 
			(当前时间 - node的创建时间)> handshakeTimeout:
		删除node	/* 规定时间内没有完成handshake,则认为它是未知的节点 */
	检查node是否disconnected,若是,则重建连接
		在连接创建成功之后:	/* 这里是异步执行的 */
		if node处于MEET状态:		/* 我们需要MEET它 */
			向它发送MEET消息
		else:
			向它发送PING消息
		清除node的MEET标记

/* 每秒随机选取一个节点,给它发PING */
if iteration % 10 == 0:	/* 每秒clusterCron调度10次,每10次发一次PING */
	从cluster节点字典中随机选取5个node,它们满足以下条件:
		1. 已连接上(有outbound link)
		2. pingSent == 0 (没有在等待PONG)
		3. 不是myself
		4. 没有处于handshake
	再从这5个node中,选取pongReceived最小的node	/* 最久没收到PONG的node*/
	if 这样的node存在:
		给它发送PING消息

/* 检查节点是否timeout,顺便为migrate收集信息 */
orphanedMasters = 0	 /* 统计orphaned master数 */
maxSlaves = 0	/* 统计单个节点拥有的最大slave数 */
thisSlaves = 0	/* 如果myself是master,表示拥有的slave数;
				   如果myself是slave,表示它的master所拥有的slave数 */
遍历cluster节点字典的每个node:
	跳过myself
	跳过没有地址(NOADDR)的node
	跳过处于handshake的node
	/* 检查node是否为orphaned master,主要是先收集信息 */
	if myself是slave && node是master && node没有FAIL:
		okSlaves = node上没有处于FAIL的slave数
		/* node是orphaned master的条件:
		   1. slots > 0
		   2. 当前没有正常运作的slave
		   3. 带有MIGRATE_TO标记:曾经有至少一个slave,或者被它failover的
		      master曾经拥有slave */
		if okSlaves == 0 && node的slots > 0 && node有MIGRATE_TO标记:
			++orphanedMasters
		maxSlaves = max(okSlaves, maxSlaves)
		if node是myself的master:
			thisSlaves = okSlaves

	/* 如果超过 cluster-node-timeout/2 都没有收到来自node的数据,
	   有可能只是连接出了问题,尝试重连 */
	pingDelay = 当前时间 - node的pingSent
	dataDelay = 当前时间 - node的dataReceived
	if node的link存在 &&		/* 存在连接的才需要检查 */
			当前时间 - link的创建时间 > cluser-node-timeout && /* 还没有重连 */
			node的pingSent > 0 &&	/* 已经对node发出了PING */
			pingDelay > cluster-node-timeout/2 &&	/* 超时没有收到PONG */
			dataDelay > cluster-node-timeout/2:	/* 超时没有收到其他数据 */
		释放掉link,下次会自动重连(参考上面的逻辑)

	/* 检查是否需要PING一下node,以保证cluster信息的有效性 */
	if node的link存在 &&
			node的pingSent == 0 &&	/* 没有在等待PONG */
			/* 太久没PING,需要PING一下node */
			当前时间 - node的pongReceived > cluster-node-timeout/2: 
		给node发送PING消息

	if 我们是node的master,而它对我们请求了manual failover:
		给node发送PING消息
	
	/* 如果timeout了,就改变node的状态 */
	if node的pingSent > 0:	/* 正在等待PONG */
		/* 加载大量数据时,PONG有可能会延时,所以如果能收到数据,
		   也能说明node还活着 */
		nodeDelay = min(pingDelay, dataDelay)	/* 最近一次收到的数据间隔 */
		if nodeDelay > cluster-node-timeout &&	/* node真的timeout了 */
				node没有处于PFAIL或FAIL:
			把node设置成timeout(PFAIL状态)

/* 检查是否可以复制master */
if myself是slave && master有地址了 && 还没开始复制master:
	更新master的IP和port,开始复制

/* 检查manual failover是否已经timeout */
if manual failover已经timeout:
	重置manual failover的状态

if myself是slave:
	处理 Manual Failover	/* 在Failover章节叙述 */
	处理 Slave Failover		/* 在Failover章节叙述 */
	
	/* 检查我们是否需要migrate到orphaned master */
	if orphanedMasters > 0 &&	/* 存在orphaned master */
			/* 我们的master拥有最多冗余的slave,所以我们可以分离出来,
			   成为其中一个orphaned master的slave */
			maxSlaves >= 2 && thisSlaves == maxSlaves &&
			cluster-allow-replica-migration:	/* 配置允许我们这么做 */
		/* Step 1: 检查cluster的状态 */
		if 我们认为当前cluster处于FAIL:
			跳过migration
		/* Step 2: 检查我们的master是否拥有多余的slave */
		if 我们的master拥有的正常slave数 < cluster-migration-barrier:
			跳过migration	/* 不能少于配置要求的最少slave数,才能做 */
		/* Step 3:查找orphaned master */
		target = null
		遍历cluster节点字典中的每个node:
			okSlaves = 0
			isOrphaned = 1
			/* 必须是正常工作,没有slave的master,
			   而且带有MIGRATE_TO标记(含义参考上面) */
			if node是slave || node处于FAIL || node没有MIGRATE_TO标记):
				isOrphaned = 0	
			if node是master:
				okSlaves = node拥有的没有处于FAIL的slave数
			if okSlaves > 0:
				isOrphaned = 0
				
			if isOrphaned:
				if target == null &&  /* 只查找第一个符合要求的node */
						node的slots > 0: /* 没有slots的master不需要slave */
					target = node
				if node的orphanedTime == 0: /* 跟踪记录开始时间 */
					设置为当前时间
			else:
				重置node的orphanedTime为0
				
			if okSlaves == maxSlaves:	/* 我们的master拥有最多的slaves */
				minID = 从node的slaves中查找出最小的ID
				if myself的ID < minID:
					candidate = myself	/* 我们当选了 */
		/* Step 4: 执行migration */			
		if target != null &&	/* 找到了orphaned master */
				candidate == myself &&	/* 我们当选了 */
				/* 需要保持orphaned一段时间,如果期间发生failover,有可能
				   使得slave和master之间的关系发生变化 */
				当前时间 - target的orphanedTime > 5000ms: 
			把target设置为我们的新master
			
/* 结束本轮调度前,保存cluster的变化 */
if cluster信息发生了变化 || 我们认为cluster处于FAIL状态:
	更新nodes.conf文件	
相关推荐
岁月变迁呀4 小时前
Redis梳理
数据库·redis·缓存
Code apprenticeship6 小时前
怎么利用Redis实现延时队列?
数据库·redis·缓存
百度智能云技术站6 小时前
广告投放系统成本降低 70%+,基于 Redis 容量型数据库 PegaDB 的方案设计和业务实践
数据库·redis·oracle
装不满的克莱因瓶6 小时前
【Redis经典面试题六】Redis的持久化机制是怎样的?
java·数据库·redis·持久化·aof·rdb
黄名富10 小时前
Redis 附加功能(二)— 自动过期、流水线与事务及Lua脚本
java·数据库·redis·lua
G_whang11 小时前
centos7下docker 容器实现redis主从同步
redis·docker·容器
.生产的驴11 小时前
SpringBoot 对接第三方登录 手机号登录 手机号验证 微信小程序登录 结合Redis SaToken
java·spring boot·redis·后端·缓存·微信小程序·maven
我叫啥都行14 小时前
计算机基础复习12.22
java·jvm·redis·后端·mysql
阿乾之铭15 小时前
Redis四种模式在Spring Boot框架下的配置
redis
on the way 12317 小时前
Redisson锁简单使用
redis