



在开发大型、复杂应用时我们常采用的开发方式就是模块化。这种大型应用的开发往往一个人是无法掌控全局的,通过模块化的方式可以将应用分解成多个具有关联的模块,并交由不同开发团队来完成。模块通过开发语言本身的机制进行构建,比如Java中我们会打包成一个JAR文件,模块之间的调用则是直接使用接口,依赖关系则可以使用Maven等工具进行管理。微服务架构中的服务其实和之前模块化开发很相似,但服务是有明确服务边界的,所以更易于开发和管控,同时也更易于单独部署和扩展。
微服务架构可以说是如何将功能分解成一系列服务的一种架构模式。对于一个应用系统包含两部分的需求:第一部分是功能性需求,用于定义一个应用是用来做什么的,该应用系统用来达到什么目的;第二部分就是非功能性需求,包括了对应用系统的扩展性、灵活性,还有性能、运维、安全、测试、监控等需求,这种非功能性需求是用来保障业务系统能够正确、顺畅地运行。而对于微服务架构来说,则着重于后一种需求。
微服务架构从结构上来看就是将一个应用拆分成多个松耦合的服务,这些服务之间通过某种协议(REST、RPC等)进行互相协作,完成原单体架构下的业务功能,但提供更灵活的部署模式,更容易扩展,降低了开发、运维上的复杂度。对于微服务来说,其中一个关键点就是各服务之间的松耦合,各服务之间通过一种“标准”的协议进行沟通,不需要理解对方服务的实现逻辑、实现方式,只要在对方所提供的服务接口没有变化的情况下不会影响自己所提供的服务功能即可。总而言之,微服务核心思路就是 分而治之 。
对于微服务中的服务可以这么理解: 服务是一个可以独立运行、提供范围有限的功能(可以是业务功能,也有可能是非业务功能)的组件。 功能具体实现隐藏在组件内部,而对外则提供访问接口,外部其他服务可以通过这些接口进行访问与交互,从这一方面来说,微服务是可以单独部署运行的。
在《架构即未来》(英文名称《The Art of Scalability》)一书中提出了一个可扩展模型: AFK扩展立方体(Scaliability Cube) ,将应用抽象总结出可扩展的三个维度:产品、流程和团队,理论上可按照这三个维度进行扩展,从而可将一个单体系统进行无限扩展,如图1-2所示。
图1-2 AFK扩展立方体
·X轴:X轴的扩展指的是服务水平复制,也就是我们可以运行多个应用实例,然后再做一个集群负载均衡。这种方式的扩展在单体应用中可以说非常典型,在系统应用性能提升中往往能够快速见效。
·Z轴:Z轴的扩展可以理解为是基于数据分区的扩展,也就是我们可以运行多个应用实例,但与X轴的扩展不同的一点是每个应用实例仅用来处理部分数据。在其之前没有负载均衡器,取而代之的是一个路由,该路由根据请求中的参数或某项属性(比如用户ID、订单ID等)将请求转发到不同的应用实例中进行处理。
·Y轴:Y轴的扩展就是接下来的微服务的功能拆分模式。基于Y轴的扩展思路可以将单体应用在业务层面上进行拆分,形成多个微服务。
X轴和Z轴的扩展仅仅是提升了应用的容量和可用性,但并没有解决随着业务发展日益巨增的开发、运维复杂度,而Y轴的扩展使得我们可以从业务功能的角度将庞大的单体应用进行分而治之,一方面降低了业务开发、运维的复杂度,另一方面通过分而治之可以实现服务故障的隔离,提高系统响应时间。再者,拆分后也可以控制每个团队的规模,让团队的工作更加聚焦,也更利于团队的成长。
微服务的设计理念参考了UNIX系统,每个微服务仅承担一种职责,并把该职责做到最好。因此,这让我们的应用看起来是一系列服务的集合。微服务架构具有以下优点。
·松耦合:基于微服务架构的应用是一系列小服务集合,这些服务之间通过非具体实现的接口及非专有通信协议进行通信(比如REST),这样只要原接口没有改变,就不会对服务消费者造成任何影响。
·抽象:一个微服务对其数据结构和数据源拥有绝对的控制权,只有该服务才可以对数据做出修改,其他微服务只有通过该服务才能够访问数据。因此,该服务可以很方便地对所能提供的数据进行有效控制。
·独立:每个微服务都可以在不影响其他微服务的情况下进行编译、打包和部署,这是单体架构应用所无法做到的。
·应对用户需求的多样性:微服务架构可以让我们轻松应对不同客户的特殊需求,通过定义良好的接口,可以让不同的微服务承担不同的职责,同时快速部署上线能力可以让用户需求尽早实现。
·更高可用性和弹性:微服务架构可以认为是一个去中心化的应用,每一个微服务都可以随时上线或下线。这样当某个微服务出现问题时只需要将其下线即可,其他同类型的微服务将承担其功能,对外仍旧可以提供服务,不会造成整个服务无法正常工作。
由于每个微服务都足够小,这可以让开发人员快速理解与掌握,而且对于微服务来说项目工程代码少,不会造成IDE速度变慢,开发和调试速度也非常有效率。微服务架构不会要求我们在一个应用中选用同一个技术栈,每个服务可以根据应用特性、开发人员特长选择合适的开发语言和框架。因为微服务足够小,非常容易进行重构或重写,同时在重构或重写的时候可以选择合适的开发语言和框架,而且一旦有更合适的技术也可以在低风险的情况下对应用进行升级改造,而不致于影响整个应用。通过微服务架构的实施,可以为我们带来开发、运维、升级上的灵活性。
因为每个服务都可以独立进行部署,开发人员可以很快对自己所开发的服务做出变更,而不会影响其他服务,也不会受到其他微服务的影响,持续集成和开发都非常灵活。
每个微服务都可以快速地实施X、Z轴扩展,并且可以为每个服务定义合适的硬件环境(I/O密集型、计算密集型),而不像单体架构应用采用大锅饭的方式,可以为组织节约硬件成本。
从另一个角度来说,微服务架构可以进行错误隔离,比如之前所讲的内存泄漏,在微服务场景下,只会影响其本身的微服务实例,而不会对其他微服务造成影响。
但微服务架构终究不是应对业务复杂化的“银弹”,从其本身来说具有以下缺点。
·可用性降低:微服务之间都是通过远程调用进行协作的,而远程调用的代名词就是不稳定,如果没有有效的方案,微服务架构可能会大大降低应用的可用性。当一个服务不可用时,有可能会引起级联反应,最终会造成应用的“雪崩效应”而拖垮整个应用。
·处理分布式事务较棘手:当一个用户请求的业务涉及多个微服务时,如何保障数据的一致性就成为一个棘手的问题。传统开发通常会使用两阶段提交的解决方案来解决这个问题。但对于微服务架构来说,这个解决方案并不是一个很好的选择,甚至在某些情况下很难实现。
·全能对象(God Classes)阻止业务拆分:在进行微服务拆分时可能最让人头痛的一个问题就是全能对象。几乎对于任何一个业务应用来说都可能存在一个或多个这样的全能对象。比如,对于电子商城应用中的订单就是这种对象,订单几乎会涉及电商应用中的每一个业务,它会阻止你进行业务拆分。
·学习难度曲线加大:微服务架构虽然可以将业务分解为更小、更容易开发的模式,但是也需要开发人员学习掌握一系列的微服务开发技术,加大了进入门槛,这也是非常有难度的一个挑战。
·组织架构变更:虽然对于单独一个微服务的部署简化了,但是整个应用部署的复杂度却提升了,需要涉及服务编排和服务治理等一系列处理,即不仅需要制定微服务之间的部署编排、关联关系、回滚计划等,还需要协调不同的团队,以及在人事组织上进行调整来适应这种变化。
到目前为止,微服务架构并没有一个业界最佳实践可以给予指导,所以构建微服务架构更像一门艺术,需要我们仔细思考,并根据业务的实际需求及发展,在实践中摸索出一套最佳方案。