1. 简述

异地多活的概念以及为什么要做异地多活这儿就不进行概述了。概念性的许多,像什么同城双活、两地三中心、三地五中心等等概念。假如有对这些容灾架构办法感兴趣的能够阅览下这篇文章进行了解:《浅谈事务级灾备的架构办法》。

阅览本篇文章之前,咱们先清晰一下背景,这样咱们后续在看的时分就不会发生困惑。

1.1 机房区别

得物多活改造一期现在有两个机房,分别是机房A和机房B。文章中大部分图中都会有标识,这就阐明是两个不同的机房。

A机房咱们界说为中心机房,也便是多活上线之前正在运用的机房。假如说到中心机房那指的便是A机房。另一个B机房,在描述的时分或许会说成单元机房,那指的便是B机房。

1.2 单元化

单元化简略点咱们直接就能够认为是一个机房,在这个单元内能够完结事务的闭环。比方说用户进入APP,阅览产品,挑选产品承认订单,下单,付出,检查订单信息,这整个流程都在一个单元中能够完结,而且数据也是存储在这个单元里边。

做单元化无非就两个原因,容灾和提高体系并发才能。可是也得考虑机房建造的规模和技能,硬件等投入的本钱。详细的就不多讲了,咱们大约了解了就行。

2. 改造点

了解改造点之前咱们先来看下现在单机房的现状是什么姿态,才干更好地协助咱们去了解为什么要做这些改造。

如上图所示,客户端的恳求进来会先到SLB(负载均衡),然后到咱们内部的网关,经过网关再分发到详细的事务服务。事务服务会依靠Redis、Mysql、 MQ、Nacos等中间件。

看完这篇异地多活的改造,我决定和架构师battle一下

已然做异地多活,那么必然是在不同区域有不同的机房,比方中心机房,单元机房。所以咱们要完结的效果如下图所示:

看完这篇异地多活的改造,我决定和架构师battle一下
咱们看上面这张图或许会感觉很简略,其实也便是一些常用的中间件,再多一个机房布置算了,这有什么难度。假如你这样想我只能说一句:格局小了啊

::: hljs-center

2.1 流量调度

::: 用户的恳求,从客户端宣布,这个用户的恳求该到哪个机房,这是咱们要改造的第一个点。

没做多活之前,域名会解析到一个机房内,做了多活后,域名会随机解析到不同的机房中。假如依照这种随机的办法是必定有问题的,关于服务的调用是无所谓的,由于没有状况。可是服务内部依靠的存储是有状况的呀。

咱们是电商事务,用户在中心机房下了一个单,然后跳转到订单概况,这个时分恳求到了单元机房,底层数据同步有推迟,一拜访报个错:订单不存在。用户当场就懵了,钱都付了,订单没了。

所以针对同一个用户,尽或许在一个机房内完结事务闭环。为了解决流量调度的问题,咱们基于OpenResty二次开宣布了DLB流量网关,DLB会对接多活操控中心,能够知道当时拜访的用户是归于哪个机房,假如用户不归于当时机房,DLB会直接将恳求路由到该用户所属机房内的DLB。

看完这篇异地多活的改造,我决定和架构师battle一下

假如每次都随机到固定的机房,再经过DLB去校对,必然会存在跨机房恳求,耗时加长。所以在这块咱们也是结合客户端做了一些优化,在DLB校对恳求后,咱们会将用户对应的机房IP直接经过Header响应给客户端。这样下次恳求的时分,客户端就能够直接经过这个IP拜访。

假如用户当时拜访的机房挂了,客户端需求降级成之前的域名拜访办法,经过DNS解析到存活的机房。 ::: hljs-center

2.2 RPC结构

:::

当用户的恳求抵达了单元机房内,理论上后续一切的操作都是在单元机房完结。前面咱们也说到了,用户的恳求尽量在一个机房内完结闭环,只是尽量,没有说悉数。

这是由于有的事务场景不合适区别单元,比方库存扣减。所以在咱们的区别里边,有一个机房是中心机房,那些不做多活的事务只会布置在中心机房里边,那么库存扣减的时分就需求跨机房调用。

恳求在中心机房,怎样知道单元机房的服务信息?所以咱们的注册中心(Nacos)要做双向同步,这样才干拿到一切机房的服务信息。

看完这篇异地多活的改造,我决定和架构师battle一下

