揭开RedisShake的秘密

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: RedisShake的设计思想,底层实现以及丰富的应用场景介绍。本文为直播内容文字整理,看直播回放,请点击文首链接~

查看精彩回放:https://developer.aliyun.com/live/145188

内容简要:

一、背景

二、RedisShake基本原理

三、应用场景

 

 

一、背景

(一)RedisShake能做什么

1.png

如上图所示,RedisShake主要能做的事情有数据迁移、版本变更、架构变更与容灾等。现在大部分的数据库都支持集群版的数据,也就是说一个逻辑单元中可以有很多个DB,不同节点之间可以通过复制的方式来实现数据同步。


从广义上来说,迁移属于同步中的一种模式,同步更加侧重于增量,迁移更加侧重于全量。


迁移有很多场景,比如架构变更,像Redis由主从版迁移成集群版,或者从2个分片迁移到3个分片,或者数据库的升级迁移,从4.0版本升级到5.0RedisShake也做了降级迁移的支持。


数据迁移可以是上云迁移,比如说用户自建的Redis数据库迁移上云,或者云上的数据库迁移到云下等,RedisShake也支持多云厂商之间的数据迁移。


容灾主要是防止不可控事情的发生,例如机房断电着火或者是地震等,使得集群中超过半数的节点不能提供正常服务,这时候备份就可以代替原数据库对外提供服务,因此异地容灾非常有必要。

 

(二)Redis持久化

Redis有两种持久化机制:RDBAOF


RDB是一个经过压缩的二进制文件,通过保存Redis数据库中的键值来记录数据库状态。

1.png

AOF通过保存Redis服务器所执行的写命令来记录数据库状态,例如:

1.png

RDBAOF文件可以恢复成一个数据库,继续提供服务。


  • Replication

复制:包括全量数据的复制和增量数据的复制。

同步操作:将从服务器的数据库状态更新至主服务器当前所处的数据库状态。Master生成RDB文件,Slave载入。

命令传播操作:主服务器的数据库状态被修改,导致主从服务器的数据库状态出现不一致时,让主从服务器的数据库重新回到一致状态。 Master执行的写命令传送到Slave

 

(三)Redis主从复制


在分布式环境中,数据副本 (Replica) 和复制 (Replication) 作为提升系统可用性和读写性能的有效手段被大量应用系统设计中,Redis也不例外。

1.png

2.8版本之前,主从同步是通过SYNC命令进行的,在2.8版本之后升级到PSYNC命令,下面分别展开介绍。

 

(四)主从复制 - SYNC

1.png

在发送slaveof ip port的时候,它首先会创建两项主服务器套接字的连接,接着向主服务器发送ping命令,目的在于检查套接字的读写状态,或者是检查主服务器是否能够正常地处理命令。


接下来进行身份验证,然后发送端口信息,最后发送SYNC命令,执行同步操作。

1.png

在主Master接收到SYNC命令之后,它会执行bgsave在后台生成一个RDB文件,并且使用一个缓冲区记录从现在开始执行所有写命令。当bgsave生成的RDB文件完成了之后,它就发送给从服务器去进行载入。在更新状态完成之后,Master再将记录在缓冲区里面的新命令发送给从服务器,这样从服务器进行执行,主从服务器就保持了一致状态。

 

  • SYNC缺陷

1.png

从服务器到主服务器的复制可以分为两种情况,一种就是初次复制,一种就是断线后的重复制。初次复制就是进行建立连接,然后进行全量和增量的同步,它的SYNC可以很好地完成任务。


但对于断线后的重复制,处于命令传播阶段的主从服务器因为网络原因而中断又重连,会再次发送SYNC命令做全量+增量同步,效率较低。


SYNC命令是一个非常耗费资源的操作,资源包括CPU、内存、磁盘、宽带、流量等。

 

(五)主从复制 - PSYNC

为了解决SYNC在处理断线重复制时候的低效问题,Redis2.8版本之后开始使用PSYNC命令,它支持完整重同步和部分重同步。


