redis 系列21 复制Replication (上)
一. 概述
使用和配置主从复制非常简单,每次当 slave 和 master 之间的连接断开时, slave 会自动重连到 master 上,并且无论这期间 master 发生了什么, slave 都将尝试让自身成为 master 的精确副本。这个系统的运行依靠三个主要的机制:
(1) 当一个 master 实例和一个 slave 实例连接正常时, master 会发送一连串的命令流来保持对 slave 的更新,以便于将自身(master)数据集的改变复制给 slave 。包括客户端的写入、key 的过期或master库的其它改变动作。
(2) 在Redis2.6之前,主从断开重连后,会进行一次快照操作(rdb)然后将快照发送给从数据库,即使断开期间只有几条命令被执行,这就使得断开重联后的数据恢复过程效率很低。Redis2.8之后,当 master 和 slave 之间的连接断开之后(因为网络问题、主库或从库检测到超时), slave 会重新连接上 master 并尝试进行"部分重同步"也叫增量复制(partial resynchronization),用于获取在断开连接期间内丢失的命令流。
(3) 当无法进行部分重同步时,slave 会请求进行"完整同步"(full resynchronization)。这会涉及到一个更复杂的过程,例如 master 需要创建所有数据的快照,将之发送给 slave ,之后在master数据集更改时持续发送命令流到 slave。也就是2.8后有了全部同步和部分重同步两种模式,而2.6之前只有全部同步模式。
二. 复制特点
Redis使用默认的异步复制,具有低延迟和高性能,是绝大多数Redis使用的复制模式。从库会异步的确认与主库定期接收到的数据量。主库不会每次去等待从库处理完命令。类似mysql半同步复制功能可以通过min-slaves配置选项来辅助。下面介绍Redis复制的一些特点:
(1) Redis使用异步复制,slave 和 master 之间异步地确认处理的数据量。
(2) 一个 master 可以拥有多个 slave。
(3) slave 可以接受其他 slave 的连接。除了多个 slave 可以连接到同一个 master 之外, slave 之间也可以像层叠状的结构(cascading-like structure)连接到其他 slave 。自Redis 4.0 版本起所有的 sub-slave 将会从 master 收到完全一样的复制流。
(4) Redis复制在 master这边是非阻塞的。这意味着 master 在一个或多个 slave 进行初次同步或者是部分重同步时,可以继续处理查询请求。
(5) 复制在 slave 这边大部分也是非阻塞的。当 slave 进行初次同步时,它可以使用旧数据集处理查询请求,假设你在redis.conf中配置了让Redis这样做的话。
(6) 复制既可以被用在可伸缩性,以便只读查询可以有多个 slave 进行(例如 O(N) 复杂度的慢操作可以被下放到 slave ),或者仅用于数据安全。
(7) 可以使用复制来避免 master 将全部数据集写入磁盘造成的开销:一种典型的技术是配置你的 master Redis.conf以避免对磁盘进行持久化,然后连接一个 slave ,其配置为不定期保存或是启用 AOF。但是,这个设置必须小心处理,因为重新启动的 master 程序将从一个空数据集开始:如果一个 slave 试图与它同步,那么这个 slave 也会被清空。
(8) 在使用Redis复制功能时,强烈建议在 master 和在 slave 中启用持久化。假如:持久化被关闭了,Redis主节点重启后其数据集合为空。而其它slave从节点会复制主节点数据,在复制时会销毁自身之前的数据副本。这样下来复制构架的所有节点数据都会被清空。
三 Redis复制同步原理
3.1 全部同步的实现
当客户端向从服务器发送slaveof命令,要求从服务器复制主服务器时,从服务器首先需要执行同步操作,将从服务器的数据库状态更新至主服务器当前所处的数据库状,过程如下:
(1) 从服务器向主服务器发送psync命令。
(2) 收到psync命令的主服务器执行BGSAVE命令,开启一个后台子进程生成一个 RDB 快照文件,并同时使用一个缓冲区记录从现在执行的所有写命令。
(3) 当主服务器的BGSAVE命令执行完,主服务器会将生成的RDB文件发送给从服务器,从服务器接收并载入这个RDB文件,然后加载文件到内存。将自己的数据库状态更新至主服务器执行BGSAVE命令时的数据库状态。
(4) 主服务器将记录在缓冲区里面的所有写命令发送给从服务器,从服务器执行这些写命令,将自己的数据库状态更新至主服务器数据库当前所处状态。这个过程以指令流的形式完成并且和Redis协议本身的格式相同。
下面是使用psync命令进行全部同步的过程:
时间 |
主服务器 |
从服务器 |
T0 |
服务器启动 |
服务器启动 |
T1 |
执行set k1 v1 |
|
T2 |
执行set k2 v2 |
|
T4 |
.. |
向主服务器发送psync命令 |
T5 |
接收到从服务器的psync命令,执行bgsave命令,创建RDB文件,并使用缓冲区记录接下来执行所有写命令. |
|
T6 |
执行set k3 v3,将这个命令记录在缓冲区中 |
|
T7 |
执行set k4 v4,将这个命令记录在缓冲区中 |
|
T8 |
Bgsave执行完成,向从服务器发送RDB文件 |
|
T9 |
接收载入RDB文件 |
|
T10 |
向从服务器发送缓冲区中保存的写命令 |
|
T11 |
接收缓冲区中的写命令,执行 |
|
T12 |
同步完成 |
同步完成 |
3.2 部分重同步的实现
在主从服务器断开后,从服务器会尝试不断的发送psync命令,使用部分重同步模式,让主从服务器重新回到一致状态。使用部分重同步主服务器只需要将从服务器缺少的写命令发送给从服务器,从服务器执行就可以了。功能由三个部份构成:
(1) 主服务器的复制偏移量(replication offset)和从服务器的复制偏移量。
(2)主服务器的复制积压缓冲区(replication backlog)。
(3) 服务器的运行ID (run ID) 。
3.2.1 复制偏移量:主服务器每次向从服务器传播N个字节的数据时,就将自己的复制偏移量的值加上N。从服务器每次接收到主服务器传播来的N个字节的数据时,就将自己的复制偏移量的值加上N。
例如:主服务器向从服务器传播长度为33个字节数据,那么主服务器的复制偏移量将更新为10086+33=10119,而从服务器在接收到主服务器传播的数据之后,也会将复制偏移量更新为10119。如果主从偏移量相同,表示主从服务器处于一致状态,反之则不一致。
3.2.2 复制积压缓冲区: 该缓冲区是由主服务器维护一个固定长度先进先出的队列,默认大小为1MB。当主服务器进行命传播时,它不仅会将写命令发送给所有从服务器,还会将写命令入队列到复制积压缓冲区中。因此主服务器的复制积压缓冲区中会保存着一部分最近传播的写命令,并且复制积压缓冲区会为队列中的每个字节记录相应的复制偏移量。
当从服务器重新连上主服务器时,从服务器会通过psync命令将自己的复制偏移量offset发送给主服务器,主服务器会根据这个复制偏移量来决定从服务器执行何种同步操作:
(1) 如果从服务器发送的offest偏移量之后的数据仍然存在于复制积压缓冲区中,那么主服务器将对从服务器执行部分重同步操作。
(2) 如果从服务器发送的如果offest偏移量之后的数据已经不存在于复制积压缓冲区中,那么主服器将对从服务器执行完整同步操作。
注意:缓冲区默认大小为1MB,如果主服务器需要执行大量写命令,又或者主从服务器断线后重连接所需的时间比较长,那么这个大小也许并不合适。查看积压缓冲区大小(单位字节)如下:
127.0.0.1:> config get repl-backlog-size
) "repl-backlog-size"
) ""
3.2.3 服务器运行ID:每个redis服务器,不论主从都有自己的运行ID。运行ID在服务器启动时自动生成,由40个随机的十六进制字符组成。当从服务器对主服务器进行初次复制时,主服务器会将自已运行的ID传送给从服务器,从服务器会将这个运行ID保存起来。当从服务器断开重连到一个主服务器时,从服务器将向当前连接的主服务器发送之前保存的运行ID
(1) 如果从服务器保存的运行ID和当前连接的主服务器的运行ID相同,那么说明从服务器断开后重连的还是之前的主服务器,主服务器将继续尝试执行部分重同步操作。
(2) 反之,如果运行ID不相同,那说明从服务器断开后重连的不是之前的主服务器,主服务器将对从服务器执行完整同步操作。
下面使用psync命令来进行断线后,重复制的过程:
时间 |
主服务器 |
从服务器 |
T0 |
主从服务器完成同步 |
主从服务器完成同步 |
T1 |
执行并传播set k1 v1 |
执行主服务器传来的set k1 v1 |
.. |
.. |
.. |
T10087 |
主从服务器连接断开 |
主从服务器连接断开 |
T10088 |
执行set k10087 v10087 |
断线后,尝试重新连接主服务器 |
T10089 |
执行set k10088 v10088 |
断线后,尝试重新连接主服务器 |
T10090 |
主从服务器重新连接 |
主从服务器重新连接 |
T10091 |
向主服务器发送psync命令 |
|
T10092 |
向从服务器返回+continue回复,表示执行部分重同步 |
|
T10093 |
接收+continue回复,表示执行部分重同步 |
|
T10094 |
主从服务器再次完成同步 |
主从服务器再次完成同步 |
四. psync命令的实现
4.1 PSYNC命令的调用方法有两种:
(1) 如果从服务器以前没有复制过任何主服务器,那么从服务器在开始一次新的复制时,将向主服务器发送psync ? -1 命令,主动请求主服务器进行完整同步。
(2) 相反,如果从服务器已经复制过某个主服务器,那么从服务器在开始一次新的复制时,将向主服务器发送 psync runid offset 命令。通过两个参数来判断应该对服务器执行哪种同步操作。
4.2 根据情况,主服务器接收到psync命令返回以下三种回复的其中一种:
(1) 如果主服务器返回 +fullresync runid offset回复,那么表示主服务器将与从服务器执行“完整同步”操作。
(2) 如果主服务器返回+continue回复,那么表示主服务器将与从服务器执行“部分重同步”操作。
(3) 如果主服务器返回-err回复,那么表示主服务器的版本低于redis 2.8,它识别不了psync命令,从服务器将向主服务器发送sync命令,并与主服务器执行完整同步操作。
下图是psync命令执行完整同步和部分重同步时可能遇到的情况:
redis 系列21 复制Replication (上)的更多相关文章
- redis 系列22 复制Replication (下)
一. 复制环境准备 1.1 主库环境(172.168.18.201) 环境 说明 操作系统版本 CentOS 7.4.1708 IP地址 172.168.18.201 网关Gateway 172. ...
- redis 系列23 哨兵Sentinel (上)
一.概述 Sentinel(哨岗或哨兵)是Redis的高可用解决方案:由一个或多个Sentinel实例(instance)组成的Sentinel系统(system)可以监视任意多个主服务器,以及这些主 ...
- 【目录】redis 系列篇
随笔分类 - redis 系列篇 redis 系列27 Cluster高可用 (2) 摘要: 一. ASK错误 集群上篇最后讲到,对于重新分片由redis-trib负责执行,关于该工具以后再介绍.在进 ...
- redis 系列25 哨兵Sentinel (高可用演示 下)
一. Sentinel 高可用环境准备 1.1 Sentinel 集群环境 环境 说明 操作系统版本 CentOS 7.4.1708 IP地址 172.168.18.200 网关Gateway 1 ...
- Redis系列(四):Redis的复制机制(主从复制)
本篇博客是Redis系列的第4篇,主要讲解下Redis的主从复制机制. 本系列的前3篇可以点击以下链接查看: Redis系列(一):Redis简介及环境安装 Redis系列(二):Redis的5种数据 ...
- redis系列--深入哨兵集群
一.前言 在之前的系列文章中介绍了redis的入门.持久化以及复制功能,如果不了解请移步至redis系列进行阅读,当然我也是抱着学习的知识分享,如果有什么问题欢迎指正,也欢迎大家转载.而本次将介绍哨兵 ...
- Redis系列总结--这几点你会了吗?
文章原创于公众号:程序猿周先森.本平台不定时更新,喜欢我的文章,欢迎关注我的微信公众号. 前面几篇已经对Redis中几个关键知识点做了介绍,本篇主要对Redis系列做一下总结以及对Redis中常见面试 ...
- Redis系列3:高可用之主从架构
Redis系列1:深刻理解高性能Redis的本质 Redis系列2:数据持久化提高可用性 1 主从复制介绍 上一篇<Redis系列2:数据持久化提高可用性>中,我们介绍了Redis中的数据 ...
- jboss eap 6.3 集群(cluster)-Session 复制(Replication)
本文算是前一篇的后续,java web application中,难免会用到session,集群环境中apache会将http请求智能转发到其中某台jboss server.假设有二个jboss se ...
随机推荐
- Eclipse 那些小技巧(值得收藏)
1.菜单命令系列 Edit→content Assist→add Alt+/ 代码关联 Windows→Next Editor→add Ctrl+Tab 切换窗口 Run→Debug Toggle L ...
- ubuntu“少折腾”
1.python版本默认python3 sudo update-alternatives --install /usr/bin/python python /usr/bin/python2 sudo ...
- react组件中刷新组件小技巧
在开发过程中,经常遇到组件数据无法更新,例如:当你用同一个表格展示不同数据的时候,当点击第5页后,再点击另外一份数据时发现还在第五页,并没有回到第一页. 怎么能让一个组件每次数据不一样时都重新加载呢, ...
- C#代码总结04---通过创建临时表DataTable进行临时编辑删除
<script type="text/javascript"> //删除 function Delete(hdGuid) { $("#hdGuid" ...
- Python-杂物
1,and和or 在一个bool and a or b语句中,当bool条件为真时,结果是a:当bool条件为假时,结果是b. a = "heaven" b = "hel ...
- URI ,URL 和 URN
URI : 统一资源标识符,用来唯一标识互联网资源,包括URL和URN URL:统一资源定位器 包含: 协议,域名,端口,路由,参数,hash https://i.cnblogs.com/EditPo ...
- js判断时间段
开始时间小于结束时间的判断,下面是封装号的方法,直接可以调用: var data = new Date(); var year = data .getFullYear(); //获取完整的年份(4位) ...
- JdbcTemplate实体映射
JdbcTemplate实体映射 如果你需要使用JdbcTemplate将查询的数据映射成Java POJO,那么这篇文章适合你. 一个例子入门 下面是一个将表中一行记录映射成Map的例子,也是Jdb ...
- Shell 脚本处理用户输入
传递参数 跟踪参数 移动变量 处理选项 将选项标准化 获得用户的输入 bash shell提供了一些不同的方法来从用户处获取数据,包括命令行参数(添加在命令后数据),命令行选项(可以修改命令行为的单个 ...
- ssh网上商城源码
本人承诺源码免费,只是出于前期发布很多免费资源反而落不到好下场,总是被一些人说三道四.就算你去找到资源版本不符合你也运行不起来.如果想要资源加QQ1397617269,或者电话短信1395630164 ...