架构设计|Redis 异地多活架构演进历程

前言

为了更好的做好容灾保障,使业务能够应对机房级别的故障,滴滴的存储服务都在多机房进行部署。本文简要分析了 Redis 实现异地多活的几种思路,以及滴滴 Redis 异地多活架构演进过程中遇到的主要问题和解决方法,抛砖引玉,给小伙伴们一些参考。

Redis 异地多活的主要思路

业界实现 Redis 异地多活通常三种思路:主从架构、Proxy双写架构、数据层双向同步架构。

主从架构

在这里插入图片描述

主从架构的思路:

  • 各机房的 Redis 通过 Proxy 对外提供读写服务,业务流量读写本机房的 Redis-proxy

  • 主机房里的 Redis-master 实例承担所有机房的写流量

  • 从机房里的 Redis-slave 实例只读,承担本机房里的读流量

主从架构的优点:

  • 实现简单,在 Proxy 层开发读写分流功能就可以实现

  • Redis 层使用原生主从复制,可以保证数据一致性

主从架构的缺点:

  • 从机房里的 Redis-proxy 需要跨机房写,受网络延时影响,业务在从机房里的写耗时高于主机房

  • 主机房故障时,从机房的写流量也会失败,需要把从机房切换为主机房,切换 Redis-master

  • 网络故障时,从机房的写流量会全部失败,为了保障数据一致性,这种场景比较难处理

Proxy 双写架构

在这里插入图片描述
Proxy 双写架构的思路:

  • 各机房的 Redis 通过 Proxy 对外提供读写服务,业务流量读写本机房的 Redis-proxy

  • 不区分主从机房,每个机房都是独立的 Redis 集群

  • 各机房的读写流量都是访问本机房的 Redis 集群

  • Proxy 层在写本机房成功后,将写请求异步发送到对端机房

Proxy 双写架构的优点:

  • 实现简单,在 Proxy 层开发双写功能就可以实现

  • 一个机房故障时,其他机房的流量不受影响

  • 网络故障时,各机房内部的流量也不受影响

Proxy 双写架构的缺点:

  • 不能保证数据一致性,Proxy 异步 write 请求可能会失败,失败丢弃请求后,导致双机房数据不一致

  • 假设机房-A的集群先上线,机房-B 后上线,Proxy 双写架构不能支持把机房-A的存量数据同步到机房-B

  • 网络故障时,异步 write 会失败后丢弃,网络恢复后,之前失败的数据已经丢弃,导致双机房数据不一致

数据层双向同步架构

在这里插入图片描述
数据层双向同步架构的思路:

  • Proxy 不关心底层 Redis 数据同步

  • 业务流量只访问本机房里的 Redis 集群

  • 在 RedisServer 层面实现数据同步

数据层双向同步架构的优点:

  • 机房-A故障时,机房-B不受影响,反向如是

  • 网络故障时,本机房流量不受影响,网络恢复后,数据层面可以拉取增量数据继续同步,数据不丢

  • 支持存量数据的同步

  • 业务访问 Redis 延时低,访问链路不受机房间网络延时影响

  • 业务单元化部署时,双机房 Redis 会有较高的数据一致性

数据层双向同步架构的缺点:

  • 实现相对比较复杂,RedisServer 改动比较大

架构演进

Codis 架构(早期架构,现已废弃)

在这里插入图片描述

Kedis 架构(线上架构)

在这里插入图片描述

第一代多活架构

在这里插入图片描述
第一代 Redis 多活基于 Codis 架构在 proxy 层实现了双写,即本机房的 Proxy 将写流量转发到对端机房的 Proxy,这个方案的特点是快速实现,尽快满足了业务多机房同步的需求。如前面 Proxy 双向架构思路所讲,本方案还存在着诸多缺点,最主要的是网络故障时,同步数据丢失的问题,为了解决这些问题,我们开发了第二代多活架构。

第二代多活架构

在这里插入图片描述
在这里插入图片描述
第二代多活基于 Kedis 架构,对 Redis-server 进行改造,可以把增量数据从 Redis 直接写入本机房的 MQ 中,由对端机房的 consumer 来消费 MQ,consumer 将数据写入对端 Redis 中。网络故障时,数据会在 MQ 堆积,待网络恢复后,consumer 可以基于故障前的 offset 继续进行消费,写入对端 Redis,从而保证在网络故障时 Redis 多活不会丢数据。

但这一代架构仍不够完美,存在以下问题:

  • ProducerThread 把数据写入 MQ 时,如果触发 MQ 限流,数据会被丢掉

  • RedisServer 内部包含了 ProducerThread,当中间内部 queue 累积数据量超过10000条时,数据会被 MainThread 丢掉

  • 中间同步数据写入 MQ,增加了跨部门依赖,同步链路长,不利于系统稳定性

  • 中间同步链路重试会造成非幂等命令执行多次,例如 incrby 重试可能造成命令执行多次造成数据不一致

  • 对于新建双活链路,不支持同步存量数据,只能从当前增量数据开始同步

  • Redis 增量数据写入 MQ,导致成本增加

