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

4次阅读

共计 11253 个字符,预计需要花费 29 分钟才能阅读完成。

1. 简述

异地多活的概念以及为什么要做异地多活这里就不进行概述了。概念性的很多,像什么同城双活、两地三核心、三地五核心等等概念。如果有对这些容灾架构模式感兴趣的能够浏览下这篇文章进行理解:《浅谈业务级灾备的架构模式》。

浏览本篇文章之前,咱们先明确一下背景,这样大家后续在看的时候就不会产生困惑。

1.1 机房划分

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

A 机房咱们定义为核心机房,也就是多活上线之前正在应用的机房。如果说到核心机房那指的就是 A 机房。另一个 B 机房,在形容的时候可能会说成单元机房,那指的就是 B 机房。

1.2 单元化

单元化简略点咱们间接就能够认为是一个机房,在这个单元内可能实现业务的闭环。比如说用户进入 APP,浏览商品,抉择商品确认订单,下单,领取,查看订单信息,这整个流程都在一个单元中可能实现,并且数据也是存储在这个单元外面。

做单元化无非就两个起因,容灾和进步零碎并发能力。然而也得思考机房建设的规模和技术,硬件等投入的老本。具体的就不多讲了,大家大略了解了就行。

2. 革新点

理解革新点之前咱们先来看下目前单机房的现状是什么样子,能力更好地帮忙大家去了解为什么要做这些革新。

如上图所示,客户端的申请进来会先到 SLB(负载平衡),而后到咱们外部的网关,通过网关再散发到具体的业务服务。业务服务会依赖 Redis、Mysql、MQ、Nacos 等中间件。

既然做异地多活,那么必然是在不同地区有不同的机房,比方核心机房,单元机房。所以咱们要实现的成果如下图所示:

大家看下面这张图可能会感觉很简略,其实也就是一些罕用的中间件,再多一个机房部署罢了,这有什么难度。如果你这样想我只能说一句:格局小了啊

::: hljs-center

2.1 流量调度

:::
用户的申请,从客户端收回,这个用户的申请该到哪个机房,这是咱们要革新的第一个点。

没做多活之前,域名会解析到一个机房内,做了多活后,域名会随机解析到不同的机房中。如果依照这种随机的形式是必定有问题的,对于服务的调用是无所谓的,因为没有状态。然而服务外部依赖的存储是有状态的呀。

咱们是电商业务,用户在核心机房下了一个单,而后跳转到订单详情,这个时候申请到了单元机房,底层数据同步有提早,一拜访报个错:订单不存在。用户当场就懵了,钱都付了,订单没了。

所以针对同一个用户,尽可能在一个机房内实现业务闭环。为了解决流量调度的问题,咱们基于 OpenResty 二次开发出了 DLB 流量网关,DLB 会对接多活控制中心,可能晓得以后拜访的用户是属于哪个机房,如果用户不属于以后机房,DLB 会间接将申请路由到该用户所属机房内的 DLB。

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

如果用户以后拜访的机房挂了,客户端须要降级成之前的域名拜访形式,通过 DNS 解析到存活的机房。
::: hljs-center

2.2 RPC 框架

:::

当用户的申请达到了单元机房内,实践上后续所有的操作都是在单元机房实现。后面咱们也提到了,用户的申请尽量在一个机房内实现闭环,只是尽量,没有说全副。

这是因为有的业务场景不适宜划分单元,比方库存扣减。所以在咱们的划分外面,有一个机房是核心机房,那些不做多活的业务只会部署在核心机房外面,那么库存扣减的时候就须要跨机房调用。

申请在核心机房,怎么晓得单元机房的服务信息?所以咱们的注册核心(Nacos)要做双向同步,这样能力拿到所有机房的服务信息。

当咱们的注册信息采纳双向复制后,对于核心服务,间接跨机房调用。对于单元服务会存在多个机房的服务信息,如果不进行管制,则会呈现调用其余机房的状况,所以 RPC 框架要进行革新。

