主从同步模式(replication)
在生产环境中,为了保证 Redis 服务的高可用,我们往往要使用 Redis 的集群模式,Redis 的集群模式有三种:主从同步集群模式、哨兵集群模式、Cluster 集群模式,本篇文章先介绍 Redis 主从同步集群模式的原理及实现。
什么是主从同步
简单来说,主从同步
就是指以一个主节点作为基准节点,将数据同步给从节点,使得主从节点的数据保持一致。这里的主节点一般也称为 Master 节点,从节点一般也叫做 Slave 节点。一个 Master 节点可以
拥有多个 Slave 节点。这种架构就叫做 一主多从
的主从架构。如果每一个 Slave 节点也作为基准节点,同时也拥有多个 Slave 节点,那么这中架构就叫做 级联结构
的主从架构。本篇文章仅研究 一主多从
主从架构。
Redis 主从同步集群模式的应用场景
场景一:Slave 作为 Master 节点的数据备份
主从服务器架构的设计,可以大大加强 Redis 服务的健壮性。当主服务器出现故障时,可以人工或自动切换到从服务器继续提供服务,同时当主服务器的数据因为某种原因不能恢复时,可以使用从服务器备份的数据。
除了这些之外,还经常使用从服务器来处理一些操作比较耗时的命令,以防止阻塞主服务器的工作,导致主服务的请求不能及时处理。
例如: Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,如果将它们全部找出来?我们知道使用 keys
命令可以扫出指定模式的 key 列表。
如果 Redis 正在线上提供服务,会有什么问题吗?因为 Redis 是单线程的,keys 指令会导致线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。这个时候如果我们可以将 Redis 配置一个从服务器,将比较耗时或者阻塞的操作都在从
服务器来操作,以防止主服务器停顿。当然除了这种解决办法,还可以使用 scan 命令(scan 命令是无阻塞的)来扫描出需要的 key , 但是有一定的重复率。可以在客户端进行去重。
场景二:数据读写分离
读写分离的场景往往是我们最多使用的场景,类似于 Mysql 读写分离,一般是主服务器来提供写操作,从服务器提供读操作。主服务器的写操作会同步给从服务器。
数据读写分离将读操作和写操作隔离开,使得读写相互不影响效率,提高了服务的读写速度。
场景三:多个从服务器根据业务拆分
此种场景其实是基于场景二的基础上增加的,当读多写少的情况下,我们还可以根据读的不同业务将多个从服务器拆分,例如,从服务器 A 专门用来提供视频业务的数据访问,从服务 B 专门用来新闻业务的数据访问,从服务器 C 专门用来提供用户的数据访问。
此种场景不仅减轻了主服务器的压力,同时也使得不同的业务数据访问互不影响。
Redis 主从同步的原理
虽然我们已经能够配置并使用主从同步的 Redis 集群,但是我们还是有必要了解一下主从同步的实现原理,这样才能在遇到问题的时候迅速判断问题的发生的原因。
Redis 主从同步分为两个过程:全量同步和增量同步
全量同步
全量同步一般发生在 Slave 的初始化阶段,也就是 Slave 节点的启动阶段。
- 从服务器连接主服务器
- 从服务器发送
SYNC
命令到主服务器 - 主服务器接收到
SYNC
命名后,开始执行BGSAVE
命令生成RDB
文件并使用缓冲区记录此后执行的所有写命令 - 主服务器
BGSAVE
执行完后,递增地将文件发送到从服务器,并在发送期间继续记录被执行的写命令 - 从服务器收到快照文件后丢弃所有旧数据,载入收到的快照
- 从服务器将快照载入内存
- 主服务器快照发送完毕后开始向从服务器发送缓冲区的写命令
- 从服务器完成对快照的载入,开始接收主服务器发送的写命令请求,并执行写命令。
- 至此,一次全量同步完成
增量同步
增量同步是指 Redis 在主从模式已经正常工作的情况下,主服务器将写操作同步到从服务器的过程
增量复制的原理当主服务器每执行一个写命令,就会将该命令发送给所有的从服务器,从服务器接收到命令之后立即执行。
深挖细节
主节点执行
BGSAVE
生成全量镜像的 RDB 文件,是如何来工作的?
首先BGSAVE
指令是用来在后台异步保存当前数据库的数据到磁盘,不会阻塞主节点的进程,当执行BGSAVE
后,会立即返回 OK, 然后 Redisfork 出一个新子进程
来专门生成全量镜像文件的工作,将数据保存到磁盘后,子进程退出。当主节点在
BGSAVE
的过程中,又有新的写请求到来,主节点怎么工作?这些写数据怎么保存?
根据 1 的细节,我们知道主节点会有一个新的子进程来单独处理全量镜像的生成工作,那么主节点父进程可以继续来接收新的请求。这里需要注意的是,当发生 fork 的时候,操作系统会采用写时复制(copy-on-write)策略
即 fork 函数发生的那一刻,父子进程共享同一块内存数据,当父进程接收到写操作时,操作系统会复制一份数据以保证子进程的数据不受影响。所以新生产的 RDB 文件存储的是执行 fork 那一刻的数据。主服务执行
BGSAVE
命令如果磁盘不够生成rdb
文件数据的大小怎么办?不能同步了吗?
可以采用无磁盘复制
技术; 通常来讲,一个完全重同步需要在磁盘上创建一个 RDB 文件,然后加载这个文件以便为从服务器发送数据。如果使用比较低速或者容量较小的磁盘,这种操作会给主服务器带来较大的压力。
Redis从2.8.18版本开始尝试支持无磁盘的复制。使用这种设置时,子进程直接将 RDB 文件通过网络发送给从服务器,不使用磁盘作为中间存储。
这里需要注意:使用硬盘备份传送是多个从节点排队等待传送,也就是说传送是串行的,而无磁盘复制
技术是主节点在传送之前会等待一段时间(可以配置,以秒为单位),希望等待多个从节点都到达后,并行传送。
相关配置键如下:# 配置取消硬盘备份 repl-diskless-sync no # 延迟时间以秒为单位,默认为5秒。如果设置为 0 秒,传送会立即启动,不会延迟 repl-diskless-sync-delay 5
主从同步的过程中,从服务器是阻塞的吗?
主从同步的过程中,也不会阻塞从服务器。当从服务器进程初始同步时,会使用旧的数据继续提供查询服务。当然这个也可以在配置文件修改。但是,需要注意的是,并不是整个过程都是不阻塞的,当从服务器接受到快照文件,需要删除旧的快照并加装新的数据集到内存,在这个短暂的
时间内,从服务器会阻塞连接进来的请求。当主从节点断开复制之后,从节点的数据会删除吗?
如果需要断开复制,从节点执行命令:slaveof no one
从节点不会删除已有的数据,只是不再接受主节点新的数据变化
Redis 主从同步的优缺点
优点
- 同一个 Master 可以部署多个 Slave
- Slave 还可以接受其他的 Slave 的连接和同步,即所谓的 级联结构。有效的减轻 Master 的压力
- 主从同步期间,主从节点均是非阻塞。不影响服务的查询和写入
- 可以很好的实现读写分离的架构,系统的伸缩性得到提高
缺点
- 主机的宕机会非常严重,导致整个数据不一致的问题。
- 全量的复制的过程中,必须保证主节点必须有足够的内存。若快照的文件过大,还会对集群的服务能力产生影响。