01 | 如何实现自我基础设施新重建-从掌握一致性与分布式事务开始
如今微服务架构已经是一个耳熟能详的概念了,在技术先进的互联网大厂,如阿里、美团、滴滴、360 等,早就已经采用了微服务架构设计;另外一些传统企业,比如房地产、医药、教育等行业的技术研发部门,因为公司数字化转型的强烈需求,也开始慢慢拥抱微服务架构。利用微服务架构,研发人员可以快速地开发企业级应用系统,为企业数字化转型赋能。可以说,我们已经全面进入了微服务架构的时代。
微服务架构融合了 DDD、DevOps、Docker、Kubernetes、云计算等技术的优势,使得技术团队开发新功能的时间周期明显缩短,上线部署新服务后,机器的弹性扩展也更加智能化。微服务架构的部署极大程度上缓解了激增的海量用户对系统的冲击,更好地支撑了企业的高速发展。
当然,随着逐渐提高的服务大规模可扩展能力,服务间的调用关系也变得更加复杂,这种跨服务的复杂调用,为分布式事务的产生提供了更大的可能性。分布式系统你一定有所了解,而分布式事务在分布式系统中的作用就是保证不同节点之间的数据一致性。因此,了解微服务架构的演进历程对于我们理解分布式事务的产生背景和原因也会带来极大的帮助。
纵观软件系统架构发展的历程,大致经历了单体架构、分层架构、SOA 架构、微服务架构、服务网格架构等阶段。目前主流互联网公司正处在微服务架构向服务网格架构过渡的阶段,部分传统公司还处在分层架构或 SOA 架构阶段。下面我们就来分析各阶段系统架构的发展情况。

单体架构——混沌初开
我们先结合下图看一下十多年前采用单体(Monolith)架构系统的情况。

单体架构系统图
在单体架构中,前、后端的代码杂糅在一个工程里,被打成一个 war 包,然后部署到一个应用服务器 Tomcat 上面,看起来一团乱麻。数据库也采用单台部署的方式,由于要处理的数据量比较小,单台数据库足以支撑业务的使用。
这个时期,并没有前端工程师和后端工程师的明确区分,也没有中间件研发工程师和数据库工程师的概念 ,几乎一个人就可以搞定所有的代码。
早期的单体不仅指前后端的业务逻辑是一个复杂、紧耦合的整体,同时,程序部署的应用服务器和访问的数据库服务器实例都是单个节点,而这样很容易出现单点故障。
单体架构的优点 | 缺点 |
架构非常简单清晰,个别工程师全栈开发,不需要依赖大规模的研发团队配合 | 不能支持大用户量的访问,也不支持复杂业务功能逻辑的开发,单个部署节点很容易出现单点故障 |
分层架构——长盛不衰
随着产品的功能需求越来越多,业务逻辑越来越复杂,单体架构的缺陷日益明显,分层架构(Layered Architecture)应运而生。
如果设计的业务系统非常复杂、超出人的为什么要分层呢?计算机界有一个非常著名的、也是大家公认的观点:我们可以通过新增加一层来解决任何想要解决的问题(Any problem in computer science can be solved by another layer of indirection)。思维限制,我们可以对该系统层层细化分解,细化后每一层专注于解决一个简单的问题,每个上层都通过调用下层提供的能力并加以扩展形成新的能力。经过层层调用和层层扩展,最终解决这个复杂问题。
水平分层主要针对后端进行分层,其前提是前端和后端先进行解耦分离。这种前后端分离也是一种分层思想,即前端专注于与用户的交互和效果的呈现,后端专注于业务逻辑功能和数据的提供。
前端一般采用 H5 和 CSS 3 等页面展示技术。由于前端技术发展迅猛,目前已经涌现大量前端框架,比如 Vue、AntDesign 等,利用框架我们可以更深入完成前端层次化和组件化开发。
后端的分层一般可以分为 API 接口适配层、业务逻辑服务层、公共服务层、数据访问层等。而数据访问层又分为:
ORM(实体关系映射)框架层,比如 MyBatis、Hibernate、Spring JDBC Template 等;
分库分表中间件层,比如 MyCat、Sharding-Sphere 等。

