Redis集群

目录

主从模式

主从第一次同步:全量同步 

第一阶段:建立链接、协商同步

第二阶段:主服务器同步数据给从服务器

第三阶段:主服务器发送新写操作命令给从服务器

命令传播

增量同步

主服务器怎么知道要将哪些增量数据发送给从服务器呢?

主从复制中replication buffer 、repl backlog buffer有什么区别?

哨兵机制

哨兵集群 

集群监控原理

集群故障恢复原理

分片集群

集群伸缩

向集群中添加新的节点

转移插槽

集群故障转移

自动故障转移

手动故障转移


由于数据都是存储在一台服务器上,可能出现如下情况:

  • 如果服务器发生了宕机,由于数据恢复是需要点时间,那么这个期间是无法服务新的请求的;
  • 如果这台服务器的硬盘出现了故障,可能数据就都丢失了。

要避免这种单点故障,最好的办法是将数据备份到其他服务器上,让这些服务器也可以对外提供服务,这样即使有一台服务器出现了故障,其他服务器依然可以继续提供服务。

主从模式

主从模式在Ubuntu下配置https://blog.csdn.net/weixin_44415582/article/details/131748066?spm=1001.2014.3001.5501

主从模式可以保证多台服务器的数据一致性,且主从服务器之间采用的是【读写分离】的方式。

读写分离:主服务器可以进行读写操作,当发生写操作时自动将写操作同步给从服务器,而从服务器一般是只读,并接受主服务器同步过来写操作命令,然后执行这条命令。

Redis集群_第1张图片

主从第一次同步:全量同步 

主从服务器间的第一次同步的过程可分为三个阶段:

  • 第一阶段是建立链接、协商同步;
  • 第二阶段是主服务器同步数据给从服务器;
  • 第三阶段是主服务器发送新写操作命令给从服务器。

Redis集群_第2张图片

第一阶段:建立链接、协商同步

执行了 replicaof 命令后,从服务器就会给主服务器发送 psync 命令,表示要进行数据同步。

psync 命令包含两个参数,分别是主服务器的replid 和复制进度 offset

  • replid,每个 Redis 服务器在启动时都会自动生产一个随机的 ID 来唯一标识自己。id一致则说明是同一数据集。每一个master都有唯一的replid,slave则会继承master节点的replid 。
  • offset,偏移量,随着记录在repl_baklog中的数据增多而逐渐增大。slave完成同步时也会记录当前同步的offset。如果slave的offset小于master的offset,说明slave数据落后于master,需要更新。

主服务器收到 psync 命令后,主服务器判断replid是否一致,若不一致,会用 FULLRESYNC 作为响应命令返回给对方,进行全量同步也就是主服务器会把所有的数据都同步给从服务器。

第二阶段:主服务器同步数据给从服务器

接着,主服务器会执行 bgsave 命令异步来生成 RDB 文件,然后从服务器收到RDB文件后,先清空当前的数据,然后载入RDB文件。但是,在主服务器会执行 bgsave 的写操作命令并没有记录到刚刚生成的 RDB 文件中,这时主从服务器间的数据就不一致了

为了保证主从服务器的数据一致性,主服务器在下面这三个时间间隙中将收到的写操作命令,写入到 replication buffer 缓冲区里

  • 主服务器生成 RDB 文件期间;
  • 主服务器发送 RDB 文件给从服务器期间;
  • 从服务器加载 RDB 文件期间;

第三阶段:主服务器发送新写操作命令给从服务器

在主服务器生成的 RDB 文件发送完,从服务器收到 RDB 文件后,丢弃所有旧数据,将 RDB 数据载入到内存。完成 RDB 的载入后,会回复一个确认消息给主服务器。

接着,主服务器将 replication buffer 缓冲区里所记录的写操作命令追加地发送给从服务器,从服务器执行来自主服务器 replication buffer 缓冲区里发来的命令,这时主从服务器的数据就一致了。

至此,主从服务器的第一次同步的工作就完成了。

命令传播

主从服务器在完成第一次同步后,双方之间就会维护一个TCP 连接,此时主从节点之间建立长连接

Redis集群_第3张图片

后续主服务器可以通过这个连接继续将写操作命令传播给从服务器,然后从服务器执行该命令,使得与主服务器的数据库状态相同。

而且这个连接是长连接的,目的是避免频繁的 TCP 连接和断开带来的性能开销。

增量同步

全量同步需要先做RDB,然后将RDB文件通过网络传输个slave,成本太高了《若RDB文件太大,会占用主服务器的网络带宽,会对主服务器响应命令请求产生影响》。因此除了第一次做全量同步,其它大多数时候slave与master都是做增量同步

若主从服务器间的网络连接断开了,那么就无法进行命令传播了,这时从服务器的数据就没办法和主服务器保持一致了,网络断开又恢复后,从主从服务器会采用增量复制的方式继续同步,也就是只会把网络断开期间主服务器接收到的写操作命令,同步给从服务器。