完整重同步和SYNC一样,部分重同步就是在处理断线重新链接之后,主节点只向从节点发送链接断开期间的写命令,它的实现基于以下三部分:

1)复制偏移量(replication offset

n  Master:每次向Slave发送n个字节数据时,就会将自己的offset+n

n  Slave:每次收到Master发送来的n个字节数据时,就会将自己的offset+n

n  如果主从服务器处于一致状态,那么MasterSlaveOffset总是相同的。

1.png

 

2)复制积压缓冲区(replication backlog

  • Master上维护的每一个固定大小(fixed-size)的FIFO队列,保存着一部分最近传播的写命令。


  • Master进行命令传播时,不仅会将命令发送给所有Slave,还会将写命令入队到复制积压缓冲区。


  • 复制积压缓冲区会为队列中的每个字节记录相应的复制偏移量;


  • Slave重连Master时,会通过PSYNC命令将自己的Offset发送给Master,如果SlaveOffsetMasterOffset不相等,并且SlaveOffset偏移量之后的数据仍存在于replication backlog中,那么Master将对Slave执行部分重同步操作;否则,需要执行完整重同步操作。

1.png

 

3)服务器IDrun ID

  • 每个Redis服务器,MasterSlave、都有run ID自动生成。


  • SlaveMaster进行初次复制时,Master会将自己的run ID传送给SlaveSlave会记录Masterrun ID


  • Slave重新连接上一个Master时,会发送之前保存的run ID,用于确认是否为同一个Master

 

1.PSYNC—fullresync

1.png

过程如上图所示,抛去刚开始的建立连接不谈,对于初次复制,它会发送一个“PSYNC ? -1”命令,主动请求主服务器去进行完整的重同步。

1.png

主服务器接收到命令之后会返回FULLRESYNC,表示执行完整重同步,下面的步骤就和SYNC是一样的。

 

2.PSYNC—partial resync

1.png

当在增量阶段突然断线,它会再次建立连接。Slave向主服务器发送run IDoffsetrun ID就是上一次复制的主服务器的运行IDoffset就是从服务器当前的复制偏移量。接收到命令之后,主服务器会通过这两个参数去判断,如果判断条件满足,就返回CONTINUE,之后发送缓冲区中的那些写命令再去执行,就回到了一致的状态。

 

 

二、RedisShake基本原理

(一)主要功能

Redis的主要功能有解析、恢复、备份、同步。


  • 同步SYNC

支持源Redis和目的Redis的数据同步,支持全量和增量数据的迁移。


  • 同步RUMP

支持源Redis和目的Redis的数据同步,仅支持全量的迁移。


  • 备份DUMP

将源Redis的全量数据通过RDB文件备份起来。


  • 恢复Restore

RDB文件恢复到目的Redis数据库。


  • 解析Decode

RDB文件进行读取,并以json格式解析存储。

 

(二)基本同步模式

1.png

基本同步模式流程图

  • 支持的Redis形态:

1)Standalone:单源拉取,主从版/单节点

2)Sentinel:从Sentinel获取地址并拉取

3)Cluster:开源Cluster模式

4)Proxy:从Proxy拉取

 

下面举例说明:

1.png

现在要将一个主从版的数据迁移到集群版,可以在配置文件中配置源端信息和目的端信息,同时在配置地址的时候,对于集群版可以配置一个分片的地址,因为它是支持自动发现的。

 

(三)数据流图

1.png

上图是SYNC模式下全量+增量的数据流图,第一次复制向源端发送了之后,源端给它发RDB文件,解析RDB文件放到Pipe中。


它可以通过并发Restore到目的端,同步完成之后就会自动启动增量。增量就是从源端拉取写命令,进行解析过滤,然后再放到目的端,同时还需要接收回复。

 

(四)全量同步

1.png

首先可以看全量同步,DbSyncer维护了连接链路,它是一个结构体,源端是6379,目的端是一个集群,它代表了一个数据链路。


