主从复制
关系型数据库通常会使用一个主服务器(master),向多个从服务器(slave)发送更新,并使用从服务器来处理所有的读请求。Redis也采用了同样的方式来实现自己的复制特性,并将其用作扩展性能的一种手段。
配置项
从服务器任然可以配置不同的选项来控制自身的行为,但是开启从服务器的配置项只有一个:
-
slaveof host port 开启从服务器
比如:
slaveof 127.0.0.1 6379
可以在客户端直接输入,也可以配置在redis.conf配置文件中启动时加载。 -
slaveof no one
用户可以通过发送
slaveof no one
命令让当前redis服务器终止复制操作,不再接受Redis主服务器的数据更新。
如果用户使用的是slaveof配置项,那么Redis在启动时首先会载入当前可用的任何rdb文件或aof文件。然后连接服务器进行复制过程。
如果用户使用的是slaveof命令,那么Redis会立即尝试连接主服务器,并在连接成功后,开始进行复制过程。
Redis主从复制过程
步骤 | 主服务器操作 | 从服务器操作 |
---|---|---|
1 | 等待命令进入。。。 | 连接(重连)主服务器,发送SYNC 命令 |
2 | 开始执行BGSAVE ,并使用缓冲区记录BGSAVE 之后执行的所有写命令 | 根据配置选项来决定是继续使用现有的数据(如果有的话)来处理客户端的命令请求,还是向发送请求的客户端返回错误 |
3 | BGSAVE 执行完毕,向从服务器发送快照文件,并在发送期间,继续使用缓冲区记录被执行的写命令 | 清空掉内存中的所有数据(如果有),开始载入主服务器发来的快照文件 |
4 | 快照文件发送完毕,开始向从服务器发送存储在缓冲区里面的写命令 | 完成对快照文件的解释操作,像往常一样开始接收命令请求 |
5 | 缓冲区存储的写命令发送完毕;从现在开始,每执行一个写命令,就向从服务器发送相同的写命令 | 执行主服务器发来的所有存储在缓冲区里面的写命令;并从现在开始,接收并执行主服务器传来的每个写命令 |
当有新的从服务器连接主服务器时:
-
如果主服务器的步骤3尚未执行,那么所有的从服务器都会接收到相同的快照文件和缓冲区写命令;
-
如果主服务器的步骤3正在执行或已经执行完毕,当主服务器与较早进行连接的从服务器执行完上述5个步骤以后,主服务器会与新的从服务器执行一次新的步骤1-5。
补充:
- Redis在进行复制期间,也会尽可能的处理接收到的命令请求。如果主从服务器直接的网络带宽不足,或主服务器没有足够的内存来创建子进程和创建写命令的缓冲区,那么Redis处理命令请求的效率都会降低。因此,尽管不是必需的,但在实际中最好还是让主服务器只使用50%-65%的内存,剩余的30%-45%内存用于执行
BGSAVE
命令和创建记录写命令的缓冲区。 - Redis会尽可能的减少复制所需的工作,但是如果从服务器连接的时间并不凑巧,那么主服务器就需要多做一些额外的工作。此外,如果多个从服务器同时连接主服务器的时候,同步多个从服务器所占用的带宽可能会使其他命令请求难以传递给主服务器,与主服务器位于同网络中的其他硬件网速可能也会受到影响。
注意:
- 从服务器在进行同步时,会清空自己的所有数据。
- Redis不支持主主复制。被互相设置为主服务器的两个Redis实例只会持续占用大量处理器资源,并连续不断地尝试与对方通信,根据客户端连接的服务器不同,客户端的请求可能会得到不一致的数据,或者完全得不到数据。
- 一个master可以有多个slave,但是一个slave只能有一个master。
主从链
因为Redis的主服务器和从服务器并没有特别不同的地方,所以从服务器也可以拥有自己的从服务器,并由此形成主从链(master/slave chaining)。
从服务器对从服务器进行复制在操作上和从服务器对主服务器进行复制的唯一区别在于:
如果从服务器A拥有从服务器B,那么当从服务器A在执行复制过程步骤4的时候,将断开与从服务器B的连接,导致从服务器B需要从新连接并重新同步(resync)。
当读请求的数量远远超出一台Redis服务器的处理范围,用户就需要添加新的从服务器来处理读请求。随着负载不断上升,主服务器可能无法快速的更新所有的从服务器,或者因为重新连接和重新同步从服务器导致系统超载。
为缓解这个问题,用户可以创建一个由Redis主从节点(master/slave node)组成的中间层来分担主服务的复制工作:
尽管主从服务器之间不一定要组成一个树状结构,但这种结构对于Redis复制来说是可行的。
为了将数据保存到多台机器上面,用户首先需要为主服务器设置多个从服务器,然后对每个从服务器设置AOF持久化(appendonly yes
和appendfsync everysec
,如果有需要,主服务器也可进行相同设置)。这样的话,用户就可以让多台服务器以1秒的频率将数据同步到硬盘上了。如果要验证主服务器是否已经将写数据发送至从服务器,用户需要在向主服务器写入真正的数据后,再向主服务器写入一个唯一的虚构值,然后再检查虚构值是否存在于从服务器来判断写数据是否已经到达从服务器。除此之外,我们还可以发送INFO
命令,检查aof_pending_bio_fsync的值是否为0来判断。
扩展
验证rdb文件和aof文件
redis-check-aof
redis-check-dump
在系统故障发生之后,用于检查AOF文件,快照文件的状态,在用需要的情况下对文件进行修复(redis-check-aof --fix appendonly.aof
)
修复AOF文件的方法非常简单,将删除掉发现第一个错误的命令及出错命令之后的所有命令(大部分情况下是文件末尾的不完整的写命令)。然而快照文件(RDB)目前是没有办法修复,本身快照文件进行了压缩。
手动更换故障主服务器
假如:
master A:192.168.0.1 6379
slave B:192.168.0.2 6379
new C:192.168.0.3 6379
A宕机了。
方法1:新的Redis服务器C作为Redis从服务器B的主服务器。先向B发送save命令,创建快照文件,将快照文件复制到C服务器,启动C,然后让B服务器成为服务器C的从服务器。然后就是更新客户端的配置,更换正确的写配置。
ssh root@192.168.0.2
redis-client
save
quit
scp /usr/local/redis/dump.db 192.168.0.3:/usr/local/redis/
ssh root@192.168.0.3
redis-server start
exit
ssh root@192.168.0.2
redis-client
slaveof 192.168.0.3 6379
quit
方法2:从服务器B变为主服务器,并为升级后的主服务器创建从服务器C
上述的方法是手动处理,后续介绍Redis Sentinel(哨兵),可监视指定的主从服务器,在主服务器下线时进行故障转移。
参考:《Redis 实战》