Redis集群_第4张图片

主要有三个步骤:

  • 从服务器在恢复网络后,会发送 psync 命令给主服务器
  • 主服务器收到该命令后,然后用 CONTINUE 响应命令告诉从服务器接下来采用增量复制的方式同步数据;
  • 然后主服务将主从服务器断线期间,所执行的写命令发送给从服务器,然后从服务器执行这些命令。

主服务器怎么知道要将哪些增量数据发送给从服务器呢?

  • repl_backlog_buffer,是一个【环形】缓冲区,用于主从服务器断连后,从中找到差异的数据;
  • replication offset,标记上面那个缓冲区的同步进度,主从服务器都有各自的偏移量,主服务器使用 master_repl_offset 来记录自己「」到的位置,从服务器使用 slave_repl_offset 来记录自己「」到的位置。

在主服务器进行命令传播时,不仅将写命令发送给从服务器,还将写命令写入repl_backlog_buffer 缓冲区里,因此 这个缓冲区里会保存着最近传播的写命令。

网络断开后,当从服务器重新连上主服务器时,从服务器会通过 psync 命令将自己的复制偏移量 slave_repl_offset 发送给主服务器,主服务器根据自己的 master_repl_offset 和 slave_repl_offset 之间的差距,然后来决定对从服务器执行哪种同步操作:

  • Redis集群_第5张图片

    如果判断出从服务器要读取的数据还在 repl_backlog_buffer 缓冲区里,那么主服务器将采用增量同步的方式
  • Redis集群_第6张图片

    相反,如果判断出从服务器要读取的数据已经不存在 repl_backlog_buffer 缓冲区里,那么主服务器将采用全量同步的方式

当主服务器在 repl_backlog_buffer 中找到主从服务器差异(增量)的数据后,就会将增量的数据写入到 replication buffer 缓冲区,其缓存将要传播给从服务器的命令。

Redis集群_第7张图片

repl_backlog_buffer 缓行缓冲区的默认大小是 1M,并且由于它是一个环形缓冲区。为了避免在网络恢复时,主服务器频繁地使用全量同步的方式,我们应该调整下 repl_backlog_buffer 缓冲区大小,尽可能的大一些,减少出现从服务器要读取的数据被覆盖的概率,从而使得主服务器采用增量同步的方式。

主从复制中replication buffer 、repl backlog buffer有什么区别?

  • 出现的阶段不一样:
    • repl backlog buffer 是在增量复制阶段出现,保证主从一致性。而且一个主节点只分配一个 repl backlog buffer
    • replication buffer 是在全量复制阶段和增量复制阶段都会出现,主节点会给每个新连接的从节点,在主节点的内存中分配一个 replication buffer用来缓存即将发送给从服务器的写命令
  • 这两个 Buffer 都有大小限制的,当缓冲区满了之后,发生的事情不一样:
    • 当 repl backlog buffer 满了,因为是环形结构,会直接覆盖起始位置数据;
    • 当 replication buffer 满了,会导致连接断开,删除缓存,从节点重新连接,重新开始全量复制

哨兵机制

哨兵(Sentinel)机制,它的作用是实现主从节点故障转移。它会监测主节点是否存活,如果发现主节点挂了,它就会选举一个从节点切换为主节点,并且把新主节点的相关信息通知给从节点和客户端。

Ubuntu下配置哨兵集群https://blog.csdn.net/weixin_44415582/article/details/131748680?spm=1001.2014.3001.5501

哨兵的作用:

  • 监控:Sentinel 会不断检查您的master和slave是否按预期工作

  • 自动故障恢复:如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后也以新的master为主

  • 通知:Sentinel充当Redis客户端的服务发现来源,当集群发生故障转移时,会将最新信息推送给Redis的客户端

哨兵集群 

在哨兵集群中,哨兵节点之间是通过 Redis 的发布者/订阅者机制来相互发现的。哨兵 A 把自己的 IP 地址和端口的信息发布到__sentinel__:hello 频道上,哨兵 B 和 C 订阅了该频道。那么此时,哨兵 B 和 C 就可以从这个频道直接获取哨兵 A 的 IP 地址和端口号。然后,哨兵 B、C 可以和哨兵 A 建立网络连接。

主节点知道所有【从节点】的信息,所以哨兵会每 10 秒一次的频率向主节点发送 INFO 命令来获取所有【从节点】的信息。

Redis集群_第8张图片

集群监控原理

Sentinel基于心跳机制监测服务状态,每隔1秒向集群的每个实例发送ping命令:

  • 主观下线:如果某sentinel节点发现某实例未在规定时间响应(配置项 down-after-milliseconds 参数设定的,单位是毫秒),则认为该实例主观下线
  • 客观下线:若超过指定数量(quorum)的sentinel都认为该实例主观下线,则该实例客观下线。quorum值最好超过Sentinel实例数量的一半<一般是哨兵个数的二分之一加一>(防止主节点因为假死被故障切换啦)

Redis集群_第9张图片