2.2.1 定义路由类型

(1)默认路由
申请到核心机房,会优先调用核心机房内的服务,如果核心机房无此服务,则调用单元机房的服务,如果单元机房没有此服务则间接报错。

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

(3)核心路由
申请到单元机房,那么间接调用核心机房的服务,核心机房没有服务则报错。申请到核心机房,那么就本机房调用。

2.2.2 业务革新

业务方须要对本人的接口(Java interface)进行标记是什么类型,通过 @HARoute 加在接口下面。标记实现后,在 Dubbo 接口进行注册的时候,会把路由类型放入到这个接口的元数据外面,在 Nacos 后盾能够查看。前面通过 RPC 调用接口外部所有的办法都会依照标记类型进行路由。

如果标记为单元路由,目前咱们外部的标准是办法的第一个参数为小写的 long buyerId,RPC 在路由的时候会依据这个值判断用户所在的机房。

路由逻辑如下:

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 分片,如丝般顺滑的安稳迁徙》,外面有实现形式。

2.3.2 分布式 ID

单元化的库,数据层面会做双向同步复制操作。如果间接用表的自增 ID 则会呈现上面的抵触问题:

这个问题能够通过设置不同机房有不同的自增步长来解决,比方核心机房的自增步长为奇数,单元机房的自增步长为偶数。但比拟麻烦,后续可能会减少更多的机房。咱们采纳了一种一劳永逸的形式,接入全局惟一的分布式 ID 来防止主键的抵触。

2.3.2.1 客户端接入

目前,接入分布式 ID 有两种形式,一种是利用内通过基础架构提供的 jar 包接入,具体逻辑如下:

2.3.2.2 彩虹桥接入

另一种就是在彩虹桥中对具体的表配置 ID 的生成形式,反对对接分布式 ID 服务。

2.3.3 业务革新

2.3.3.1 单元化库写申请必须携带 ShardingKey

在 Dao 层对表进行操作的时候,会通过 ThreadLocal 设置以后办法的 ShardingKey,而后通过 Mybatis 拦截器机制,将 ShardingKey 通过 Hint 的形式放入 SQL 中,带给彩虹桥。彩虹桥会判断以后的 ShardingKey 是否属于以后机房,如果不是间接禁写报错。

这里跟大家简略的阐明下为什么切流过程中要禁写,这个其实跟 JVM 的垃圾回收有点类似。如果不对操作禁写,那么就会一直的产生数据,而咱们切流,肯定要保障以后机房的数据全副同步过来了之后才开始失效流量规定,否则用户切到另一个机房,数据没同步完,就会产生业务问题。除了彩虹桥会禁写,RPC 框架外部也会依据流量规定进行阻断。

2.3.3.2 数据库连贯指定连贯模式

连贯模式的定义有两种,别离是核心和单元。

如果利用的数据源指定了连贯模式为核心,那么在核心机房能够失常初始化数据源。在单元机房不会初始化数据源。

如果利用的数据源指定了连贯模式为单元,那么在核心机房和单元机房都能够失常初始化数据源。

这里解释下为什么要有连贯模式这个设计?

在咱们的我的项目中,会呈现同时连贯 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 来实现所有机房的缓存生效。

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 中,至于另一个机房的消费者要不要生产,这就要让业务场景去决定。

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 音讯幂等生产

这个点其实依据多活没有多大关系,就算不做多活,音讯生产场景,必定是要做幂等解决的,因为音讯自身就有重试机制。独自拎进去说是因为在多活场景下除了音讯自身的重试会导致音讯反复生产,另外在切流的过程中,属于切流这部分用户的音讯会被复制到另一个机房从新进行生产,在从新生产的时候,会基于工夫点进行音讯的从新投放,所以有可能会生产到之前曾经生产了的音讯,这点必须留神。

再解释下为什么切流过程中会有音讯生产失败以及须要复制到另一个机房去解决,如下图所示:

用户在以后机房进行业务操作后,会产生音讯。因为是单元订阅,所以会在以后机房进行生产。生产过程中,产生了切流操作,生产逻辑外面对数据库进行读写,然而单元表的操作都携带了 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 注册一个超时工作,指定某个工夫点,你要回调我。在回调的逻辑逻辑里去判断订单是否已实现领取,如果没有则勾销。

2.7.1 业务革新

2.7.1.1 工作注册调整

在注册超时核心工作的时候,业务方须要辨认工作是否要合乎单元化的规范。如果此工作只是对核心数据库进行操作,那么这个工作回调在核心机房即可。如果此工作是对单元数据库操作,那么在注册工作的时候就须要指定 buyerId,超时核心在触发回调的时候会依据 buyerId 进行路由到用户所属机房进行解决。

目前超时核心是只会在核心机房进行部署,也就是所有的工作都会在核心机房进行调度。如果工作注册的时候没有指定 buyerId,超时核心在回调的时候就不晓得要回调哪个机房,默认回调核心机房。要想让超时核心依据多活的路由规定进行回调,那么注册的时候必须指定 buyerId。

3. 服务划分

浏览完下面的革新内容,置信大家还有一个纳闷点就是我的服务该怎么划分呢?我要不要做单元化呢?

3.1 整体方向

首先要依据整个多活的一个整体指标和方向去梳理,比方咱们的整体方向就是买家交易的外围链路必须实现单元化革新。那么这整个链路所有依赖的上下游都须要革新。

用户浏览商品,进入确认订单,下单,领取,查问订单信息。这个外围链路其实波及到了很多的业务域,比方:商品,出价,订单,领取,商家等等。

在这些曾经明确了的业务域上面,可能还有一些其余的业务域在撑持着,所以要把整体的链路都梳理进去,一起革新。当然也不是所有的都必须做单元化,还是得看业务场景,比方库存,必定是在交易外围链路上,然而不须要革新,必须走核心。

3.2 服务类型

3.2.1 核心服务

核心服务只会在核心机房部署,并且数据库也肯定是核心库。能够对整个利用进行打标成核心,这样内部拜访这个服务的接口时都会被路由到核心机房。

3.2.2 单元服务

单元服务会在核心机房和单元机房同时部署,并且数据库也肯定是单元库。单元服务是买家维度的业务,比方确认订单,下单。

买家维度的业务,在接口定义上,第一个参数必须是 buyerId,因为要进行路由。用户的申请曾经依据规定进行分流到不同的机房,只会操作对应机房外面的数据库。

3.2.3 核心单元服务

核心单元服务也就是说这个服务外面既有核心的接口也有单元的接口。并且数据库也是有两套。所以这种服务其实也是要在两个机房同时部署的,只不过是单元机房只会有单元接口过去的流量,核心接口是没有流量的。

一些底层的撑持业务,比方商品,商家这些就属于核心单元服务。撑持维度的业务是没有 buyerId 的,商品是通用的,并不属于某一个买家。

而撑持类型的业务底层的数据库是核心单元库,也就是核心写单元读,写申请是在核心进行,比方商品的创立,批改等。操作后会同步到另一个机房的数据库外面。这样的益处就是能够缩小咱们在外围链路中的耗时,如果商品不做单元化部署,那么浏览商品或者下单的时候查问商品信息都必须走核心机房进行读取。而当初则会就近路由进行接口的调用,申请到核心机房就调核心机房的服务,申请到单元机房就调单元机房的服务,单元机房也是有数据库的,不须要跨机房。

从久远思考,还是须要进行拆分,把核心的业务和单元的业务拆开,这样会比拟清晰。对于前面新同学在定义接口,操作数据库,缓存等都有益处,因为当初是混合在一起的,你必须要晓得以后这个接口的业务属于单元还是核心。