当咱们的注册信息选用双向仿制后,关于中心服务,直接跨机房调用。关于单元服务会存在多个机房的服务信息,假如不进行操控,则会出现调用其他机房的状况,所以RPC结构要进行改造。

2.2.1 界说路由类型

(1)默许路由 恳求到中心机房,会优先调用中心机房内的服务,假如中心机房无此服务,则调用单元机房的服务,假如单元机房没有此服务则直接报错。

(2)单元路由 恳求到单元机房,那么阐明此用户的流量规矩是在单元机房,接下来一切的RPC调用都只会调用单元机房内的服务,没有服务则报错。

(3)中心路由 恳求到单元机房,那么直接调用中心机房的服务,中心机房没有服务则报错。恳求到中心机房,那么就本机房调用。

2.2.2 事务改造

事务方需求对自己的接口(Java interface)进行符号是什么类型,经过@HARoute加在接口上面。符号完结后,在Dubbo接口进行注册的时分,会把路由类型放入到这个接口的元数据里边,在Nacos后台能够检查。后边经过RPC调用接口内部一切的办法都会依照符号类型进行路由。

假如符号为单元路由,现在咱们内部的规范是办法的第一个参数为小写的long buyerId,RPC在路由的时分会依据这个值判别用户地点的机房。

路由逻辑如下:

看完这篇异地多活的改造,我决定和架构师battle一下

2.2.3 改造过程

  • 接口仿制一份,命名为UnitApi,第一个参数加long buyerId。在新接口的完结里边调用老接口,新旧接口共存。
  • 将UnitApi发布上线,此刻没有流量。
  • 事务方需求晋级其他域的API包,将老接口的调用切换为新的UnitApi,此处添加开关操控。
  • 上线后,经过开关操控调用走UnitApi,有问题可关闭开关。
  • 下线老的API,完结切换。

2.2.4 遇到的问题

2.2.4.1 其他场景切单元接口

除了RPC直接调用的接口,还有一大部分是经过Dubbo泛化过来的,这块在上线后也需求将流量切到UnitApi,等老接口没有恳求量之后才干下线。

2.2.4.2 接口分类

接口进行分类,之前没有多活的束缚,一个Java interface中的办法或许各种各样,假如现在你的interface为单元路由,那么里边的办法第一个参数都有必要加buyerId,其他没有buyerId场景的办法要挪出去。

2.2.4.3 事务层面调整

事务层面调整,比方之前查询订单只需求一个订单号,可是现在需求buyerId进行路由,所以接入这个接口的上游都需求调整。

2.3 数据库

恳求顺畅的抵达了服务层,接下来要跟数据库打交道了。数据库咱们界说了不同的类型,界说如下:

(1)单元化 此库为单元库,会一同在两个机房布置,每个机房都有完整的数据,数据选用双向同步。

(2)中心化 此库为中心库,只会在中心机房布置。

(3)中心单元化 此库为中心单元库,会一同在两个机房布置,中心能够读写,其他机房只能读。中心写数据后单向仿制到另一个机房。

2.3.1 署理中间件

现在各个事务方用的都是客户端办法的Sharding中间件,每个事务方的版本还不共同。在多活切流的过程中需求对数据库禁写来确保事务数据的准确性,假如没有一致的中间件,这将是一件很费事的事情。

所以咱们经过对ShardingSphere进行深度定制,二次开发数据库署理中间件 彩虹桥。各事务方需求接入彩虹桥来替换之前的Sharding办法。在切换过程中,怎么确保稳定滑润搬迁,出问题怎么快速康复,咱们也有一套成功的实践,咱们能够看下我之前写的这篇文章《客户端分片到Proxy分片,如丝般顺滑的平稳搬迁》,里边有完结办法。

看完这篇异地多活的改造,我决定和架构师battle一下

2.3.2 分布式ID

单元化的库,数据层面会做双向同步仿制操作。假如直接用表的自增ID则会出现下面的抵触问题:

看完这篇异地多活的改造,我决定和架构师battle一下

这个问题能够经过设置不同机房有不同的自增步长来解决,比方中心机房的自增步长为奇数,单元机房的自增步长为偶数。但比较费事,后续或许会添加更多的机房。咱们选用了一种一了百了的办法,接入全局唯一的分布式ID来防止主键的抵触。

2.3.2.1 客户端接入

现在,接入分布式ID有两种办法,一种是运用内经过根底架构供给的jar包接入,详细逻辑如下:

看完这篇异地多活的改造,我决定和架构师battle一下

2.3.2.2 彩虹桥接入

另一种便是在彩虹桥中对详细的表装备ID的生成办法,支撑对接分布式ID服务。

看完这篇异地多活的改造,我决定和架构师battle一下

2.3.3 事务改造

2.3.3.1 单元化库写恳求有必要带着ShardingKey

在Dao层对表进行操作的时分,会经过ThreadLocal设置当时办法的ShardingKey,然后经过Mybatis阻拦器机制,将ShardingKey经过Hint的办法放入SQL中,带给彩虹桥。彩虹桥会判别当时的ShardingKey是否归于当时机房,假如不是直接禁写报错。

这儿跟咱们简略的阐明下为什么切流过程中要禁写,这个其实跟JVM的废物回收有点类似。假如不对操作禁写,那么就会不断的发生数据,而咱们切流,一定要确保当时机房的数据悉数同步过去了之后才开端收效流量规矩,不然用户切到另一个机房,数据没同步完,就会发生事务问题。除了彩虹桥会禁写,RPC结构内部也会依据流量规矩进行阻断。

2.3.3.2 数据库衔接指定衔接办法

衔接办法的界说有两种,分别是中心和单元。

假如运用的数据源指定了衔接办法为中心,那么在中心机房能够正常初始化数据源。在单元机房不会初始化数据源。

假如运用的数据源指定了衔接办法为单元,那么在中心机房和单元机房都能够正常初始化数据源。

看完这篇异地多活的改造,我决定和架构师battle一下

这儿解说下为什么要有衔接办法这个规划?

在咱们的项目中,会出现一同衔接2个库的状况,一个单元库,一个中心库。假如没有衔接办法,上层代码是一份,这个项目会在中心和单元两个机房一同布置,也便是两个当地都会去创立数据源。

但实际上,我的中心库只需求在中心机房衔接就能够了,由于中心库一切的操作都是中心接口,流量必定会走中心,我在单元机房去衔接是没有意义的。另一个问题便是我不需求在单元机房保护中心库的数据库信息,假如没有衔接办法,那么单元机房的彩虹桥也有必要要有中心库的信息,由于项目会进行衔接。

2.3.4 遇到的问题

2.3.4.1 单元接口中不能拜访中心数据库

假如接口符号成了单元接口,那么只能操作单元库。在曾经没有做多活改造的时分,基本上没有什么中心和单元的概念,一切的表也都是放在一同的。多活改造后,咱们会依据事务场景对数据库进行区别。

区别后,中心库只会被中心机房的程序运用,在单元机房是不允许衔接中心库。所以单元接口里边假如涉及到对中心库的操作,必定会报错。这块需求调整成走中心的RPC接口。

2.3.4.2 中心接口不能拜访单元数据库

跟上面相同的问题,假如接口是中心的,也不能在接口里边操作单元库。中心接口的恳求都会强制走到中心机房,假如里边有涉及到另一个机房的操作,也有必要走RPC接口进行正确的路由,由于你中心机房不能操作另一个机房的数据库。

2.3.4.3 批量查询调整

比方批量依据订单号进行查询,可是这些订单号不是同一个买家。假如随意用一个订单的买家作为路由参数,那么其他一些订单其实是归于另一个单元的,这样就有或许存在查询到旧数据的问题。

这样批量查询的场景,只能针对同一个买家可用,假如是不同的买家需求分批调用。

2.4 Redis

Redis在事务中用的比较多,在多活的改造中也有许多当地需求调整。关于Redis首要咱们清晰几个界说:

不做双向同步 Redis不会和数据库相同做双向同步,也便是中心机房一个Redis集群,单元机房一个Redis集群。每个机房的集群中只存在一部分用户的缓存数据,不是全量的。

Redis类型 Redis分为中心和单元,中心只会在中心机房布置,单元会在中心和单元两个机房布置。

2.4.1 事务改造

2.4.1.1 Redis多数据源支撑

多活改造之前,每个运用都有一个单独的Redis集群,多活改造后,由于运用没有进行单元化和中心的拆分,所以一个运用中会存在需求衔接两个Redis的状况。一个中心Redis,一个单元Redis。

根底架构供给的Redis包需求支撑多数据源的创立,而且界说通用的装备格局,事务方只需求在自己 的装备里边指定集群和衔接办法即可完结接入。此处的衔接办法跟数据库的共同。

