Redis主从同步:数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。这使得Redis可执行单层树复制。存盘可以有意无意的对数据进行写操作。由于完全实现了发布/订阅机制,使得从数据库在任何地方同步树时,可订阅一个频道并接收主服务器完整的消息发布 记录。同步对读取操作的可扩展性和数据冗余很有帮助。
持久化保证了即使 redis 服务重启也会丢失数据,因为 redis 服务重启后会将硬盘上持久化的数据恢复到内存中,但是当 redis 服务器的硬盘损坏了可能会导致数据丢失,如果通过 redis 的主从复制机制就可以避免这种单点故障,如下图:
工作原理:
-
Redis的主从结构可以采用一主多从或者级联结构,Redis主从复制可以根据是否是全量分为全量同步和增量同步。
-
主 redis 中的数据有两个副本(replication)即从 redis1 和从 redis2,即使一台 redis 服务器宕机其它两台 redis 服务也可以继续提供服务。
-
主 redis 中的数据和从 redis 上的数据保持实时同步,当主 redis 写入数据时通过主从复制机制会复制到两个从 redis 服务上。
-
只有一个主 redis,可以有多个从 redis。
-
主从复制不会阻塞 master,在同步数据时,master 可以继续处理 client 请求。
-
一个 redis 可以即是主又是从,如下图:
主从复制过程
2.8以后实现PSYNC的机制,实现断线重连
1、完整复制过程
在 redis2.8 版本之前主从复制过程如下图:
- slave 服务启动,slave 会建立和 master 的连接,发送 sync 命令。
- master 启动一个后台进程将数据库快照保存到 RDB 文件中
注意:此时如果生成 RDB 文件过程中存在写数据操作会导致 RDB 文件和当前主 redis 数据不一致,所以此时 master 主进程会开始收集写命令并缓存起来。
- master 就发送 RDB 文件给 slave
- slave 将文件保存到磁盘上,然后加载到内存恢复
- master 把缓存的命令转发给 slave
注意:后续 master 收到的写命令都会通过开始建立的连接发送给 slave。
当 master 和 slave 的连接断开时 slave 可以自动重新建立连接。如果 master 同时收到多个 slave 发来的同步连接命令,只会启动一个进程来写数据库镜像,然后发送给所有 slave。
完整复制的问题:
在 redis2.8 之前从 redis 每次同步都会从主 redis 中复制全部的数据,如果从 redis 是新创建的从主 redis 中复制全部的数据这是没有问题的,但是,如果当从 redis 停止运行,再启动时可能只有少部分数据和主 redis 不同步,此时启动 redis 仍然会从主 redis 复制全部数据,这样的性能肯定没有只复制那一小部分不同步的数据高。
2、部分复制
从机连接主机后,会主动发起 PSYNC 命令,从机会提供 master 的 runid(机器标识,随机生成的一个串) 和 offset(数据偏移量,如果offset主从不一致则说明数据不同步),主机验证 runid 和 offset 是否有效,runid 相当于主机身份验证码,用来验证从机上一次连接的主机,如果 runid 验证未通过则,则进行全同步,如果验证通过则说明曾经同步过,根据 offset 同步部分数据。
主从复制实践
1、准备三个redis数据库配置文件
背景: 一主两从
- 6380为主,6381和6382 为从
cd /opt/redis_conf
vim redis-6380.conf
# 写入以下配置
port 6380
daemonize yes
pidfile /data/6380/redis.pid
loglevel notice
logfile "/data/6380/redis.log"
dbfilename dump.rdb
dir /data/6380
protected-mode no
- 再创建两个配置文件6381和6382
sed "s/6380/6381/g" redis-6380.conf > redis-6381.conf
sed "s/6380/6382/g" redis-6380.conf > redis-6382.conf
- 创建数据文件目录
[root@qishi666 redis_conf]# mkdir -p /data/6380
[root@qishi666 redis_conf]# mkdir -p /data/6381
[root@qishi666 redis_conf]# mkdir -p /data/6382
2、启动redis数据库
[root@qishi666 redis_conf]# redis-server redis-6380.conf
[root@qishi666 redis_conf]# redis-server redis-6381.conf
[root@qishi666 redis_conf]# redis-server redis-6382.conf
3、确保这三个redis数据库是完全独立的数据库
4、给两个从服务器配置文件再添加一行配置(很重要)
在6381和6382配置文件添加这一行配置,表示指定主服务器为6380
slaveof 127.0.0.1 6380
5、重启数据库
pkill redis
redis-server /opt/redis_conf/redis-6380.conf
redis-server /opt/redis_conf/redis-6381.conf
redis-server /opt/redis_conf/redis-6382.conf
6、查看主从数据库状态
redis-cli -p 6380 info
redis-cli -p 6380 info replication
7、添加数据进行测试
8、手动进行主从复制故障切换
- 关闭6381的从库身份
redis-cli -p 6381
info replication
slaveof no one
- 将6382设为6381的从库
6382连接到6381:
[root@db03 ~]# redis-cli -p 6382
127.0.0.1:6382> SLAVEOF no one
127.0.0.1:6382> SLAVEOF 127.0.0.1 6381