0%

Redis持久化和主从模式和哨兵模式

Redis虽然是基于内存操作的,但是其还是可以支持持久化到文件的,不然一个服务宕机就没法玩了,Redis持久化,是为了保存数据,主从模式,已经哨兵模式 也是为了围绕保存数据,以及更稳定的提供数据服务而设计的.

持久化

默认情况下 Redis 是通过异步的方式备份数据. 通过配置文件可以看到,Redis 可以配置两种持久会数据的方式.

如果我们需要让Redis按我们指定的配置启动.可以这样操作:

1
redis-server redis.conf

开启持久化之后,即使服务重启.Redis服务会将持久化的数据恢复.

RDB | 快照模式(SNAPSHOTTING)

通过redis.conf 配置文件,可以找到如下配置内容.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

################################ SNAPSHOTTING ################################
每多少秒(900/300/60) 有多少次(1/10/10000)数据操作(写/修改) 保存一次
save 900 1
save 300 10
save 60 10000

当后台写保存出错 停止写
stop-writes-on-bgsave-error yes

将数据保存到rdb文件时 是否启用压缩
rdbcompression no

检查数量
rdbchecksum yes

指定rdb文件名
dbfilename dump.rdb

指定数据(log文件/rdb文件)保存路径
dir /usr/local/redis-5.0.2/data/6379

之前说过,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的时候,会开启进程专门负责保存数据, 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

############################## APPEND ONLY MODE ###############################
是否开启 AOF
appendonly no

aof持久化保存文件名称
appendfilename "appendonly.aof"

aof 同步策略 3种策略(no always everysec)
# appendfsync always
appendfsync everysec
# appendfsync no

注释说如果有延时问题就开启
no-appendfsync-on-rewrite no

aof文件达到上次重写 多少percent触发重写
auto-aof-rewrite-percentage 100

第一次aof文件重写触发大小
auto-aof-rewrite-min-size 64mb

重启修复数据
aof-load-truncated yes

aof 混合 RDB 持久化
aof-use-rdb-preamble yes

AOF 重写

前面说了,开启AOF之后,Redis会根据同步策略,将Redis对数据的操作记录持久化到.aof文件. 如果时间长了, .aof文件必然很大.

假设一个这样的场景, Redis频繁对一个字段进行修改, 会导致.aof存储了很多对这个字段操作的历史过程, 我们持久化的目的是为了保存最终数据,而不是操作数据的过程,所以中间的操作历史存储在.aof文件中几乎没有任何价值,反倒是占用空间.

因此, Redis 有一个AOF 重写机制: 开启一个新进程负责重新.aof文件.

将.aof文件中无用的操作记录移除,只保留最后的数据记录.

.aof 文件格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
[root@oldconan 6379]# cat appendonly.aof 
*2
$6
SELECT
$1
0
*3
$3
set
$1
a
$1
a
*3
$3
set
$1
b
$1
b
*3
$3
set
$3
aaa
$3
aaa
*3
$3
set
$3
ccc
$3
ccc

1
2
3
4
5
*2
$6
SELECT
$1
0

数据存储

1
2
3
4
5
6
7
*3       # 开始标记
$3 # 表示后面的字符长度
set # 操作
$1 # 表示后面的字符长度
a # key
$1 # 表示后面的字符长度
a # value

AOF RDB 混合模式

在Redis服务重启的时候, 需要从持久化文件中恢复数据,

如果是从RDB文件中恢复,虽然恢复快,可能数据不全.

如果从AOF文件中恢复,AOF文件通常比较大,恢复慢.

所谓小朋友才做选择,成年人是都要. 我们想要AOF 模式和 RDB 模式两个结合使用.发挥两种模式的优势.

首先我们需要了解下两种模式的区别

rdb-aof

可以通过设置aof-use-rdb-preamble yes来开启混合模式.

1
aof-use-rdb-preamble yes

混合模式

重启Redis恢复数据:

  • 存储在.aof文件的旧的数据,加载进内存,同时会通过RDB的方式存储到新的.aof文件.原先的.aof文件被覆盖.

  • 新进来的数据,会通过原本AOF的方式持久化其操作.

这样一来,appendonly.aof文件就不是前面给出的那种样子了,而是rdb里的二进制数据和原aof文件里面操作记录一起了.

模式服务

主从模式

主从模式的设计初衷: 增加slave节点,缓解Master的压力,实现读写分离.

主从模式配置

1
2
3
Slave 关键配置 
replicaof 172.30.60.2 6379 从本机6379的redis实例复制数据,Redis5.0之前使用slaveof
replica‐read‐only yes 配置从节点只读

主从复制

全量复制

如果是一个新增的Slave Redis实例 , 在启动这台新实例的时候, 会建立主从关系, Slave节点实例需要冲主实例中同步数据. 此时做的是全量复制.

Redis2.4.16版本全量复制大概流程图如下:

