初始概念
单元,根据百科释义,指样本中自为一体或自成系统的独立成分,不可再分,否则就改变了事物的性质。
单元化架构是一种软件系统部署架构,它将系统按功能和数据特征划分为一个个单元。拆分维度根据应用的组织模式会有所不同,可以按功能垂直拆分,也可以按数据水平拆分,取决于自治的范围。理想情况下,每个单元是一个能完成所分配业务操作的自包含集合,包含了业务所需的所有服务、数据和资源。
严格意义上讲,单元化不是一种具体架构,而是一种架构思想,与其说它是设计出来的,不如说是发展出来的,发展于业务对扩展性和可用性日益增长的需求,扩展性在于规模增长,可用性在于业务连续。
单元化不是银弹,只是业务发展到一定阶段,触达到扩展性与可用性瓶颈时的一种解法。架构复杂度必然与实现复杂度和管理复杂度相关,选定一种架构,尤其是往选定架构迭代受多种因素影响,例如旧系统现状、可选技术栈、人力储备和经济开销等,技术是其中基础但不显得重要的事,组织、金钱与时间,还有不可言说的业务体感,缺一不可。
从何而来
技术架构发展大体上是集中式向分布式演进的过程,受限于某些不可抗因素而产生变化。一方面是组织变革的因素,例如大团队拆小团队,服务因此被迫进行分离;另一方面是物理限制的因素,例如单机规格不能无限提升,于是从纵向扩展(Scale-up)转向横向扩展(Scale-out),打开了分而治之的潘多拉魔盒。
分治有两个核心,一是隔离,二是连接,隔离指对象的拆分方式,连接指对象的访问方式。随着应用场景的变化,逐渐形成一些代表性的技术架构,如下表。
技术架构 |
拆分方式 |
访问方式 |
适用场景 |
单体架构 |
无隔离,应用程序和数据库部署在一台主机 |
应用与数据库本地调用 |
最原始的架构,不考虑使用大型机的场景,适用于某些资源欠缺的初建项目 |
数据分离架构 |
应用程序和数据库分别部署在不同主机 |
应用与数据库远程调用 |
避免应用服务与数据库资源争抢、应用服务无状态水平扩展、应用前后端分离 |
多层数据架构 |
在数据分离的基础上,数据区分不同功用组件 |
应用根据不同需求调用相应数据组件 |
访问加速(如缓存),聚合查询(如搜索),需解决数据有效性问题 |
读写分离架构 |
在数据分离的基础上,数据库分读写库 |
应用根据读写场景连接不同数据库 |
数据库单体压力,适用读多写少场景的数据库分流,需解决读数据时效问题 |
数据水平拆分 |
在数据分离的基础上,数据按逻辑分片分库 |
应用多点连接不同数据库,按分片规则选择数据库 |
主库压力无法纵向扩展消化,按自定义切片拆分数据,需解决规则变更后数据迁移问题 |
数据垂直拆分 |
在数据分离的基础上,数据按业务场景分库 |
应用多点连接不同数据库,根据业务场景选择数据库 |
主库压力无法纵向扩展消化,按业务领域拆分数据,需解决跨库一致性和事务性问题 |
应用垂直拆分 |
在数据拆分的基础上,应用也按业务场景拆分 |
应用单点连接同场景数据库 |
业务按领域拆分自治,独立演进,需解决应用服务发现和通信问题 |
可以看到,技术架构不完全是线性递进和前向兼容的,每类架构都有其适用场景和亟需解决的问题,一个技术架构由其静态分布和动态编排组成,分布的是逻辑与数据,编排的是依赖和流量,前者突出建设,后者突出治理。
业务的正确性以数据的正确性为准绳,治理的核心基本都能归结为引导流量到合适的数据中去,数据分布的流动是正确导流必解的难题,数据分布变更的收敛窗口可能也是系统可用性的缺失窗口。
如何减少此类影响是每种数据模型必然要考虑的事,手段或有三种,
- (1)完全不考虑变更,指数据强一致性;
- (2)减少变更范围,指数据分片粒度;
- (3)加快收敛速度,指数据同步时效。
从需求来看,单元化面向的是单数据中心无法满足的局限性,例如资源限制(单机房容量)和数据合规(数据不离境),以及派生的异地容灾(流量多活)和体验优化(就近调度)等。
同样是自治,单元化与传统技术架构的主要区别在于视角和粒度,前述架构的进化路线比较符合康威定律下的功能自治,在系统的局部视角,以服务团队为组织边界,单元化是业务整体的区域自治,在系统的全局视角,各业务团队协同配合。
类似地,单元化也可以有垂直拆分和水平拆分的模式,但完全的垂直拆分实际是剥离两个毫不相干的系统,所以单元化一般是水平拆分的模式——每个单元都具备业务系统的完整功能,但只处理一部分不重叠的数据,所有单元合起来构成完整的业务数据。
现实情况要比模型更复杂一些,可能会出现业务数据不能整体水平拆分的情况,这也意味着单元间会有流量耦合,即流量不在单元内闭环,会从系统某个模块寻找其依赖时逃逸出去。
严格意义上讲这是业务问题,可以通过数据设计进行优化,但总归不能完全避免,技术上要给出解法,这是前面提到的正确导流场景,同样地,单元化也要解决数据分布变更窗口的一致性问题。
基本模型
单元化是区域级别的调度,是在物理区域上进行逻辑划分后的数据流量管理。
以应用发布目标为部署单元(Cell),指代应用运行的物理分区,在这之上建立逻辑分区维度,一是描述容灾区域的容灾单元(Unit),一般与可用区或机房对应,例如广州单元、北京单元,二是描述业务特点的逻辑单元(Zone),在容灾单元内,一般与流量分配规则对应,如中心单元、普通单元。三者关系示意如下图。
在实际业务中,不一定所有功能都按相同的分片逻辑水平拆分到不同单元,如集中库存,也不一定所有功能都需要严格地分拆闭环,如商品详情,通过不同的逻辑单元角色,赋予部署其中的应用服务相应的路由逻辑,便于理解和管理,共有三类:
- 中心单元(Center Zone):适用于数据不可拆分或还未拆分的应用服务,标识主容灾单元,数据读写均在主单元内。
- 普通单元(Normal Zone):适用于数据水平拆分,流量在单元内闭环的应用服务,数据读写本地单元,其他分片的流量将被接入层转发或数据层拦截。
- 本地单元(Local Zone):适用于副本类或只读类(或读多写少,不考虑写冲突)的应用服务,数据读写本地单元,不限制数据分片。
同一应用服务只会部署到一类逻辑单元中,否则会出现路由冲突,根据不同逻辑单元的路由特性,每个容灾单元内最多只有一个中心单元和本地单元,但可以有多个普通单元,如下图所示。
一般来说各逻辑单元内应用服务都读写本地数据库,流量通过应用服务之间调用进行控制。
- 正常情况下流量入口也应是普通单元内的应用服务,否则从入口侧就失去了分区高可用的意义
- 普通单元内的应用服务之间调用在该单元内闭环
- 普通单元内的应用服务如依赖本地化的服务,则直接调用相同容灾单元内的本地单元服务
- 普通单元内的应用服务如依赖中心化的服务,则远程调用主容灾单元内的中心单元服务
考虑RPC调用的读写放大概率,一次远程RPC多次本地DB性能表现优于一次本地RPC多次远程DB,但会存在计算资源空闲问题,如上图中心单元2,实践中可以低规格部署用于容灾,接管后再弹性扩容。
应用架构
单元化应用架构也有循序迭代的模式,粒度从粗到细,成本由低到高,适用于业务发展的不同阶段,一般有主备、双活和多活三类架构,特点如下所述。
- 主备:数据主备集群模式,实现比较简单,业务改造成本低,不需要过多考虑多中心数据读写冲突问题,流量层和应用层能常态化跨中心多活,数据层通过容灾主备切换实现高可用。
- 双活:基于业务数据分片的单元化模式,流量在单元内闭环,单元故障影响不外溢,相比主备架构业务体验更好、故障爆炸半径更小、容灾切换更平滑,但应用改造成本更高,要求业务数据拆分和流量标记。
- 多活:双活架构的多地扩展,依赖于底层数据存储的多地分布,容灾效果最好,建设成本最高,对中间件要求也最高。
主备
根据数据集群主备角色区分主备数据中心,一般情况下主中心承载大部分业务流量,备中心承担分流、热备、演练以及主中心故障后接管等职能。
主要操作:
- 不同容灾单元各部署一套应用
- 配置两地数据库集群之间同步
- 设置主中心,分配单元流量,读写主单元数据集群
- 逻辑单元只有普通单元,服务之间调用本地闭环
- 数据同步防回环,激活从主到备单边链路
架构特点:
- 备中心请求存在跨单元数据读写,需综合考虑机房距离、网络延迟和流量比例
- 跨中心数据同步为异步同步,故障时需考虑RPO
- 日常主备中心切换管控下无数据损失(禁写保护+延迟追平)
双活
根据业务数据分片调拨业务流量,数据读写均在本地,各中心角色对等,任一中心故障都可由另一中心接管。
双活架构以用户业务主动拆分为基础,其中具体的数据组件会反向约束架构所能达到的最终效果。
数据组件分为两类:
- 普通数据库:双数据集群,数据通过异步同步传播,无强距离约束,RPO预期不为0
- 分布式数据库:单数据集群,数据通过一致性算法传播,适用于同城双活,RPO预期为0
普通数据库 |
主要操作:
架构特点:
|
分布式数据库 |
主要操作:
架构特点:
|
多活
多活是双活的扩展,多个数据集群间互相同步管理成本和风险较高(如两两同步、星状同步),多活只考虑使用分布式数据库的情况,按地域扩展,推荐有同城多活、两地三中心和三地五中心三种模式。
同城多活是前面分布式数据库下同城双活的标准部署模式,三副本构建分布式数据库集群,数据库按数据分片设置主节点,应用服务读写本地数据分片节点,流量在单元内闭环。
两地三中心在延迟可接受的情况下可以直接采用单数据集群的模式,建设方法与同城多活相同。在异地延迟不可忽略的情况下,采用同城双活+异地主备的模式,其中同城双活采用分布式数据库,管理模式类似前述主备架构。
三地五中心消除两地三中心架构当中异地备中心的资源浪费和数据延迟问题,实现地域级别数据无损容灾,建设方法与同城多活相同,只是多地域多单元的扩展。