详细的Redis实例信息会在装备中心一致保护,不需求事务方关心,这样在做机房扩容的时分,事务方是不需求调整的,装备如下:

spring.redis.sources.carts.mode=unit
spring.redis.sources.carts.cluster-name=cartsCuster

一同咱们在运用Redis的时分要指定对应的数据源,如下:

@Autowired
@Qualifier(RedisTemplateNameConstants.REDIS_TEMPLATE_UNIT) 
private RedisTemplate<String, Object> redisTemplate;

2.4.1.2 数据共同性

数据库缓存场景,由于Redis不会双向同步,就会存在数据的不共同性问题。比方用户一开端在中心机房,然后缓存了一份数据。进行切流,切到单元机房,单元机房又缓存了一份数据。再进行切回中心机房的操作,此刻中心机房里的缓存是旧的数据,不是最新的数据。

所以在底层数据改变的时分,咱们需求对缓存进行失效操作,这样才干确保数据的终究共同性。单纯依托缓存的失效时刻来抵达共同性不是一个合适的计划。

这儿咱们的计划是选用订阅数据库的binlog来进行缓存的失效操作,能够订阅本机房的binlog,也能够订阅其他机房的binlog来完结一切机房的缓存失效。

看完这篇异地多活的改造,我决定和架构师battle一下

2.4.2 遇到的问题

2.4.2.1 序列化协议兼容

在接入新的Redis Client包后,测验环境出现了老数据的兼容问题。大部分运用都没问题,有单个运用虽然用了一致的底层包,可是自己定制了序列化办法,导致Redis按新的办法安装后没有用到自界说的协议,这块也是进行了改造,支撑多数据源的协议自界说。

2.4.2.2 分布式锁的运用

现在项目中的分布式锁是基于Redis完结,当Redis有多个数据源之后,分布式锁也需求进行适配。在运用的当地要区别场景,默许都是用的中心Redis来加锁。

可是单元接口里边的操作都是买家场景,所以这部分需求调整为单元Redis锁方针进行加锁,这样能够提高性能。其他的一些场景有涉及到全局资源的确定,那就用中心Redis锁方针进行加锁。

2.5 RocketMQ

恳求抵达服务层后,跟数据库和缓存都进行了交互,接下来的逻辑是要发一条音讯出去,其他事务需求监听这个音讯做一些事务处理。

假如是在单元机房宣布的音讯,发到了单元机房的MQ中,单元机房的程序进行消费,是没有问题的。但假如中心机房的程序要消费这个音讯怎样办?所以MQ跟数据库相同,也要做同步,将音讯同步到另一个机房的MQ中,至于另一个机房的消费者要不要消费,这就要让事务场景去决定。

看完这篇异地多活的改造,我决定和架构师battle一下

2.5.1 界说消费类型

2.5.1.1 中心订阅

中心订阅指的是音讯无论是在中心机房宣布的仍是单元机房宣布的,都只会在中心机房进行消费。假如是单元机房宣布的,会将单元的音讯仿制一份到中心进行消费。

2.5.1.2 一般订阅

一般订阅便是默许的行为,指的是就近消费。在中心机房发送的音讯就由中心机房的消费者进行消费,在单元机房发送的音讯就由单元机房的消费进行消费。

2.5.1.3 单元订阅

单元订阅指的是音讯会依据ShardingKey进行音讯的过滤,无论你在哪个机房发送音讯,音讯都会仿制到另一个机房,此刻两个机房都有该音讯。经过ShardingKey判别当时音讯应该被哪个机房消费,契合的才会进行消费,不契合的结构层面会主动ACK。

2.5.1.4 全单元订阅

全单元订阅指的是音讯无论在哪个机房宣布,都会在一切的机房进行消费。

2.5.2 事务改造

2.5.2.1 音讯发送方调整

音讯发送方,需求结合事务场景进行区别。假如是买家场景的事务音讯,在发音讯的时分需求将buyerId放入音讯中,详细怎样消费由消费方决定。假如消费方是单元消费的话那么有必要依靠发送方的buyerId,不然无法知道当时音讯应该在哪个机房消费。

2.5.2.2 音讯消费方指定消费办法

前面说到了中心订阅,单元订阅,一般订阅,全单元订阅多种办法,究竟要怎样选便是要结合事务场景来定的,定好后在装备MQ信息的时分指定即可。