假如说原来配置的是一个三主三从的集群模式,那么就会开启三个DbSyncer,同时有ID对它进行标识。每个DbSyncer管理一个连接,如6379首先是向RDB文件发送过来,然后Loader会解析出一些信息,包括DBKeyType等,然后放到Pipe中。然后需要向目的端写入,写入的时候全量模式支持并发。


Pipe出来后先进行过滤,因为RedisShake支持DBKeySlot这些级别的过滤,用户可以设置黑白名单。正常情况下就可以Restore到目的端,然后再接收回复。对于lua ,可以进行script load,也可以设置过滤lua。对于BigKey,需要根据编码形式进行拆分解析。

 

(五)增量同步

1.png

全量同步结束之后会自动开启增量同步,增量同步主要是由四个协程完成。

第一个协程定期从源端获取RedisShake的偏移量。


第二个协程主要是从源端拉取写命令。因为原来是模拟源端的一个从,从执行写命令的时候会发送一条BinlogRedisShakeRedisShake读到之后交给Decoder,然后会将Binlog解析成一个原生命令,同时还会计算一下偏移量。得到命令后有Key,然后就可以进行过滤,再放到Sendbuffer中,Sendbuffer就是最终要发送到目的端的一些写命令。


第三个协程就是Sender,它执行发送逻辑,从Sendbuffer中取出写命令,并不是立即发送过去,它是和Checkpoint绑成一个事务,一块写入目的端。断点续传的原理是会先放到cache里边,就像是一层缓存,然后触发一定条件之后就去执行sendFunc函数。这是一个事务,它会先去写这些增数据,然后再去修改Checkpoint值。


第四个协程就是接收目的端的回复,可能是写入成功,也可能是写入出错的,主要用于统计。


下面我们模拟发送一个命令,观察会发生什么事情。

1.png

首先源客户发送了一个“SET msg hello”,然后源端会以一个Binlog的形式写入到RedisShakeRedisShake读到之后先解析出原生的写命令,就会调用Send函数。Send函数目的端是一个集群,它需要知道自己应该发送到哪个节点上。


因为集群方式有槽概念,RedisShake还维护了 Slot数组,它的 index就是槽的ID,它对应的值就是槽所在的节点上。Node是一个结构体,里边有一个字段address,就是节点的地址。


调用Send函数的时候,首先需要获取到这个Key是应该发送到哪个节点上,会调用getNodeByKey,实际上就是对Key进行一次Hash,调用的是crc16算法。Key会算到它在哪个槽上,然后再通过下面 Slots数组,就知道这个槽是在哪个节点上,然后再调用do把它写入到 node上,写入之后会Receive目的端的回复。然后我们就需要去检查这个回复是什么,如果是有异常的话,就会直接将这个结果返回过去,再由上一层去进行判断。


假如说是move或者是ask,可能会调用回调函数handleMovehandleAsk两个重定向。


(六)MOVE/ASK重定向

1.MOVE重定向

1.png

上图为MOVE重定向流程图,因为RedisShake是模拟一个客户端,然后RedisShake向节点写命令时,这个节点也会进行一次Hash去看它是不是应该在写到自身。如果是的话就执行,不是的话就返回一个MOVE


这个MOVE代表这个Key应该写到这个节点上,因为目的端可能会进行扩容,所以说槽的分布可能是会有变化,RedisShake支持进行扩缩容。收到MOVE的时候,它会提取到目标节点的信息,再向目标节点重新发送键命令。

 

2.ASK重定向

1.png

上方为ASK重定向流程图,主要是发生在Slots迁移的时候,RedisShakeA节点发送键命令的时候,A在同一向里回复一个ASK转向,表示这一次向B去写入,然后RedisShake再向B发送键命令。

 

(七)断点续传原理

断点续传是RedisShake2.0版本增加的功能,是根据Redis PSYNC协议写的,下方是它的流程图。

1.png

如上图所示,目的端开启了断点续传,获取到Checkpoint保存的最大偏移量,然后通过PSYNC指令发送源端,然后在源端去检查是否合法。


