前言

  与大多数db一样,Redis也提供了复制机制,以满足故障恢复和负载均衡等需求。复制也是Redis高可用的基础,哨兵和集群都是建立在复制基础上实现高可用的。复制不仅提高了整个系统的容错能力,还可以水平扩展,实现在一个重读取的应用中,通过增加多个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./.bottle/etc/redis.conf

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

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

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

127.0.0.1:> slaveof 127.0.0.1
OK

  从节点日志:

:S  May ::50.389 * Connecting to MASTER 127.0.0.1:
:S May ::50.389 * MASTER <-> SLAVE sync started
:S May ::50.390 * Non blocking connect for SYNC fired the event.
:S May ::50.390 * Master replied to PING, replication can continue...
:S May ::50.390 * Trying a partial resynchronization (request 47770067272eb8101489fe7c00c8e838125c3aa3:).
:S May ::50.392 * Full resync from master: e91e683b1e13332f97ecb9fa90ecdace460ab4ca:
:S May ::50.392 * Discarding previously cached master state.
:S May ::50.491 * MASTER <-> SLAVE sync: receiving bytes from master
:S May ::50.492 * MASTER <-> SLAVE sync: Flushing old data
:S May ::50.492 * MASTER <-> SLAVE sync: Loading DB in memory
:S May ::50.492 * MASTER <-> SLAVE sync: Finished with success

  主节点日志:

:M  May ::50.391 * Slave 127.0.0.1: asks for synchronization
:M May ::50.391 * Partial resynchronization not accepted: Replication ID mismatch (Slave asked for '47770067272eb8101489fe7c00c8e838125c3aa3', my replication IDs are '160af1c75f86edc50186e3e4a4dc6ecb5e3fa586' and '')
:M May ::50.391 * Starting BGSAVE for SYNC with target: disk
:M May ::50.391 * Background saving started by pid
:C May ::50.395 * DB saved on disk
:M May ::50.490 * Background saving terminated with success
:M May ::50.491 * Synchronization with slave 127.0.0.1: succeeded

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

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

  在主实例上添加新的key:

127.0.0.1:> set Lin
OK

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

127.0.0.1:> get Lin
""

只读

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

slave-read-only yes

二.工作原理

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

127.0.0.1:> info replication
# Replication
role:master
connected_slaves:
slave0:ip=127.0.0.1,port=,state=online,offset=,lag=
master_replid:e91e683b1e13332f97ecb9fa90ecdace460ab4ca

master_replid2:
master_repl_offset:1093

second_repl_offset:-
repl_backlog_active:
repl_backlog_size:
repl_backlog_first_byte_offset:
repl_backlog_histlen: 127.0.0.1:> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:
master_link_status:up
master_last_io_seconds_ago:
master_sync_in_progress:
slave_repl_offset:1107

slave_priority:
slave_read_only:
connected_slaves:
master_replid:e91e683b1e13332f97ecb9fa90ecdace460ab4ca

master_replid2:
master_repl_offset:1107

second_repl_offset:-
repl_backlog_active:
repl_backlog_size:
repl_backlog_first_byte_offset:
repl_backlog_histlen:
  • master_replid是master启动时生成的随机字符串,用来标识主实例
  • master_repl_offset是复制流中的一个偏移量,master处理完写入命令后,会把命令的字节长度做累加记录,统计在该字段。该字段也是实现部分复制的关键字段。
  • slave_repl_offset同样也是一个偏移量,从节点收到主节点发送的命令后,累加自身的偏移量,通过比较主从节点的复制偏移量可以判断主从节点数据是否一致。

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

三.数据同步

  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秒内缓冲区消耗持续大于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篇第一个帖子一样:

https://www.cnblogs.com/GrimMjx/p/10662254.html

