订阅 subscribe channel1 channel2 .. 发布消息 publish channel message 退订 unsubscribe channel 模式匹配 psubscribe ch* 订阅所有以ch开头的频道 模式退订 punsubscribe ch* 发布订阅使用场景: 哨兵模式,Redisson框架使用 在Redis哨兵模式中,哨兵通过发布与订阅的方式与Redis主服务器和Redis从服务器进行通信 Redisson是一个分布式锁框架,在Redisson分布式锁释放的时候,是使用发布与订阅的方式通知的, Redis事务 Redis的事务是通过multi、exec、discard和watch这四个命令来完成的。 Redis的单个命令都是原子性的,所以这里需要确保事务性的对象是命令集合。 Redis将命令集合序列化并确保处于同一事务的命令集合连续且不被打断的执行 Redis不支持回滚操作 事务命令 multi:用于标记事务块的开始,Redis会将后续的命令逐个放入队列中,然后使用exec原子化地执行这个 命令队列 exec:执行命令队列 discard:清除命令队列 watch:监视key unwatch:清除监视key 用multi开启事务之后,再输入的命令不会立即执行,直到使用exec执行命令队列 事务机制 1. 事务开始 在RedisClient中,有属性flags,用来表示是否在事务中,flags=REDIS_MULTI 2. 命令入队 RedisClient将命令存放在事务队列中 (EXEC,DISCARD,WATCH,MULTI除外) 3. 事务队列 multiCmd *commands 用于存放命令 4. 执行事务 RedisClient向服务器端发送exec命令,RedisServer会遍历事务队列,执行队列中的命令,最后将执 行的结果一次性返回给客户端。 慢查询设置 在redis.conf中可以配置和慢查询日志相关的选项: #执行时间超过多少微秒的命令请求会被记录到日志上 0 :全记录 <0 不记录 slowlog-log-slower-than 10000 #slowlog-max-len 存储慢查询日志条数 slowlog-max-len 128 config set的方式可以临时设置,redis重启后就无效 config set slowlog-log-slower-than 微秒 config set slowlog-max-len 条数 查看日志:slowlog get [n] 查看日志数量的 slowlog len 清除日志 slowlog reset 使用slowlog get 可以获得执行较慢的redis命令,针对该命令可以进行优化: 1、尽量使用短的key,对于value有些也可精简,能使用int就int。 2、避免使用keys *、hgetall等全量操作。 3、减少大key的存取,打散为小key 4、将rdb改为aof模式 rdb fork 子进程 主进程阻塞 redis大幅下降 关闭持久化 , (适合于数据量较小) 改aof 命令式 5、想要一次添加多条数据的时候可以使用管道 6、尽可能地使用哈希存储 7、尽量限制下redis使用的内存大小,这样可以避免redis使用swap分区或者出现OOM错误 内存与硬盘的swap 监视器 Redis客户端通过执行MONITOR命令可以将自己变为一个监视器,实时地接受并打印出服务器当前处理 的命令请求的相关信息。 此时,当其他客户端向服务器发送一条命令请求时,服务器除了会处理这条命令请求之外,还会将这条 命令请求的信息发送给所有监视器。 客户端成为监视器命令: monitor Redis监控平台: Grafana 是一个开箱即用的可视化工具,具有功能齐全的度量仪表盘和图形编辑器,有灵活丰富的图形 化选项,可以混合多种风格,支持多个数据源特点。 Prometheus是一个开源的服务监控系统,它通过HTTP协议从远程的机器收集数据并存储在本地的时序 数据库上。 redis_exporter为Prometheus提供了redis指标的导出,配合Prometheus以及grafana进行可视化及监 控。 Redis持久化: 一、RDB:redis默认持久化方式,是通过快照方式持久化数据。 触发方式: 1. 符合自定义配置的快照规则( 在redis.conf中配置:save 多少秒内 数据变了多少,如 save 900 1 # 表示15分钟(900秒钟)内至少1个键被更改则进行快照。) 2. 执行save或者bgsave命令 3. 执行flushall命令 4. 执行主从复制操作 (第一次) 优点: 1、 RDB是二进制压缩文件,占用空间小,便于传输(传给slaver) 2、主进程fork子进程,由子进程生成rdb文件,可以最大化Redis性能,redis中的 数据量不能太多,复制过程中主进程阻塞 3、数据恢复时快 缺点: 不保证数据完整性,会丢失最后一次快照以后更改的所有数据 2、AOF:默认不开启 ,以记录操作日志的方式持久化 保存方式: 1、不保存,只有redis关闭、AOF功能关闭、缓存满时会执行save命令,执行save时主线程会阻塞 2、每秒钟保存一次,save命令由后台子进程执行,不会阻塞主进程,推荐使用 3、每个命令都会保存一次,save由主进程执行,会阻塞 AOF数据还原的流程:服务器端生成一个伪客户端,然后从aof文件中读取命令执行
3、混合持久化:redis4.0开始支持混合持久化,即RDB+AOF RDB的头+AOF的身体---->appendonly.aof 开启:
aof-use-rdb-preamble yesRDB与AOF对比: 1、RDB存某个时刻的数据快照,采用二进制压缩存储,文件小。AOF存操作命令,采用文本存储(混合),文件大。 2、RDB性能高、AOF性能较低,但是RDB生成快照时会阻塞主进程,数据量大时也会影响性能 3、RDB在配置触发状态会丢失最后一次快照以后更改的所有数据,AOF设置为每秒保存一次,则最多丢2秒的数据 4、Redis以主服务器模式运行,RDB不会保存过期键值对数据,Redis以从服务器模式运行,RDB会保 存过期键值对,当主服务器向从服务器同步时,再清空过期键值对。AOF写入文件时,对过期的key会追加一条del命令,当执行AOF重写时,会忽略过期key和del命令 当用redis做数据库时,rdb与aof都要开启 当用redis做缓存时,只需要开启aof即可 Redis底层数据结构:
redisDb数据结构
typedef struct redisDb {
int id; //id是数据库序号,为0-15(默认Redis有16个数据库)
long avg_ttl; //存储的数据库对象的平均ttl(time to live),用于统计
dict *dict; //存储数据库所有的key-value
dict *expires; //存储key的过期时间
dict *blocking_keys;//blpop 存储阻塞key和客户端对象
dict *ready_keys;//阻塞后push 响应阻塞客户端 存储阻塞后push的key和客户端对象
dict *watched_keys;//存储watch监控的的key和客户端对象
} redisDb;
redisObject数据结构:
typedef struct redisObject {
unsigned type:4;//类型 五种对象类型
unsigned encoding:4;//编码
void *ptr;//指向底层实现数据结构的指针
//...
int refcount;//引用计数
//...
unsigned lru:LRU_BITS; //LRU_BITS为24bit 记录最后一次被命令程序访问的时间
//...
}robj;
type类型:
1、String
redis使用
SDS
(简单动态字符串)存储字符串和整形
struct sdshdr{
//记录buf数组中已使用字节的数量
int len;
//记录 buf 数组中未使用字节的数量
int free;
//字节数组,用于保存字符串
char buf[];
}
SDS优势:
方便获取长度,长度=free+len+1
由于记录了长度,在可能造成缓冲区溢出时会重新分配内存,杜绝缓冲区溢出
可以存储二进制数据,
2、跳跃表:(有序列表)
类似二分查找
插入节点时,对每一层的操作进行随机(二分之一的概率)插入或者不插入 3、散列表(Hash): 数组+链表 hash表数组初始长度是4,后面每次扩容都是翻倍 4、压缩列表(ziplist): 压缩列表(ziplist)是由一系列特殊编码的连续内存块组成的顺序型数据结构,节省内存, 是一个字节数组,可以包含多个节点(entry)。每个节点可以保存一个字节数组或一个整数。
sorted-set和hash元素个数少且是小整数或短字符串(直接使用) list用快速链表(quicklist)数据结构存储,而快速链表是双向列表与压缩列表的组合。(间接使用) 5、整数集合(intset) 整数集合(intset)是一个有序的(整数升序)、存储整数的连续存储结构。 当集合元素都是整数并且数值都小于2^64时,会使用 6、快速列表(quicklist) 快速列表是redis列表的底层实现 快速列表就是一个双向列表,里面每一个元素都是ziplist 缓存淘汰策略: redis默认的缓存淘汰策略是禁止驱逐 设置maxmemory,当redis使用内存量接近该值时,会执行缓存淘汰 redis删除数据方式有定时删除、惰性删除、主动删除三种,redis采用惰性删除和主动删除两种 1、定时删除:在创建键的时候同时创建一个定时器,到时间了就删掉。会消耗cpu 2、惰性删除:读取数据的时候先检查一下数据是否有效,如果失效了,就删掉 3、主动删除:通过设置主动删除策略,来删除不符合条件的键,默认是no-envoction(禁止驱逐) 一、lru:最近最少使用
删除那些最近没有被使用的键。原理是记录了每个键的最后访问时间,当淘汰机制触发时,redis会随机挑选一批元素,从中取出lru最大的值进行淘汰
Lru分为两种:volatile-lru和allkeys-lru
1、volatile-lru是从设置了过期时间的key中数据淘汰(性能没有allkeys好,因为还要存过期时间)
2、allkeys-lru是从所有数据中进行数据淘汰(一般用这种即可)
二、lfu:最近最少使用 原理是记录访问次数,删除访问次数少的数据 lfu也分为两种:volatile-lfu和allkeys-lfu 三、random,随机删除分为两种volatile-random和allkeys-random
四、ttl 从设置了过期时间的key中删除即将过期的数据。可以自己控制缓存删除策略 五、noenviction 禁止驱逐(默认的) 缓存预热: 缓存预热就是提前将缓存数据写到redis里面,避免用户使用的时候再写缓存 1、数据量不大的时候,可以在项目启动的时候写入 2、采用定时任务的方式刷新缓存 缓存常见问题 一、缓存穿透: 高并发查询的key不存在(数据库也不存在),访问会直接请求db 解决方案: 1、不存在的key也放到缓存中,并且赋值为空(过期时间不能太长)。这种方式,面对恶意攻击时(制造大量不存在的key进行请求)就不好用了 2、使用布隆过滤器。在缓存前加一层 布隆过滤器 ,先去查过滤器中是否存在key,不存在直接返回,存在的话就去访问缓存和db 布隆过滤器就是一个很长的二进制向量+多个hash函数组成。 假设我们布隆过滤器是一个64位的二进制和三个hash函数组成,当缓存中存在数据的时候,对这个key分别进行hash函数运算,得到的偏移量分别是0,16,37,那么就把这三位的数值置成1.当再进来一个请求key的时候,进行hash之后偏移量是12,45,48,这三位的二进制值分别是0,1,1,不全是1,所以这个key就不在缓存中存在。 使用很长的二进制以及多个hash函数的原因就是解决hash冲突,二进制代替字符串也节省空间 二、缓存雪崩: 短时间内,大量的key失效(或者redis重启),使得请求都打到数据库上 1、对不同的key设置不同的过期时间 2、设置二级缓存(可能数据不一致) 3、使用高可用(主从集群,可能有脏读) 三、缓存击穿: 超高并发访问的key失效了,导致请求打到服务器 1、使用分布式锁控制访问线程,使用setnx互斥锁先判断,这样其他线程就在等待,保证不会有高并发去访问数据库 2、不设置超时时间(这样会出现数据库数据更新,缓存数据不及时更新的情况,可以用延时双删策略处理) 延时双删: 数据库数据更新的时候,删除缓存数据。过两秒钟再删一次。这样避免数据库更新没有commit的时候,缓存已经删除了,有请求进来读的还是老数据,又把老数据读到缓存中了,造成脏读的问题 四、数据不一致 缓存跟数据库数据不一致 强一致性很难,可保证最终一致。更新数据库和删除缓存不是一个原子操作,时序不可控,高并发情况下会产生数据不一致。 解决方案: 1)、 延时双删解决。 2)、设置缓存过期时间 3)、记录缓存删除失败日志,然后跑脚本删除 五、数据并发竞争 多个redis客户端同时set同一个key引起的并发问题 1、用分布式锁+时间戳 用setnx设置分布式锁,再保存一个时间戳来保证set的顺序 2、使用消息队列 六、hot key 有大量的请求访问redis某个key,由于流量集中达到了网络上限,导致redis宕机,造成缓存击穿 发现热key: 1、预估hot key,比如秒杀商品,火爆新闻 2、客户端进行统计key的访问量 3、如果是proxy,如codis,可以在代理端统计 4、利用redis自带的命令,monitors、hotkeys()执行缓慢,一般不要用 5、利用大数据流式计算,如spark、flink 解决热key 1、把分布式缓存变成本地缓存。当发现热key时,把缓存数据取出,直接读本地缓存,用Ehcache、Guava Cache都可以(数据不会保证时时一致) 2、主从节点的redis可以在主节点备份一份热点数据,访问的时候随机访问到服务器上面,均摊压力 3、熔断限流 比如每个实例限制每秒最多请求缓存集群400次,一超过就熔断返回“服务器异常稍后刷新”的提示。 七、big key 影响 1、 大key会大量占用内存,在集群中无法均衡 2、 Redis的性能下降,主从复制异常 3、 在主动删除或过期删除时会操作时间过长而引起服务阻塞(删除del命令是一个阻塞命令) 如何发现大key 1、 redis-cli --bigkeys命令。可以找到某个实例5种数据类型(String、hash、list、set、zset)的最大key。但如果Redis 的key比较多,执行该命令会比较慢 2、获取redis的rdb文件, 通过rdbtools分析rdb生成csv文件,再导入MySQL或其他数据库中进行分析统计,根据size_in_bytes统计bigkey 优化 1、String类型的大key,可以存mongo啥的。如果必须要存redis,就单独存储,不要跟其他的key一起存储,采用一主一从或者多从方式 2、将单个key拆成多个,用mget批量获取 3、hash、set、zset、list类型元素过多,可以拆开(类似分页) 4、删除大key的时候,不要用del命令,会阻塞。用unlink命令,这个会先把key删除,然后再异步删除value 用redis做mybatis的二级缓存,分布式环境下可以使用 分布式锁 用watch实现乐观锁 1、利用redis的watch功能,监控这个redisKey的状态值 2、获取redisKey的值 3、创建redis事务 4、给这个key的值+1 5、然后去执行这个事务,如果key的值被修改过则回滚,key不加1 实现分布式锁 1、使用set(推荐使用)
public boolean getLock(String lockKey,String requestId,int expireTime) {
//NX:保证互斥性
// hset 原子性操作 只要lockKey有效 则说明有进程在使用分布式锁
String result = jedis.set(lockKey, requestId, "NX", "EX", expireTime);
if("OK".equals(result)) {
return true;
}
return false;
}
2、使用setnx
public boolean getLock(String lockKey,String requestId,int expireTime) {
Long result = jedis.setnx(lockKey, requestId);
if(result == 1) {
//成功设置 进程down 永久有效 别的进程就无法获得锁
jedis.expire(lockKey, expireTime);
return true;
}
return false;
}
删除锁
1、 (del命令实现) -- 并发有问题
public static void releaseLock(String lockKey,String requestId) {
if (requestId.equals(jedis.get(lockKey))) {
jedis.del(lockKey);
}
}
问题在于如果调用jedis.del()方法的时候,这把锁已经不属于当前客户端的时候会解除他人加的锁。
那么是否真的有这种场景?答案是肯定的,比如客户端A加锁,一段时间之后客户端A解锁,在执行
jedis.del()之前,锁突然过期了,此时客户端B尝试加锁成功,然后客户端A再执行del()方法,则将客户
端B的锁给解除了。
2、 (redis+lua脚本实现)—推荐
public static boolean releaseLock(String lockKey, String requestId) {
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return
redis.call('del', KEYS[1]) else return 0 end";
Object result = jedis.eval(script, Collections.singletonList(lockKey),
Collections.singletonList(requestId));
if (result.equals(1L)) {
return true;
}
return false;
}
Redission分布式锁
分布式集群架构中的session分离
用spring-session-data-redis(SpringSession),可以实现基于redis来实现的session分离
Redis高可用方案:
一、主从复制
主redis不需要配置,从redis修改redis.conf文件
# slaveof 哨兵检测模式 1、哨兵获取主从服务器信息,有两种方式:订阅方式、命令连接 订阅方式:哨兵每2秒向主从服务器发一个消息,消息会携带哨兵自身信息以及自助服务器信息 命令连接:哨兵每10秒向主服务器发送一个命令,获取主服务器以及从服务器的信息 哨兵之间不需要相互检测是否正常,因为可以互相通过对服务器的命令获取其他哨兵的信息 2、检测主从服务器状态: 哨兵每秒会向所有建立了连接的服务器发送ping命令,实例在 down-after-milliseconds毫秒内没有返回,就认为是下线了。当哨兵检测服务器下线之后,会向其他的哨兵发送查询命令,如果其他哨兵(数量达到配置中的quorum数量,一般是哨兵总数的二分之一以上)也认为该服务器下线了,就认为这个服务器真的下线了 3、故障转移 1、选举一个leader哨兵,使用raf选举t算法(一般就是谁最先发现下线的服务器,谁就是哨兵leader) leader哨兵会进行的操作 1. 它会将失效Master 的其中一个Slave 升级为新的Master , 并让失效Master 的其他Slave 改为复制新的Master ; 2. 当客户端试图连接失效的Master 时,集群也会向客户端返回新Master 的地址,使得集群可以使用现在的Master 替换失效Master 。 3. Master 和Slave 服务器切换后, Master 的redis.conf 、Slave 的redis.conf 和sentinel.conf 的配置文件的内容都会发生相应的改变,即, Master 主服务器的redis.conf配置文件中会多一行replicaof 的配置, sentinel.conf 的监控目标会随之调换。 哨兵选新主节点的逻辑: 1. 过滤掉主观下线的节点 2. 选择slave-priority(权限)最高的节点,如果由则返回没有就继续选择(一般都不会这只这个) 3. 选择出复制偏移量最大的系节点,因为复制偏移量越大则数据复制的越完整,如果有就返回了,没有就继续 4. 选择run_id最小的节点,因为run_id越小说明重启次数越少,越稳定 集群: 主从模式主要实现高可用、高性能(读写分离,可能会有数据一致性的问题),但是如果数据量很多,一个主服务器放不下,就需要多台主服务器解决高扩展问题,这时候就需要用到集群了 集群中,数据是分区的,是横向扩展的 数据分区方式: 1、范围分区(服务器端) 对key的不同的范围分区,比如1~10000分配到redis1,10000~20000分配到redis2 好处:简单,方便迁移和扩展 缺点:热点数据分配不均,性能损失;非数字型key无法使用 2、hash分区(服务器端) Redis实例=hash(key)%N N是主机个数 好处:支持热点数据,热点数据分布均匀,性能好 缺点:扩展性差,需要重新计算,迁移复杂 3、一致性hash(服务器端) 普通hash是对主机数取模,一致性hash,是对2^32(42亿)取模。然后用服务的ip地址hash之后对2^32取模。来了 key之后,得到hash值,往后找,找到第一个ip的hash值,就落在这台服务器上面
扩容:如上图,redis主机ABC,假如再加一个D,位于AC之间,那么BC上面的数据都不会落在D上面,只需要把A上面的数据重新分配就好了 hash环偏移问题:
可以增加主机解决,但是成本较高。还可以使用虚拟节点,
一致性hash缺点: 1、复杂度高,客户端需要自己处理路由、高可用、故障转移等问题 4、代理端分区(逐渐被淘汰了) 常见代理端有codis,Twitter codis将所有的keymore划分到1024个槽位,同时保存了槽位和服务分组的映射关系
proxy优点: 1、客户端不需要关心数据分区 2、支持在线数据迁移 3、高可用, 4、自动进行数据均衡 5、最大支持1024个redis实例 缺点: 1、redis是自己的一个单独分支,不能保持跟官方一致(codis已经不再更新了,慢慢被淘汰了,大趋势是使用原生rediscluster) 2、codis的proxy只有一个,整个性能会下降20% 3、某些命令不支持 5、官方cluster分区 Redis3.0之后,官方提出了完整的集群解决方案,包括 sharding(分区)、replication(复制)、failover(故障转移)。称为RedisCluster。 Redis5.0前采用redis-trib进行集群的创建和管理,需要ruby支持 Redis5.0可以直接使用Redis-cli进行集群的创建和管理 cluster是去中心化,没有中心节点,是点对点(p2p)的集群架构
cluster分片原理: cluster使用了16384(2^14)个slot哈希槽,把所有的节点映射到solt上面,采用平均分配和连续分配。加入有5个节点: redis先对key进行crc16算法(这个算法是16位的算法,但是slot只使用了14位,作者发博客说是因为他觉得16384足够了,一般redis集群最多不会超过1000个节点)进行计算,然后对16384取模,找到哈希槽,就找到了哈希槽映射的节点 slot一定要连续,否则cluster不能工作 优势 1、高性能 Redis Cluster 的性能与单节点部署是同级别的。 多主节点、负载均衡、读写分离 2、高可用 Redis Cluster 支持标准的 主从复制配置来保障高可用和高可靠。 Redis Cluster 也实现了一个类似 Raft 的共识方式,来保障整个集群的可用性。 3、易扩展 向 Redis Cluster 中添加新节点,或者移除节点,都是透明的,不需要停机。 水平、垂直方向都非常容易扩展。 数据分区,海量数据,数据存储 4、原生 部署 Redis Cluster 不需要其他的代理或者工具,而且 Redis Cluster 和单机 Redis 几乎完全兼容。 搭建cluster最少需要三台主服务器,三台从服务器 客户端连接集群: ./redis-cli -h 127.0.0.1 -p 7001 -c -c代表是以redis集群方式进行连接 集群连接重定向: 一、moved重定向 1.每个节点通过通信都会共享Redis Cluster中槽和集群中对应节点的关系 2.客户端向Redis Cluster的任意节点发送命令,接收命令的节点会根据CRC16规则进行hash运算与 16384取余,计算自己的槽和对应节点 3.如果保存数据的槽被分配给当前节点,则去槽中执行命令,并把命令执行结果返回给客户端 4.如果保存数据的槽不在当前节点的管理范围内,则向客户端返回moved重定向异常 5.客户端接收到节点返回的结果,如果是moved异常,则从moved异常中获取目标节点的信息 6.客户端向目标节点发送命令,获取命令执行结果
二、ask重定向 在对集群进行扩容和缩容时,需要对槽及槽中数据进行迁移 当客户端向某个节点发送命令,节点向客户端返回moved异常,告诉客户端数据对应的槽的节点信息如果此时正在进行集群扩展或者缩空操作,当客户端向正确的节点发送命令时,槽及槽中数据已经被迁移到别的节点了,就会返回ask,这就是ask重定向机制 1.客户端向目标节点发送命令,目标节点中的槽已经迁移支别的节点上了,此时目标节点会返回ask转向给客户端 2.客户端向新的节点发送Asking命令给新的节点,然后再次向新节点发送命令 3.新节点执行命令,把命令执行结果返回给客户端
moved和ask的区别 1、moved:槽已确认转移 2、ask:槽还在转移过程中 迁移: 1、向节点B发送状态变更命令,将B的对应slot 状态置为importing。 2、向节点A发送状态变更命令,将A对应的slot 状态置为migrating。 3、向A 发送migrate 命令,告知A 将要迁移的slot对应的key 迁移到B。 4、当所有key 迁移完成后,cluster setslot 重新设置槽位。 集群容灾 故障检测 集群中的每个节点都会定期地(每秒)向集群中的其他节点发送PING消息 如果在一定时间内(cluster-node-timeout),发送ping的节点A没有收到某节点B的pong回应,则A将B标识为pfail。 A在后续发送ping时,会带上B的pfail信息, 通知给其他节点。 如果B被标记为pfail的个数大于集群主节点个数的一半(N/2 + 1)时,B会被标记为fail,A向整个集群广播,该节点已经下线。 其他节点收到广播,标记B为fail。 从节点选举 raft,每个从节点,都根据自己对master复制数据的offset,来设置一个选举时间,offset越大(复制数据越多)的从节点,选举时间越靠前,优先进行选举。 slave 通过向其他master发送FAILVOER_AUTH_REQUEST 消息发起竞选,master 收到后回复FAILOVER_AUTH_ACK 消息告知是否同意。 slave 发送FAILOVER_AUTH_REQUEST 前会将currentEpoch 自增,并将最新的Epoch 带入到FAILOVER_AUTH_REQUEST 消息中,如果自己未投过票,则回复同意,否则回复拒绝。 所有的Master开始slave选举投票,给要进行选举的slave进行投票,如果大部分master node(N/2 +1)都投票给了某个从节点,那么选举通过,那个从节点可以切换成master。 RedisCluster失效的判定: 1、集群中半数以上的主节点都宕机(无法投票) 2、宕机的主节点的从节点也宕机了(slot槽分配不连续) 变更通知 当slave 收到过半的master 同意时,会成为新的master。此时会以最新的Epoch 通过PONG 消息广播自己成为master,让Cluster 的其他节点尽快的更新拓扑结构(node.conf)。 副本漂移 我们知道在一主一从的情况下,如果主从同时挂了,那整个集群就挂了。为了避免这种情况我们可以做一主多从,但这样成本就增加了。 Redis提供了一种方法叫副本漂移,这种方法既能提高集群的可靠性又不用增加太多的从机。
Master1宕机,则Slaver11提升为新的Master1集群检测到新的Master1是单点的(无从机) 集群从拥有最多的从机的节点组(Master3)中,选择节点名称字母顺序最小的从机(Slaver31)漂移到单点的主从节点组(Master1)。 具体流程如下(以上图为例): 1、将Slaver31的从机记录从Master3中删除 2、将Slaver31的的主机改为Master1 3、在Master1中添加Slaver31为从节点 4、将Slaver31的复制源改为Master1 5、通过ping包将信息同步到集群的其他节点