如果需要的写指令还在复制缓存区中,它就会回复一个Continue,然后进入增量同步,如果不是的话就会进行全量同步。


主从版的断点续传方案会在每个节点DB上记录一个Checkpoint,名字固定是RedisShake Checkpoint,类型是Hash

1.png

在写数据的时候,Redis是将Checkpoint和数据捆绑成一个事务写入目的端的。


  • 讨论两个问题:

1)为什么每个逻辑DB都记录一个Checkpoint

2)为什么要将Checkpoint和数据捆绑成一个事务写入目的Redis端?

关于问题一,分DB存储的优势就是在刚启动的时候,只需要拉取所有DBoffset,挑取最大的就知道它是在哪个DB上,上一次是在哪个DB,以及同步的最大偏移量。


关于问题二,捆绑封装成一个事务是为了保证一致性。

 

 

三、应用场景

(一)数据同步——SYNC

1.png

SYNC模式下支持全量同步与增量同步,当然它有一个限制,需要源端支持PSYNC/SYNC,在向源端发送SYNC/PSYNC命令的时候,可以收到源端的回复。源端、目的端的形态可以是主从集群/Proxy/Cluster,迁移也可以用于云下到云上,云上到云下这种混合云迁移。

 

(二)多云厂商之间数据迁移

对于某些云上redis,比如部分云厂商不支持SYNC/PSYNC权限,如何进行迁移?

1.png

RedisShake对于这种场景也做了支持,比如绕过SYNCPSYNC的同步方式。它是以Scan的方式从源端Redis获取到全量数据,再写入到目的端,实现数据迁移。


比如有一个fetcher,它会先Scan一定的数据量, 然后配置COUNT,然后将收到的KeyDUMP下来放到PIPE中,然后writerPIPE中取到Restore到目的端,同时它也有BigKey的优化。

 

(三)多活

多活通常是用于解决因地域网络传输层面带来的问题,也就是异地多活。比如说业务层面想要在北京机房写入一条数据,要求在上海机房也能够读到,同样反过来也可以,这样会需要做到一个多活。

1.png

上图给出来的是一个根据RedisShake创建多活的方案,是一种伪多活而不是真正的多活。


用户需要编写一个Proxy进行流量分发,比如对a或者是b库的写操作都分发在左边的DB,对c库的写操作都分发到右边的DBRedisShake提供了按库过滤的功能,可以配置源库到目的库的Shake链路值,同步ab,然后目的库到源库的只同步c,这样就解决了一个环形复制的问题。

 

(四)数据备份与恢复

1.png

数据备份使用dump功能,就可以直接备份一份rdb,将这些rdb根据时间命名。

1.png

  • 数据恢复restore
  • 自建Redis迁移上云
  • 云上数据迁移到云下
  • 将数据库恢复至之前的状态,数据回滚
  • 配合Filter使用,只恢复部分Key
  • ……

 

(五)RDB文件解析decode

  • RDB文件解析 decode

1)读取RDB文件,以JSON格式解析存储

2)可以进行Key分析

 

  • 高版本向低版本迁移

源端版本大于目的端版本,比如源端是4.0,目的端2.8,某些数据结构格式已经修改导致无法同步,可以通过配置绕过这个限制。

 

  • 扫描迁移 rump

SCAN的方式从源端Redis获取全量数据,写入到目的端,实现数据迁移。

  • 对于不支持sync/psync权限的迁移
  • 跨云迁移

 

(六)全球分布式缓存—全球级联同步场景

假如用户业务遍布全球,有很多个数据中心,之间的数据迁移也可以用RedisShake,它支持全球级联同步,方便用户进一步扩大自己的业务。

1.png

 

(七)检验迁移后的数据

1.png

redis-full-check是用来检验两个Redis数据是否一致的工具。


通常在用RedisShake进行数据迁移之后,可以用这个工具进行校验,它的原理主要是通过全量对比源端和目的端Redis中的数据方式来进行数据校验。


