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文件	
相关推荐
Oak Zhang1 小时前
sharding-jdbc自定义分片算法,表对应关系存储在mysql中,缓存到redis或者本地
redis·mysql·缓存
门牙咬脆骨2 小时前
【Redis】redis缓存击穿,缓存雪崩,缓存穿透
数据库·redis·缓存
门牙咬脆骨2 小时前
【Redis】GEO数据结构
数据库·redis·缓存
墨鸦_Cormorant4 小时前
使用docker快速部署Nginx、Redis、MySQL、Tomcat以及制作镜像
redis·nginx·docker
Dlwyz6 小时前
问题: redis-高并发场景下如何保证缓存数据与数据库的最终一致性
数据库·redis·缓存
飞升不如收破烂~7 小时前
redis的List底层数据结构 分别什么时候使用双向链表(Doubly Linked List)和压缩列表(ZipList)
redis
吴半杯9 小时前
Redis-monitor安装与配置
数据库·redis·缓存
会code的厨子10 小时前
Redis缓存高可用集群
redis·缓存
尽兴-11 小时前
Redis模拟延时队列 实现日程提醒
java·redis·java-rocketmq·mq
Karoku06616 小时前
【企业级分布式系统】ELK-企业级日志分析系统
运维·数据库·redis·mysql·elk·缓存