Redis主从复制原理总结
和Mysql主从复制的原因一样,Redis虽然读取写入的速度都特别快,但是也会产生读压力特别大的情况。为了分担读压力,Redis支持主从复制,Redis的主从结构可以采用一主多从或者级联结构,Redis主从复制可以根据是否是全量分为全量同步和增量同步。下图为级联结构。
全量同步
Redis全量复制一般发生在Slave初始化阶段,这时Slave需要将Master上的所有数据都复制一份。具体步骤如下:
- 从服务器连接主服务器,发送SYNC命令;
- 主服务器接收到SYNC命名后,开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所有写命令;
- 主服务器BGSAVE执行完后,向所有从服务器发送快照文件,并在发送期间继续记录被执行的写命令;
- 从服务器收到快照文件后丢弃所有旧数据,载入收到的快照;
- 主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令;
- 从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令;
完成上面几个步骤后就完成了从服务器数据初始化的所有操作,从服务器此时可以接收来自用户的读请求。
增量同步
Redis增量复制是指Slave初始化后开始正常工作时主服务器发生的写操作同步到从服务器的过程。
增量复制的过程主要是主服务器每执行一个写命令就会向从服务器发送相同的写命令,从服务器接收并执行收到的写命令。
Redis主从同步策略
主从刚刚连接的时候,进行全量同步;全同步结束后,进行增量同步。当然,如果有需要,slave 在任何时候都可以发起全量同步。redis 策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进行全量同步。
注意点
如果多个Slave断线了,需要重启的时候,因为只要Slave启动,就会发送sync请求和主机全量同步,当多个同时出现的时候,可能会导致Master IO剧增宕机。
Redis主从复制的配置十分简单,它可以使从服务器是主服务器的完全拷贝。需要清除Redis主从复制的几点重要内容:
1 2 3 4 5 6 7 8 9 10 11 |
|
主从复制的一些特点:
1 2 3 4 5 6 7 8 9 10 11 |
|
Redis大概主从同步是怎么实现的?
1 2 3 4 5 6 7 8 9 10 11 12 |
|
主从同步中需要注意几个问题
1 2 3 4 5 6 7 8 9 10 11 12 |
|
当主服务器不进行持久化时复制的安全性
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Redis主从复制是如何工作的
1 2 3 4 5 6 7 8 9 10 11 12 |
|
部分重新同步
1 2 3 4 5 6 7 8 9 10 |
|
无磁盘复制
1 2 3 4 |
|
配置
1 2 3 4 5 6 7 8 9 10 |
|
只读从服务器
1 2 3 4 5 6 7 8 |
|
限制有N个以上从服务器才允许写入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Redis 持久化日志
RDB 是主进程 fork一个子进程进行的、所以不影响主进程的操作。
AOF 和主进程是一个线程(redis是单线程)会对主进程对外提供请求的效率造成影响,接收请求、处理请求、写aof文件这三步是串行原子执行的。而非异步多线程执行的。
====== 通过redis实现服务器崩溃等数据恢复 ======
由于redis存储在内存中且提供一般编程语言常用的数据结构存储类型,所以经常被用于做服务器崩溃宕机的数据恢复处理。服务器可以在某些指定过程中将需要保存的数据以json对象等方式存储到redis中,也就是我们常说的快照,当服务器运行时读取redis来判断是否有待需要恢复数据继续处理的业务。当一次业务处理结束后再删除redis的数据即可。redis提供两种将内存数据导出到硬盘实现数据备份的方法:
1)RDB方式(默认)
RDB方式的持久化是通过快照(snapshotting)完成的,当符合一定条件时Redis会自动将内存中的所有数据进行快照并存储在硬盘上。进行快照的条件可以由用户在配置文件中自定义,由两个参数构成:时间和改动的键的个数。当在指定的时间内被更改的键的个数大于指定的数值时就会进行快照。RDB是redis默认采用的持久化方式,在配置文件中已经预置了3个条件:
save 900 1 #900秒内有至少1个键被更改则进行快照
save 300 10 #300秒内有至少10个键被更改则进行快照
save 60 10000 #60秒内有至少10000个键被更改则进行快照
可以存在多个条件,条件之间是"或"的关系,只要满足其中一个条件,就会进行快照。 如果想要禁用自动快照,只需要将所有的save参数删除即可。
Redis默认会将快照文件存储在当前目录(可CONFIG GET dir来查看)的dump.rdb文件中,可以通过配置dir和dbfilename两个参数分别指定快照文件的存储路径和文件名。
Redis实现快照的过程
- Redis使用fork函数复制一份当前进程(父进程)的副本(子进程);
- 父进程继续接收并处理客户端发来的命令,而子进程开始将内存中的数据写入硬盘中的临时文件;
- 当子进程写入完所有数据后会用该临时文件替换旧的RDB文件,至此一次快照操作完成。
- 在执行fork的时候操作系统(类Unix操作系统)会使用写时复制(copy-on-write)策略,即fork函数发生的一刻父子进程共享同一内存数据,当父进程要更改其中某片数据时(如执行一个写命令 ),操作系统会将该片数据复制一份以保证子进程的数据不受影响,所以新的RDB文件存储的是执行fork一刻的内存数据。
Redis在进行快照的过程中不会修改RDB文件,只有快照结束后才会将旧的文件替换成新的,也就是说任何时候RDB文件都是完整的。这使得我们可以通过定时备份RDB文件来实 现Redis数据库备份。RDB文件是经过压缩(可以配置rdbcompression参数以禁用压缩节省CPU占用)的二进制格式,所以占用的空间会小于内存中的数据大小,更加利于传输。
除了自动快照,还可以手动发送SAVE或BGSAVE命令让Redis执行快照,两个命令的区别在于,前者是由主进程进行快照操作,会阻塞住其他请求,后者会通过fork子进程进行快照操作。 Redis启动后会读取RDB快照文件,将数据从硬盘载入到内存。根据数据量大小与结构和服务器性能不同,这个时间也不同。通常将一个记录一千万个字符串类型键、大小为1GB的快照文件载入到内 存中需要花费20~30秒钟。 通过RDB方式实现持久化,一旦Redis异常退出,就会丢失最后一次快照以后更改的所有数据。这就需要开发者根据具体的应用场合,通过组合设置自动快照条件的方式来将可能发生的数据损失控制在能够接受的范围。如果数据很重要以至于无法承受任何损失,则可以考虑使用AOF方式进行持久化。
日志格式
是压缩过的占用体积小,容灾恢复快
$cat dump.rdb
REDIS0008 redis-ver4.0.1
redis-bits@ctimeYused-mem
aof-preamblerepl-id(484f9d49a700c4b9b136f0fd40d2d6e5a8460438
repl-offa;^foobarfoobar^KJ_U
OMG...一堆乱码隐约可以看到一些和redis相关的字符串为了更直观的感受下RDB的内容我们用redis自带的工具redis-check-rdb来看下
redis-check-rdb dump.rdb
[offset 0] Checking RDB file dump.rdb
[offset 26] AUX FIELD redis-ver = '4.0.1'
[offset 40] AUX FIELD redis-bits = '64'
[offset 52] AUX FIELD ctime = '1504234774'
[offset 67] AUX FIELD used-mem = '2139016'
[offset 83] AUX FIELD aof-preamble = '0'
[offset 133] AUX FIELD repl-id = '484f9d49a700c4b9b136f0fd40d2d6e5a8460438'
[offset 148] AUX FIELD repl-offset = '0'
[offset 150] Selecting DB ID 0
[offset 173] Selecting DB ID 2
[offset 194] Checksum OK
[offset 194] \o/ RDB looks OK! \o/
[info] 2 keys read
[info] 1 expires
[info] 0 already expired
这下就好看多了首先可以看到是一些AUX FIELD辅助域4.0特有用来配合全新的主从同步方式PSYNC2后面会专门来介绍PSYNC2然后可以看到DB0和DB2是有内容的Checksum也OK最后是说一共有2个key其中一个设置了过期时间到目前为止还都没有过期。
2)AOF方式
默认情况下Redis没有开启AOF(append only file)方式的持久化,可以在redis.conf中通过appendonly参数开启:
appendonly yes
在启动时Redis会逐个执行AOF文件中的命令来将硬盘中的数据载入到内存中,载入的速度相较RDB会慢一些
开启AOF持久化后每执行一条会更改Redis中的数据的命令,Redis就会将该命令写入硬盘中的AOF文件。AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的,默认的文件名是appendonly.aof,可以通过appendfilename参数修改:
appendfilename appendonly.aof
配置redis自动重写AOF文件的条件
auto-aof-rewrite-percentage 100 # 当目前的AOF文件大小超过上一次重写时的AOF文件大小的百分之多少时会再次进行重写,如果之前没有重写过,则以启动时的AOF文件大小为依据
auto-aof-rewrite-min-size 64mb # 允许重写的最小AOF文件大小
配置写入AOF文件后,要求系统刷新硬盘缓存的机制
# appendfsync always # 每次执行写入都会执行同步,最安全也最慢
appendfsync everysec # 每秒执行一次同步操作
# appendfsync no # 不主动进行同步操作,而是完全交由操作系统来做(即每30秒一次),最快也最不安全
Redis允许同时开启AOF和RDB,既保证了数据安全又使得进行备份等操作十分容易。此时重新启动Redis后Redis会使用AOF文件来恢复数据,因为AOF方式的持久化可能丢失的数据更少
日志格式
没有压缩的,文件大,容灾恢复慢
同样的数据我们来看下在AOF文件中是如何保存的
$cat appendonly.aof
*2
$6
SELECT
$1
0
*3
$3
set
$3
foo
$3
bar
*3
$9
PEXPIREAT
$3
foo
$13
1504255377087
*2
$6
很明显一条一条的没有压缩的命令
3)混合RDF/AOF 方式
在redis4.0 可以开启会和模式,默认时关闭的
混合持久化同样也是通过bgrewriteaof完成的,不同的是当开启混合持久化时,fork出的子进程先将共享的内存副本全量的以RDB方式写入aof文件,然后在将重写缓冲区的增量命令以AOF方式写入到文件,写入完成后通知主进程更新统计信息,并将新的含有RDB格式和AOF格式的AOF文件替换旧的的AOF文件。简单的说:新的AOF文件前半段是RDB格式的全量数据后半段是AOF格式的增量数据,如下图:
数据恢复
当我们开启了混合持久化时,启动redis依然优先加载aof文件,aof文件加载可能有两种情况如下:
aof文件开头是rdb的格式, 先加载 rdb内容再加载剩余的 aof。
aof文件开头不是rdb的格式,直接以aof格式加载整个文件。
日志格式
此时的aof文件已经和只开启AOF持久化文件不一样了,上半部分是RDB持久化的数据,下半部分是AOF格式数据。
显而易见前半段是RDB格式的全量数据后半段是redis命令格式的增量数据。