为了解决以上问题,我们开发了第三代架构

第三代多活架构

在第三代架构中,我们细化了设计目标,主要思路是保证同步链路中的数据不丢不重,同时去掉对 MQ 的依赖,降低多活成本。

在这里插入图片描述
第三代架构中,我们去掉了 MQ 和 consumer,新增了 syncer 组件。syncer 组件模拟 Redis-slave 从 Redis-master 中拉取增量数据,这样把数据同步和 Redis 进行解耦,便于后续多机房扩展。

在第三代架构中,Redis 遇到了回环、重试、数据冲突、增量数据存储和读取等问题,接下来一一介绍我们应对这些问题的解决方案。

1、回环问题

机房-A 写入的数据同步到机房-B,防止数据再传回机房-A。
在这里插入图片描述
为了解决回环问题,我们开发了防回环机制:

  • Redis 增加 shardID 配置,标识唯一分片号

  • Redis 请求中增加 opinfo,记录元信息,包含 shardID

在这里插入图片描述

  • 机房-A 的 Proxy 写入了 set k v 请求

  • 机房-A 的 Redis-master 向 syncer 同步 set k v opinfo[shardID-1] 请求

  • syncer 向机房-B 写入 set k v opinfo[shardID-1] 请求

  • 这样机房-B 根据 shardID-1 识别出这条请求是机房-A 生产的数据,因此不会再向机房-A 同步本条请求

2、重试问题

机房-A 写入的 incrby 请求同步到机房-B,由于中间链路的重试,导致机房-B 可能执行了多次。
在这里插入图片描述
为了解决重试问题,我们开发了防重放机制:

  • Redis 增加 opid,标识唯一请求号

  • Redis 请求中增加 opinfo,记录元信息[opid]

在这里插入图片描述

  • 机房-A 的 Proxy 写入了 incrby k 1 请求

  • 机房-A 的 Redis-master 向 syncer 同步了 incrby k 1 opinfo[opid=100] 请求, 之前同步的 opid=99 的请求已经成功

  • syncer 向机房-B 写入 incrby k 1 opinfo[opid=100] 请求

  • 机房-B 的 Redis 里存储了防重放信息 shardID-1->opid[99]

  • 机房-B 的 Redis 发现新请求的 opid=100>本地的99,判断为新请求

  • 机房-B的 Redis 执行这条请求,并把防重放信息更新为shardID-1->opid[100]

  • 假设机房-A 的 syncer 将本条请求进行了重试,又执行了一遍 incrby k 1 opinfo[opid=100]

  • 机房-B 的 Redis 发现新请求 opid=100 等于本地的100,判断为重复请求

  • 机房-B 的 Redis 忽略掉本地请求,不执行

3、数据冲突问题

双机房同时修改同一个 key 导致数据不一致
在这里插入图片描述
对于数据冲突,不同数据类型的不同操作的数据合并,如果单从存储层解决,是一个非常复杂的话题。如果业务层做了单元化部署,则不会出现这种问题。如果业务层没有做单元化,我们开发了冲突检测功能,来帮助业务及时发现数据冲突,最后数据以哪边为准来修正,需要业务同学来决策。

冲突检测机制:

  • Redis 记录 key 的最后 write 时间

  • Redis 请求中增加 opinfo,记录元信息 [timestamp]

  • 如果 opinfo.timestamp<=key_write_time,则记录冲突 key

在这里插入图片描述
时间T1<T2<T3

  • T1时间,用户在机房-A 写入请求 set k v1

  • T2时间,用户在机房-B 写入请求 set k v2,并记录k的最后修改时间为T2

  • 由于网络同步延时,T3时间,syncer 把T1时间写入的 set k v1请求发送到了机房-B

  • 机房-B 的 Redis 执行 set k v1 时发现 timestamp 为T1,但 k 的最后修改时间为T2

  • 由于T1<T2,机房-B 的 Redis 判断这是一次冲突,并记录下来,然后执行该条请求

以上是冲突检测的基本原理,这是一个旁路统计,帮助用户发现一些潜在冲突数据。

4、增量数据存储和读取问题

因为 syncer 只是同步组件,不会存储数据,所以需要考虑当网络故障时,增量数据的存储和读取问题。

在这里插入图片描述
为了解决这个问题,我们对 Redis 的 aof 机制进行了改造,可以在网络故障时,增量数据都堆积在 Redis 的磁盘上,在网络恢复后,syncer 从 Redis 里拉取增量 aof 数据发送到对端机房,避免数据丢失。