比方中心订阅就合适你整个服务都是中心的,其他机房都没布置,这个时分必定合适中心订阅。比方你要对缓存进行铲除,就比较合适全单元订阅,一旦数据有改变,一切机房的缓存都铲除去。

2.5.3 遇到的问题

2.5.3.1 音讯幂等消费

这个点其实依据多活没有多大关系,就算不做多活,音讯消费场景,必定是要做幂等处理的,由于音讯自身就有重试机制。单独拎出来说是由于在多活场景下除了音讯自身的重试会导致音讯重复消费,另外在切流的过程中,归于切流这部分用户的音讯会被仿制到另一个机房从头进行消费,在从头消费的时分,会基于时刻点进行音讯的从头投进,所以有或许会消费到之前已经消费了的音讯,这点有必要注意。

再解说下为什么切流过程中会有音讯消费失利以及需求仿制到另一个机房去处理,如下图所示:

看完这篇异地多活的改造,我决定和架构师battle一下

用户在当时机房进行事务操作后,会发生音讯。由于是单元订阅,所以会在当时机房进行消费。消费过程中,发生了切流操作,消费逻辑里边对数据库进行读写,可是单元表的操作都带着了ShardingKey,彩虹桥会判别ShardingKey是否契合当时的规矩,发现不契合直接禁写报错。这批切流用户的音讯就悉数消费失利。比及流量切到另一个机房后,假如不进行音讯的从头投递,那么这部分音讯就丢掉了,这便是为什么要仿制到另一个机房进行音讯的从头投递。

2.5.3.2 切流场景的音讯次序问题

上面讲到了在切流过程中,会将音讯仿制到另一个机房进行从头消费,然后是基于时刻点去回放的,假如你的事务音讯自身便是一般的Topic,在音讯回放的时分假如同一个场景的音讯有多条,这个次序并不一定是依照之前的次序来消费,所以这儿涉及到一个消费次序的问题。

假如你之前的事务场景自身便是用的次序音讯,那么是没问题的,假如之前不是次序音讯,这儿就有或许有问题,我举个比方阐明下:

有个事务场景,触发一次功能就会发生一条音讯,这个音讯是用户级别的,也便是一个用户会发生N条音讯。消费方会消费这些音讯进行存储,不是来一次音讯就存储一条数据,而是同一个用户的只会存储一条,音讯里边有个状况,会依据这个状况进行判别。

比方下面的音讯总共投递了3条,按正常次序消费终究的成果是status=valid。

10:00:00  status=valid
10:00:01  status=invalid 
10:00:02  status=valid

假如音讯在另一个机房从头投递的时分,消费次序变成了下面这样,终究成果便是status=invalid。

10:00:00  status=valid
10:00:02  status=valid 
10:00:01  status=invalid

解决计划有下面几种:

  • Topic换成次序音讯,以用户进行分区,这样就能确保每个用户的音讯严厉依照发送次序进行消费。

  • 对音讯做幂等,已消费过就不再消费。可是这儿跟一般的音讯不同,会有N条音讯,假如对msgId进行存储,这样就能够判别是否消费过,可是这样存储压力太大,当然也能够只存储最近N条来减小存储压力。

  • 音讯幂等的优化办法,让音讯发送方每发送一次,都带一个version,version有必要是递加。消费方消费音讯后把当时version存储起来,消费之前判别音讯的version是否大于存储的version,满意条件才进行消费,这样既防止了存储的压力也能满意事务的需求。

2.6 Job

Job在咱们这边用的不多,而且都是老的逻辑在用,只要几个清晨统计数据的使命,新的都接入了咱们自研的TOC(超时中心)来管理。

2.6.1 事务改造

2.6.1.1 中心机房履行

由于Job是老的一套体系,现在也只要个位数的使命在履行,所以在底层结构层面并没有支撑多活的改造。后续会将Job的逻辑搬迁到TOC中。

所以咱们有必要在事务层面进行改造来支撑多活,改造计划有两种,分别介绍下:

(1)两个机房一同履行Job,数据处理的时分,比方处理用户的数据,经过根底架构供给的才能,能够判别用户是否归于当时机房,假如数据就履行,不然就越过这条数据。

(2)从事务场景动身,Job都是清晨去履行的,不归于在线事务,对数据共同性要求没那么高。即使不按单元化去处理数据,也没什么问题。所以只需求在中心机房履行Job即可,另一个机房咱们能够经过装备让Job使命不进行收效。