如图可以看到,比较的方式是内部多轮次进行比较,每次比较都会先抓取比较Key。第一轮是从源端进行抓取,后面从Sqlite中进行抓取。抓取之后如果存在有差异的部分,会存在SqliteDB中,后面的抓取直接去更新Sqlite中的数据就可以了。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
3月前
|
存储 开发框架 .NET
C#语言究竟隐藏了哪些秘密?一文带你揭开编程界的神秘面纱
【8月更文挑战第22天】C#是微软推出的面向对象编程语言,以其简洁的语法和强大的功能,在软件开发领域占据重要地位。作为一种强类型语言,C#确保了代码的可读性和可维护性。它支持多种数据类型,如整型、浮点型及复合类型如类和结构体。类是核心概念,用于定义对象的属性和行为。C#还包括方法、异常处理、集合类型如列表和字典,以及泛型和LINQ等高级特性,支持异步编程以提高应用响应性。.NET Core的推出进一步增强了C#的跨平台能力。
70 3
|
3月前
|
前端开发 开发者
new操作符背后的秘密:揭开Web前端对象创建的神秘面纱!
【8月更文挑战第23天】在Web前端开发中,`new`操作符是创建对象实例的核心。本文以`Person`构造函数为例,通过四个步骤解析`new`操作符的工作原理:创建空对象、设置新对象原型、执行构造函数并调整`this`指向、判断并返回最终对象。了解这些有助于开发者更好地理解对象实例化过程,从而编写出更规范、易维护的代码。
39 0
|
3月前
|
安全 数据安全/隐私保护 Python
【震撼揭秘】:密码大战公钥!解锁信息安全认证技术的惊天秘密与实战应用,带你领略数字世界的终极防线!
【8月更文挑战第20天】信息安全中,认证技术确保用户身份真实,本文对比基于口令认证与基于公钥基础设施(PKI)认证。前者简便但易受攻击,常需配合多因素认证加强安全性;后者利用数字证书及公/私钥机制,提供更高安全保障。随着技术演进,未来认证手段将更趋多元高效。
56 2
|
5月前
|
Java 开发者
震惊!Java命名规范背后的惊天秘密,你真的了解吗?
【6月更文挑战第15天】Java命名规范提升代码可读性。标识符须以字母、下划线或$开头,避免数字开头。变量用camelCase,如`myVariable`;类与方法用PascalCase,如`MyClass`和`myMethod`。常量全大写加下划线,如`MAX_VALUE`。避免关键字冲突,确保可维护性。
44 10
|
数据安全/隐私保护
【杂(瞎)谈(聊)】易经当中的密码学
看到这个标题,估计可能会有不少读者会有疑问,易经这不是个文学作品吗,怎么和数学相关的密码学给搞到一起了,这不是标题党蛤, 下面小Q来给大家聊聊在易经当中所体现的一些密码学的思想,有些资料来源也不太确定,我凭借记忆进行搜索的,如有错误还请各位读者海涵。
【杂(瞎)谈(聊)】易经当中的密码学
|
UED
探究用户心里的秘密,互联网营销
  无论是产品经理、前后端开发人员、架构师、数据分析师,我们都是为用户服务的。在社会这个大家庭里,我们都是用户。我们都是用户却各有所好。你喜欢这个,我喜欢那个,也有我们都喜欢的。那么在我们的心理隐藏着什么样的秘密呢?这些常态和非常态是否有章可循呢?   心理学是一门“心”的学问。
871 0
|
安全 算法 区块链
在谈论区块链之前,我们需要一把密码学的钥匙
区块链的风口上谁都想起飞,然而应用变化日新月异,比特币、以太坊只是区块链与现实场景结合的一部分,理论却是所有应用的根基。
1497 0
|
安全 区块链 数据安全/隐私保护
会玩“植物大战僵尸”,你就能搞懂比特币和区块链
比特币就像是“植物大战僵尸”中的阳光一样,是一种虚拟货币,只是过去在游戏里,它被叫作“虚拟道具”。
1381 0