前言

通过前几篇文章,大家了解了redis的强大:性能高、应用场景的广泛、操作简单等。当然这些优点都是建立在redis服务可用的情况下,那么怎么保证redis的可用性呢?本篇文章带大家了解下redis如何实现服务的高可用?

正文

Redis(单机—集群)

本篇文章会从redis单节点讲到redis集群的演变过程,在redis中实现高可用的方式无非是持久化、复制、哨兵以及集群。下面带大家依次了解他们的作用以及解决了怎样的问题。

Redis单机

redis单机,顾名思义,只有一台redis服务器,必然无法高可用。该机器宕机会直接影响程序的运行。那这有什么可聊的呢?非也,redis单机是集群的基础,我们都知道,redis是基于内存存储的,单机虽然会有高可用的问题,但是宕机后数据不丢失是必须要解决的问题。那么如何实现呢?持久化到磁盘无疑是最好的选择。那么redis的持久化方式有哪些呢?— 包括AOF和RDB。

  • RDB

RDB是redis默认持久化的方式,又叫快照。想必大家对快照还是足够熟悉的,举个例子,就好比我们打游戏的存档。我们在某个环节存档后,即使后面死了也不用从头再来,而是从存档的地方读档后就可以继续游戏了。也就是说如果redis服务挂了,那么重启后redis就会读档最近的一次存档(RDB文件),然后继续运行。这样就保证了数据不会完全丢失,但是他的缺点大家应该也想到了—丢失存档到宕机这段时间的数据。那么redis是怎么控制RDB的频率呢?下面我带大家了解下。

//第一种  主动触发
1. save命令 保存当前快照  同步操作 其他操作等他(不建议使用)
2. bgsave命令  保存当前快照  异步操作
3. flushall命令  清表时 备份快照 空rdb文件 无意义
4. shutdown命令  保证服务器正常关闭并且不丢失数据 

//第二种  被动触发
#所谓的被动也就是通过配置文件指定  一段时间内如果操作次数超过指定值 进行快照
打开 redis.conf文件,找到SNAPSHOTTING 对应内容
save <seconds> <changes>
# save ""   此项开启,不适用RDB操作
save 900 1:表示900 秒内如果至少有 1 个 key 的值变化,则保存
save 300 10:表示300 秒内如果至少有 10 个 key 的值变化,则保存
save 60 10000:表示60 秒内如果至少有 10000 个 key 的值变化,则保存

// 注意 被动触发rdb,redis会fork出一个子进程来处理保存工作,不会影响主进程。
  • AOF

AOF持久化方式,redis默认关闭。它采用的是通过日志的形式记录每个写操作,并记录在某个aof文件中。也就是每个写操作都会更新aof文件,无疑该方式特点就是简单粗暴,往往AOF文件要比RDB大得多。Redis重启时会根据aof文件的指令,从头到尾执行一次以恢复数据。AOF有三种更新日志的策略,下面带大家了解下。

//aof 只能通过配置文件设置同步策略
#由于默认关闭 首先开启aof  打开redis.conf文件 找到APPEND ONLY MODE 对应内容
1.修改appendonly yes
2.修改更新策略
# appendfsync always   (同步持久化,每次发生数据变化会立刻写入到磁盘中。性能较差当数据完整性比较好(慢,安全))
appendfsync everysec  出厂默认推荐,每秒异步记录一次(默认值)
# appendfsync no  不同步

 

 

RDB

AOF

使用场景

大规模数据恢复

误删紧急恢复(去掉误删命令,重新执行)

文件大小

相对较小

相对较大(过大时,进行重写命令)

性能


数据丢失情况

丢失快照之后的数据

丢失1秒钟的数据

数据恢复速度



RDB和AOF的基本情况大家已经有所了解,那么到底用什么呢? 答案是:我全都要。用RDB方式做冷备。用AOF方式做热备,美滋滋呀。有人就问了,既然AOF需要 ,那么为什么不只用AOF? 因为那样有两个问题,第一,你通过AOF做冷备,没有RDB做冷备,来的恢复速度更快; 第二,RDB每次简单粗暴生成数据快照,更加健壮,可以避免AOF这种复杂的备份和恢复机制的bug。

 

Redis主从

redis主从可以解决高可用吗?从节点高可用,但是主节点存在单点故障问题,所以该方案不是redis高可用方案。那么它存在的价值是什么?答案是:读写分离操作,会大大提高单节点服务性能, 就好比mysql主从,主库用来写,从库用来读,redis亦是如此。这种方式在我们的哨兵,集群中也是起着相当重要的作用。下面我们会介绍其架构图以及主从同步原理。我们都知道mysql主从是通过binlog实现的,那么redis也是通过binlog吗?并不是,大家请看。

redis 如何清空 lpush的数据 清除redis数据_服务器

  • 全量同步