可是这种办法需求去梳理Job里的数据操作,假如有对中心库操作的,没关系,自身便是在中心机房跑。假如有对单元库操作的,需求调整为走RPC接口。

2.7 TOC

TOC是咱们内部用的超时中心,当咱们有需求需求在某个时刻点进行触发事务动作的时分都能够接入超时中心来处理。

举个比方:订单创立后,N分钟内没有付出就主动撤销。假如事务方自己完结,要么定时扫表进行处理,要么用MQ的推迟音讯。有了TOC后,咱们会在订单创立之后,往TOC注册一个超时使命,指定某个时刻点,你要回调我。在回调的逻辑逻辑里去判别订单是否已完结付出,假如没有则撤销。

看完这篇异地多活的改造,我决定和架构师battle一下

2.7.1 事务改造

2.7.1.1 使命注册调整

在注册超时中心使命的时分,事务方需求识别使命是否要契合单元化的规范。假如此使命只是对中心数据库进行操作,那么这个使命回调在中心机房即可。假如此使命是对单元数据库操作,那么在注册使命的时分就需求指定buyerId,超时中心在触发回调的时分会依据buyerId进行路由到用户所属机房进行处理。

现在超时中心是只会在中心机房进行布置,也便是一切的使命都会在中心机房进行调度。假如使命注册的时分没有指定buyerId,超时中心在回调的时分就不知道要回调哪个机房,默许回调中心机房。要想让超时中心依据多活的路由规矩进行回调,那么注册的时分有必要指定buyerId。

看完这篇异地多活的改造,我决定和架构师battle一下

3. 服务区别

阅览完上面的改造内容,信任咱们还有一个疑问点便是我的服务该怎样区别呢?我要不要做单元化呢?

3.1 全体方向

首要要依据整个多活的一个全体方针和方向去梳理,比方咱们的全体方向便是买家买卖的中心链路有必要完结单元化改造。那么这整个链路一切依靠的上下游都需求改造。

用户阅览产品,进入承认订单,下单,付出,查询订单信息。这个中心链路其实涉及到了许多的事务域,比方:产品,出价,订单,付出,商家等等。

在这些已经清晰了的事务域下面,或许还有一些其他的事务域在支撑着,所以要把全体的链路都梳理出来,一同改造。当然也不是一切的都有必要做单元化,仍是得看事务场景,比方库存,必定是在买卖中心链路上,可是不需求改造,有必要走中心。

3.2 服务类型

3.2.1 中心服务

中心服务只会在中心机房布置,而且数据库也一定是中心库。能够对整个运用进行打标成中心,这样外部拜访这个服务的接口时都会被路由到中心机房。

3.2.2 单元服务

单元服务会在中心机房和单元机房一同布置,而且数据库也一定是单元库。单元服务是买家维度的事务,比方承认订单,下单。

买家维度的事务,在接口界说上,第一个参数有必要是buyerId,由于要进行路由。用户的恳求已经依据规矩进行分流到不同的机房,只会操作对应机房里边的数据库。

看完这篇异地多活的改造,我决定和架构师battle一下

3.2.3 中心单元服务

中心单元服务也便是说这个服务里边既有中心的接口也有单元的接口。而且数据库也是有两套。所以这种服务其实也是要在两个机房一同布置的,只不过是单元机房只会有单元接口过来的流量,中心接口是没有流量的。

一些底层的支撑事务,比方产品,商家这些就归于中心单元服务。支撑维度的事务是没有buyerId的,产品是通用的,并不归于某一个买家。

而支撑类型的事务底层的数据库是中心单元库,也便是中心写单元读,写恳求是在中心进行,比方产品的创立,修正等。操作后会同步到另一个机房的数据库里边。这样的优点便是能够减少咱们在中心链路中的耗时,假如产品不做单元化布置,那么阅览产品或者下单的时分查询产品信息都有必要走中心机房进行读取。而现在则会就近路由进行接口的调用,恳求到中心机房就调中心机房的服务,恳求到单元机房就调单元机房的服务,单元机房也是有数据库的,不需求跨机房。

看完这篇异地多活的改造,我决定和架构师battle一下

从久远考虑,仍是需求进行拆分,把中心的事务和单元的事务拆开,这样会比较清晰。关于后边新同学在界说接口,操作数据库,缓存等都有优点,由于现在是混合在一同的,你有必要要知道当时这个接口的事务归于单元仍是中心。

