详解Redis复制原理


Posted in Redis onJune 04, 2021

前言

本文主要介绍Redis复制机制

详解Redis复制原理

一.配置与实践

配置

Redis实例分为主节点(master)和从节点(slave),默认情况下都是主节点。每一个从节点只能有一个主节点,但是每一个主节点可以有多个从节点(注意数量,多个从节点会导致主节点写命令多次发送从而过度消耗网络带宽,可用树状结构降低主节点负载)。复制是单向的,只能从主节点复制到从节点。配置复制的方式由以下3种:

  • 在redis-slave.conf配置文件中加入slaveof {masterHost} {masterPort}
  • 在redis-server启动命令后加入 --slaveof {masterHost} {masterPort}
  • 启动后直接使用命令slaveof {masterHost} {masterPort}

综上,Redis支持在启动之前配置,也支持运行中动态配置。

实践

我们用动态配置的方法来配置,先起一个端口为6379的Redis实例,作为主节点:

redis-server /usr/local/Cellar/redis/4.0.9/.bottle/etc/redis.conf

再起一个端口为6380的Redis实例,作为6379的从节点:

redis-server /usr/local/Cellar/redis/4.0.9/.bottle/etc/redis-slave.conf

用客户端连到从节点,使用slaveof命令,slaveof配置都是在从节点发起的。

127.0.0.1:6380> slaveof 127.0.0.1 6379

OK

从节点日志:

75585:S 06 May 16:27:50.389 * Connecting to MASTER 127.0.0.1:6379

75585:S 06 May 16:27:50.389 * MASTER <-> SLAVE sync started

75585:S 06 May 16:27:50.390 * Non blocking connect for SYNC fired the event.

75585:S 06 May 16:27:50.390 * Master replied to PING, replication can continue...

75585:S 06 May 16:27:50.390 * Trying a partial resynchronization (request 47770067272eb8101489fe7c00c8e838125c3aa3:1).

75585:S 06 May 16:27:50.392 * Full resync from master: e91e683b1e13332f97ecb9fa90ecdace460ab4ca:0

75585:S 06 May 16:27:50.392 * Discarding previously cached master state.

75585:S 06 May 16:27:50.491 * MASTER <-> SLAVE sync: receiving 215 bytes from master

75585:S 06 May 16:27:50.492 * MASTER <-> SLAVE sync: Flushing old data

75585:S 06 May 16:27:50.492 * MASTER <-> SLAVE sync: Loading DB in memory

75585:S 06 May 16:27:50.492 * MASTER <-> SLAVE sync: Finished with success

主节点日志:

75553:M 06 May 16:27:50.391 * Slave 127.0.0.1:6380 asks for synchronization

75553:M 06 May 16:27:50.391 * Partial resynchronization not accepted: Replication ID mismatch (Slave asked for '47770067272eb8101489fe7c00c8e838125c3aa3', my replication IDs are '160af1c75f86edc50186e3e4a4dc6ecb5e3fa586' and '0000000000000000000000000000000000000000')

75553:M 06 May 16:27:50.391 * Starting BGSAVE for SYNC with target: disk

75553:M 06 May 16:27:50.391 * Background saving started by pid 75675

75675:C 06 May 16:27:50.395 * DB saved on disk

75553:M 06 May 16:27:50.490 * Background saving terminated with success

75553:M 06 May 16:27:50.491 * Synchronization with slave 127.0.0.1:6380 succeeded

可以看到,第一次建立复制关系的时候,主节点和从节点进行了一次全量复制,见图:

详解Redis复制原理

当完成复制的建立之后,接下来主节点会持续的把写命令发送给从节点,保证主从数据一致。

在主实例上添加新的key:

127.0.0.1:6379> set Lin 112131

OK

在从实例查看刚刚添加的key:

127.0.0.1:6380> get Lin

"112131"

只读

由于复制只能从主节点到从节点,对于从节点的数据修改主节点无法感知,为了避免主从实例之间的数据不一致。从节点默认配置为只读模式:

slave-read-only yes

二.工作原理

