1.1.1 从单体系统到微服务架构
在软件技术发展的很长一段时间内,软件系统都表现为一种单体系统。时至今日,很多单体系统仍然在一些行业和组织中得到开发和维护。所谓单体系统,简单来讲就是把一个系统所涉及的各个组件都打包成一个一体化结构并进行部署和运行。单体系统存在一些固有的问题,在本节中,我们从这些问题出发来剖析微服务架构的诞生背景和特性。
1.单体系统存在的问题
图1-1展示的就是一个典型的单体系统,我们可以看到在应用服务器上同时运行着面向用户的Web服务层、封装业务逻辑的业务逻辑层和完成数据持久化操作的数据访问层组件,这些组件作为一个整体进行统一的开发、部署和维护。
图1-1 单体系统
单体架构简单且容易实现,但随着公司或者组织业务的不断扩张、业务结构的不断变化以及用户量的不断增加,单体架构面临着越来越多的挑战,已逐渐无法适应互联网时代的快速发展。让我们一起来分析一下。
对于大多数系统而言,架构设计是为了满足业务需求。衡量架构好坏与否的一个重要方面是看其面对复杂业务变更时所具有的灵活性,也就是我们通常所说的可扩展性(Extensibility)。可扩展性是指系统在经历不可避免的变更时足够灵活,针对提供这样的灵活性所要付出的成本进行平衡的能力。所谓可扩展,扩展的是业务。当向一个现有系统中添加新业务功能时,如果不需要改变原有的业务体系而只需把新功能封闭在一个新的模块或子系统中就能完成整体业务的升级,我们就可以认为该系统具有较好的可扩展性。显然,单体系统不具备良好的可扩展性,因为对系统业务进行任何一处修改,都需要重新构建整个系统并进行发布。单体系统内部没有根据业务结构进行合理的拆分是导致其可扩展性低下的主要原因。
前面讲到单体系统的可扩展性很差,实际上它的可伸缩性同样也有问题。所谓可伸缩(Scalability),伸缩的是性能,即当系统性能出现问题时,如果我们只需要简单地添加应用服务器等硬件设备就能避免系统出现性能瓶颈,那么该系统无疑具备较高的可伸缩性。通常,我们会考虑采用水平伸缩的方法实现可伸缩性。当考虑水平伸缩时,一般的做法是建立一个集群,在集群中不断地添加新节点,然后借助前端的负载均衡器,将用户的请求按照某种算法分配到不同的节点上。但是,由于单体系统的所有程序代码都运行在服务器上的同一个进程中,内存密集型和CPU密集型并存,也就要求所有应用的服务器都必须有足够的内存和强劲的CPU来满足需求。这种方法成本会比较高,而且资源利用率通常都比较低下。
以图1-2所示内容为例,单体系统中的组件A的负载已经达到了80%,也就是到了不得不对系统的运行能力进行扩容的时候,但同一系统的另外两个组件B和C的负载还没有到其处理能力的20%。由于单体系统中的各个组件是打包在同一个运行包中的,因此虽然通过添加一个额外的系统运行实例可以将需要扩容组件的负载降低一半,但是显然其他组件的利用率变得更为低下,造成了资源浪费。另外,对于那些需要保持类似会话(Session)数据的需求而言,扩容之后的运行机制在如何保持各个服务器之间数据的一致性上也存在较大的实现难度。
图1-2 单体系统的可伸缩性问题
最后,我们需要认识到,在软件开发过程中,代码腐化在一定程度上是一种不可避免的现象。在单体系统中,由于缺乏合理的业务和技术实现边界,随着产品业务功能的增多,当出现缺陷时,有可能引起缺陷的原因组合比较多,这会导致分析缺陷、定位缺陷、修复缺陷的成本相应增加,也就意味着缺陷的平均修复周期可能会延长,从而影响产品的正常迭代和演进。同时,随着功能不断叠加,单体系统的代码结构也日益复杂,修复一个缺陷的同时还有可能引入其他的缺陷,在很多技术团队并不具备完善的持续集成(Continuous Integration, CI)和持续交付(Continuous Delivery, CD)能力的客观条件下,很可能导致出现问题越修越多的不良循环。
针对以上集中式单体系统普遍存在的问题,基本的解决方案就是微服务架构系统的合理构建。
2.微服务架构的特性
软件工程大师Martin Fowler在“Microservices”一文中提到,微服务架构具有服务组件化、按业务能力组织服务、去中心化和基础设施自动化等核心特性。
组件(Component)是一种可独立替换和升级的软件单元。在日常开发过程中可能会设计和使用很多组件,这些组件可能服务于系统内部,也可能存在于系统所运行的进程之外。而服务就是一种进程外组件,服务之间利用HTTP完成交互。服务组件化的主要目的是服务可以独立部署。如果你的应用程序是由一个运行在独立进程中的很多组件组成的,那么对任何一个组件的改变都将导致必须重新部署整个应用程序。但是如果你把应用程序拆分成很多服务,显然,通常你只需要重新部署那个改变的服务。在微服务架构中,每个服务运行在独立的进程中,服务与服务之间采用轻量级通信机制进行交互。
当寻找把一个大的应用程序进行拆分的方法时,研发过程通常都会围绕产品团队、UED(用户体验设计)团队、App前端团队和服务端团队展开,这些团队也就是通常所说的职能团队(Function Team)。当使用这种标准对团队进行划分时,任何一个需求变更,无论大小,都将导致跨团队协作,从而增加沟通和协作成本。而微服务架构下的划分方法有所不同,它倾向于围绕业务功能的组织来分割服务。这些服务面向具体的业务结构,而不是面向某项技术能力。因此,团队是跨职能的(Cross-Functional)特征团队(Feature Team),包含用户体验、项目管理和技术研发等开发过程所要求的所有岗位和技能。每个服务都围绕着业务进行构建,并且能够被独立部署到生产环境。
集中式系统的一个好处是技术的标准化,但采用微服务的团队更喜欢不同的标准。把集中式系统中的组件拆分成不同的服务,我们在构建这些服务时就会有更多的选择。对具体的某一个服务而言,应该根据业务上下文,选择合适的语言和工具进行构建。另外,微服务架构也崇尚对数据进行分散管理,让每个服务管理自己的数据库,无论是相同数据库的不同实例,还是不同的数据库系统。
许多使用微服务架构的产品或者系统,其团队拥有丰富的持续集成和持续交付经验。团队使用微服务架构构建软件需要更广泛地依赖基础设施自动化技术。
当然,在微服务中同样需要考虑网络传输的三态性、异构性、数据一致性和服务容错性设计等分布式系统所需要考虑的问题。随着本书内容的展开,会对这些特性进行详细的分析和讨论。