1
2
3
4
5
REDIS_REPL_NONE             slave 默认状态
REDIS_REPL_CONNECT slave 连接到Master之前的状态(只有是这个状态才可以连接到Master)
REDIS_REPL_CONNECTING 连接过程状态
REDIS_REPL_TRANSFER 接受.RDB文件状态
REDIS_REPL_CONNECTED 完成连接
1
2
3
4
5
REDIS_REPL_WAIT_BGSAVE_START  bgsave开始
REDIS_REPL_WAIT_BGSAVE_END bgsave结束

REDIS_REPL_SEND_BULK 进入发送rdb的状态
REDIS_REPL_ONLINE 完成rdb发送,准备发送更新数据

Redis2.4.16版本全量复制

部分复制

如果一台因为某种原因导致主从服务短暂断开连接的Slave,当Slave重新连接后,也会需要从Master 同步数据, 如果在2.8之前只要是断开主从连接,都会执行全力复制, 在Redis 2.8之后支持部分复制, 只会同步断开之后的数据,而不是直接清空自己原有的数据做全量复制(有前提,不能断开太久,数据不能过量).

在redis 2.8 之后引入了如下内容:

  • 在Slave 与 Master 建立连接,都会创建一个repl_backlog环形buffer;
1
2
3
4
5
6
repl_backlog          环形buffer
repl_backlog_size buffer大小
repl_backlog_idx 环形buffer 尾脚标
repl_backlog_off buffer当前偏移量(n%size)

repl_backlog_time_limit 时间极限
  • Slave 与 Master 都有一个runid(Redis 启动时生成). 同时Slave中会保存一个和Master对应的偏移量reploff;

Redis2.8部分复制

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
2
repl-backlog-size  3600    指定释放buffer时间
repl-backlog-size 1mb 指定buffer大小

哨兵模式

简单的主从模式,只有一个Master ,如果 Master 挂了,就相当于Redis服务整个瘫痪. 哨兵模式可以有效的解决这种问题;

哨兵模式

Sentinel哨兵是特殊的redis服务,不提供读写服务,主要用来监控redis实例.

Client 第一次从Sentinel中找到Master服务,后续就可以直接Master节点.

当Redis Master 发生变化,Sentinel 哨兵会第一时间感知到, 发起选举,一定时间之后选出新的Master 并发送给Client.

配置哨兵模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
设置sentinel id
bind 172.30.60.2

设置端口
port 26379

开启守护(后台执行)
daemonize yes

pid信息存储路径
pidfile "/var/run/redis-sentinel-26379.pid"

日志文件名称
logfile "26379.log"

数据存储路径
dir "/usr/local/redis-5.0.2/data"

sentinel唯一id
sentinel myid d7345d4b86e96410e15db64555d37abdbf79b696

脚本相关配置
sentinel deny-scripts-reconfig yes

配置Master mymaster是名称 ip port 2 = 选举规则(sentinel总数/2 + 1 ) !!!!
sentinel monitor mymaster 172.30.60.2 6380 2

sentinel config-epoch mymaster 2

sentinel leader-epoch mymaster 2

Sentinel 哨兵可以认为是一个特殊的Redis服务.

按照上面的配置 ,只需要创建 3个sentinel ,修改下不同的端口; 让后启动 Master 和 2个 Slave ,在启动3个sentinel; 上图的哨兵服务就已经搭建好了.

如果主服务挂了,Sentinel 哨兵选出了新的Master 会将 Slave 中的配置更改.

1
2
3
4
5
6
这里我们设置的 

6780 端口的Redis 服务是Master, 6379,6781 是Slave;

26379 ,26380, 26381 端口是3个Sentinel

启动 Master 和 Slave 检查数据:

1
2
3
4
5
[root@oldconan redis-5.0.2]# src/redis-server config/redis_6379.conf 
[root@oldconan redis-5.0.2]# src/redis-server config/redis_6380.conf
[root@oldconan redis-5.0.2]# src/redis-server config/redis_6381.conf

进入客户端

哨兵模式

启动Sentinel: Redis有专门启动哨兵的命令

1
2
3
4
5
启动
[root@oldconan redis-5.0.2]# src/redis-sentinel sentinelConfig/sentinel-26379.conf
[root@oldconan redis-5.0.2]# src/redis-sentinel sentinelConfig/sentinel-26380.conf
[root@oldconan redis-5.0.2]# src/redis-sentinel sentinelConfig/sentinel-26381.conf

哨兵模式

1
2
3
4
检查
[root@oldconan redis-5.0.2]# src/redis-cli -h 172.30.60.2 -p 26380

> info

哨兵模式

杀死Master .后面看Sentinel 中的信息;

1
2
3
kill 6540
src/redis-cli -h 172.30.60.2 -p 26380
info

过一会之后,新Master 被选举出现.

新master出现

虽然说是可以一会之后,会选举出新的Master ,但是这个过一会有个十来二十秒的时间,如果真的在生产上,是不可能运行这种情况出现的.所以哨兵模式还不是我们想要的.

参考链接