本文介绍: 为了更好做好容灾保障,使业务能够应对机房级别的故障滴滴存储服务都在多机房进行部署本文简要分析了 Redis 实现异地多活几种思路,以及滴滴 Redis 异地多活架构演进过程遇到的主要问题解决方法,抛砖引玉,给小伙伴们一些参考。Redis 异地多活的主要思路业界实现 Redis 异地多活通常三种思路:主从架构、Proxy双写架构、数据双向同步架构。主从架构主从架构的思路:各机房的 R…

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

Redis 异地多活的主要思路

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

主从架构

dc32c83646230825ff660d459951c9e3.png

主从架构的思路:

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

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

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

主从架构的优点

主从架构的缺点

Proxy 双写架构  

b56b4351ace4eccc894a167f2af12769.png

Proxy 双写架构的思路:

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

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

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

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

Proxy 双写架构的优点:

Proxy 双写架构的缺点:

数据层双向同步架构   

60b713379f14423a84cc02b73d5a5fd7.png

数据层双向同步架构的思路:

  1. Proxy 不关心底层 Redis 数据同步

  2. 业务流量访问本机房里的 Redis 集群

  3. 在 RedisServer 层面实现数据同步

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

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

滴滴 Redis 架构

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

df6f8363ef0b1b99aeb301ab441b0d4d.png

Kedis 架构(线上架构)

47a243d5d33a003b1cca272b608eecea.png

滴滴 Redis 异地多活架构的演进

第一代多活架构       

de33ee962fb974d03d43434b780a65ad.png

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

第二代多活架构

39596cde2376c39afa83f322cde0724a.png

130e3adce62dfde1bc1a997d1f2d44e1.png

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

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

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

第三代多活架构

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

c21863acc90499f36b7c2c6f55fa5fbe.png

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

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

1、回环问题

机房-A 写入的数据同步到机房-B,防止数据再传回机房-A。

01502b752c4ee628d3131d92b91bd389.png

为了解决回环问题,我们开发了防回环机制

  1. Redis 增加 shardID 配置标识唯一分片

  2. Redis 请求中增加 opinfo记录信息包含 shardID   

330b438fb756ea76d700c63be105d274.png

  • 机房-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 可能执行了多次。 

60c3c3bf175fab532be2fa58b2fe9dcc.png

为了解决重试问题,我们开发了防重放机制

  1. Redis 增加 opid标识唯一请求号

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

523135f8310d9e434c494162a715e5b2.png

3、数据冲突问题

双机房同时修改同一个 key 导致数据不一致

1b00ab699a3dc59bbab23eda14a72041.png

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

冲突检测机制

  1. Redis 记录 key最后 write 时间

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

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

f6116f6bc59989b9aa45880b0b6dd090.png

时间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 只是同步组件,不会存储数据,所以需要考虑网络故障时,增量数据的存储和读取问题。

7a10335c5ae8fa90d640da1c6fb9785d.png

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

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

34fb53592553e604e57d02c4e1c85529.png

feaef328382a14af99b046f6f0ec28cd.png

开源 Redis 是在主线程中进行 aof 写盘,当磁盘 IO 过高时,Redis 写盘可能造成业务访问 Redis 耗时抖动。因此我们开发了 aof 异步写盘机制

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

原文地址:https://blog.csdn.net/DiDi_Tech/article/details/134410944

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_40854.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注