aof 机制改造有:aof 文件切分、aof 增量复制、aof 异步写盘

在这里插入图片描述

  • 将 aof 文件切分为多个小文件,保存增量数据

  • 当增量数据超过配置的阈值时,Redis 自动删除最旧的 aof 文件

  • 当 Redis 重启时,加载 rdb 文件和 rdb 之后的 aof 文件,可以恢复全部数据

  • 当网络故障恢复后,syncer 根据故障前的 opid 向 Redis 请求拉取增量数据,发送到对端机房
    在这里插入图片描述
    开源 Redis 是在主线程中进行 aof 写盘,当磁盘 IO 过高时,Redis 写盘可能造成业务访问 Redis 耗时抖动。因此我们开发了 aof 异步写盘机制:

  • Redis 的主线程将 aof 数据写入 queue 中

  • bio 线程来消费 queue

  • bio 线程将 aof 数据写入磁盘

这样 Redis 的访问耗时不受磁盘 IO 的影响,更好的保证稳定性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/498564.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

电商搬家上货软件分享,官方授权API接口,一键铺货更安全!

最近不少地方气温回暖&#xff0c;不少卖家开始布局春夏款产品&#xff0c;首先需要解决的就是货源和上货问题。 当我们看到市面上某款产品很有市场&#xff0c;想要复制到自己店铺来卖&#xff0c;如何操作呢&#xff1f; 按照之前的玩法&#xff0c;是直接借助工具从别人店…

初识PySide6/PyQt6:基础简介及环境的安装配置与使用(一)

文章目录 一、基础简介二、PySide 6/PyQt 6具有的特性三、PySide 6/PyQt 6之间的区别四、搭建PyQt 6 环境4.1 安装PyQt64.2 测试PyQt6环境4.3 pycharm 配置Qt Designer、PyUIC 五、Qt Designer使用&#xff08;基础开发流程实操&#xff09;六、官方文档 一、基础简介 PySide …

从AutoCAD切换到DraftSight,您需要了解的信息

如果您正在使用其他二维软件进行设计&#xff0c;那么切换到DraftSight是很容易的&#xff0c;DraftSight具有您熟悉的界面和命令&#xff0c;同时还可以定制软件界面以符合您的使用习惯。 关于DraftSight DraftSight利用强大的2D绘图和3D建模功能&#xff0c;优化你的设计流…

在word中显示Euclid Math One公式的问题及解决(latex公式,无需插件)

问题&#xff1a;想要在word中显示形如latex中的花体字母 网上大多解决办法是安装Euclid Math One。安装后发现单独的符号插入可行&#xff0c;但是公式中选择该字体时依然显示默认字体。 解决办法&#xff1a;插入公式后&#xff0c;勾选左上角的latex 在公式块中键入latex代码…

PowerBI加权计算权重

1.打开主页&#xff0c;点击快速度量值 2.计算里面 选择计算&#xff1a;每个类别的加权平均值 3.就是添加数据&#xff0c;基值&#xff08;就是你要计算的值&#xff09;粗细&#xff08;就是你要用那个值计算权重&#xff09;类别&#xff08;就是你是要乘以那个类别&#x…

C语言数据结构基础——排序

目录 1.插入排序 2.冒泡排序 3. 堆排序 4.希尔排序 5.直接选择排序 6.快速排序☆☆ 6.1快速排序基础 6.2关于快速排序的时间复杂度 6.3随机数法和三数取中法 6.4其他的单趟实现方法 6.4.1挖坑法 6.4.2前后指针版快速排序☆ 6.4.3非递归实现快排☆ 7.归并排序 7.1递归…

|行业洞察·碳纤维|《中国碳纤维行业现状与发展趋势-39页》

报告内容的详细解读&#xff1a; 1. 战略性新材料的重要性 碳纤维是一种轻质高强的高性能纤维材料&#xff0c;在航空航天、国防军工、高端装备制造等领域具有不可替代的作用。碳纤维的应用有助于减少能源消耗和降低碳排放&#xff0c;符合全球可持续发展的要求。 |趋势洞察…

2024/03/28(C++·day4)

一、思维导图 二、练习题 1、写出三种构造函数&#xff0c;算术运算符、关系运算符、逻辑运算符重载尝试实现自增、自减运算符的重载 #include <iostream>using namespace std;// 构造函数示例 class MyClass { private:int data; public:// 默认构造函数MyClass() {da…

【3DsMax+Pt】练习案例

目录 一、在3DsMax中展UV 二、在Substance 3D Painter中绘制贴图 一、在3DsMax中展UV 1. 首先创建如下模型 2. 选中如下三条边线作为接缝 重置剥 发现如下部分还没有展开 再选一条边作为接缝 再次拨开 拨开后的UV如下 二、在Substance 3D Painter中绘制贴图 1. 新建项目&am…