水平分层架构图
分层架构的思想不仅在设计业务系统时普遍应用,在设计开源框架时也是首选的架构方式。以 Dubbo 框架为例,它主要是微服务架构体系中进行服务之间互相调用的 RPC 通信框架,并在此基础上提供了诸如负载均衡、服务注册发现等服务治理能力。这个框架主要是采用分层架构思想设计的,内部总共分为十层,每一层都解决某一个特定的问题(感兴趣可以点击这个链接参考学习)。
对于开发模式来说,后端分层提高了我们开发复杂业务系统和支撑大规模用户请求访问的能力。至于部署模式,将后端程序与前端代码分离,后端单独打成 war 包,部署到多台机器上,可以形成分布式弹性扩展的能力。
面向服务化架构(SOA 架构)——理想丰满
随着用户量不断上升,虽然后端服务进行了水平分层,但是所有的后端代码打成一个 war 包,分布式部署在多台机器,也导致了机器资源的严重浪费。每台机器部署程序的粒度过大,而且整个后端包含的各个功能模块之间相互影响和依赖也比较严重,每一个模块功能的修改发版都需要整体代码打包部署上线。那么面对这些问题又该如何解决呢?在此情境下,业务功能的垂直拆分应运而生。
以常见的客户关系管理系统(CRM 系统)为例。一般该系统涉及客户信息管理、活动管理、销售管理、产品管理、用户管理等模块,这些模块之间是紧耦合的关系,迫切需要把各个模块拆分成独立的子系统。但拆分之后如何组装集成,却成了业界一大困扰,尤其当不同的子系统采用异构的语言和异构的技术开发,又该怎么处理呢?
这些问题的解决需要有一整套新的架构模式,恰好此时面向服务化架构(SOA Architecture)“以服务为中心”的架构思想诞生并流行起来。它的产生主要源于大型企业中各个系统集成的需求,通过抽象出来“服务”概念,将各个系统模块以“服务”为单元进行集成和串联,以减少系统集成整合的负担。
比如刚提到的 CRM 系统中包含的模块,我们就可以抽象出来下图中一个个的“服务”,每个服务之间通过 ESB 服务总线进行串联调用。

CRM 系统架构图
SOA 架构的产生给大型企业级系统的 IT 服务集成带来了极大方便,消除了不同部门异构语言系统之间不互通导致的“信息孤岛”问题,实现了 IT 系统资产的重用。
但是 SOA 系统也有很多的缺陷,主要问题是无法适应互联网超大用户请求的发展,因为 SOA 服务采用的 ESB 服务总线有很大的瓶颈,不方便进行服务的扩展。
尽管 SOA 只火爆了几年、落地也不是太好,主要是一些大型的软件公司(比如 IBM)在使用,但是它明确提出了“服务”的概念,也为后来微服务架构的出现奠定了基础。
微服务架构——如日中天
你有没有想过微服务架构为什么叫“微服务”,而不是“宏服务”呢?
我们先要明确,“微”代表着小,“宏”是大的意思。而之所以叫“微服务”,一是因为“服务”的概念早已有之,微服务中的“服务”与 SOA 中“服务”的概念一脉相承。二是微服务中“服务”的粒度要比 SOA 的子系统级别的“服务”粒度更小一些,所以叫“微服务”。“宏服务”的概念近期才在国外提出来,出现的时间段远远晚于“微服务”,也没有太多的人响应,因为“宏服务”并没有太多新的内容,只是强调微服务的拆分粒度过细之后会引发一系列问题(包括分布式事务问题),所以建议服务的粒度更大一些。
Docker 等容器工具的助力,使得微服务架构成为主流,微服务(MicroService)架构模式不仅解决了 SOA 架构中 ESB 的瓶颈问题,并且具备了以下新的特点。
通常采用模型驱动设计(DDD)的思想,按照业务领域将一个大业务拆分成一些小的业务单元,每个业务单元对应一个小的服务进行技术实现。
微服务拆分的粒度比之前面向服务的架构(SOA 架构)会更细一点,这些小的服务实现单元相对独立,可以使用不同的编程语言和不同的开发框架去开发,也可以独立地部署在不同的服务器平台上。服务独立部署之后,服务进程之间可以独立运行,不受到其他服务发版上线、迭代升级的影响。
拆分后的微服务之间要求“高内聚、低耦合”,单个服务职责比较单一,服务一般有自己独立的数据存储,即数据库一般是独立的。这样实际上也是对数据库进行了一个垂直的拆分,使得数据库不会因为数据量猛增造成系统瓶颈。
一般采用自动化的方式进行大规模服务的持续集成和持续发布。服务由不同的团队分别进行开发后,可以分别进行单元测试,通过自动化的方式进行各个环境的测试和部署,最后滚动升级发布到线上,提高了研发团队的整体工作效率。
下图是一个常见的微服务架构图,图中分布式服务 A 有自己的独立数据库,分布式服务 B1 和 B2 共同使用一个数据库(这种情况是微服务设计的一个反模式,不推荐)。分布式服务 C 和 D 都有自己的独立数据存储,但 C 调用 D 的时候,没有直接采用 RPC 远程调用,而是 C 先发消息到消息中心,D 通过订阅消息的方式处理 C 的请求数据,这样服务之间就实现了松耦合,我们也建议在微服务架构设计中多采用基于消息中心的松耦合方式。

