写点什么

redis 系列之——高可用(主从、哨兵、集群)

作者:诸葛小猿
  • 2020 年 7 月 12 日
  • 本文字数:7646 字

    阅读完需:约 25 分钟

redis系列之——高可用(主从、哨兵、集群)

Redis 系列目录


redis系列之——分布式锁


redis系列之——缓存穿透、缓存击穿、缓存雪崩


redis系列之——Redis为什么这么快?


redis系列之——数据持久化(RDB和AOF)


redis系列之——一致性hash算法


redis系列之——高可用(主从、哨兵、集群)


redis系列之——事物及乐观锁


redis系列之——数据类型geospatial:你隔壁有没有老王?


redis系列之——数据类型bitmaps:今天你签到了吗?


布隆过滤器是个啥!


所谓的高可用,也叫 HA(High Availability),是分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计减少系统不能提供服务的时间。


如果在实际生产中,如果 redis 只部署一个节点,当机器故障时,整改服务都不能提供服务了。这就是我们常说的单点故障。


如果 redis 部署了多台,当一台或几台故障时,整个系统依然可以对外提供服务,这样就提高了服务的可用性。


今天我们就聊聊 redis 高可用的三种模式:主从模式,*哨兵模式*,集群模式


一、主从模式


一般,系统的高可用都是通过部署多台机器实现的。redis 为了避免单点故障,也需要部署多台机器。


因为部署了多台机器,所以就会涉及到不同机器的的数据同步问题。


为此,redis 提供了 Redis 提供了复制(replication)功能,当一台 redis 数据库中的数据发生了变化,这个变化会被自动的同步到其他的 redis 机器上去。


redis 多机器部署时,这些机器节点会被分成两类,一类是主节点(master 节点),一类是从节点(slave 节点)。一般主节点可以进行读、写操作,而从节点只能进行读操作。同时由于主节点可以写,数据会发生变化,当主节点的数据发生变化时,会将变化的数据同步给从节点,这样从节点的数据就可以和主节点的数据保持一致了。一个主节点可以有多个从节点,但是一个从节点会只会有一个主节点,也就是所谓的一主多从结构。



1.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 |


1.2.配置


主节点配置


主节点按照正常的配置配好即可。


从节点配置


使用默认的配置启动机器,机器都是主节点。如果想要让机器变成从节点,需要在 conf 服务器上配置主从复制的相关参数。


  • 在从节点的配置文件 redis.conf 中指定主节点的信息(如果需要的话,可以配置主节点的登录密码,主从复制相关的参数)。三台从节点的配置是一样的。


# 配置主节点的ip和端口slaveof 192.168.1.10 6379# 从redis2.6开始,从节点默认是只读的slave-read-only yes# 假设主节点有登录密码,是123456masterauth 123456
复制代码


  • 也可以不配置上面的文件,使用 redis-server 命令,在启动从节点时,通过参数--slaveof 指定主节点是谁。。


./redis-server --slaveof 192.168.1.10 6379
复制代码


  • 也可以不配上面的文件,正常启动 redis 机器,然后通过redis-cli的命令行执行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命令,可以关闭从服务器的复制功能。同时原来同步的所得的数据集都不会被丢弃。


1.3.机器启动


首先启动主节点,然后一台一台启动从节点。


1.4.主从复制的机制



  • 从数据库连接主数据库,发送 SYNC 命令;

  • 主数据库接收到 SYNC 命令后,可以执行 BGSAVE 命令生成 RDB 文件并使用缓冲区记录此后执行的所有写命令;

  • 主数据库 BGSAVE 执行完后,向所有从数据库发送快照文件,并在发送期间继续记录被执行的写命令;

  • 从数据库收到快照文件后丢弃所有旧数据,载入收到的快照;

  • 主数据库快照发送完毕后开始向从数据库发送缓冲区中的写命令;

  • 从数据库完成对快照的载入,开始接受命令请求,并执行来自主数据库缓冲区的写命令;(从数据库初始化完成)

  • 主数据库每执行一个写命令就会向从数据库发送相同的写命令,从数据库接收并执行收到的写命令(从数据库初始化完成后的操作)

  • 出现断开重连后,2.8 之后的版本会将断线期间的命令传给从数据库,增量复制。

  • 主从刚刚连接的时候,进行全量同步;全同步结束后,进行增量同步。当然,如果有需要,slave 在任何时候都可以发起全量同步。Redis 的策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进行全量同步。


1.5.主从模式的优缺点


优点


  • 支持主从复制,主机会自动将数据同步到从机,可以进行读写分离;

  • 为了分载 Master 的读操作压力,Slave 服务器可以为客户端提供只读操作的服务,写服务依然必须由 Master 来完成;

  • Slave 同样可以接受其他 Slaves 的连接和同步请求,这样可以有效地分载 Master 的同步压力;

  • Master 是以非阻塞的方式为 Slaves 提供服务。所以在 Master-Slave 同步期间,客户端仍然可以提交查询或修改请求;

  • Slave 同样是以阻塞的方式完成数据同步。在同步期间,如果有客户端提交查询请求,Redis 则返回同步之前的数据。


