在当今的互联网业内,很多大型互联网系统,比如淘宝、支付宝、网商银行等,都已经实现了单元化架构,并从中获益匪浅,更多企业正加入其中。为什么要做单元化,单元化架构能给系统带来什么样的能力。本文将从架构发展历史的角度作为切入点来了解一下单元化架构的发展历史以及一些落地方案。
支付请求要从客户端发送到服务端,服务端最终再把结果返回客户端,必然会有一次异地网络往返。应用进程内部会发生很多次业务逻辑运算,耗时忽略不计。应用会访问多次数据库,一笔支付请求按10次数据库访问算(对于支付系统来说并不算多,一笔业务可能涉及到各种数据校验、数据修改)。耗时大头在无可避免的用户到机房物理距离上,系统内部处理耗时很小。
到了服务化时代,一个好的RPC框架追求的是让远程服务调用像调本地方法一样简单。随着服务的拆分、业务的发展,原本进程内部的调用变成了网络调用。由于应用都部署在同一个机房内,业务整体网络耗时仍然在可接受范围内。开发人员一般也不会特别在意这个问题,RPC服务被当成几乎无开销成本地使用,应用的数量在逐渐膨胀。
服务化拆分,解决了应用层的可扩展性问题。随着业务的发展,物理机房逐渐成为系统容量的瓶颈。要突破单机房的容量限制,最直观的解决办法就是再建新的机房,机房之间通过专线连成同一个内部网络。
应用可以部署一部分节点到第二个机房,数据库也可以将主备库交叉部署到不同的机房。这一阶段,只是解决了机房容量不足的问题,两个机房逻辑上仍是一个整体。日常会存在两部分跨机房调用,积少成多也很可观:
“距离”是一个矛盾体:距离越远,同时受同一灾害(电力故障、网络故障、自然灾害等)影响的可能性就越低,另一方面,网络访问延时就越高。同城级距离(几十公里)是一个实践临界值,前述的同城多机房架构,整体耗时在可接受范围内;而跨城访问耗时被复杂业务链路放大后,将明显影响业务。
对容灾要求不高的系统,做到同城多机房的程度就足够了,可以省去不少设计复杂度。但是金融行业有异地容灾的要求,就不得不面对距离带来的访问延迟问题。
“两地三中心”是一种在金融系统中广泛应用的跨数据中心扩展与跨地区容灾部署模式,但也存在一些问题。异地灾备机房距离数据库主节点距离过远、访问耗时过长,所以无法直接访问主库。异地备节点数据又不是强一致的,所以无法直接提供在线服务。
在扩展能力上,由于跨地区的备份中心不承载核心业务,不能解决核心业务跨地区扩展的问题;在成本上,灾备系统仅在容灾时使用,资源利用率低,成本较高;在容灾能力上,由于灾备系统冷备等待,容灾时可用性低,切换风险较大。
回头来看历史的架构演进历史,我们不难发现从一开始的单点架构,会遇到扩展性差,维护困难
的问题;然后升级到到SOA架构,容易遇到容量受限,机房级单点
的问题;再升级到同城多机房架构以及两地三中心架构又会带来城市级单点
的问题。
多地多机房部署,是互联网系统的必然发展方向,一个系统要走到这一步,也就必然要解决上面提到的问题:流量调配、数据拆分、延时等。业界有很多技术方案可以用来解决这些问题,而承载这些方案的,是一个部署架构。尽管可采用的部署架构不止一个,但不论是纯理论研究,还是一些先行系统的架构实践,都把“单元化部署”推崇为最佳方案。
单元(即单元化应用服务产品层的部署单元),是指一个能完成所有业务操作的自包含集合,在这个集合中包含了所有业务所需的所有服务,以及分配给这个单元的数据。单元化架构就是将单元作为部署的基本单位,在全站所有机房中部署多个单元,每个机房内单元数目不固定,任一单元均部署系统所需的全部应用,数据则是全量数据按照某种维度划分后的一部分。
传统意义上的 SOA 化(服务化)架构,服务是分层的,每层的节点数量不尽相同,上层调用下层时,随机选择节点。
单元化架构下,服务仍然是分层的,不同的是每一层中的任意一个节点都属于且仅属于某一个单元,上层调用下层时,仅会选择本单元内的节点。
一个单元,是一个五脏俱全的缩小版整站,它是全能的,因为部署了所有应用;但它不是全量的,因为只能操作一部分数据。能够单元化的系统,很容易在多机房中部署,因为可以轻松将多个单元部署在一个机房内,而将另外几个单元部署在其他机房内。通过在业务入口处设置一个流量调配器,可以调整业务流量在单元之间的比例。
从上述对单元的定义和特性描述中,可以推导出单元化架构要求系统必须具备的一项能力:数据分区,实际上正是数据分区决定了各个单元可承担的业务流量比例。数据分区(shard),即是将全局数据按照某一个维度水平划分开来,每个分区的数据内容互不重叠,这也就是数据库水平拆分所做的事情。
仅把数据分区了还不够,单元化的另外一个必要条件是,全站所有业务数据分区所用的拆分维度和拆分规则都必须一样。若是以用户分区数据,那交易、收单、微贷、支付、账务等全链路业务都应该基于用户维度拆分数据,并且采用一样的规则拆分出同样的分区数。比如,以用户 id 末 2 位作为标识,将每个业务的全量数据都划分为 100 个分区(00-99)。
有了以上两个基础,单元化才可能成为现实。把一个或几个数据分区,部署在某个单元内,这些数据分区占总量数据的比例,就是这个单元能够承担的业务流量比例。 执行数据分区时一个很重要的问题是分区维度的选择,一个好的维度,应该:
以用户为服务主体的系统(很多面向用户的系统,比如支付宝)通常可以按用户维度对数据分区,这是一个最佳实践。