前言:所谓的高可用,也叫HA(High Availability),是分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计减少系统不能提供服务的时间。 如果在实际生产中,如果redis只部署一个节点,当机器故障时,整改服务都不能提供服务了。这就是我们常说的单点故障。 如果redis部署了多台,当一台或几台故障时,整个系统依然可以对外提供服务,这样就提高了服务的可用性。 今天我们就聊聊redis高可用的三种模式:主从模式,哨兵模式,集群模式。

1、主从模式

一般,系统的高可用都是通过部署多台机器实现的。redis为了避免单点故障,也需要部署多台机器。因为部署了多台机器,所以就会涉及到不同机器的的数据同步问题。
为此,redis提供了Redis提供了复制(replication)功能,当一台redis数据库中的数据发生了变化,这个变化会被自动的同步到其他的redis机器上去。
redis多机器部署时,这些机器节点会被分成两类,一类是主节点(master节点),一类是从节点(slave节点)。一般主节点可以进行读、写操作,而从节点只能进行读操作。同时由于主节点可以写,数据会发生变化,当主节点的数据发生变化时,会将变化的数据同步给从节点,这样从节点的数据就可以和主节点的数据保持一致了。一个主节点可以有多个从节点,但是一个从节点会只会有一个主节点,也就是所谓的一主多从结构。
三、Redis主从、哨兵、集群 - 图1

机器规划

机器名称 IP 端口
master 192.168.1.10 6379
slave1 192.168.1.11 6379
slave2 192.168.1.12 6379
slave3 192.168.1.13 6379

如何配置

主节点按照正常配置配置好即可。从节点需要修改相关参数,修改redis.conf

  1. # 配置主节点的ip和端口,注意:Redis 5.0之后使用replicaof 192.168.0.60 6379
  2. slaveof 192.168.1.10 6379
  3. # 从redis2.6开始,从节点默认是只读的
  4. slave-read-only yes
  5. # 假设主节点有登录密码,是123456
  6. masterauth 123456

也可以不需要做配置,但是从节点启动参数需要指定:
./redis-server --slaveof 192.168.1.10 6379
启动时,先启动主节点,再启动从节点。

切换主节点

系统运行时,如果master挂掉了,可以在一个从库(如slave1)上手动执行命令slaveof no one,将slave1变成新的master;在slave2和slave3上分别执行slaveof 192.168.1.11 6379 将这两个机器的主节点指向的这个新的master;同时,挂掉的原master启动后作为新的slave也指向新的master上。
执行命令slaveof no one命令,可以关闭从服务器的复制功能。同时原来同步的所得的数据集都不会被丢弃。

主从复制的原理

image.png

主从模式优缺点

优点

  • 支持主从复制,主机会自动将数据同步到从机,可以进行读写分离;
  • 为了分载Master的读操作压力,Slave服务器可以为客户端提供只读操作的服务,写服务依然必须由Master来完成;
  • Slave同样可以接受其他Slaves的连接和同步请求,这样可以有效地分载Master的同步压力;
  • Master是以非阻塞的方式为Slaves提供服务。所以在Master-Slave同步期间,客户端仍然可以提交查询或修改请求;
  • Slave同样是以阻塞的方式完成数据同步。在同步期间,如果有客户端提交查询请求,Redis则返回同步之前的数据。

缺点

  • Redis不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或者手动切换前端的IP才能恢复;
  • 主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还会引入数据不一致的问题,降低了系统的可用性;
  • 如果多个Slave断线了,需要重启的时候,尽量不要在同一时间段进行重启。因为只要Slave启动,就会发送sync请求和主机全量同步,当多个Slave重启的时候,可能会导致Master IO剧增从而宕机。

    2、哨兵模式

    主从模式下,当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费事费力,还会造成一段时间内服务不可用。这种方式并不推荐,实际生产中,我们优先考虑哨兵模式。这种模式下,master宕机,哨兵会自动选举master并将其他的slave指向新的master。
    在主从模式下,redis同时提供了哨兵命令redis-sentinel,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是哨兵进程向所有的redis机器发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。
    哨兵可以有多个,一般为了便于决策选举,使用奇数个哨兵。哨兵可以和redis机器部署在一起,也可以部署在其他的机器上。多个哨兵构成一个哨兵集群,哨兵直接也会相互通信,检查哨兵是否正常运行,同时发现master宕机哨兵之间会进行决策选举新的master。
    三、Redis主从、哨兵、集群 - 图3
    哨兵的作用:

  • 通过发送命令,让Redis服务器返回监控其运行状态,包括主服务器和从服务器;

  • 当哨兵监测到master宕机,会自动将slave切换到master,然后通过发布订阅模式通过其他的从服务器,修改配置文件,让它们切换主机;
  • 然而一个哨兵进程对Redis服务器进行监控,也可能会出现问题,为此,我们可以使用多个哨兵进行监控。各个哨兵之间还会进行监控,这样就形成了多哨兵模式。

