Redis高可用方案详解

在生产环境下,单机部署的Redis服务一旦宕机,所有依赖Redis服务的主流服务都会受到影响, 这时就需要一种Redis高可用方案。
一般来说, 一个高可用的方案要满足以下三点要求:

  • 数据备份(冗余) 数据冗余在不同的节点上,防止数据丢失
  • 故障自动切换 正在服务的节点故障时,可以自动地切换到备用节点。
  • 在线扩容(缩容) 即可以根据需要动态地增加、减少服务实例。

一、主从复制

类似于MYSQL的主从同步, 是将一台Redis服务器的数据(主节点)复制到其他的Redis服务器上(从节点),且数据的复制是单向的,只能由主节点到从节点。Redis 主从复制支持 主从同步从从同步 两种,后者是 Redis 后续版本新增的功能,以减轻主节点的同步负担。

主从复制原理

1.slave节点初次启动时主动向master发起TCP连接,并发起同步请求(psync命令), master接收连接(可要求授权认证),并将slave的信息保存起来。

2.master节点收到同步请求,执行BGSAVE命令生成rdb文件,文件生成后发送给slave。

3.slave收到后首先清楚自己的旧数据, 然后载入收到的rdb文件, slave更新至master执行bgsave命令前的状态。

4.master将保存rdb文件期间收到的写命令发送给slave, slave更新至主节点的最新状态。

5.此后master每有写命令,就会主动发送给slave节点。

主从节点会分别维护一个复制便宜量(复制的字节数), 当出现网络中断等情况时,重连后会从偏移量处开始进行部分复制,避免了全量复制的重型操作。

主从复制配置

主从复制master节点不需要做任何配置, 只需要在slave的配置文件中加入: slaveof <masterip> <masterport>
从节点启动时就会自动向主节点发起连接,完成主从同步的一系列过程。

优点

主从复制提供了基本的数据多节点备份功能, 当主节点发生故障时,可以启用从节点继续提供服务。

缺点

无法实现故障的自动切换, 主节点故障时,需要手动将程序(客户端)的配置从主节点切换为从节点,然后重启客户端程序。
Tips: 主从复制的机制是其他高可用方式的基础, 下面介绍的哨兵方式和集群方式都依赖于主从复制机制。

二、哨兵

上图 展示了一个典型的哨兵架构图,它由两部分组成,哨兵节点和数据节点(主节点+从节点)

  • 哨兵节点: 哨兵系统由一个或多个哨兵节点组成,哨兵节点是特殊的 Redis 节点,不存储数据。
  • 数据节点: 主节点和从节点都是数据节点。

哨兵方式在主从复制的基础上, 实现了故障自动切换的功能:

  • 监控(Monitoring): 哨兵会不断地检查主节点和从节点是否运作正常。
  • 自动故障转移(Automatic failover):主节点 不能正常工作时,哨兵会开始 自动故障转移操作,它会将失效主节点的其中一个 从节点升级为新的主节点,并让其他从节点改为复制新的主节点。
  • 配置提供者(Configuration provider): 客户端在初始化时,通过连接哨兵来获得当前 Redis 服务的主节点地址。
  • 通知(Notification): 哨兵可以将故障转移的结果发送给客户端。

快速开始

以下我们以一主二从三哨兵的架构来搭建一个哨兵系统

找到 redis.conf 文件复制三份分别命名为 redis-master.conf redis-slave1.conf
redis-slave2.conf 分别作为一个主节点和两个从节点的配置

配置如下:

#redis-master.conf    master配置
port 6379
daemonize yes
logfile "6379.log"
dbfilename "dump-6379.rdb"
 
#redis-slave1.conf   slave1配置
port 6380
daemonize yes
logfile "6380.log"
dbfilename "dump-6380.rdb"
slaveof 127.0.0.1 6379
 
#redis-slave2.conf    slave2配置
port 6381
daemonize yes
logfile "6381.log"
dbfilename "dump-6381.rdb"
slaveof 127.0.0.1 6379

然后启动三个redis实例:

redis-server redis-master.conf
redis-server redis-slave1.conf
redis-server redis-slave2.conf

节点启动后,我们执行 redis-cli 默认连接到我们端口为 6379 的主节点执行 info Replication 检查一下主从状态是否正常

按照上面同样的方法,我们给哨兵节点也创建三个配置文件。(哨兵节点本质上是特殊的 Redis 节点,所以配置几乎没什么差别,只是在端口上做区分就好)

# redis-sentinel-1.conf
port 26379
daemonize yes
logfile "26379.log"
sentinel monitor mymaster 127.0.0.1 6379 2

# redis-sentinel-2.conf
port 26380
daemonize yes
logfile "26380.log"
sentinel monitor mymaster 127.0.0.1 6379 2

