详解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 相关文章推荐
redis配置文件中常用配置详解
Apr 14 Redis
详解RedisTemplate下Redis分布式锁引发的系列问题
Apr 27 Redis
详解Redis主从复制实践
May 19 Redis
5分钟教你docker安装启动redis全教程(全新方式)
May 29 Redis
SpringBoot 集成Redis 过程
Jun 02 Redis
Redis缓存-序列化对象存储乱码问题的解决
Jun 21 Redis
厉害!这是Redis可视化工具最全的横向评测
Jul 15 Redis
redis requires ruby version2.2.2的解决方案
Jul 15 Redis
浅谈redis整数集为什么不能降级
Jul 25 Redis
Redis Cluster 集群搭建你会吗
Aug 04 Redis
Redis 异步机制
May 15 Redis
Redis基本数据类型String常用操作命令
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图像处理类代码分享
2012/01/19 PHP
php判断正常访问和外部访问的示例
2014/02/10 PHP
php简单实现sql防注入的方法
2016/04/22 PHP
php实现跨域提交form表单的方法【2种方法】
2016/10/17 PHP
Laravel源码解析之路由的使用和示例详解
2018/09/27 PHP
JQuery获取元素文档大小、偏移和位置和滚动条位置的方法集合
2010/01/12 Javascript
发布一个基于javascript的动画类 Fx.js
2010/11/05 Javascript
jQuery函数的第二个参数获取指定上下文中的DOM元素
2014/05/19 Javascript
JavaScript中对象property的读取和写入方法介绍
2014/12/30 Javascript
学习JavaScript设计模式(单例模式)
2015/11/26 Javascript
JavaScript实现显示函数调用堆栈的方法
2016/04/21 Javascript
详解Angular-Cli中引用第三方库
2017/05/21 Javascript
js实现网页版贪吃蛇游戏
2020/02/22 Javascript
小程序接入腾讯位置服务的详细流程
2020/03/03 Javascript
使用vue构建多页面应用的示例
2020/10/22 Javascript
实践Python的爬虫框架Scrapy来抓取豆瓣电影TOP250
2016/01/20 Python
Flask框架踩坑之ajax跨域请求实现
2019/02/22 Python
Python中的sys.stdout.write实现打印刷新功能
2020/02/21 Python
Keras load_model 导入错误的解决方式
2020/06/09 Python
来自全球大都市的高级街头服饰:Pegador
2018/01/03 全球购物
意大利在线药房:shop-farmacia.it
2019/03/12 全球购物
华为的Java面试题
2014/03/07 面试题
C#面试题问题集
2016/04/02 面试题
Java语言程序设计测试题改错题部分
2014/07/22 面试题
利用promise及参数解构封装ajax请求的方法
2021/03/24 Javascript
幼儿园教师培训制度
2014/01/16 职场文书
《胡杨》教学反思
2014/02/16 职场文书
《和田的维吾尔》教学反思
2014/04/14 职场文书
化学专业毕业生求职信
2014/07/28 职场文书
家庭财产分割协议书范本
2014/11/24 职场文书
班主任工作实习计划
2015/01/16 职场文书
暑期社会实践个人总结
2015/03/06 职场文书
淘宝客服专员岗位职责
2015/04/07 职场文书
优秀范文:《但愿人长久》教学反思3篇
2019/10/24 职场文书
python入门之算法学习
2021/04/22 Python
mysql left join快速转inner join的过程
2021/06/30 MySQL