哨兵很像常用的注册中心zookeeper的功能。

机器规划

机器名称 IP Redis端口 哨兵端口
master 192.168.1.10 6379 (哨兵一)26379
slave 1 192.168.1.11 6379 (哨兵二)26379
slave 2 192.168.1.12 6379 (哨兵三)26379
slave 3 192.168.1.13 6379 (哨兵四)26379

如何配置

redis.conf配置文件和主从模式一模一样,不再赘述,这里主要说一下哨兵配置文件。首先在conf文件夹下面手动建文件
sentinel.conf,做如下配置:

  1. # 禁止保护模式
  2. protected-mode no
  3. # 配置监听的主服务器,这里sentinel monitor代表监控,mymaster代表服务器的名称,可以自定义,
  4. #192.168.1.10代表监控的主服务器,6379代表端口,2代表只有两个或两个以上的哨兵认为主服务器不可用的时候,才会进行failover操作。
  5. sentinel monitor mymaster 192.168.1.10 6379 2
  6. # sentinel author-pass定义服务的密码,mymaster是服务名称,123456是Redis服务器密码
  7. sentinel auth-pass mymaster 123456

哨兵模式工作流程

  • 每个Sentinel(哨兵)进程以每秒钟一次的频率向整个集群中的Master主服务器,Slave从服务器以及其他Sentinel(哨兵)进程发送一个 PING 命令。
  • 如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel(哨兵)进程标记为主观下线(SDOWN)
  • 如果一个Master主服务器被标记为主观下线(SDOWN),则正在监视这个Master主服务器的所有 Sentinel(哨兵)进程要以每秒一次的频率确认Master主服务器的确进入了主观下线状态
  • 当有足够数量的 Sentinel(哨兵)进程(大于等于配置文件指定的值)在指定的时间范围内确认Master主服务器进入了主观下线状态(SDOWN), 则Master主服务器会被标记为客观下线(ODOWN)
  • 在一般情况下, 每个 Sentinel(哨兵)进程会以每 10 秒一次的频率向集群中的所有Master主服务器、Slave从服务器发送 INFO 命令。
  • 当Master主服务器被 Sentinel(哨兵)进程标记为客观下线(ODOWN)时,Sentinel(哨兵)进程向下线的 Master主服务器的所有 Slave从服务器发送 INFO 命令的频率会从 10 秒一次改为每秒一次。
  • 若没有足够数量的 Sentinel(哨兵)进程同意 Master主服务器下线, Master主服务器的客观下线状态就会被移除。若 Master主服务器重新向 Sentinel(哨兵)进程发送 PING 命令返回有效回复,Master主服务器的主观下线状态就会被移除。

    哨兵模式的优缺点

    优点

  • 哨兵模式是基于主从模式的,所有主从的优点,哨兵模式都具有。

  • 主从可以自动切换,系统更健壮,可用性更高。

    缺点

  • 具有主从模式的缺点,每台机器上的数据是一样的,内存的可用性较低。

  • Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。

    三、集群模式

    Redis 的哨兵模式基本已经可以实现高可用,读写分离 ,但是在这种模式下每台 Redis 服务器都存储相同的数据,很浪费内存,所以在redis3.0上加入了 Cluster 集群模式,实现了 Redis 的分布式存储,对数据进行分片,也就是说每台 Redis 节点上存储不同的内容;
    三、Redis主从、哨兵、集群 - 图4
    这里的6台redis两两之间并不是独立的,每个节点都会通过集群总线(cluster bus),与其他的节点进行通信。通讯时使用特殊的端口号,即对外服务端口号加10000。例如如果某个node的端口号是6379,那么它与其它nodes通信的端口号是16379。nodes之间的通信采用特殊的二进制协议。
    对客户端来说,整个cluster被看做是一个整体,客户端可以连接任意一个node进行操作,就像操作单一Redis实例一样,当客户端操作的key没有分配到该node上时,Redis会返回转向指令,指向正确的node,这有点儿像浏览器页面的302 redirect跳转。
    根据官方推荐,集群部署至少要 3 台以上的master节点,最好使用 3 主 3 从六个节点的模式。测试时,也可以在一台机器上部署这六个实例,通过端口区分出来。

    如何配置

    详情参阅
    Redis-cluster安装配置文档.docx

    运行机制

    在 Redis 的每一个节点上,都有这么两个东西,一个是插槽(slot),它的的取值范围是:0-16383,可以从上面redis-trib.rb执行的结果看到这16383个slot在三个master上的分布。还有一个就是cluster,可以理解为是一个集群管理的插件,类似的哨兵。
    当我们的存取的 Key到达的时候,Redis 会根据 crc16的算法对计算后得出一个结果,然后把结果和16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,通过这个值,去找到对应的插槽所对应的节点,然后直接自动跳转到这个对应的节点上进行存取操作。
    当数据写入到对应的master节点后,这个数据会同步给这个master对应的所有slave节点。
    为了保证高可用,redis-cluster集群引入了主从模式,一个主节点对应一个或者多个从节点。当其它主节点ping主节点master 1时,如果半数以上的主节点与master 1通信超时,那么认为master 1宕机了,就会启用master 1的从节点slave 1,将slave 1变成主节点继续提供服务。
    如果master 1和它的从节点slave 1都宕机了,整个集群就会进入fail状态,因为集群的slot映射不完整。如果集群超过半数以上的master挂掉,无论是否有slave,集群都会进入fail状态。
    redis-cluster采用去中心化的思想,没有中心节点的说法,客户端与Redis节点直连,不需要中间代理层,客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。

    集群扩缩容

    对redis集群的扩容就是向集群中添加机器,缩容就是从集群中删除机器,并重新将16383个slots分配到集群中的节点上(数据迁移)。扩缩容也是使用集群管理工具 redis-tri.rb。
    扩容时,先使用redis-tri.rb add-node将新的机器加到集群中,这是新机器虽然已经在集群中了,但是没有分配slots,依然是不起做用的。在使用 redis-tri.rb reshard进行分片重哈希(数据迁移),将旧节点上的slots分配到新节点上后,新节点才能起作用。
    缩容时,先要使用 redis-tri.rb reshard移除的机器上的slots,然后使用redis-tri.rb add-del移除机器。

    集群模式的优缺点

    优点

  • 采用去中心化思想,数据按照 slot 存储分布在多个节点,节点间数据共享,可动态调整数据分布;

  • 可扩展性:可线性扩展到 1000 多个节点,节点可动态添加或删除;
  • 高可用性:部分节点不可用时,集群仍可用。通过增加 Slave 做 standby 数据副本,能够实现故障自动 failover,节点之间通过 gossip 协议交换状态信息,用投票机制完成 Slave 到 Master 的角色提升;
  • 降低运维成本,提高系统的扩展性和可用性。