我们先讲3个比较关键的参数:master_replid、master_repl_offset和slave_repl_offset。我们分别在master6379和slave6380上执行info replication

127.0.0.1:6379> info replication

# Replication

role:master

connected_slaves:1

slave0:ip=127.0.0.1,port=6380,state=online,offset=1093,lag=1

master_replid:e91e683b1e13332f97ecb9fa90ecdace460ab4ca

master_replid2:0000000000000000000000000000000000000000

master_repl_offset:1093

second_repl_offset:-1

repl_backlog_active:1

repl_backlog_size:1048576

repl_backlog_first_byte_offset:1

repl_backlog_histlen:1093

 

 

127.0.0.1:6380> info replication

# Replication

role:slave

master_host:127.0.0.1

master_port:6379

master_link_status:up

master_last_io_seconds_ago:9

master_sync_in_progress:0

slave_repl_offset:1107

slave_priority:100

slave_read_only:1

connected_slaves:0

master_replid:e91e683b1e13332f97ecb9fa90ecdace460ab4ca

master_replid2:0000000000000000000000000000000000000000

master_repl_offset:1107

second_repl_offset:-1

repl_backlog_active:1

repl_backlog_size:1048576

repl_backlog_first_byte_offset:1

repl_backlog_histlen:1107

master_replid是master启动时生成的随机字符串,用来标识主实例

master_repl_offset是复制流中的一个偏移量,master处理完写入命令后,会把命令的字节长度做累加记录,统计在该字段。该字段也是实现部分复制的关键字段。

slave_repl_offset同样也是一个偏移量,从节点收到主节点发送的命令后,累加自身的偏移量,通过比较主从节点的复制偏移量可以判断主从节点数据是否一致。

当从实例连接到主实例时,从实例会发送master_replid和master_repl_offset(标识与主实例同步的最后一个快照)请求部分复制。如果主实例接收部分复制的话则从最后一个偏移量开始增量进行部分复制,否则将进行全量复制。如图:

详解Redis复制原理

三.数据同步

Redis在2.8之前使用sync命令完成主从数据同步,Redis在2.8及以上使用psync命令完成主从数据同步,同步过程分为:全量复制和部分复制

全量复制

全量复制是Redis最早支持的复制方式,也是主从第一次建立复制的时候必须经历的。它会把主节点全部数据一次性发送给从节点,当数据量较大的时候,会对主从节点和网络造成很大开销。主节点执行bgsave保存RDB文件,然后将这个文件发送给从节点,从节点收到RDB文件后,会先将内存中的所有数据清除,然后再将RDB文件中的数据导入。

主实例在复制过程中是完全异步的,因此不会阻塞主节点的请求。在这一期间内主节点的所有写入命令数据都保存在从客户端缓冲区(slave client buffer)内,在从节点加载完RDB文件后,主节点会将这个缓冲区的内容发送给从节点。

从客户端缓冲区默认大小限制为:

client-output-buffer-limit slave 256mb 64mb 60

意思是如果60秒内缓冲区消耗持续大于64MB或者直接超过256MB时,主节点将直接关闭复制客户端连接,造成全量同步失败。

部分复制

在高版本的Redis实现中,master_replid和offset存储在RDB文件中。当从实例在复制过程中,因网络闪断等原因造成的数据丢失场景,Redis能够从rdb文件中重新加载master_replid和offset,从而使部分重新同步成为可能。因为补发的数据远小于全量数据,所以可以有效的避免全量复制带来的负载和消耗。

之前说过,从节点连接主节点之后,会使用master_replid和master_repl_offset请求主节点,首先判断master_replid是否和自己的master_replid一致,然后检查请求中的master_repl_offset是否能从缓冲区(replication backlog)中获取,如果偏移量在backlog范围内,那么可以进行部分复制。如果在断开连接期间主节点收到的写入命令的数量超过了backlog缓冲区的容量,那么会进行全量复制。默认情况下backlog为1MB。

以上就是详解Redis复制原理的详细内容,更多关于Redis复制原理的资料请关注三水点靠木其它相关文章!