搞懂Redis复制原理的更多相关文章

  1. 彻底搞懂Redis主从复制原理及实战

    欢迎关注公众号:「码农富哥」,致力于分享后端技术 (高并发架构,分布式集群系统,消息队列中间件,网络,微服务,Linux, TCP/IP, HTTP, MySQL, Redis), Python 等 ...

  2. 深入理解redis复制原理

    原文:深入理解redis复制原理 1.复制过程 2.数据间的同步 3.全量复制 4.部分复制 5.心跳 6.异步复制 1.复制过程 从节点执行 slaveof 命令. 从节点只是保存了 slaveof ...

  3. Redis 复制原理及特性

    摘要 早期的RDBMS被设计为运行在单个CPU之上,读写操作都由经单个数据库实例完成,复制技术使得数据库的读写操作可以分散在运行于不同CPU之上的独立服务器上,Redis作为一个开源的.优秀的key- ...

  4. 一文搞懂vim复制粘贴

    转载自本人独立博客https://liushiming.cn/2020/01/18/copy-and-paste-in-vim/ 概述 复制粘贴是文本编辑最常用的功能,但是在vim中复制粘贴还是有点麻 ...

  5. Redis从出门到高可用--Redis复制原理与优化

    Redis从出门到高可用–Redis复制原理与优化 单机有什么问题? 1.单机故障; 2.单机容量有瓶颈 3.单机有QPS瓶颈 主从复制:主机数据更新后根据配置和策略,自动同步到备机的master/s ...

  6. redis复制原理和应用

    1.前言 说到分布式高可用,必然少不了复制,一来是为了做个冗余备份防止数据丢失,二来还可以达到分流来提高性能的目的.基本架构: 下面用M表示Master(主服务器),S表示Slave(从服务器),话不 ...

  7. 一文搞定 Redis 复制(全会的举个手看看)

    阅读本文大概需要 5 分钟. 本文大纲 复制过程 数据间的同步 全量复制 部分复制 心跳 异步复制 总结 一.复制过程 Step 1:从节点执行 slaveof 命令. Step 2:从节点只是保存了 ...

  8. 一篇文章彻底搞懂base64编码原理

    开始 在互联网中的每一刻,你可能都在享受着Base64带来的便捷,但对于Base64的基础原理又了解多少?今天这篇文章带领大家了解一下Base64的底层实现. base64是什么东东呢? Base64 ...

  9. 搞懂MySQL GTID原理

    从MySQL 5.6.5 开始新增了一种基于 GTID 的复制方式.通过 GTID 保证了每个在主库上提交的事务在集群中有一个唯一的ID.这种方式强化了数据库的主备一致性,故障恢复以及容错能力. GT ...

随机推荐

  1. HDU 5115 Dire Wolf ——(区间DP)

    比赛的时候以为很难,其实就是一个区间DP= =..思路见:点我. 区间DP一定要记住先枚举区间长度啊= =~!因为区间dp都是由短的区间更新长的区间的,所以先把短的区间更新完.. 代码如下: #inc ...

  2. c源码编译

    #include<stdio.h> #include<math.h> //程序中要调用求平方根函数sqrt int main() { double a,b,c,disc,x1, ...

  3. websocket聊天体验

    light-example-4j/websocket目录有client-to-server.peer-to-peer两个示例项目,解决了我的两个问题:在线聊天.日志查看. 在线聊天,后续可以支持:最近 ...

  4. JvmOverloads kotlin(14)(转)

    在Kotlin中@JvmOverloads注解的作用就是:在有默认参数值的方法中使用@JvmOverloads注解,则Kotlin就会暴露多个重载方法.可能还是云里雾里,直接上代码,代码解释一切:如果 ...

  5. Mysql 纪录用户操作日志

    有时,我们想追踪某个数据库操作记录,如想找出是谁操作了某个表(比如谁将字段名改了). 二进制日志记录了操作记录,线程号等信息,但是却没有记录用户信息,因此需要结合init-connect来实现追踪. ...

  6. Request.Params用法,后台接收httpget参数

    使用Request.Params["id"]来获取参数是一种比较有效的途径. request.params其实是一个集合,它依次包括request.querystring.requ ...

  7. Simple Cel Shading 钟馗

    Made with Unity Unannouced project Character Art by Chris P

  8. vue 添加一个二级目录

    原先的: http://xxx.xx.xxx.xxx:xxx/#/ 现在的: http://xxx.xx.xxx.xxx:xxx/guangfu/#/

  9. Failed to install the following Android SDK packages as some licences have not been accepted.

    问题描述: 执行gradle tasks报错: gradle tasks > Configure project :app Exception /package.xml. Probably th ...

  10. python 学习笔记(二):为元组的每个元素命名,提高程序的可读性

    在程序中有些数据为固定格式时,即字段数量确定.字段位置顺序确定不变,我们就可以用元组来储存.使用元组的优势是储存空间很小,访问速度也很快.如下代码对每个学生信息用元组来表示: # ('Jim', 16 ...