缺点

  • 1.Redis Cluster是无中心节点的集群架构,依靠Goss协议(谣言传播)协同自动化修复集群的状态
  • 但 GosSIp有消息延时和消息冗余的问题,在集群节点数量过多的时候,节点之间需要不断进行 PING/PANG通讯,不必须要的流量占用了大量的网络资源。虽然Reds4.0对此进行了优化,但这个问题仍然存在。
  • 2.数据迁移问题
  • Redis Cluster可以进行节点的动态扩容缩容,这一过程,在目前实现中,还处于半自动状态,需要人工介入。在扩缩容的时候,需要进行数据迁移。
  • 而 Redis为了保证迁移的一致性,迁移所有操作都是同步操作,执行迁移时,两端的 Redis均会进入时长不等的阻塞状态,对于小Key,该时间可以忽略不计,但如果一旦Key的内存使用过大,严重的时候会接触发集群内的故障转移,造成不必要的切换。

    四、总结

    主从模式:master节点挂掉后,需要手动指定新的master,可用性不高,基本不用。
    哨兵模式:master节点挂掉后,哨兵进程会主动选举新的master,可用性高,但是每个节点存储的数据是一样的,浪费内存空间。数据量不是很多,集群规模不是很大,需要自动容错容灾的时候使用。
    集群模式:数据量比较大,QPS要求较高的时候使用。 Redis Cluster是Redis 3.0以后才正式推出,时间较晚,目前能证明在大规模生产环境下成功的案例还不是很多,需要时间检验。