Redis 相关文章推荐
在K8s上部署Redis集群的方法步骤
Apr 27 Redis
Redis IP地址的绑定的实现
May 08 Redis
使用Redis实现秒杀功能的简单方法
May 08 Redis
SpringBoot 集成Redis 过程
Jun 02 Redis
Windows中Redis安装配置流程并实现远程访问功能
Jun 07 Redis
redis 存储对象的方法对比分析
Aug 02 Redis
SpringBoot集成Redis的思路详解
Oct 16 Redis
Redis 持久化 RDB 与 AOF的执行过程
Nov 07 Redis
redis的list数据类型相关命令介绍及使用
Jan 18 Redis
Redis数据同步之redis shake的实现方法
Apr 21 Redis
muduo TcpServer模块源码分析
Apr 26 Redis
Redis特殊数据类型Geospatial地理空间
Jun 01 Redis
Windows下redis下载、redis安装及使用教程
深入理解redis中multi与pipeline
Jun 02 #Redis
SpringBoot 集成Redis 过程
Jun 02 #Redis
详解Redis基本命令与使用场景
Django使用redis配置缓存的方法
Jun 01 #Redis
详解Redis集群搭建的三种方式
May 31 #Redis
浅谈Redis主从复制以及主从复制原理
You might like
php初始化对象和析构函数的简单实例
2014/03/11 PHP
在PHP站点的页面上添加Facebook评论插件的实例教程
2016/01/08 PHP
tp5实现微信小程序多图片上传到服务器功能
2018/07/16 PHP
PHP中Session ID的实现原理实例分析
2019/08/17 PHP
jQuery 学习 几种常用方法
2009/06/11 Javascript
js 格式化时间日期函数小结
2010/03/20 Javascript
Javascript中实现trim()函数的两种方法
2015/02/04 Javascript
js简单实现标签云效果实例
2015/08/06 Javascript
前端框架Vue.js中Directive知识详解
2016/09/12 Javascript
jquery.validate表单验证插件使用方法解析
2016/11/07 Javascript
第一次接触神奇的前端框架vue.js
2016/12/01 Javascript
JS实现改变HTML上文字颜色和内容的方法
2016/12/30 Javascript
Vue非父子组件通信详解
2017/06/12 Javascript
详解Vue 数据更新了但页面没有更新的 7 种情况汇总及延伸总结
2020/05/28 Javascript
vue插件--仿微信小程序showModel实现模态提示窗功能
2020/08/19 Javascript
解决Vue-cli3没有vue.config.js文件夹及配置vue项目域名的问题
2020/12/04 Vue.js
[01:36:57]【09DOTA2第一视角】小骷髅
2014/04/16 DOTA
python脚本实现统计日志文件中的ip访问次数代码分享
2014/08/06 Python
详解python使用Nginx和uWSGI来运行Python应用
2018/01/09 Python
python 输出上个月的月末日期实例
2018/04/11 Python
Python高斯消除矩阵
2019/01/02 Python
anaconda如何查看并管理python环境
2019/07/05 Python
python用类实现文章敏感词的过滤方法示例
2019/10/27 Python
pandas实现DataFrame显示最大行列,不省略显示实例
2019/12/26 Python
keras打印loss对权重的导数方式
2020/06/10 Python
使用Keras中的ImageDataGenerator进行批次读图方式
2020/06/17 Python
python matplotlib工具栏源码探析二之添加、删除内置工具项的案例
2021/02/25 Python
CSS3 transition 实现通知消息轮播条
2020/10/14 HTML / CSS
html5 Canvas画图教程(10)—把面拆成线条模拟出圆角矩形
2013/01/09 HTML / CSS
Ref与out有什么不同
2012/11/24 面试题
班级德育工作实施方案
2014/02/21 职场文书
师德师风的心得体会
2014/09/02 职场文书
2014年数学教师工作总结
2014/12/03 职场文书
python实现高效的遗传算法
2021/04/07 Python
CSS中妙用 drop-shadow 实现线条光影效果
2021/11/11 HTML / CSS
Python用tkinter实现自定义记事本的方法详解
2022/03/31 Python