在前面的一篇博客中【Redis多实例及主从复制环境搭建】简单的介绍了一下redis的主从复制原理以及搭建redis的主从复制环境,
Redis的复制是基于rdb方式的持久化实现的,即主数据库端在后台保存rdb快照,从数据库端则接受并载入快照文件、这样的实现优点是可以显著的简化逻辑,复用已有的代码,但是缺点也是非常明显的:
(1)当主数据库禁用rdb快照时[删除配置文件中的save语句],如果执行了复制初始化的操作,redis依然会生成rdb快照,所以下次启动后主数据库会以该快照恢复数据。因为复制发生的时间不能确定,这使得恢复数据可能是任何的时间点的。
(2)因为复制初始化的时候需要在硬盘中创建rdb快照文件,所以如果硬盘的性能很慢时,这一过程会对性能产生影响。举个例子来说,当使用redis做缓存系统时,因为可能不需要持久化,所以服务器的硬盘读写速度可能较差。但是当该缓存系统使用一主多从的架构时,每次和从数据库与同步,redis都会执行一次快照,同时对硬盘进行读写,导致性能降低。
因此,从redis2.8.18版本开始,redis引入了无硬盘复制选项,开启该选项时,redis在与从数据库进行复制初始化时将不会将快照内容存储到硬盘上,而是直接通过网络的发送给数据库,有效的避免了性能的瓶颈问题。
可以在配置文件中使用如下的参数配置来开启该功能:
repl-diskless-sync yes
一、全量复制
全量复制的过程:
1、从服务器向主服务器发送PSYNC命令,携带主服务器的runid和复制偏移量;第一次的话,slave不知道master 的 runid,所以是?,偏移量是-1
2、主服务器验证runid和自身runid是否一致,如不一致,则进行全量复制;
3、Master把自己的runid和offset(偏移量)发给slave
4、Slave将master的runid和offset进行保存
5、Master进行bgsave,生成RDB文件
6、在生成RDB文件的过程中,如果master再有写操作,会将写操作放入repl_back_buffer缓冲区
7、将写好的RDB文件传递给slave,将缓冲区内的数据传送给slave
8、Salve清楚原来的数据,加载RDB和缓冲区数据
全量复制的开销包括以下几个方面:
1、bgsave时间
2、RDB文件网络传输时间
3、从节点清空数据时间
4、从节点加载RDB数据时间
二、增量复制
接下来重点说一下增量复制,了解了全量复制后,我们会出现这样的一个疑问:
当主从数据库连接断开后,从数据库会发送SYNC命令来重新进行一次完整复制操作。【提示:redis 2.8版本之后从数据库会向主数据库发送PSYNC命令来代替SYNC以实现增量复制】这样即使主从断开期间数据库的变化很小,甚至没有,也需要将数据库中的所有数据重新快照并传送一次。在正常的网络应用环境中,这种实现方式显然不是很理想。Redis 2.8版本的重要更新之一就是主从断线重连的情况下的增量复制。
增量复制是基于下面三点实现的:
(1)从数据库会存储主数据库的运行id[run id]。每一个redis实例运行都会有一个唯一的运行id,每当实例重新启动后,就会重新生成一个新的运行id。
(2)在复制同步阶段,主数据库每将一个命令传送给从数据库时,都会同时把该命令存放在一个积压队列中(backlog),并记录下当前积压队列中存放命令的的偏移量。
(3)同时,从数据库接受到主数据库传来的命令时,会影响该命令的偏移量。
以上的3点是实现增量复制的基础。如上所述,当主从连接准备就绪后,从数据库会发送一条SYNC命令来告诉主数据库可以开始把所有数据同步过来,而2.8版本后,不在发送SYNC命令,取而代之的是PSYNC,格式为“PSYNC 主数据库的运行id 断开前最新的命令偏移量”。当主数据库收到PSYNC命令后,会执行以下的判断来决定此次重连是否可以执行增量复制:
(1)首先,主数据库会判断从数据库传来的运行id是否和自己的运行id相同、这一步骤的意义在于确保从数据库之前确实是和自己同步的,以避免从数据库拿到错误的数据[比如主数据库在断开期间重启过,会造成数据的不一致]。
(2)然后判断从数据库最后同步成功的命令的偏移量是否在积压队列中,如果在则可以执行增量复制,并将积压队列中的相应的命令发送给从数据库。如果此次重连不满足增量复制的条件,主数据库会进行一次全部同步。
下面简单的解释一下什么是积压队列:
积压队列在本质上是一个固定长度的循环队列,默认情况下积压队列的大小为1M,可以通过配置文件中的repl-backlog-size参数来调整大小。很容易理解的是,积压队列越大,其允许的主从数据库断线的时间就越长。根据主从数据库之间的网络状态,设置一个合理的积压队列很重要。因为积压队列存储的的内容是命令本身,如:set name wjq,所以估算积压队列的大小只需要估计主从数据库断线的时间中主数据库可能执行的命令大小即可。
与积压队列相关的另一个配置选项使repl-backlog-ttl,即当所有从数据库与主数据库断开连接后,经过多久时间可以释放积压队列的内存空间。默认是1小时[3600s];
我们可以看到主节点记录了从节点的偏移量信息。
关于redis主从复制环境搭建可参考:Redis多实例及主从复制环境搭建【http://blog.itpub.net/31015730/viewspace-2155578/】
下面配置文件redis.conf中关于主从复制的一些配置参数进行了解释说明:
关于redis配置文件的参数介绍可参考:redis配置文件中各参数详解【http://blog.itpub.net/31015730/viewspace-2154818/】
################################# REPLICATION #################################
# 将当前节点设置为运行在机器127.0.0.1上的6379端口实例的从节点
# slaveof <masterip> <masterport>
slaveof 127.0.0.1 6379
# 主节点设置验证密码,从节点在进行复制请求时,需要通过auth进行验证
# masterauth <master-password>
masterauth qcloud@2018
# 从节点和主节点失去连接或者从节点正处于复制数据过程中,从节点响应客户端的方式
# “yes” 从节点使用旧数据响应客户端请求
# “no”从节点给客户端反馈一个错误信息"SYNC with master in progress"
slave-serve-stale-data yes
# 从Redis 2.6开始 从节点默认只读模式。有时可以将从节点配置为可写模式,但是只能存储临时的数据,因为主从同步会很快删除这些临时数据。
# 同时注意从节点不能暴露给不安全的网络环境下
slave-read-only yes
# 从机器会每隔10秒钟 向主发送ping命令 以保住主节点活着
# repl-ping-slave-period 10
# 这是个响应超时的时间,需要从两个角度来看
# 从的角度来看,批量传输数据、从ping主等
# 主的角度来看,REPLCONF ACK pings等
# 这个值一定要大于repl-ping-slave-period 这个值
# repl-timeout 60
# 若配置为yes,则禁用NO_DELAY,则TCP协议栈会合并小包统一发送,这样可以减少主从节点间的包数量并节省带宽,但会增加数据同步到slave的时间。
# 若配置为no,表明启用NO_DELAY,则TCP协议栈不会延迟小包的发送时机,这样数据同步的延时会减少,但需要更大的带宽。
# 通常情况下,应该配置为no以降低同步延时,但在主从节点间网络负载已经很高的情况下,可以配置为yes。
repl-disable-tcp-nodelay no
# 主节点的复制缓冲区大小,默认是1M,根据实际情况可以调大这个数值
# repl-backlog-size 1mb
# 当主失去所有从节点时,默认经过3600秒回释放复制缓冲区中的值
# 当设置为0时,意味着从不释放
# repl-backlog-ttl 3600
#Redis哨兵Sentinel会根据slave的优先级选举一个master。最低的优先级的slave,当选master。
#而配置成0,永远不会被选举。默认为100
slave-priority 100
#表示只有当3个(或以上)的从库连接到主库时,主库才是可写的,否则会返回错误
# min-slaves-to-write 3
#表示允许从库最长失去连接的时间,如果从库最后与主库联系(即发送“replconf ack”命令)的时间小于这个值,则认为从库还在保持与主库的连接。
# min-slaves-max-lag 10
更多关于redis的相关知识可参考:【http://blog.itpub.net/31015730/cid-185228-list-1/】
Redis 4.0集群环境部署【http://blog.itpub.net/31015730/viewspace-2155989/】
作者:SEian.G(苦练七十二变,笑对八十一难)
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/31015730/viewspace-2156282/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/31015730/viewspace-2156282/