1 微服务出现的背景
最初,许多企业服务的内部实现都是单体架构的。如下图所示,下图是《微服务架构设计模式》提供的虚构的某订餐企业的系统架构图,该架构提供的服务包括餐厅管理、订单管理、配送管理、支付、通知和结算。通过REST API和Web页面的方式来让送餐员、消费者和餐馆使用,通过一些适配器来使用外部的数据库、消息服务、邮件服务和支付服务。该系统内部是模块化的,但是该应用在部署的时候还是被打包为一个WAR包,并部署和运行到tomcat上,所以这是一个单体架构的系统。

单体架构有如下好处:
- 开发简单
RD只需要维护一个项目 - 部署简单
RD只需要将一个WAR包复制到安装了tomcat的服务器。(在SOA或者微服务中,对于一个功能的更改,很可能涉及部署多个服务。)
单体架构在使用的过程中,渐渐的发现了单体地狱的问题。什么是单体地狱呢,主要体现为单体巨大导致的如下这些问题:
- 可维护性:过度的复杂性会让RD难以维护
该单体过于复杂,以至于RD难以了解该系统的全貌。此外,多个团队维护一个项目,不利于项目的维护,导致职责不清。 - 持续集成、持续部署和持续发布的问题:开发速度慢,部署速度慢
单体过于巨大,导致每次编辑(项目巨大导致IDE慢)、构建、运行和测试这几个步骤花费的时间较长,降低开发的速度。由于单体过于巨大,导致提交代码后的自动化测试都运行很长时间,部署和上线也花费很长时间,大大降低了交付的速度。 - 可靠性:交付可靠的单体应用存在挑战
因为如下两个原因导致了可靠性的问题:1)单体巨大,不可能全部覆盖和运行所有的自动化测试,导致有些功能缺乏测试就进入线上环境;2)单体之间都共享同一个JVM或者机器资源,导致业务之间缺乏故障隔离。例如某段代码的内存泄露,耗尽机器资源,导致单体的所有业务都崩溃。 - 可维护性:需要长期依赖于某个可能已经过时的技术栈
单体架构在采用新的框架和编程语言是风险较高的,维护项目的RD不得不很可能一直采用老的过时的框架和语言。重构整个项目需要消耗巨大的人力,又可能引入较多的bug。
后来,人们渐渐发现,单体架构不容易做到代码/服务复用。于是,提出了SOA(service-oriented architecture,面向服务的架构)的概念,做到尽可能的服务共享。传统的SOA有如下的特点:
- 重点是业务功能的复用
- 有统一的治理和标准
- 使用ESB(Enterprise Service bus,企业服务总线)协议来通信
- 支持多种消息协议
根据功能复用的原则,传统的SOA会对单体进行拆分。因此,SOA解决了单体巨大的问题。看起来很完美,但SOA存在如下问题:
- 在单体拆分上,没有理论指导
- 存储仍然采用同一份,没有将数据存储也一起拆分
在SOA的基础上,结合很多软件大师对于SOA的研究,包括Eric Evans对于领域驱动设计的研究,Martin Fowler提出了微服务的概念。微服务可以认为是对SOA进行了改良:
- 采用领域驱动设计来拆分服务,而不是根据功能服务用的原则。当然,拆分服务的副作用之一是功能复用。
- 每个根据业务拆分的微服务都需要有自己的数据存储,不能和其他业务共享同一个数据库。
因此,我们会发现其实微服务和SOA很像,甚至可以认为微服务其实就是SOA 2.0(SOA的改良版),对于SOA的服务拆分有了具体的指导。这里,我们讲的也是SOA 2.0的内容。
2 需要解决的问题
需要解决单体架构中出现的问题,包括以下这些
- 单个项目代码复杂性太大的问题
- 开发速度慢、部署速度慢的问题
- 单体可靠性的问题
- 代码技术栈难以灵活更换的问题
3 微服务做了哪些事情
微服务对于架构提出如下要求:
- 服务拆分。按照业务能力或者子域拆分服务
- 服务拆分之后,多个服务之间需要通信。服务之间采用同步RPC或者异步消息机制进行通信
- 多个服务之间需要有服务发现机制
- 多个服务之间需要解决相互依赖的可靠性,即限流和熔断机制
- 使用Saga来解决数据一致性的问题 一个业务可能涉及多个服务的多个数据更改,这就涉及到分布式事务来解决数据的一致性问题。一种解决方式是使用Saga来解决,后面会提到。
- 一个查询涉及多个服务的数据,需要解决数据查询的问题 可以使用API组合器和CQRS(Command Query Responsiblity Segregation,命令查询职责分离)模式来解决调用多个服务的问题。
- 认证、授权、配置平台、监控、分布式追踪、设计等问题在微服务的情况下会有新的挑战
4 微服务解决了哪些问题
- 单个项目代码复杂性太大的问题。每个团队维护一个业务功能。
- 开发和部署速度慢的问题
- 单体可靠性的问题 将单体根据子域拆分为多个服务,并通过限流和熔断等措施来保证可靠性。
- 代码技术栈难以灵活更换的问题