缺点


  • Redis 不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或者手动切换前端的 IP 才能恢复;

  • 主机宕机,宕机前有部分数据未能及时同步到从机,切换 IP 后还会引入数据不一致的问题,降低了系统的可用性;

  • 如果多个 Slave 断线了,需要重启的时候,尽量不要在同一时间段进行重启。因为只要 Slave 启动,就会发送 sync 请求和主机全量同步,当多个 Slave 重启的时候,可能会导致 Master IO 剧增从而宕机。

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

  • redis 的主节点和从节点中的数据是一样的,降低的内存的可用性


二、哨兵模式


主从模式下,当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费事费力,还会造成一段时间内服务不可用。这种方式并不推荐,实际生产中,我们优先考虑哨兵模式。这种模式下,master 宕机,哨兵会自动选举 master 并将其他的 slave 指向新的 master。


在主从模式下,redis 同时提供了哨兵命令redis-sentinel,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是哨兵进程向所有的 redis 机器发送命令,等待 Redis 服务器响应,从而监控运行的多个 Redis 实例。


哨兵可以有多个,一般为了便于决策选举,使用奇数个哨兵。哨兵可以和 redis 机器部署在一起,也可以部署在其他的机器上。多个哨兵构成一个哨兵集群,哨兵直接也会相互通信,检查哨兵是否正常运行,同时发现 master 宕机哨兵之间会进行决策选举新的 master



哨兵模式的作用:


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

  • 当哨兵监测到 master 宕机,会自动将 slave 切换到 master,然后通过发布订阅模式通过其他的从服务器,修改配置文件,让它们切换主机;

  • 然而一个哨兵进程对 Redis 服务器进行监控,也可能会出现问题,为此,我们可以使用多个哨兵进行监控。各个哨兵之间还会进行监控,这样就形成了多哨兵模式。


哨兵很像 kafka 集群中的 zookeeper 的功能。


2.1.机器规划


| 机器名称 | IP | 端口 |

| ---------- | ------------ | ----- |

| master | 192.168.1.10 | 6379 |

| slave 1 | 192.168.1.11 | 6379 |

| slave 2 | 192.168.1.12 | 6379 |

| slave 3 | 192.168.1.13 | 6379 |

| sentinel 1 | 192.168.1.14 | 26379 |

| sentinel 2 | 192.168.1.15 | 26379 |

| sentinel 3 | 192.168.1.16 | 26379 |


这里我们将哨兵进程和 redis 分别部署在不同的机器上,避免因为 redis 宕机导致 sentinel 进程不可用。


2.2.配置


redis.conf 的配置和上面主从模式一样,不用变。这里主要说一下哨兵的配置。


每台机器的哨兵进程都需要一个哨兵的配置文件sentinel.conf,三台机器的哨兵配置是一样的。


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


2.3.机器启动


首先启动主节点,然后一台一台启动从节点。


redis 集群启动完成后,分别启动哨兵集群所在机器的三个哨兵,使用redis-sentinel /path/to/sentinel.conf命令。


2.4.哨兵模式的工作


  • 每个 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 主服务器的主观下线状态就会被移除。


假设 master 宕机,sentinel 1 先检测到这个结果,系统并不会马上进行 failover(故障转移)选出新的 master,仅仅是 sentinel 1 主观的认为 master 不可用,这个现象成为主观下线。当后面的哨兵也检测到主服务器不可用,并且数量达到一定值时,那么哨兵之间就会进行一次投票,投票的结果由 sentinel 1 发起,进行 failover 操作。切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为客观下线。这样对于客户端而言,一切都是透明的。


2.5.主从模式的优缺点


优点


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

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


缺点


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

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


三、集群模式


先说一个误区:Redis 的集群模式本身没有使用一致性 hash 算法,而是使用 slots 插槽。这是很多人的一个误区。这里先留个坑,后面我会出一期《 redis 系列之——一致性 hash 算法》。


Redis 的哨兵模式基本已经可以实现高可用,读写分离 ,但是在这种模式下每台 Redis 服务器都存储相同的数据,很浪费内存,所以在 redis3.0 上加入了 Cluster 集群模式,实现了 Redis 的分布式存储,对数据进行分片,也就是说每台 Redis 节点上存储不同的内容;



这里的 6 台 redis 两两之间并不是独立的,每个节点都会通过集群总线(cluster bus),与其他的节点进行通信。通讯时使用特殊的端口号,即对外服务端口号加 10000。例如如果某个 node 的端口号是 6379,那么它与其它 nodes 通信的端口号是 16379。nodes 之间的通信采用特殊的二进制协议。


对客户端来说,整个 cluster 被看做是一个整体,客户端可以连接任意一个 node 进行操作,就像操作单一 Redis 实例一样,当客户端操作的 key 没有分配到该 node 上时,Redis 会返回转向指令,指向正确的 node,这有点儿像浏览器页面的 302 redirect 跳转。


根据官方推荐,集群部署至少要 3 台以上的 master 节点,最好使用 3 主 3 从六个节点的模式。测试时,也可以在一台机器上部署这六个实例,通过端口区分出来。


3.1.机器规划


| 机器名称 | IP | 端口 |