# redis-sentinel-3.conf
port 26381
daemonize yes
logfile "26381.log"
sentinel monitor mymaster 127.0.0.1 6379 2

其中,sentinel monitor mymaster 127.0.0.1 6379 2 配置的含义是:该哨兵节点监控 127.0.0.1:6379 这个主节点,该主节点的名称是 mymaster,最后的 2 的含义与主节点的故障判定有关:至少需要 2 个哨兵节点同意,才能判定主节点故障并进行故障转移。

执行下方命令将哨兵节点启动起来:

redis-server redis-sentinel-1.conf --sentinel
redis-server redis-sentinel-2.conf --sentinel
redis-server redis-sentinel-3.conf --sentinel

使用 redis-cil 工具连接哨兵节点,并执行 info Sentinel 命令来查看是否已经在监视主节点了

# 连接端口为 26379 的 Redis 节点
➜  ~ redis-cli -p 26379
127.0.0.1:26379> info Sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=127.0.0.1:6379,slaves=2,sentinels=3

三、集群方式

哨兵方式虽然实现了故障自动切换, 但是实际为客户端提供读写服务的Redis仍然只有主节点一个,所以受限于单机的内存容量。

  • 集群方式采用数据分片的方式将数据存储在多个节点上,突破了单机的存储限制。
  • 集群中的每个节点都可以对客户端提供读写服务, 集群相对于单机拥有更高的并发能力。

上图 展示了 Redis Cluster 典型的架构图,集群中的每一个 Redis 节点都 互相两两相连,客户端任意 直连 到集群中的 任意一台,就可以对其他 Redis 节点进行 读写 的操作。

数据分片

Redis 集群使用数据分片来实现, 一个 Redis 集群包含 16384 个哈希槽(hash slot), 数据库中的每个键都属于这 16384 个哈希槽的其中一个, 集群使用公式 CRC16(key) % 16384 来计算键 key 属于哪个槽。集群中的每个节点负责处理一部分哈希槽。

搭建Redis集群

要让集群正常工作至少需要3个主节点,在这里我们要创建6个redis节点,其中三个为主节点,三个为从节点。为了方便演示,这6个redis部署在同一台机器, 采用不同的端口号(7000 ~ 7005)。

准备配置文件

6个Redis节点的配置文件分别命名为node_7000.conf, node_7001.conf , ......, node_7005.conf,

除了端口号不同外,其余配置相同, 配置如下:

# 后台执行
daemonize yes
# 端口号
port 7000
# 为每一个集群节点指定一个 pid_file
pidfile ~/Desktop/redis-cluster/redis_7000.pid
# 启动集群模式
cluster-enabled yes
# 每一个集群节点都有一个配置文件,这个文件是不能手动编辑的。确保每一个集群节点的配置文件不通
cluster-config-file nodes-7000.conf
# 集群节点的超时时间,单位:ms,超时后集群会认为该节点失败
cluster-node-timeout 5000
# 最后将 appendonly 改成 yes(AOF 持久化)
appendonly yes

启动6个Redis实例

redis-server redis_7000.conf
redis-server redis_7001.conf
redis-server redis_7002.conf
redis-server redis_7003.conf
redis-server redis_7004.conf
redis-server redis_7005.conf

使用ps -ef | grep redis查看

可以看到6个Redis实例都以cluster的方式启动了

实例启动后还处于各自独立的状态,还没有形成集群,需要手动执行命令建立集群。

建立集群

执行命令:

redis-cli --cluster create --cluster-replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005

--replicas 1 的意思是:我们希望为集群中的每个主节点创建一个从节点。

看到 [OK] 的信息之后,就表示集群已经搭建成功了,可以看到,这里我们正确地创建了三主三从的集群。

验证集群

使用 redic-cli 任意连接一个节点:

redis-cli -c -h 127.0.0.1 -p 7000
127.0.0.1:7000>
  • -c表示集群模式;-h 指定 ip 地址;-p 指定端口。
127.0.0.1:7000> SET name xiaoming
-> Redirected to slot [5798] located at 127.0.0.1:7001
OK
127.0.0.1:7001>

可以看到这里 Redis 自动帮我们进行了 Redirected 操作跳转到了 7001 这个实例上

我们可以在任意节点使用cluster nodes 查看节点列表

故障模拟

从图中我们可以看到7005实例是7001实例的从节点, 我们现在停掉7001的实例(kill -9)

然后我们连接现存的任一节点,读取name值

发现仍然可以从7005的实例上读取到值,集群仍然是正常运转的。

当我们把7005实例也停掉后,集群就会变得不可用

posted @ 2020-11-05 13:36  starst  阅读(3214)  评论(0编辑  收藏  举报