集群故障恢复原理

Redis集群_第10张图片

一旦发现master故障,sentinel需要在salve中选择一个作为新的master,选择依据是这样的:

  • 首先会判断slave节点与master节点断开时间长短,如果超过指定值(down-after-milliseconds * 10)则会排除该slave节点

  • 然后判断slave节点的slave-priority值,越小优先级越高,如果是0则永不参与选举

  • 如果slave-prority一样,则判断slave节点的offset值,越大说明数据越新,优先级越高

  • 最后是判断slave节点的运行id大小,越小优先级越高。

当选出一个新的master后,故障切换流程如下:

  • sentinel给备选的slave节点发送slaveof no one命令,让该节点成为master

  • sentinel给所有其它slave发送slaveof 192.168.150.101 7002 命令,让这些slave成为新master的从节点,开始从新的master上同步数据。

  • 最后,sentinel将故障节点(旧master)标记为slave,当故障节点恢复后会自动成为新的master的slave节点

分片集群

当 Redis 缓存数据量大到一台服务器无法缓存时,就需要使用 Redis 分片集群(Redis Cluster )方案,它将数据分布在不同的服务器上,以此来降低系统对单主节点的依赖,从而提高 Redis 服务的读写性能。
Redis Cluster主节点互相之间通过心跳机制监控互相状态,而每个主节点的从节点不支持读写操作,只是做个备份。

Ubuntu下配置分片集群https://blog.csdn.net/weixin_44415582/article/details/131748887?spm=1001.2014.3001.5501

Redis Cluster 方案采用哈希槽(Hash Slot),来处理数据和节点之间的映射关系。在 Redis Cluster 方案中,一个切片集群共有 16384 个哈希槽,这些哈希槽类似于数据分区,每个键值对都会根据它的 key,被映射到一个哈希槽中,具体执行过程分为两大步:

  • 数据key不是与节点绑定,而是与插槽绑定。redis会根据key的有效部分计算插槽值,分两种情况:
    key中包含"{}",且“{}”中至少包含1个字符,“{}”中的部分是有效部分
    key中不包含“{}”,整个key都是有效部分
  • 根据键值对的 key的有效部分,按照 CRC16 算法 (opens new window)计算一个 16 bit 的值。
  • 再用 16bit 值对 16384 取模,得到 0~16383 范围内的模数,每个模数代表一个相应编号的哈希槽。

通过以下两种方案被映射到具体的 Redis 节点上

  • 平均分配: 在使用 cluster create 命令创建 Redis 集群时,Redis 会自动把所有哈希槽平均分布到集群节点上。比如集群中有 9 个节点,则每个节点上槽的个数为 16384/9 个。
  • 手动分配: 可以使用 cluster meet 命令手动建立节点间的连接,组成集群,再使用 cluster addslots 命令,指定每个节点上的哈希槽个数。

需要注意的是,在手动分配哈希槽时,需要把 16384 个槽都分配完,否则 Redis 集群无法正常工作。

集群伸缩

向集群中添加新的节点

cd /tmp

创建一个文件夹
mkdir 7004

拷贝配置文件
cp redis.conf /7004

修改配置文件
sed /s/6379/7004/g 7004/redis.conf

启动
redis-server 7004/redis.conf

执行添加命令 192.168.150.101:7004《添加节点》 192.168.150.101:7001《集群中已知节点》
redis-cli --cluster add-node  192.168.150.101:7004 192.168.150.101:7001

通过命令检查集群状态:
redis-cli -p 7001 cluster nodes

Redis集群_第11张图片

但是,可以看到7004节点的插槽数量为0,因此没有任何数据可以存储到7004上

转移插槽

将0~3000的插槽从7001转移到7004

与7001建立连接
redis-cli --cluster reshard 192.168.150.101:7001

Redis集群_第12张图片

 询问要移动多少个插槽,我们计划是3000个

Redis集群_第13张图片

 询问,你的插槽是从哪里移动过来的?

  • all:代表全部,也就是三个节点各转移一部分

  • 具体的id:目标节点的id

  • done:没有了

集群故障转移

自动故障转移

情景:7002宕机,7001,7003正常

1)首先是7002实例与其它实例失去连接

直接停止一个redis实例,端口7002
redis-cli -p 7002 shutdown

2)然后是疑似宕机:

 3)最后是确定下线,自动提升一个slave为新的master:

 4)当7002再次启动,就会变为一个slave节点了:

手动故障转移

利用cluster failover命令可以手动让集群中的某个master宕机切换到执行cluster failover命令的这个slave节点(主从切换),实现无感知的数据迁移。其流程如下

Redis集群_第14张图片

cluster failover命令可以指定三种模式:

  • 默认的流程,如图1~6歩

  • force:省略了对offset的一致性校验

  • takeover:直接执行第5歩,忽略数据一致性、忽略master状态和其它master的意见

案例需求:在7002这个slave节点执行手动故障转移,重新夺回master地位

你可能感兴趣的:(Redis,redis)