| -------- | ------------ | ---- |

| master 1 | 192.168.1.11 | 6379 |

| master 2 | 192.168.1.12 | 6379 |

| master 3 | 192.168.1.13 | 6379 |

| slave 1 | 192.168.1.21 | 6379 |

| slave 2 | 192.168.1.22 | 6379 |

| slave 3 | 192.168.1.23 | 6379 |


3.2.配置


修改redis.conf 的配置文件:


# 开启redis的集群模式cluster-enabled yes# 配置集群模式下的配置文件名称和位置,redis-cluster.conf这个文件是集群启动后自动生成的,不需要手动配置。cluster-config-file redis-cluster.conf
复制代码


3.3.机器启动


6 个 Redis 服务分别启动成功之后,这时虽然配置了集群开启,但是这六台机器还是独立的。使用集群管理命令将这 6 台机器添加到一个集群中。


借助 redis-tri.rb 工具可以快速的部署集群。


只需要执行redis-trib.rb create --replicas 1 192.168.1.11:6379 192.168.1.21:6379 192.168.1.12:6379 192.168.1.22:6379 192.168.1.13:6379 192.168.1.23:6379就可以成功创建集群。


该命令执行创建完成后会有响应的日志,通过相关的日志就可以看出集群中机器的关系(不一定和上图对应),执行的日志如下:


>>> Performing hash slots allocation on 6 nodes...Master[0] -> Slots 0 - 5460Master[1] -> Slots 5461 - 10922Master[2] -> Slots 10923 - 16383Adding replica 192.168.1.21:6379 to 192.168.1.11:6379Adding replica 192.168.1.22:6379 to 192.168.1.12:6379Adding replica 192.168.1.23:6379 to 192.168.1.13:6379M: 80c80a3f3e33872c047a8328ad579b9bea001ad8 192.168.1.11:6379   slots:[0-5460] (5461 slots) masterS: b4d3eb411a7355d4767c6c23b4df69fa183ef8bc 192.168.1.21:6379   replicates 6788453ee9a8d7f72b1d45a9093838efd0e501f1M: 4d74ec66e898bf09006dac86d4928f9fad81f373 192.168.1.12:6379   slots:[5461-10922] (5462 slots) masterS: b6331cbc986794237c83ed2d5c30777c1551546e 192.168.1.22:6379   replicates 80c80a3f3e33872c047a8328ad579b9bea001ad8M: 6788453ee9a8d7f72b1d45a9093838efd0e501f1 192.168.1.13:6379   slots:[10923-16383] (5461 slots) masterS: 277daeb8660d5273b7c3e05c263f861ed5f17b92 192.168.1.23:6379   replicates 4d74ec66e898bf09006dac86d4928f9fad81f373Can I set the above configuration? (type 'yes' to accept): yes                  #输入yes,接受上面配置>>> Nodes configuration updated>>> Assign a different config epoch to each node>>> Sending CLUSTER MEET messages to join the cluster
复制代码


执行完成后自动生成配置的 redis-cluster.conf 文件。


登录集群:redis-cli -c -h 192.168.1.11 -p 6379 -a 123456 # -c,使用集群方式登录


查看集群信息:192.168.1.11:6379> CLUSTER INFO #集群状态


列出节点信息:192.168.1.11:6379> CLUSTER NODES #列出节点信息


添加数据:


192.168.1.11:6379> set name aaa-> Redirected to slot [13680] located at 192.168.1.13:6379                #说明最终将数据写到了192.168.1.13:6379上OK
复制代码


获取数据:


192.168.1.11:6379> get name-> Redirected to slot [13680] located at 192.168.1.13:6379                #说明最终到192.168.1.13:6379上读数据"aaa"
复制代码


3.4.运行机制


在 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 节点直连,不需要中间代理层,客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。


3.5.集群扩缩容


对 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移除机器。


3.8.集群模式的优缺点


优点


采用去中心化思想,数据按照 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 以后才正式推出,时间较晚,目前能证明在大规模生产环境下成功的案例还不是很多,需要时间检验。


完成,收工!



传播知识,共享价值】,感谢小伙伴们的关注和支持,我是【诸葛小猿】,一个彷徨中奋斗的互联网民工!!!



用户头像

诸葛小猿

关注

我是诸葛小猿,一个彷徨中奋斗的互联网民工 2020.07.08 加入

公众号:foolish_man_xl

评论 (2 条评论)

发布
用户头像
哨兵直接 -> 哨兵之间

多个哨兵构成一个哨兵集群,哨兵直接也会相互通信,检查哨兵是否正常运行,同时发现 master 宕机哨兵之间会进行决策选举新的 master

2021 年 09 月 27 日 13:48
回复
用户头像
这里应该是”Slave 同样以非阻塞的方式完成数据同步。在同步期间,如果有客户端提交查询请求,Redis 则返回同步之前的数据。“

Slave 同样是以阻塞的方式完成数据同步。在同步期间,如果有客户端提交查询请求,Redis 则返回同步之前的数据。

2021 年 09 月 27 日 13:45
回复
没有更多了
redis系列之——高可用(主从、哨兵、集群)