拆分也不是相对的,还是那句话得从业务场景登程。像订单外面的买家和卖家的业务,我感觉能够拆分,后续保护也比拟不便。然而像商品这种,并不存在两种角色,就是商品,对商品的增删改成在一个我的项目中也不便保护,只不过是要进行接口的分类,将新增,批改,删除的接口标记为核心。

4. 切流计划

后面咱们也提到了再切流过程中,会禁写,会复制 MQ 的音讯到另一个机房从新生产。接下来给大家介绍下咱们的切流计划,可能帮忙大家更粗浅的了解整个多活的异样场景下解决流程。

(1)下发禁写规定
当须要切流的时候,操作人员会通过双活控制中心的后盾进行操作。切流之前须要先进行已有流量的清理,须要下发禁写规定。禁写规定会下发到核心和单元两个机房对应的配置核心外面,通过配置核心去告诉须要监听的程序。

(2)彩虹桥执行禁写逻辑
彩虹桥会用到禁写规定,当禁写规定在配置核心批改后,彩虹桥能立马感知到,而后会依据 SQL 中携带的 shardingkey 进行规定的判断,看以后 shardingkey 是否属于这个机房,如果不属于则进行拦挡。

(3)反馈禁写失效后果
当配置变更后会推送到彩虹桥,配置核心会感知到配置推送的后果,而后将失效的后果反馈给双活控制中心。

(4)推送禁写失效工夫给 Otter
双活控制中心收到所有的反馈后,会将全副失效的工夫点通过 MQ 音讯通知 Otter。

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

(6)Otter 同步实现反馈同步后果
失效工夫点之前的数据全副同步实现后会通过 MQ 音讯反馈给双活控制中心。

(7)下发最新流量规定
双活核心收到 Otter 的同步实现的反馈音讯后,会下发流量规定,流量规定会下发到 DLB,RPC, 彩虹桥。

后续用户的申请就会间接被路由到正确的机房。

5. 总结

置信大家看了这篇文章,对多活的革新应该有了肯定的理解。当然本篇文章并没有把所有多活相干的革新都解释分明,因为整个革新的范畴切实是太大了。本篇次要讲的是中间件层面和业务层面的一些革新点和过程,同时还有其余的一些点都没有提到。比方:机房网络的建设、公布零碎反对多机房、监控零碎反对多机房的整个链路监控,数据巡检的监控等等。

多活是一个高可用的容灾伎俩,但实现的老本和对技术团队的要求十分高。在实现多活的时候,咱们应该联合业务场景去进行设计,不是所有零碎,所有性能都要满足多活的条件,也没有 100% 的可用性,有的只是在极其场景下对业务的一些取舍罢了,优先保障外围性能。

以上就是咱们在多活革新中的一些教训,分享进去心愿能够对正在浏览的你有一些帮忙。

文 / 尹吉欢


线下流动举荐 :得物技术沙龙「企业合作效率演进之路」(总第 19 期)
工夫 :2023 年 7 月 16 日 14:00 ~ 2023 年 7 月 16 日 18:00
地点:(上海杨浦)黄兴路 221 号互联宝地 C 栋 5 楼 (宁国路地铁站 1 号口出)

流动亮点:在当今竞争日益强烈的商业环境中,企业合作效率成为企业团队胜利的要害。越来越多的企业意识到,通过信息化建设和工具化的反对,能够大幅晋升合作效率,并在行业中获得冲破。本次沙龙将涵盖多个主题,这些主题将为与会者提供丰盛的思考和教训,助力企业合作效率的晋升。通过得物技术沙龙这个交流平台,您将有机会与其余企业的代表一起学习、借鉴彼此的教训和做法。独特探讨企业外部合作效率的最佳实际,驱动企业长期生存和倒退。退出得物技术沙龙,与行业先驱者们一起开启合作效率的新篇章!让咱们独特为合作效率的冲破而致力!

点击报名:[得物技术沙龙「企业合作效率演进之路」(总第 19 期)
本文属得物技术原创,来源于:[得物技术官网]
未经得物技术许可严禁转载,否则依法追究法律责任!

正文完
 0