Redis虽然是基于内存操作的,但是其还是可以支持持久化到文件的,不然一个服务宕机就没法玩了,Redis持久化,是为了保存数据,主从模式,已经哨兵模式 也是为了围绕保存数据,以及更稳定的提供数据服务而设计的.
持久化
默认情况下 Redis 是通过异步的方式备份数据. 通过配置文件可以看到,Redis 可以配置两种持久会数据的方式.
如果我们需要让Redis按我们指定的配置启动.可以这样操作:
1 | redis-server redis.conf |
开启持久化之后,即使服务重启.Redis服务会将持久化的数据恢复.
RDB | 快照模式(SNAPSHOTTING)
通过redis.conf 配置文件,可以找到如下配置内容.
1 |
|
之前说过,Redis 默认情况下 是通过RDB 快照的方式保存数据. 只要
1 | save xxs yycount |
有设置,就会启动RDB持久化方式.如果想禁用RDB持久化方式,可以将save 全部注释.
我们在链接到Redis-cli时,也可以手动调用RDB持久化方式,通过save命令或者bgsave命令手动让Redis执行持久化数据到 .rdb文件.
其中save 是同步操作,会阻塞Redis的其他命令.
bgsave
bgsave 后台保存Redis主线程的数据 ,不会阻塞Redis主线程的命令. bgsave有一个写时复制(copy on write)机制.
写时复制(copy on write)机制: 开启一个新进程用于保存Redis主线程的数据,即使在Redis 主线程进行进行写操作时,也是可以正常保存数据的.
在执行bgsave的时候,会开启进程专门负责保存数据, bgsave 将Redis 主线程内存中的数据fork 一份,将数据保存到.rdb 文件.
如果客户端只是单纯的读redis数据,没有任何影响;
如果客户端需要写数据,新写的数据会被复制一份,bgsave会把这份复制数据保存到.rdb文件.
.rdb文件
.rdb文件 打开之后看不到直接存储的数据,而是一堆二进制数据.
不管 save xx yy 怎么设置,RDB持久化的方式都感觉差点意思:
设置的太紧凑,就频繁调用,设置的太稀疏,数据又容易丢失(如果宕机,还没触发bgsave).
AOF(APPEND ONLY MODE)
前面觉得RDB持久化的方式总是感觉差点意思.不管怎么配置都觉着不靠谱.
AOF的方式,是将Redis主线程操作记录到appendonly.aof文件(文件名可以通过配置修改), 可以通过appendfsync 配置同步策略,如果配置的策略是everysec, 及时宕机事故发生,也只是丢失1s的数据,而且还可以通过其他策略避免这种情况的发生.
下面是redis.conf 文件中关于AOF的配置
1 |
|
AOF 重写
前面说了,开启AOF之后,Redis会根据同步策略,将Redis对数据的操作记录持久化到.aof文件. 如果时间长了, .aof文件必然很大.
假设一个这样的场景, Redis频繁对一个字段进行修改, 会导致.aof存储了很多对这个字段操作的历史过程, 我们持久化的目的是为了保存最终数据,而不是操作数据的过程,所以中间的操作历史存储在.aof文件中几乎没有任何价值,反倒是占用空间.
因此, Redis 有一个AOF 重写机制: 开启一个新进程负责重新.aof文件.
将.aof文件中无用的操作记录移除,只保留最后的数据记录.
.aof 文件格式
1 | [root@oldconan 6379]# cat appendonly.aof |
头
1 | *2 |
数据存储
1 | *3 # 开始标记 |
AOF RDB 混合模式
在Redis服务重启的时候, 需要从持久化文件中恢复数据,
如果是从RDB文件中恢复,虽然恢复快,可能数据不全.
如果从AOF文件中恢复,AOF文件通常比较大,恢复慢.
所谓小朋友才做选择,成年人是都要. 我们想要AOF 模式和 RDB 模式两个结合使用.发挥两种模式的优势.
首先我们需要了解下两种模式的区别
可以通过设置aof-use-rdb-preamble yes来开启混合模式.
1 | aof-use-rdb-preamble yes |
重启Redis恢复数据:
存储在.aof文件的旧的数据,加载进内存,同时会通过RDB的方式存储到新的.aof文件.原先的.aof文件被覆盖.
新进来的数据,会通过原本AOF的方式持久化其操作.
这样一来,appendonly.aof文件就不是前面给出的那种样子了,而是rdb里的二进制数据和原aof文件里面操作记录一起了.
模式服务
主从模式
主从模式的设计初衷: 增加slave节点,缓解Master的压力,实现读写分离.
主从模式配置
1 | Slave 关键配置 |
全量复制
如果是一个新增的Slave Redis实例 , 在启动这台新实例的时候, 会建立主从关系, Slave节点实例需要冲主实例中同步数据. 此时做的是全量复制.
Redis2.4.16版本全量复制大概流程图如下:
1 | REDIS_REPL_NONE slave 默认状态 |
1 | REDIS_REPL_WAIT_BGSAVE_START bgsave开始 |
部分复制
如果一台因为某种原因导致主从服务短暂断开连接的Slave,当Slave重新连接后,也会需要从Master 同步数据, 如果在2.8之前只要是断开主从连接,都会执行全力复制, 在Redis 2.8之后支持部分复制, 只会同步断开之后的数据,而不是直接清空自己原有的数据做全量复制(有前提,不能断开太久,数据不能过量).
在redis 2.8 之后引入了如下内容:
- 在Slave 与 Master 建立连接,都会创建一个repl_backlog环形buffer;
1 | repl_backlog 环形buffer |
- Slave 与 Master 都有一个runid(Redis 启动时生成). 同时Slave中会保存一个和Master对应的偏移量reploff;
1 : 当Slave 和 Master 建立连接就会创建一个repl_backlog环形buffer, 同时 Slave 增加了一个状态REDIS_RECIVE_PONG;
2: Slave 中有一个唯一的runid 和 reploff(默认-1), Slave 尝试 PONG Master 请求是否能部分复制.
Slave 与 Master 断开超过指定时间之后,repl_backlog环形buffer会被释放;
Slave 与 Master 断开之后,Master 中有很多的数据操作,导致偏移量是n*size;
上面几种情况都会让Master认为不能部分复制.
3:不管是新的Redis,还是网络瞬断导致的重新连接, Slave 都会 PONG Master;
4: 如果不允许部分复制,则执行全量复制;
5: Slave 和 Master 正常工作时,Master 的每一次操作都会保存到repl_backlog 中并更新repl_backlog_off. 并同步到Slave.
6: Slave 和 Master 因为网络超时,Slave 会主动断开连接,保存runid 和 偏移量 reploff( 和repl_backlog_off 对应,一般 repl <= repl_backlog_off ).
7: 重新连接,PONG Master ,尝试部分复制.
1 | repl-backlog-size 3600 指定释放buffer时间 |
哨兵模式
简单的主从模式,只有一个Master ,如果 Master 挂了,就相当于Redis服务整个瘫痪. 哨兵模式可以有效的解决这种问题;
Sentinel哨兵是特殊的redis服务,不提供读写服务,主要用来监控redis实例.
Client 第一次从Sentinel中找到Master服务,后续就可以直接Master节点.
当Redis Master 发生变化,Sentinel 哨兵会第一时间感知到, 发起选举,一定时间之后选出新的Master 并发送给Client.
配置哨兵模式
1 | 设置sentinel id |
Sentinel 哨兵可以认为是一个特殊的Redis服务.
按照上面的配置 ,只需要创建 3个sentinel ,修改下不同的端口; 让后启动 Master 和 2个 Slave ,在启动3个sentinel; 上图的哨兵服务就已经搭建好了.
如果主服务挂了,Sentinel 哨兵选出了新的Master 会将 Slave 中的配置更改.
1 | 这里我们设置的 |
启动 Master 和 Slave 检查数据:
1 | [root@oldconan redis-5.0.2]# src/redis-server config/redis_6379.conf |
启动Sentinel: Redis有专门启动哨兵的命令
1 | 启动 |
1 | 检查 |
杀死Master .后面看Sentinel 中的信息;
1 | kill 6540 |
过一会之后,新Master 被选举出现.
虽然说是可以一会之后,会选举出新的Master ,但是这个过一会有个十来二十秒的时间,如果真的在生产上,是不可能运行这种情况出现的.所以哨兵模式还不是我们想要的.