Java Swing游戏开发学习20

内容来自RyiSnow视频讲解 这一节讲的是Monster野兽、就是常说的游戏中的怪&#xff0c;打怪升级的那个怪。 前言 本节目标 实现怪处理碰撞和伤害&#xff08;当玩家player碰到怪会掉血&#xff09; 实现 添加怪到窗口 这里只使用了2张图片&#xff0c;每个方向移动都是用…

C语言用if语句设计选择结构程序

在C语言中&#xff0c;if语句是一种常用的选择结构语句&#xff0c;用于根据条件选择性地执行不同的代码块。if语句的设计使得程序可以根据条件的真假进行分支控制&#xff0c;从而实现灵活的程序逻辑。本文将深入介绍C语言中如何使用if语句设计选择结构程序&#xff0c;包括if…

激光焊接机在不锈钢三角阀制造中的应用与发展

不锈钢三角阀激光焊接机是一种专门用于焊接不锈钢三角阀的高效、精准设备。这种设备在不锈钢三角阀的制造过程中起到了至关重要的作用&#xff0c;其应用主要体现在以下几个方面&#xff1a; ​ 一、激光焊接机在不锈钢三角阀制造中的应用 激光焊接机以其独特的优势&#xff…

金属板材成型仿真软件 Altair® Inspire™ Form,完整的冲压仿真环境

Inspire Form 是一个完整的冲压仿真环境&#xff0c;产品设计师和工艺工程师可以使用该环境&#xff0c;有效地优化设计、对稳健的制造进行仿真、降低材料成本。 借助快速简便的可行性模块&#xff0c;用户可以在几秒钟内完成零部件分析&#xff0c;从而在产品开发早期阶段预测…

李宏毅【生成式AI导论 2024】第6讲 大型语言模型修炼_第一阶段_ 自我学习累积实力

背景知识:机器怎么学会做文字接龙 详见:https://blog.csdn.net/qq_26557761/article/details/136986922?spm=1001.2014.3001.5501 在语言模型的修炼中,我们需要训练资料来找出数十亿个未知参数,这个过程叫做训练或学习。找到参数后,我们可以使用函数来进行文字接龙,拿…

【Pt】马灯贴图绘制过程 02-制作锈迹

目录 一、边缘磨损效果 二、刮痕效果 三、边缘磨损与刮痕的混合 四、锈迹效果 本篇效果&#xff1a; 一、边缘磨损效果 将智能材质“Iron Forge Old” 拖入图层 打开“Iron Forge Old” 文件夹&#xff0c;选中“Sharpen”&#xff08;锐化&#xff09;&#xff0c;增大“…

fpga 通过axi master读写PS侧DDR的仿真和上板测试

FPGA和ARM数据交互是ZYNQ系统中非常重要的内容。PS提供了供FPGA读写的AXI-HP接口用于两者的高速通信和数据交互。一般的&#xff0c;我们会采用AXI DMA的方式去传输数据&#xff0c;DMA代码基本是是C编写&#xff0c;对于FPGA开发者来说不利于维护和debug。本文提供一种手写AXI…

《思考,快与慢》揭示了决策过程中直觉反应与理性分析的关系 - 三余书屋 3ysw.net

思考&#xff0c;快与慢 你好&#xff0c;今天我们要分享的是《思考&#xff0c;快与慢》。作者是丹尼尔卡尼曼&#xff0c;2002年诺贝尔经济学奖获得者。他开辟了经济学中的一个新分支——行为经济学。在《思考&#xff0c;快与慢》这部作品中&#xff0c;他深入探讨了行为经…

JVM篇详细分析

JVM总体图 程序计数器&#xff1a; 线程私有的&#xff0c;每个线程一份&#xff0c;内部保存字节码的行号&#xff0c;用于记录正在执行字节码指令的地址。&#xff08;可通过javap -v XX.class命令查看&#xff09; java堆&#xff1a; 线程共享的区域&#xff0c;用来保存对…

搭建企业微信知识库,这些注意事项你必须知道

| 企业微信知识库是什么&#xff1f; 简单来说&#xff0c;企业微信知识库就是一个集中存储、管理和分享企业内部信息的置于企业微信中的系统。你可以把它想象成一个超级大的“资料库”&#xff0c;里面装满了公司的各种知识、文档、流程、经验等等。这个“资料库”不仅方便员工…

劳保鞋厂家与您聊聊:从事电力行业工作人员穿什么功能的劳保鞋

电力行业属于危险系数较高的行业&#xff0c;工作人员在工作中面临电力的潜在危险&#xff0c;如电击、高温、机械伤害、高空作业等风险。这就要有专业的安全设备&#xff0c;才能尽可能的保护电力工作人员的安全&#xff0c;真真正正起到防范的作用。因此&#xff0c;穿着合适…