说到全量复制,大家是不是想到了上边的RDB文件,哈哈没错,全量复制基于该文件进行操作,简单快捷,具体交互请看流程图。

redis 如何清空 lpush的数据 清除redis数据_数据_02

1.slave服务器向master发送psync命令(此时发送的是psync ? -1),告诉master我需要同步数据了。
2.master接收到psync命令后会进行BGSAVE命令生成RDB文件快照。
3.生成完后,会将RDB文件发送给slave。
4.slave接收到文件会载入RDB快照,并且将数据库状态变更为master在执行BGSAVE时的状态一致。


//执行bgsave后的命令,master会存在缓冲区中,然后等待slave同步完成,发送该命令给slave完成同步。
5.master会发送保存在缓冲区里的所有写命令,告诉slave可以进行同步了
6.slave执行这些写命令。
  • 命令传播

命令传播基于全量复制,在进行首次全量复制后,redis master进行的写操作,会fork一个线程发送此命令给slave,slave执行此命令做到主从同步。

redis 如何清空 lpush的数据 清除redis数据_服务器_03

fork子线程发送master写操作到slave
  • 重新复制

大家是不是觉得上边已经解决了主从同步的问题?非也非也,假如从库与主库断了10分钟,10分钟后又要重连,那么这种场景如果要执行全量RDB是不是没什么必要呢!所以为了解决这种场景,redis采用重新复制的逻辑,大家请看。

redis 如何清空 lpush的数据 清除redis数据_服务器_04

看了上边的流程图,是不是发现了很大的漏洞呀!主库怎么知道你这个从库是我的从库呢?主库怎么知道你什么时候掉线呢? 针对这种老大找不到下属的情况,redis增加了三个名词。服务器运行ID、复制偏移量、复制积压缓冲区。

1.服务器运行ID
每个redis服务器开启后会生成运行ID。
当进行初次同步时,master会将自己的ID告诉slave,slave会记录下来,当slave断线重连后,发现ID是这个master的就会尝试进行部分重同步。当ID与现在连接的master不一样时会进行完整重同步。

2.复制偏移
复制偏移量包括master复制偏移量和slave复制偏移量,当初次同步过后两个数据库的复制偏移量相同,之后master执行一次写命令,那么master的偏移量+1,master将写命令给slave,slave执行一次,slave偏移量+1,这样版本就能一致。

3.复制积压缓冲区
定义:复制积压缓冲区是一个保存在主节点的一个固定长度的先进先出的队列,默认大小 1MB。这个队列在 slave 连接时创建。这时主节点响应写命令时,不但会把命令发送给从节点,也会写入复制缓冲区。
作用:其实前两点已经可以完美同步数据了,这个东西并不是为了解决此问题而诞生的。之前redis首次全量同步的用到的缓冲区大家是否还记得? 跟那个一个道理,redis短时间掉线,也许偏移量不同步,但是缓冲区数据还没有消失,直接再发一遍缓冲区中的数据就行了,没必要走那么多流程,方便同步操作。

Redis哨兵

主从模式已经实现了读操作的高可用,那么保证写操作高可用是不是此架构就完美了! 那么怎么解决mater单点问题呢?答案是如果master挂掉了,那么找一个slave成为主节点不就可以了吗!让哨兵监控所有主从节点,当主节点挂了,哨兵指定某个从节点为主。顺着该思路我们引入了哨兵模式。

redis 如何清空 lpush的数据 清除redis数据_数据_05

PS:当哨兵监控到master挂掉后,通知某个slave成为master,实现高可用。但是上图依然存在问题:哨兵单点故障问题,所以哨兵也需要集群模式。

redis 如何清空 lpush的数据 清除redis数据_redis_06

redis哨兵架构图如上。那么监控具体是如何实现的呢? 下图是正常情况下监控流程。

//下图注释
1.每个哨兵会给其他哨兵,master,所有slave每隔1秒钟发送一个ping命令,确认其状态。
2.每个哨兵会给master,所有slave每隔10秒钟发送一个info命令,获取信息。
3.图上并未体现的,每隔两秒会给被监控的master,所有slave发送哨兵信息,以及master信息。

redis 如何清空 lpush的数据 清除redis数据_redis 如何清空 lpush的数据_07

一切正常时,哨兵们工作情况如上图,假如某个哨兵发现master没有回复自己又会怎样呢?

异常情况

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

redis 如何清空 lpush的数据 清除redis数据_数据_08

哨兵模式到此我们已经讲完了,具体的搭建我这里不做阐述,用的时候搞一下就行了,这玩意看完就忘,理解了原理才是关键。那么哨兵是完美的吗?并不是,同一时刻master永远只有一个,那么写操作带来的压力过大怎么办呢?而且哨兵模式单节点无法扩容,所有的数据都在一个节点,是有瓶颈的。