redis主从架构
# Redis主从架构
redis主从架构 -> 读写分离架构 -> 可支持水平扩展的读高并发架构
# 1. 基本原理
redis采用异步方式复制数据到slave节点,不过redis 2.8开始,slave node会周期性地确认自己每次复制的数据量
一个master node是可以配置多个slave node的
slave node也可以连接其他的slave node
slave node做复制的时候,是不会block master node的正常工作的
slave node在做复制的时候,也不会block对自己的查询操作,它会用旧的数据集来提供服务; 但是复制完成的时候,需要删除旧数据集,加载新数据集,这个时候就会暂停对外服务了
slave node主要用来进行横向扩容,做读写分离,扩容的slave node可以提高读的吞吐量
写操作存放在master node,同时在异步把master上的信息,同步到每个slave node上。
# 2. master持久化的意义
如果采用了主从架构,那么建议必须开启master node的持久化!不建议用slave node作为master node的数据热备,因为那样的话,如果你关掉master的持久化,可能在master宕机重启的时候数据是空的,然后可能一经过复制,salve node数据也丢了
master -> RDB和AOF都关闭了 -> 全部在内存中
master宕机,重启,是没有本地数据可以恢复的,然后就会直接认为自己IDE数据是空的
master就会将空的数据集同步到slave上去,所有slave的数据全部清空,100%的数据丢失
第二个,master的各种备份方案,要不要做,万一说本地的所有文件丢失了; 从备份中挑选一份rdb去恢复master; 这样才能确保master启动的时候,是有数据的
即使采用了后续讲解的高可用机制,slave node可以自动接管master node,但是也可能sentinal还没有检测到master failure,master node就自动重启了,还是可能导致上面的所有slave node数据清空故障
# Redis主从复制原理
Redis主从复制可以根据是否是全量分为全量同步和增量同步。
主从刚刚连接的时候,进行全量同步;全同步结束后,进行增量同步。当然,如果有需要,slave 在任何时候都可以发起全量同步。redis 策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进行全量同步。
当启动一个slave node的时候,它会发送一个PSYNC命令给master node,如果这是slave node重新连接master node,那么master node仅仅会复制给slave部分缺少的数据; 否则如果是slave node第一次连接master node,那么会触发一次full resynchronization
开始full resynchronization的时候,master会启动一个后台线程,开始生成一份RDB快照文件,同时还会将从客户端收到的所有写命令缓存在内存中。RDB文件生成完毕之后,master会将这个RDB发送给slave,slave会先写入本地磁盘,然后再从本地磁盘加载到内存中。然后master会将内存中缓存的写命令发送给slave,slave也会同步这些数据。
slave node如果跟master node有网络故障,断开了连接,会自动重连。master如果发现有多个slave node都来重新连接,仅仅会启动一个rdb save操作,用一份数据服务所有slave node。
主从复制特点:
- Redis使用异步复制。但从Redis 2.8开始,从服务器会周期性的应答从复制流中处理的数据量。
- 一个主服务器可以有多个从服务器。
- 从服务器也可以接受其他从服务器的连接。除了多个从服务器连接到一个主服务器之外,多个从服务器也可以连接到一个从服务器上,形成一个图状结构。
- Redis主从复制不阻塞主服务器端。也就是说当若干个从服务器在进行初始同步时,主服务器仍然可以处理请求。
- 主从复制也不阻塞从服务器端。当从服务器进行初始同步时,它使用旧版本的数据来应对查询请求,假设你在redis.conf配置文件是这么配置的。否则的话,你可以配置当复制流关闭时让从服务器给客户端返回一个错误。但是,当初始同步完成后,需要删除旧的数据集和加载新的数据集,在这个短暂的时间内,从服务器会阻塞连接进来的请求。
- 主从复制可以用来增强扩展性,使用多个从服务器来处理只读的请求(比如,繁重的排序操作可以放到从服务器去做),也可以简单的用来做数据冗余。
- 使用主从复制可以为主服务器免除把数据写入磁盘的消耗:在主服务器的redis.conf文件中配置“避免保存”(注释掉所有“保存“命令),然后连接一个配置为“进行保存”的从服务器即可。但是这个配置要确保主服务器不会自动重启(要获得更多信息请阅读下一段)
# Redis主从复制流程
slave node启动,仅仅保存master node的信息,包括master node的host和ip,但是复制流程没开始master host和ip是从哪儿来的,redis.conf里面的slaveof配置的
slave node内部有个定时任务,每秒检查是否有新的master node要连接和复制,如果发现,就跟master node建立socket网络连接
slave node发送ping命令给master node
口令认证,如果master设置了requirepass,那么salve node必须发送masterauth的口令过去进行认证
master node第一次执行全量复制,将所有数据发给slave node
master node后续持续将写命令,异步复制给slave node
# 1. 全量复制
Redis全量复制一般发生在Slave初始化阶段,这时Slave需要将Master上的所有数据都复制一份
master执行bgsave,在本地生成一份rdb快照文件
master node将rdb快照文件发送给salve node,如果rdb复制时间超过60秒(repl-timeout),那么slave node就会认为复制失败,可以适当调节大这个参数
对于千兆网卡的机器,一般每秒传输100MB,6G文件,很可能超过60s
master node在生成rdb时,会将所有新的写命令缓存在内存中,在salve node保存了rdb之后,再将新的写命令复制给salve node
client-output-buffer-limit slave 256MB 64MB 60,如果在复制期间,内存缓冲区持续消耗超过64MB,或者一次性超过256MB,那么停止复制,复制失败
slave node接收到rdb之后,清空自己的旧数据,然后重新加载rdb到自己的内存中,同时基于旧的数据版本对外提供服务
- 从服务器 (opens new window)连接主服务器,发送SYNC命令;
- 主服务器接收到SYNC命名后,开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所有写命令;
- 主服务器BGSAVE执行完后,向所有从服务器发送快照文件,并在发送期间继续记录被执行的写命令;
- 从服务器收到快照文件后丢弃所有旧数据,载入收到的快照;
- 主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令;
- 从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令;
rdb生成、rdb通过网络拷贝、slave旧数据的清理、slave aof rewrite,很耗费时间
如果slave node开启了AOF,那么会立即执行BGREWRITEAOF,重写AOF
# 2. 增量复制
- 如果全量复制过程中,master-slave网络连接断掉,那么salve重新连接master时,会触发增量复制
- master直接从自己的backlog中获取部分丢失的数据,发送给slave node,默认backlog就是1MB
- msater就是根据slave发送的psync中的offset来从backlog中获取数据的
# 3. 异步复制
- master每次接收到写命令之后,现在内部写入数据,然后异步发送给slave node
# 心跳机制
master默认每隔10秒发送一次心跳,salve node每隔1秒发送一个心跳
redis 判断接点是否正常工作,基本都是通过互相的 ping-pong 心态检测机制,如果有一半以上的节点去 ping 一个节点的时候没有 pong 回应,集群就会认为这个节点挂掉了,会断开与这个节点的连接。
redis 主从节点发送的心态间隔是不一样的,而且作用也有一点区别:
redis 主节点默认每隔 10 秒对从节点发送 ping s命令,判断从节点的存活性和连接状态,可通过参数repl-ping-slave-period控制发送频率。
redis 从节点每隔 1 秒发送 replconf ack{offset} 命令,给主节点上报自身当前的复制偏移量,目的是为了:
- 实时监测主从节点网络状态;
- 上报自身复制偏移量, 检查复制数据是否丢失, 如果从节点数据丢失, 再从主节点的复制缓冲区中拉取丢失数据。
- 实时监测主从节点网络状态;