微服务架构图
微服务刚出现时,由于采用统一网关作为外部服务调用的公共入口,我们也称之为基于网关的微服务架构。在统一网关这层我们主要提供一些通用能力,如鉴权、路由、限流、安全策略、负载均衡等。
基于网关的微服务架构目前已经成为主流架构,但随着微服务数量的不断膨胀和大规模业务的扩展,该架构模式也产生了一些新的痛点:大量的微服务需要调用消息中心、日志平台、用户中心等基础服务,这些基础中间件对业务服务的代码侵入性强,中间件与微服务版本依赖的问题突出。为了解决这些业务服务与底层基础通用服务之间耦合的问题,产生了服务网格(Service Mesh)架构。
Java Code Geeks提出了六种微服务设计模式分别为:聚合器微服务设计模式、代理微服务设计模式、分支微服务设计模式、数据共享微服务设计模式、异步消息传递微服务设计模式。有兴趣的读者可以自己去仔细阅读一下:
https://www.javacodegeeks.com/2015/04/microservice-design-patterns.html
服务网格架构——初露锋芒
目前服务网格架构还处于各大公司的探索期和落地尝试中,不仅在阿里有大规模应用,在其他公司,如美团等也都有很多落地的实践。即便如此,目前服务网格还不是十分成熟,因为它并没有解决大规模服务调用的复杂度问题,只是将一部分复杂度下沉到了基础设施中。
具体来讲,在服务网格架构中,一方面我们可以将基础中间件的服务能力抽象到 sidercar 中,另一方面也可以将原来基于网关中的能力(常见的包括服务注册发现、服务路由、负载均衡、熔断限流、认证鉴权等)专门抽象提取到 sidercar 模块中。通过这些公共能力的关注点分离,达到公共能力服务和业务服务解耦的目的。解耦之后的整体架构如下图所示:

服务网格架构图
服务网格架构(Service Mesh)是一个新的架构模式,你会发现随着架构的演变和升级,系统的架构模块越来越多,也越来越复杂。

图片来自:Pattern: Service Mesh
那么该架构会不会是解决系统架构的终极架构模式呢?在使用中会不会发现新的使用问题呢?答案是肯定的,任何系统的架构都不可能解决所有问题。只有以应用场景驱动设计的架构才是合适的架构,特定的场景采用特定的架构模式,这已经成为业界的共识。
我们在解决实际问题时候也需要根据实际的场景进行落地改造,切记不可照搬照抄,要结合业务来批判吸收。
除了服务网格架构之外,从其他角度考虑,还有一些不同的架构模式,比如:事件驱动架构、微内核架构、云原生架构、Serverless 架构等。除了这几种架构模式,你还知道哪些架构设计模式呢?欢迎留言一起讨论。
总结
这一讲我们重点讲解了微服务架构在演变过程中涉及的单体架构、分层架构、SOA 架构、微服务架构及服务网格架构。希望你在自己设计系统架构时,能够了解每一种架构的优缺点。同时需要记住一句话:利用简单架构就可以解决问题的情况下我们绝不必采用复杂的架构,而复杂架构内部的各个模块一定要设计得清晰合理。
下一讲我将详细讲解微服务架构带来的分布式事务问题,带你了解什么是分布式事务问题,以及相应的解决方案。

相关文章推荐:
01 | 如何实现自我基础设施新重建-从掌握一致性与分布式事务开始
10 | 从乐观的思路(OCC、MVCC)来看并发控制的技术实现




