详解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 27 Redis
Redis实现订单自动过期功能的示例代码
May 08 Redis
Redis 配置文件重要属性的具体使用
May 20 Redis
Windows下redis下载、redis安装及使用教程
Jun 02 Redis
解析Redis Cluster原理
Jun 21 Redis
redis requires ruby version2.2.2的解决方案
Jul 15 Redis
基于Redis结合SpringBoot的秒杀案例详解
Oct 05 Redis
使用RedisTemplat实现简单的分布式锁
Nov 20 Redis
Redis之RedisTemplate配置方式(序列和反序列化)
Mar 13 Redis
redis数据结构之压缩列表
Mar 21 Redis
redis protocol通信协议及使用详解
Jul 15 Redis
Redis配置外网可访问(redis远程连接不上)的方法
Dec 24 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 动态执行带有参数的类方法
2009/04/10 PHP
php和数据库结合的一个简单的web实例 代码分析 (php初学者)
2011/07/28 PHP
ThinkPHP写第一个模块应用
2012/02/20 PHP
php存储过程调用实例代码
2013/02/03 PHP
PHP版 汉字转码的实现详解
2013/06/09 PHP
js 判断checkbox是否选中的实现代码
2010/11/23 Javascript
浏览器打开层自动缓慢展开收缩实例代码
2013/07/04 Javascript
jquery实现点击文字可编辑并修改保存至数据库
2014/04/15 Javascript
avalonjs制作响应式瀑布流特效
2015/05/06 Javascript
JavaScript设置表单上传时文件个数的方法
2015/08/11 Javascript
浅谈JavaScript对象与继承
2016/07/10 Javascript
Boostrap基础教程之JavaScript插件篇
2016/09/08 Javascript
Bootstrap企业网站实战项目4
2016/10/14 Javascript
JavaScript判断浏览器及其版本信息
2017/01/20 Javascript
Bootstrap Tooltip显示换行和左对齐的解决方案
2017/10/11 Javascript
对angular 监控数据模型变化的事件方法$watch详解
2018/10/09 Javascript
浅谈vue中关于checkbox数据绑定v-model指令的个人理解
2018/11/14 Javascript
react项目如何使用iconfont的方法步骤
2019/03/13 Javascript
[45:46]2014 DOTA2国际邀请赛中国区预选赛5.21 HGT VS DT
2014/05/23 DOTA
[01:18]PWL开团时刻DAY10——一拳超人
2020/11/11 DOTA
如何在Python函数执行前后增加额外的行为
2016/10/20 Python
Python爬虫框架Scrapy实例代码
2018/03/04 Python
对Python中9种生成新对象的方法总结
2018/05/23 Python
对python:print打印时加u的含义详解
2018/12/15 Python
python中property属性的介绍及其应用详解
2019/08/29 Python
python 字典访问的三种方法小结
2019/12/05 Python
西安众合通用.net笔试题
2013/03/18 面试题
幼儿园新学期寄语
2014/01/18 职场文书
财务内勤岗位职责
2014/04/17 职场文书
领导班子四风问题对照检查材料
2014/09/27 职场文书
12.4全国法制宣传日活动方案
2014/11/02 职场文书
年会邀请函范文
2015/01/30 职场文书
扬州个园导游词
2015/02/06 职场文书
升学宴家长致辞
2015/07/27 职场文书
pycharm部署django项目到云服务器的详细流程
2021/06/29 Python
Vue图片裁剪组件实例代码
2021/07/02 Vue.js