拆分也不是肯定的,仍是那句话得从事务场景动身。像订单里边的买家和卖家的事务,我觉得能够拆分,后续保护也比较便利。可是像产品这种,并不存在两种角色,便是产品,对产品的增删改成在一个项目中也便利保护,只不过是要进行接口的分类,将新增,修正,删去的接口符号为中心。

4. 切流计划

前面咱们也说到了再切流过程中,会禁写,会仿制MQ的音讯到另一个机房从头消费。接下来给咱们介绍下咱们的切流计划,能够协助咱们更深刻的了解整个多活的反常场景下处理流程。

看完这篇异地多活的改造,我决定和架构师battle一下

(1)下发禁写规矩 当需求切流的时分,操作人员会经过双活操控中心的后台进行操作。切流之前需求先进行已有流量的整理,需求下发禁写规矩。禁写规矩会下发到中心和单元两个机房对应的装备中心里边,经过装备中心去告知需求监听的程序。

(2)彩虹桥履行禁写逻辑 彩虹桥会用到禁写规矩,当禁写规矩在装备中心修正后,彩虹桥能立马感知到,然后会依据SQL中带着的shardingkey进行规矩的判别,看当时shardingkey是否归于这个机房,假如不归于则进行阻拦。

(3)反应禁写收效成果 当装备改变后会推送到彩虹桥,装备中心会感知到装备推送的成果,然后将收效的成果反应给双活操控中心。

(4)推送禁写收效时刻给Otter 双活操控中心收到一切的反应后,会将悉数收效的时刻点经过MQ音讯告知Otter。

(5)Otter进行数据同步 Otter收到音讯会依据时刻点进行数据同步。

(6)Otter同步完结反应同步成果 收效时刻点之前的数据悉数同步完结后会经过MQ音讯反应给双活操控中心。

(7)下发最新流量规矩 双活中心收到Otter的同步完结的反应音讯后,会下发流量规矩,流量规矩会下发到DLB,RPC,彩虹桥。

后续用户的恳求就会直接被路由到正确的机房。

5. 总结

信任咱们看了这篇文章,对多活的改造应该有了一定的了解。当然本篇文章并没有把一切多活相关的改造都解说清楚,由于整个改造的范围实在是太大了。本篇首要讲的是中间件层面和事务层面的一些改造点和过程,一同还有其他的一些点都没有说到。比方:机房网络的建造、发布体系支撑多机房、监控体系支撑多机房的整个链路监控,数据巡检的监控等等。

多活是一个高可用的容灾手法,但完结的本钱和对技能团队的要求十分高。在完结多活的时分,咱们应该结合事务场景去进行规划,不是一切体系,一切功能都要满意多活的条件,也没有100%的可用性,有的只是在极端场景下对事务的一些取舍算了,优先确保中心功能。

以上便是咱们在多活改造中的一些经验,共享出来希望能够对正在阅览的你有一些协助。

文/ 尹吉欢

看完这篇异地多活的改造,我决定和架构师battle一下

线下活动引荐: 得物技能沙龙「企业协作功率演进之路」(总第 19 期)

时刻:2023 年 7 月 16 日 14:00 ~ 2023 年 7 月 16 日 18:00

地点:(上海杨浦)黄兴路 221 号互联宝地 C 栋 5 楼 (宁国路地铁站 1 号口出)

活动亮点:在当今竞赛日益剧烈的商业环境中,企业协作功率成为企业团队成功的要害。越来越多的企业意识到,经过信息化建造和工具化的支撑,能够大幅提高协作功率,并在职业中获得打破。本次沙龙将包括多个主题,这些主题将为与会者供给丰富的思考和经验,助力企业协作功率的提高。

经过得物技能沙龙这个交流平台,您将有机会与其他企业的代表一同学习、学习彼此的经验和做法。共同讨论企业内部协作功率的最佳实践,驱动企业长时间生计和开展。参加得物技能沙龙,与职业先驱者们一同开启协作功率的新篇章!让咱们共同为协作功率的打破而努力!

点击报名:[得物技能沙龙「企业协作功率演进之路」(总第 19 期)]本文属得物技能原创,来源于:[得物技能官网 )](tech.dewu.com/)

未经得物技能许可禁止转载,不然依法追究法律责任! 作者:得物技能链接:tech.dewu.com/article?id=…