单元化架构基本设计
关于架构分层的一些显著定义
Access Layer
- 面向 App 客户端公网访问。
Computing Layer
- 内网所有无状态的计算模块集合
Storage Layer
- 所有存储的集合
关于单元化的一些显著定义
单元(Set)
- 单元的划分可以是任何维度,比如电商对的买家用户维度。
- 单元对的划分粒度使用 Mapping 手段,可以根据需求做到任何粒度,比如单个买家用户的粒度。
- 对于 Access Layer,Computing Layer,Storage Layer,同个单元内不允许出现任何单元性质的流量调度。
本地服务/本地数据(Local service/Local data)
本地服务包含单元内闭环的无状态服务,也包含一些服务于本地数据的 DAL 服务。
本地数据最显著的特征是所有涉及 Storage 的 Write 操作都发生在当前单元所包含的 Storage Layer。
中心服务/中心数据(Global service/Global datat)
中心服务一般包含但是不限于一些中心中心数据的 DAL 服务。
中心数据最显著的特征是所有涉及 Storage 的 Write 操作都发生在目标归属单元所包含的 Storage Layer。
One Region One Set
现状
水平扩展性
- Access Layer 和 computing Layer 随 VDC 建设很容易水平扩展
- Storage Layer 无法水平扩展,容量上限取决于最小 VDC 的容量。
容灾
- Access Layer 使用 DNS 完成流量转移,有 automatic failover 能力
- computing Layer 目前仍然采取人工切流?暂时处于 manual failover 的状态
- Storage Layer 以 RDS 为例,master 需要人工切换,且存在切换后的数据不一致问题,实际切换流程和事后处理繁琐
存储成本
- 以 RDS 为例,随着 VDC 的扩充建设,数据冗余程度越来越高,利用率越来越低。
访问亲和性
- Access Layer 和 computing Layer 很容易做到同 VDC 访问,并且 VDC 级别的整体宕机,流量转移后仍可保持。
- 由于数据在所有 VDC 内冗余,Storage Layer 弱一致性读请求,也容易做到同 VDC 访问,强一致性读和写请求组则无法完全保证同 VDC。
理想架构
水平扩展性
- Access Layer 和 Computing Layer 随 VDC 建设很容易水平扩展。
- Storage Layer 无法水平扩展,容量上限取决于最小 VDC 容量。
容灾
- Access Layer 使用 DNS + 多层代理等一系列方式完成流量转移,有 automatic failover 的能力。
- Computing Layer 使用自动熔断技术达到 automatic failover。
- Storage Layer 以 RDS 为例,构建三个 VDC 的 HA 组,HA 组内使用拨测故障发现/MGR/自研 Paxos/Raft 技术达到读写 automatic failover,其余多处的 VDC 为 Learner 角色,只提供只读服务。
存储成本
- 以 RDS 为例,随着 VDC 的扩充建设,数据冗余程度越来越高,利用率越来越低。
访问亲和性
- Access Layer 和 Computing Layer 很容易做到同 VDC 访问,并且 VDC 级别的整体宕机,流量转移后仍可保持。
- 由于数据在所有 VDC 内冗余,Storage Layer 弱一致性请求,也很容易做到同 VDC 访问,强一致性读和写请求则无法完全保证同 VDC。
Storage Layer 水平扩展和成本问题
- 3 的整数倍 VDC 机房条件下(如3,6,9...),Storage Layer 水平扩展较为容易,以 3 VDC 为单位进行数据再次分片即可。
- 非 3 的整数倍 VDC 的机房条件下(如5,7....),Storage Layer 的水平扩展较为复杂,但如果为了追求极致的成本,可以采用完美 sharing 方案,如下图。
架构优点
维护成本低
- 由于一个物理 Region 内只有一个单元,所以单元的元信息只需要到 Region 维度即可,而 Region 下的 VDC、 VAU 的部署信息只需要跟随公司建设,单元化架构内无需感知。
- 由于同单元内不出现任何单元化架构下的流量调度,一个 Region 下的流量拓扑只需要继承现有形式。
容灾简洁
- 无论是 Computing Layer 还是 Storage Layer 的容灾,由于没有引入单元化架构的负担,可以很方便的跟随业界最近简洁优雅的思路去迭代建设,从而有希望达到最高级的全自动容灾的理想状态。
架构缺点
对机房建设要求高
- 5 VDC 比 6 VDC 的部署难度高,不对等资源的 VDC 比对等资源的 VDC 情况部署难度高。
- 如果想追求极致成本,在机房条件不好的情况下尝试完美 sharding,资源的部署和管理复杂度大幅提升。
Region 内很难人为的调度流量
- 以电商大促为例,如有同 Region 内临时性的 VDC 建设或者流量调度。
一些对比方案的思考
One Region Multiple Set
- 部分解决了对机房建设的要求问题,但在机房资源不对等的,非 3 整数倍机房条件下,如果追求极致成本,单元的划分仍然非常困难。
- 放弃部分同单元内的容灾,可以采取不对等的单元划分方法,如 5 VDC 划分为 3/2 或者3/1/1,也就是同 Region 内即出现了 3 VDC 的容灾,同时有基于单元化流量调度的容灾,网络拓扑很复杂。
- 基于同单元的封闭性,Write 操作只落在单元的 Storage Layer,也就是说同 Region 内,有大量的并行写入,其产生的数据双向/多向同步问题,进一步导致数据的一致性问题,在同 Region 下高度耦合的流量拓扑环境会得到极大的放大。
- Region 内划分单元,给单元化机构本身带来了极大的管理成本,这些划分得到元信息,单元化架构都必须感知。
one VDC one Set(一个特例)
- 解决了对机房建设的要求问题。
- 解决了一些水平扩展难的问题。
- 通过单元化的流量调度去完成容灾,大幅牺牲了容灾的简洁性,同时削弱了容灾的健壮性,不符合业界主流思想,代价过高(6.2详解)。
Multiple Region Multiple Set
架构演进阶段一(达到流量可调度的状态)
全量数据跨 Region 同步
- Local Data 单元内本地写入,双向数据同步,提供数据最终一致性(双向数据同步没有完备的一致性解决方案,只能通过 LWW 和后置性的数据校验达到最终一致性)。
- 本单元写入的数据提供本地强一致读。
- 跨单元流动过来的数据提供本地弱一致性读。
- Global Data 可能跨 Region 回源写入,延迟高,单向数据同步,提供数据最终一致性。
- 跨单元回源读取数据提供强一致性读,延迟高。(取决于同城多机房的存储容灾建设情况)
- 本地体提供弱一致性读。
- 由于数据全量同步,可能无法支持一些小机房单元化部署。
流量调度
流量调度除了最基本的修改 Mapping 或下发规则之外,还需要解决数据一致性问题,从而引出很多其他步骤,这里不展开。
- 提供跨单元,也就是跨 Region 的流量调度能力,比如将 Set 1 部分用户调度到 Set 2。
- 可通过修改单元 Mapping 做到极细粒度的调度,比如调度几个用户,只需要修改这几个用户的 Mapping 数据,或者通过一定的二次 Mapping 规则,调度大规模用户,比如某个号段的用户将 Set 1 Mapping 为 Set 2。
架构演进阶段二(达到数据按需同步达到状态)
面向 Storage Layer 改造
基于在线统计的方式预估数据流向。无业务侵入,但解决难度非常大,面临统计空间,性能,统计准确度等问题,做不好可能会退化为全同步。
面向 Computing Layer 改造
基于明确的业务进行准确的数据流向判定。业务侵入大,解决难度随业务复杂增大,面临搭建业务层数据同步通道,业务改造健壮性等问题,由于业务改造大,做不好可能会导致数据灾难。
架构演进阶段三(Region 物理距离 < 2000KM 下达到 Global Data 可容灾)
国内多 Region 满足 < 2000KM,适合迭代到此架构。国外如新加坡到美国物理距离过长,则不适合。
构建跨 Region 的强一致性数据库
- Global Data 剥离出来逻辑上不存在于任何一个单元,以 RDS 为例,采用 MGR 或者自研 Paxos 同步协议进行 3 Region 部署,使得达到 Region 级别的高可用。
- 参与一致性协议的 3 个节点存储全量数据,Leader 节点提供强一致性读写,延迟高,非 Leader 节点提供弱一致性读,通过亲和性优先同 Region 读取,延迟低。
- 一些小 Region 可作为 Learner 节点,存储全量数据,提供弱一致性读。如构建按需同步能力,Learner 节点可进一步优化为存储部分数据。
Local Data 去单元化
- 如业务能接受较高的写延迟(mean 100ms-200ms),从而将 Global Data 的构建方式同时应用于 Local Data,那 Storage Layer 将彻底从单元化剥离,提供多 Region 一致的数据库读写体验。
提供低延迟的强一致性读
建设原子钟,提供 TrueTime 能力,从而能提供本地的强一致读,对于 RDS 来说,等于做了一个 F1 + Spanner。
数据存放的合规问题
以上单元化架构解决不了合规问题,因为没有精确的对用户数据进行切分存放,即使构建了按需同步的能力,对于合规要求来说也是不足够的或者无法证明的。
合规需要解决的问题
数据切分
- 合规问题一般存在于跨国,往往物理距离 > 2000KM,一般解决合规问题要求我们把用户的数据根据国家维度来进行切分,所以基本可以人为是 Region 级别的单元划分,不需要考虑 Region 内的单元化。
- 如何切分数据,是一个业务比较强相关的问题,需要逐个击破。
跨单元数据按需流动
- 由于数据进行了单元化切分,并且由于单元化的封闭性(参考附录6.2),那么必然存在一些数据根据需要进行跨单元流动。比如 A 单元用户给 B 单元用户转账,那么封闭性决定 A 单元用户只能写 A 单元的 Storage Layer,这个数据如何流动到 B 单元的 Storage Layer 是一个难题,目前暂时没有在 Storage Layer 能解决的业界经验,而在 Computing Layer 去解决,将带来成倍的业务复杂度。
- 跨单元数据按需流动还存在数据的一致性问题,也需要细致的解决。
合规单元化建设分两步走
阶段一:牺牲单元化的封闭性
- 由于跨单元数据按需流动的复杂性,我们在建设合规单元化的时候,可以考虑先牺牲封闭性,也就是直接进行跨单元写数据。
- 跨单元在合规问题上往往意味着跨 Region,并且是分布在两个国家的 Region,跨单元写入的延迟问题需要考虑。
阶段二:找回单元化的封闭性
- 构建跨单元数据按需流动,一个比较漫长的过程。
一些推导思路和设计原则
为何单元化要强调封闭性
回看 2.1 的单元定义,单元最显著的特征就是所有 Write 操作都发生在当前单元所包含的 Storage Layer,这就是显著的封闭性定义,这里探讨一个问题,这个特性是怎么推导出来的?当我们去建设一个没有这个特性的单元化架构,是有意义的吗?
单元化最核心的需求
同城 VDC 的水平扩展
当同城 VDC 不断扩展,且 VDC 之间的通信专线带宽较小,无法容纳巨量的跨 VDC 请求,我们希望将各自 VDC 的请求都最大化的落在同 VDC,从而减少 VDC 之间通信的带宽压力,从而引出单元化建设,以及本地单元的封闭性。
但解决这个问题其实存在更好的方法,比如有条件的情况下提升一下通信专线的带宽,那么问题自然迎刃而解。
异地 VDC 的水平扩展
当 VDC 的建设扩展到异地的时候,VDC 之间的通信问题存在一个巨大的拦路虎,那就是延迟,这个是物理距离决定的,没有任何方法可以改进。此时必须想尽一切办法减少跨 VDC 之间的通信,从而引出单元化建设,并推导出单元化封闭性的必要性。
对于一些写延迟容忍极高,读多写少且读写比巨大,对一致性要求不高的业务,即使需要进行异地 VDC 的水平扩展,也未必需要进行单元化建设。
失去封闭性的单元化等于没有单元化
观察以上两个架构,都是解决水平扩展问题,左边使用的是 Tradition sharding 方法啊解决,右边使用单元化架构解决。
当我们在同城多 VDC 内通信带宽容量足够的情况下,显而易见的是左边 Tradition sharding 方法在水平扩展上取得更好啊的效果,而完全没必要采用右边的单元化架构,接下来分析一下两种架构的优缺点。
Tradition sharding
- 优点:Access Layer 和 Computing Layer 没有引入新概念,无需任何改动,存储层进行数据 sharding,按容灾要求构建 Replication,对业务层完全透明。Access Layer 和 Computing Layer 都很容易达到 automatic failover 的状态, Storage Layer随着各个存储组件的技术迭代,也能在不远的未来达到 automatic failover 的目标。
- 缺点:由于允许跨 VDC 的调用,跨 VDC 通信带宽要求高。
Set Architecture
- 优点:单元的封闭性使得跨 VDC 的调用极少(存在少量往中心服务的流量),对跨 VDC 通信带宽要求比较低,另外单元化通过时解决了 Storage Layer 的数据 sharding 问题。
- 缺点:由于单元之间的流量调度没有完备的 automatic failover 方案(数据双向流动导致的不一致性问题所致),目前一般采用人工切流的方法,等于在 Access Layer ,Computing Layer ,Storage Layer 都丧失了 automatic failover 的能力。
单元化的切流能力不能替代常态性的容灾
建设单元化架构后,不同单元之间的流量调度,一定程度上能作为容灾能力的补充,但仅仅是补充,不能期望去完全替代当前常态化的容灾体系建设。
单元化对容灾能力有一定的补充
- 异地 VDC 容灾:当异地整个 Region 宕机后,可通过单元化切流的方式将流量调度到其他正常的 Region。
- 没有同城容灾条件的 VDC 容灾:一些小 Region 只有一个 VDC,当这个 VDC 宕机后,可通过单元化切流的方式完成容灾。
常态性的容灾必须做到 automatic
- Region 整体宕机,概率极低,不是常态性。
- VDC 整体宕机,概率也不高,此时不建设成 automatic,而采用单元化切流的方式,也不是不可容忍。
- VDC 内网波动,VDC 部分宕机,VDC 之间的专线故障等,概率高,必须有常态性的容灾方式去应对,通过单元化切流的方式,是不可接受也是不合适的,必须有 automatic 的能力或者有这个建设目标才行。
关键点设计
跨单元存储数据双向同步
由于单元的封闭性,不同单元的写入都落在所属单元,也就是对于一个存储模块来说,在不同单元的写入是并行的,而每个写入的数据都要同步到其他单元,这就引出不同单元间数据双向同步的问题。
Sql 新增数据
以 RDS 为例,新增数据就是 Insert,数据双向同步,如果没有进行特殊处理,则两边 Insert 生成的自增 ID 可能会冲突,导致不可预期的问题。
RDS 的行数据可能存在因果性,需要解决因果一致性问题。
自定义 RDS ID 生成算法
基于 Logic Clock (Vector Clock)算法生成 ID,并针对单元化做特殊设计。
朴素 Logic Clock 自增 ID 生成算法
Logic Clock 算法解决并行时间线上的局部因果一致性问题。
- 每个 Set 的 ID 增长分配一个固定 Step,一般 >= Set_size。
- 当没有数据同步的发生,各自 Set 的时间线遵循这个 Step 进行 ID 自增,如 Set 2 为 2,5,8,11... 的自增序列。
- 当没有数据同步的发生,说明因果性只各自存在于各个 Set 自身,ID 的自增单调性满足因果一致性。
- 当存在数据同步的发生,因果性则跨 Set 存在,如上图的 Set 1 的 7 同步到了 Set 2,虽然当前 Set 2 的自增 ID 只到 2,但如果此时自增的下一个 ID 为 5, 5 < 7 ,则破坏了因果一致性,所以给予 Vector Clock 算法啊,此时的 5 则直接丢弃,下一个 ID 应该是自增 ID 系列里面的第一个 > 7 的 ID,即为 8。
这个朴素算法虽然能解决自增 ID 的冲突问题,但实际在生产环境,还存在很多工程问题,比如 Step 的灵活性配置,比如由于 ID 自增算法移到了数据库事务之外,对于同一个 Set 内,会很大概率产生乐观冲突问题,即同一时刻产生相同的 ID。
需要基于朴素算法,进一步设计满足工程化要求的单元化自增 ID 生成算法。
单元化自增 ID 生成算法
该算法解决了数据双向同步产生的冲突问题,并且 ID 的生成算法不依赖第三方远程服务,同时满足因果一致性。
该算法每次生成 ID 依赖对数据当前最大的 ID 的查询,性能较差,但应该能接受。
- Clock_id 代表时钟,Clock_id 每次前进步长为 1,以当前 Set 所见的最大 Clock_id 为基准。即 New_clock_id = (clock_id@max_id) + 1。由于跨 Set 同步发生,clock_id 可能发生跳跃而保证因果一致性。
- 以 Set_id 替代 vector clock 算法里的 Step,保证每个 Set 生成的 ID 不会冲突。
- 16 位的 Random_num 解决同 Set 内分配 ID 的冲突问题,是的乐观锁发生概率极低,可忽略不计。
- 4 位的预留信息,可用于自校验,校验这个 ID 的生成是否正确。
NoSql 新增数据
以 ByteKV 为例,ByteKV 的 Key 如何生成一般由业务指定,并且不同 Key 直接一般不存在因果性,即使由于,业务侧也必须感知并且有解决能力,所以 NoSql 数据库在新增数据上,一般不需要做特殊的增量设计。
更新数据
数据双向同步,目前没有或者说不存在解决一致性的完备方法,只能通过 LWW (Last-Write-Wins) 和配合后置性的数据校验,或者人肉指定最终版本(不建议),达到数据最终一致性。而 LWW 要求数据的每次更新必须有 Version 的概念,如何生成这个 Version?有两种典型方式。
- 使用本地系统时钟作为 Version:不同单元的时钟同步差异,时钟回拨,时钟扰动问题,都会带来数据的因果一致性问题,但其优点是获取本地时钟性能高且方便。
- 使用 Logic Clock 算法生成 Version:不依赖本地时钟系统,满足因果一致性。但有个致命的缺点是每次更新都必须读出当前版本,性能差,可能涉及较多业务改造。
删除数据
Deleted wins 满足最终一致性,删除状态永远是最终状态。
新增/更新/删除 混合操作
参考Conflict-free replicated data type细致解决。
Mapping
Mapping 解决了如何将业务信息转换为单元化架构需要理解的最核心的信息。
采用分层设计,最大化隔离业务和架构,最大化精简架构感知的信息,最大化减少架构内流通的信息。
业务可感知信息的定义
- Query feature vector:请求特征向量,包含一个请求多维度的特征,如 UID,Country 等业务可以理解和随着业务发展不断扩充的信息。
- QueryTarget feature vector:请求目标特征向量,一般指 PSM/Method 粒度的信息,如 Type 表示是否 Global Data 等业务可以理解的信息。
单元化架构可见可感知信息的定义
- Set_id: 每个请求都被明确归属到一个但愿啊,Set_id 是这个单元的全局唯一标识。
- Route_info:每个请求目标的单元化路由信息,包含所有部署单元,通过 Set_id 可找到对应单元的路由信息。(如一个 Region 只包含一个单元,那这个信息往往只有一个 Region 字段)
Multiple Mapping (业务信息和架构信息之间的桥梁)
Multiple Mapping 指多层映射,通过将 Query feature vector 映射到 Set_id 或 QueryTarget feature vector 映射到 Route_info,其中映射手段随着业务的发展不断迭代,同时根据不同的灵活性需求也需要设计不同的映射手段,根据不同的生效实时性也需要设计不同的映射手段。
经过 Mapping 后,单元化架构内不需要再感知 feature vector 之类的业务信息。
通过数据库存储进行 Mapping
数据库 Mapping 可以根据需求做到极细粒度。
- 比如为每个 UID 都在数据库记录好对应的 Set_id,每次查出来即可完成 Mapping。
- 比如为每个 PSM/Method 都在数据记录好对应的 Route_info,每次查出来即可完成 Mapping。
通过配置进行 Mapping
配置 Mapping 的粒度取决于规则设计,由于配置的规模限制,往往粒度较粗,但灵活性非常高。通过配置 Mapping,能实时完成非常灵活,复杂的请求 Set_id 变更,从而达到大规模流量调度的目标。
- 比如可以设计一个配置规则,当满足条件"UID mod 100 == 0 aand Country == CN" 的时候,Set_id 为 3。
一个例子
正确路由能力
关键路由信息的计算
在 Access Layer 计算 Set_id
- AGW 作为 Access Layer 的末端,Computing Layer 的前端,Query feature vector 充足,非常适用于计算 Set_id。
- 使用 AGW 的 Handler/Loader 能力,基于 Query feature vector 和 Mapping 配置计算出请求的归属 Set_id 并注入到 ByteTIM,理想情况下每个请求只需要计算一次,下游不再进行 Set_id 的计算。
- 如计算出来的 Set_id 非当前 AGW 所属单元,则进行请求重定向,或者将请求转发到相应正确的 AGW。
在 Mesh egress 计算 Route_info
- Mesh egress 作为当前 PSM 的末端,下游 PSM 的前端,有请求转发能力,需要在此处计算出下游 PSM 的归属单元,也就是 Query Target 的 Route_info。
- 可使用 Mesh 的 WASM 能力,基于 Query target feature vector 和 Mapping 配置计算出目标的 Route_info,从而判断该目标是否在本单元部署,或者目标单元属于 Global Data,需要转发请求到对应的单元。
在 PSM 服务 Server Handler 计算 PSM 服务的 Set_id
- Server handler 是该 PSM 所有请求最后的屏障,即使请求在 Client 端(也就是 Mesh egress)已经计算过路由,但由于 Client 的 Mapping 配置无法做到原子变更(7.3.2详解),导致 Client 端路由可能出错,只有加上服务端拦截才能保证最终正确性。
对于一些没有经过 Mesh 的流量,提供 SDK 进行 Routing
- 比如一些 mq 的 consumer 处理逻辑
Mapping 配置的安全变更
Mapping 配置与操作流量进行事务绑定
- 不能提供高度灵活性,发散性的 Mapping 配置变更能力,比如一次性变更了多个规则,涉及多个单元,或同时产生 Set_id 和 Route_info 的变更。
- 针对具体操作流程(如流量调度)进行变更事务的精细化设定,保证操作流程生效的正确性。
两阶段变更配置
阶段一:发布一个中间状态的配置,不进行流量调度,但是禁止写入操作。
阶段二:确认阶段一配置已经全网发布生效,发布最终路由配置,进行读写流量调度。
对于配置系统的要求
- 配置最终一致性要求,发布期间离线的节点重新上线后版本对齐。
- 发布状态观测要求,具备配置全网生效情况的观测。
- 配置多版本发布,回滚能力等。
如何禁写
- Access Layer 进行禁写。Computing Layer 禁写难度较大,管理成本也较大,缺少 Set_id 的计算信息。
防止路由死循环
- 不同单元因为配置的错误(不一定是人为导致,配置不一致性缺陷也可能导致)导致都互相认为需要调度到对方,最终导致流量调度的死循环,造成巨大的影响,必须要解决此问题。
- 一般可通过请求转发次数累加标记来避免此类问题,但由于 Go 语言的数据透传能力有缺陷,当标记丢失的时候,仍然可造成死循环。
流量调度(切流)
客户端上流量调度
主动调度
- 当 app/web 仍然能和 Access layer 通信的时候,Access layer 可以响应切流操作,则通过 Redirect 的方式主动通知端上进行调度。
- 当 app/web 已经无法和 Access Layer 通信且无法和边缘接入节点通信,则只能通过 DNS 或者自建 DNS 进行切换,但这个方法响应太慢,app 端有条件的话应该建设 automatic failover,即自动寻找其他单元进行接入。
服务端服务流量调度
- 一般进入 Access Layer 或 Computing Layer 的流量调度,只是用于引导各种原因错误流量,以及进行 Global Data 的读写调度。
Session 登录态问题
永久性流量调度
- 如将浙江用户调度到华东机房,并保持稳定。
- 调度特点:粒度细,缓慢
临时性流量调度
- 如华东机房整体性故障,应急响应紧急进行流量调度到华北,待故障恢复应该回切,临时性调度不应该持续过长时间。
- 调度特点:粒度粗,快速。
单元灾备
数据全量同步情况下,流量可直接调度到不同单元,可暂时不考虑单元灾备。
单元管理
- 新增 PSM 一般默认为 Global Data,当设置为 Local Data 的时候,需要进行细致的确认已经判断是否需要业务改造。
单元观测
- 建设整体的容灾观测大盘,提供面向业务和运维维度的看板。
讨论
一些问题
- 中台服务计算层和存储层都需要进行单元划分吗?计算层的 PSM 是否都已经做了 Cluster 级别的隔离部署,如果没有的话如何划分单元?存储层一些还没有进行 cluster 划分,或者是做了 method 切分,没计划做 cluster 划分的服务,如何划分单元化。
- 当以当前同城容灾的方式,将 HL 流量人工切换到 LF,在单元化不感知不变更调度情况下,能否正常工作?是否等于要求在一个 Region 下,不同的 VDC 下的 Cluster 一定是对等的?
- 未来朝着 automatic failover 进一步建设同城容灾的时候,RPC 框架层换 VDC 重试挑选节点,是否需要感知到单元化的 cluster 信息?从而挑选到另外一个 VDC 下的正确 Cluster 的节点?
- 对于单元是否存在两种模式?管理成本是否过高?
- 一种是水平扩展模式,比如华北的 Set 1 和华东对等 Set 2 等,这种模式隐含这不同单元直接有用户的交互,两两之间需求进行双向同步。
- 一种是业务隔离模式,比如华北的 Set 1 和华北的 Set 11,或华北的 Set 1 和华东的 Set 12 等,这种模式,隐含着不同单元肯定所属不同业务,不可能产生任何交互,两两之间不需要进行双向同步。
- 以上架构,打破了单元化几个比较优秀的特性,比如单元具备物理意义(物理意义使得单元化不用再关心单元内的调度,由底层关注即可),比如水平扩展性(水平扩展性确保了单元化的数据同步模式保持统一),但为了满足中台服务不同租户(业务)的隔离要求,是否有更好的办法。
一些想法
- 业务(租户)和单元不应该属于同一个维度,业务的一些配置信息和单元的配置信息层次不一样,强行打平到同一个维度,会产生O(N^2) 的配置复杂度,管理成本直线上升,稳定性下降。
- 单元应该是具备物理意义的单元,比如一个 Region,或一个 VDC,但不应该是多个 VDC 下的一些 Cluster 的集合。单元也应该是根据基建情况预设的并且跟随发展而不断扩展,而不是业务自行构建。比如国内构建 Region 级别的单元,那就应该只有华北和华东两个单元。
- 业务的维度可以提升到单元之上,不同业务可以根据需求选择包含哪些单元,对于同一个单元,不同的业务可以以有不同的管理配置,单元的配置在不同业务之间隔离。比如对于抖音和头条,在华北都是同属 Set 1单元,但是底下配置的中台服务 PSM/Cluster 配置等不一样。业务也可以有一些针对对所有单元都一致的全局配置。
- 在流量调度上,不同的业务读取的单元配置不一样,从而完成正确的流量调度。
- 在存储管理上,一个业务内配置的存储才会进行双向同步,不同业务的存储互不可见。
- 对于业务方,只需要关注归属自己业务的一个配置,对于中台服务,则需要关注不同业务的多个配置,控制面类似 SPD 的方式在入口处进行隔离,进入后看到的是归于一个业务的完整单元化管理视图。
如果有人看到这里,那在这里老话重提。与君共勉,路漫漫其修远兮,吾将上下而求索。
标签:Layer,Set,架构,Region,调度,VDC,设计,单元 From: https://www.cnblogs.com/codegitz/p/18010336