一般来说,要将Redis运用于工程中,只使用一台Redis服务是万万不能的,在实际的场景当中单一节点的redis容易面临风险。主要原因有:
如果服务器发生故障,就需要迁移到另外一台服务器上并且还要考虑数据同步问题,另外也存在容量瓶颈现象,当有需求需要扩容Redis内存,就需不断加升内存!
通常,我们为了避免服务的单点故障,会把数据复制到多个副本并放在不同的服务器上,且这些拥有数据副本的服务器可以用于处理客户端的读请求,扩展整体的性能!
主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master),后者称为从节点(slave);数据的复制是单向的,只能由主节点到从节点。
结构图解如下:
✦ 解析:采用读写分离。主服务器master可提供读写操作(为了减轻压力通常只处理写请求),当master的数据发生变化,master会发出命令流来保持对salve的数据更新(slave通常提供读)
默认情况下,每台Redis服务器都是主节点;一个master可以有多个slave,即一主多从,但一个从节点只能有一个主节点(爸爸可以有多个孩子,但孩子只有一个亲生父亲!)
★ 主从复制的好处:
如果是真实服务器或多个虚拟机,port 端口号可以一样,但是bind绑定的 IP 地址要不一样!
由于条件有限,这里我使用的是伪服务器,用的都是本地服务127.0.0.1,拷贝三份redis.conf 配置文件充当3个服务器,如图:
! ! 注意:大家演示操作的时候,建议默认的配置文件备份一下,恢复默认配置易忘记改动的参数
这里我分别用:6379、6380、6381 三个端口号,redis.conf 配置文件名称也记得区分一下,配置文件中的几个参数需要配置:
# 设置为后台运行
daemonize yes
-- 如果是像我一样一台机器伪造3个服务器,需要命名区分,如果是3台机器则不需要
# 保存pid的文件 ————每个conf配置文件对应自己的端口号区分下名称
pidfile /var/run/redis_6380.pid # 即redis81.conf就命名:redis_6381.pid,以此类推
# 指定日志文件, (命名区分同上)
logfile "6380.log"
# 指定rdb文件的名称 (命名区分同上)
dbfilename dump6380.rdb
-- 如果是三台机器 上述命名可以不区分,但是这里绑定IP就是机器的IP地址
# 绑定的主机地址,这里注释掉,开放ip连接
#bind 127.0.0.1
☛ 查看结果:上述三个conf 配置文件参数修改好后,再分别启动3台服务器,查看服务进程结果:
上面也讲述过了,默认情况,每台Redis服务器都是主节点,查看节点信息如下:
- redis-cli -p [端口号]:连接具体端口的客户端
- info replication:查看复制信息
根据上图所示,每台服务器默认都是主节点,所以只需要配置从机就好了,把6379当主节点,另外6380、6381 当作从节点,分别在redis80.conf 、redis81.conf 配置文件中设置参数如下:
########################## REPLICATION(主从复制) ##########################
# 在5.0版本中使用了replicaof代替了slaveof,slaveof还可以继续使用,建议使用replicaof
replicaof # 主机的IP、主机的端口
#----------------------------- 其他参数设置 ------------------------------
-- 注意1:如master设置了requirepass密码,slave用此选项指定master认证密码
# masterauth
-- 注意2:作为从服务器,默认情况下是只读的(yes),可以修改成NO,用于写(不建议)。
slave-read-only yes
具体设置:修改 80、81的conf 配置文件参数如下: 一主(79)二从(80、81)
设置完毕记得重启所有的服务和重新连接各客户端,再次查看各节点信息:
✧ 情况一:主机写入数据,从机读取数据
✧ 情况二:从机写入数据
✧ 情况三:主机宕机,从机状态如何?
宕机后的主机,重连服务后,从机状态如何?
- 主机宕机后,从机读取数据不影响
- 主机重新连接后,正常运行,写入的新数据也能被从机立刻读取!
✧ 情况四:从机宕机,主机和其他从机状态如何?
即使主机在从机宕机期间,写入新数据,从机一旦重启服务后,也能够获取到这部分数据!
☁思考:为什么从机宕机了,重连后,也能恢复主机在从机宕机期间新产生的数据呢?
注意:在2.8版本之前只有全量复制,而2.8版本后有全量和增量复制
全量复制
:将主节点中整个数据文件都发送给从节点(重型操作)增量复制
:主和从节点在中断期间,主库所执行的写命令发送给从节点注意:如中断时间过长,主节点没完全保存中断期间执行的写命令,仍然会使用全量复制
从节点宕机后,重连服务后,会自动向master发送一条sync同步命令,master收到命令后,收集所有数据集命令,再把整个数据文件传送给slave从机,完成从机的数据同步!
Redis的主从复制过程大体上分3个阶段:建立连接、数据同步、命令传播
▶ 第一阶段是主从库间建立连接、协商同步的过程
psync 命令包含了主库的 runID 和复制进度 offset 。
- runID:每个 Redis 实例启动时会自动生成的一个随机 ID,用来唯一标记这个实例。当从库和主库第一次复制时,因为不知道主库的 runID,所以将 runID 设为“?”。
- offset,此时设为 -1,表示第一次复制。
主库收到 psync 命令后,会用 FULLRESYNC 响应命令带上两个参数:主库 runID 和主库目前的复制进度 offset,返回给从库。从库收到后,记录下这两个参数。
注意:FULLRESYNC 响应表示第一次复制采用的全量复制
从库给主库发送 psync 命令,表示要进行数据同步。主库接收命令后来启动复制。
▶ 第二阶段,主库将所有数据同步给从库。
主库执行 bgsave 命令,开始全量复制,生成 RDB 文件并发给从库。从库接收后,先清空当前数据库,再加载 RDB 文件(避免从库的旧数据与主机发过来的rdb数据文件内容冲突),主库同步给从库数据过程中,不会阻塞,仍然正常接收客户端请求。
在同步数据过程中,由于主库仍可接收客户端写请求,这些新产生的写操作未记录到刚生成的RDB文件中,所以为了保证主从库的数据一致性,主库会记录 RDB 文件生成后收到的所有新写操作。再写入到专门的 replication buffer 缓冲区
▶ 第三个阶段,主库发送新写命令给从库 ( 第二阶段同步过程中新收到的写命令)
当主库把RDB 文件传送给从库完毕后,就会把 replication buffer 缓冲区中的数据再发给从库,从库再重新执行这些操作。完成主从库的数据一致性!
主库会为每一个连接到自己的客户端创建一个replication buffer,用来发送增量写命令。即从库同步主库的rdb文件阶段,主库新产生的写命令会存入到该缓冲区,等从机完成rdb文件的同步后,主库再把该缓冲区的数据发给从库继续同步,保证主从数据一致性
思考一:如果replication buffer缓冲区写满了怎么办?
答:无论客户端是普通客户端还是从库,会断开其客户端连接,重新尝试全量同步
思考二:如何避免replication buffer缓冲区写满?
答:可以在redis.config文件中配置如下参数:
# 主从复制缓存区,32mb表示缓冲区最大是32mb,8mb 60表示如果60s内写入量超过8mb,就会溢出
client-output-buffer-limit slave 32mb 8mb 60
!! 注意:把缓冲区最大值调大,或把每秒允许的写入量增加,可减小缓冲区溢出的概率。但如果连接redis服务器的客户端越多,对内存的损耗也越大,故控制从节点的数量,也可以控制缓存区对内存的开销。当然也可以控制主节点的写命令接收速率。
? 思考:第二阶段完成rdb文件的同步后,在开始执行第三阶段的时候,此时断开连接怎么办??
从库完成RDB文件同步后,会继续同步从库的增量写命令。如果同步增量写命令的过程中,主从节点中断连接了,怎么办呢?重新连接后需要再次进行全量同步吗????
答:不一定,此时依赖Repl_backlog_buffer缓冲区,请看下方增量复制详解说明。
在master主节点与slave从节点中断连接期间,主节点所产生的新的写命令,会被发送给重连后的从节点(只是中断期间产生新写命令,而不是复制全部数据给从库)
这就是为什么从机断联了,重连后,也能恢复主机在从机宕机期间新产生的数据
图解如下:
✦ Repl_backlog_buffer 环形缓冲区
主库的写命令,除了传给从库后,还会写入repl_backlog_buffer,当主从断开后,重新建立连接,从库会发送之前的那个命令:psync $master_runid $offset
这个时候,主库就会在repl_backlog_buffer中找到offset的位置,把之后的写命令写入replication buffer同步给从库。
目的:解决从库断开后,找到主从差异数据而设立的环形缓冲区,避免全量同步的性能开销
图解:
✧ 解析:如上图,主库按顺时针方向写命令,从库建立连接后,还有key3和key4这2个命令没有同步,主库只要把这2个命令同步给从库就行了。主库也会记录一个自己的offset,主库offset 和 从库offset之间的命令就是需要同步的增量命令(即 key3、key4)
✧ 注意:
redis.conf 配置文件中可设置repl_backlog_size参数的大小,降低从库重连后全量同步的概率
在进行主从复制设置时,强烈建议在主服务器上开启持久化,当不能这么做时,例如由于非常慢的磁盘性能而导致的延迟问题,应该配置实例来避免重置后自动重启
?为什么不开启持久化的主服务器自动重启非常危险呢
☛ 结论:如果数据比较重要,使用了主从复制并关闭了master的持久化,都应禁止实例自动重启
Redis 默认是磁盘复制,从2.8.18版本开始尝试支持无磁盘的复制。使用这种设置时,子进程直接将RDB通过网络发送给从服务器,不使用磁盘作为中间存储
无磁盘复制模式:master创建一个新进程直接dump RDB到slave的socket,不经过主进程,不经过硬盘。适用于disk较慢,并且网络较快的时候。
- repl-diskless-sync参数:启动无磁盘复制
- repl-diskless-sync-delay参数:传输开始的延迟时间(单位:秒)
master等待一个repl-diskless-sync-delay 的秒数,如果没slave来的话,就直接传,后来的得排队等了; 否则就可以一起传。