背景
近期阅读了 Martin Fowler 和 James Lewis 合著的一篇文章 Microservices, 文中主要描写叙述和探讨了近期流行起来的一种服务架构模式——微服务,和我近期几年工作的实践比較相关感觉深受启示。本文吸收了部分原文观点,结合自身实践经验来探讨下服务架构模式的演化。
面向服务架构(SOA)
面向服务架构 SOA 思想概念的提出已不是什么新奇事。大概在10年前就有不少相关书籍介绍过。当时 java 企业应用领域 J2EE 依旧是主流,应用程序被部署在庞大统一的符合 J2EE 规范的容器中执行,在单一进程中提供全部的功能。 而 SOA 提出的一些架构原则。在当时看来无疑是革命性的。 由于业已存在的大量单一庞大的应用。依照 SOA 的思想和架构原则来改造无疑相当于推翻又一次开发一遍,在成本上非常难接受。 因此早期的 SOA 通常和另外一个术语关联在一起——ESB(企业服务总线)。 当时在 SOA 的实施思路上无一例外的选择了 ESB 模式来整合集成大量单一庞大的应用,以保护企业前期投入成本。
因此 ESB 事实上是 SOA 特定历史阶段的一种实现方式。
然而,愿望总是美好的,现实却要残酷的多。过去这些年我们看到了非常多实施 ESB 搞砸了的项目。投入几百万,产出差点儿为 0,因此 SOA 这个概念也蒙上了不详的标签。 近几年流行起来的服务化架构,其拥护者開始拒绝使用包裹着失败阴影的 SOA 这个标签,而称其为微服务架构(Microservices Architecture Style)。
但事实上 微服务架构依旧是 SOA 架构思想的一种实现。
微服务架构(Microservices)
对微服务架构我们没有一个明白的定义。但简单来说微服务架构是:
採用一组服务的方式来构建一个应用,服务独立部署在不同的进程中。不同服务通过一些轻量级交互机制来通信,比如 RPC、HTTP 等。服务可独立扩展伸缩,每一个服务定义了明白的边界,不同的服务甚至能够採用不同的编程语言来实现,由独立的团队来维护。
微服务架构特征(Characteristics)
1. 通过服务实现组件化
传统实现组件的方式是通过库(library)。传统组件是和应用一起执行在进程中,组件的局部变化意味着整个应用的又一次部署。 通过服务来实现组件。意味着将应用拆散为一系列的服务执行在不同的进程中,那么单一服务的局部变化仅仅需又一次部署相应的服务进程。 另外将服务作为组件能够更明白的定义出组件的边界,由于服务之间的调用是跨进程的,清晰的边界和职责定义是设计时必须考虑的。
2. 按业务能力来划分服务与组织团队
康威定律(Conway's law)指出:
organizations which design systems ... are constrained to produce designs which are copies of the communication structures of these organizations.
不论什么设计系统的组织。终于产生的设计等同于组织之内、之间的沟通结构。
传统开发方式中,我们将project师按技能专长分层为前端层、中间层、数据层。前端相应的角色为UI、页面构建师等,中间层相应的角色为服务端业务开发project师,数据层相应着DBA等角色。 事实上传统应用设计架构的分层结构正反应了不同角色的沟通结构。 而微服务架构的开发模式不同于传统方式,它将应用按业务能力来划分为不同的服务,每一个服务都要求在相应业务领域的全栈(从前端到后端)软件实现,从界面到数据存储到外部沟通协作等等。 因此团队的组织是跨功能的,包括实现业务所需的全面的技能。 近年兴起的全栈project师正是由于架构和开发模式的转变而出现,当然具备全栈的project师事实上非常少,但将不同领域的project师组织为一个全栈的团队就easy的多。
3. 服务即产品
传统的应用开发都是基于项目模式的,开发团队依据一堆功能列表开发出一个软件应用并交付给客户后,该软件应用就进入维护模式,由还有一个维护团队负责,开发团队的职责结束。 而微服务架构的倡导者提议避免採用这样的项目模式。更倾向于让开发团队负责整个产品的全部生命周期。Amazon 对此提出了一个观点:
You buidl it, you run it.
开发团队对软件在生产环境的执行负全部责任,让服务的开发人员与服务的使用者(客户)形成每天的交流反馈,来自直接client的反馈有助于开发人员提升服务的质量。
4. 智能终端与哑管道
微服务架构抛弃了 ESB 过度复杂的业务规则编排、消息路由等。 服务作为智能终端。全部的业务智能逻辑在服务内部处理。而服务间的通信尽可能的轻量化,不加入不论什么额外的业务规则。
5. 去中心统一化
传统应用中倾向採用统一的技术平台或产品来解决全部问题。 不是每一个问题都是钉子。也不是每一个解决方式都是一个锤子。 问题有其详细性,解决方式也应有其针对性。
用最适合的技术方案去解决详细的问题,在大一统的传统应用中事实上非常难做到,而微服务的架构意味着,你能够针对不同的业务服务特征选择不同的技术平台或产品,有针对性的解决详细的业务问题。
6. 基础设施自己主动化
单一进程的传统应用被拆分为一系列的多进程服务后。意味着开发、调试、測试、集成、监控和公布的复杂度都会相应增大。 必须要有合适的自己主动化基础设施来支持微服务架构模式,否则开发、运维成本将大大添加。
7. Design for failure
正由于将服务独立在不同的进程中后,引入了额外的失败因素。
不论什么时刻对服务的调用都可能由于服务方不可用导致失败,这就要求服务的消费方须要优雅的处理此类错误。
这事实上是相对传统应用开发方式的一个缺点。只是随着一些开源服务化框架的出现,对业务开发人员而言适当的屏蔽了相似的错误处理,只是开发人员依旧须要知道对服务的调用是全然不同于进程内的方法或函数调用的。
8. 进化设计
一旦採用了微服务架构模式,那么在服务须要变更时我们要特别小心,服务提供者的变更可能引发服务消费者的兼容性破坏。时刻谨记保持服务契约(接口)的兼容性。 对于解耦服务消费方和服务提供方,伯斯塔尔法则(Postel's law)特别适用:
Be conservative in what you send, be liberal in what you accept.
发送时要保守,接收时要开放。
依照伯斯塔尔法则的思想来设计实现服务调用时。发送的数据要更保守,意味着最小化的传送必要的信息,接收时更开放意味着要最大限度的容忍信息的兼容性。
多余的信息不认识能够忽略。而不应该拒绝或抛出错误。
微服务架构应用
採用微服务架构面临的第一个问题就是怎样将一个单一应用拆分为多个服务。 有一个一般的原则是,单一服务提供的功能是能够独立被替换和升级的。 也就是说假设有 A 和 B 两个功能,假设 A 功能发生变化时同一时候 B 功能也须要变化。那么 A 和 B 这两个功能应该被划在一个服务中。
微服务架构应用的成功经验近年已越来越多。比如国外的 Amazon,Netflix。国内如阿里都採用微服务架构取得了非常多正面的成功案例。 但通过上文所述微服务架构特征看出。事实上微服务架构模式有利有弊,须要依据实际的业务、团队、环境进行细致权衡利弊。
当中的服务拆分带来的额外开发、測试、运维、监控的复杂度。在现有的环境、团队下能否够非常好的支持。
另外。有人可能会说。我一開始不採用微服务架构方式。而是在单一进程内基于清晰定义的模块化方式,模块之间通过接口调用。到了适当阶段,必要的时候再将模块拆分为服务。 事实上这个想法显得过于理想,由于进程内良好定义的接口通常不是非常好的服务化接口。
一開始没有考虑服务化的设计方法。那么后期拆分时依旧是一个痛苦的过程。
总结
正如。Martin Fowler 在其文中所说。微服务架构是否就是企业应用开发的未来。还有待时间的检验。 就眼下的情况看,对此我们能够保持慎重的乐观,这条路依旧值得去探索。 实际不论什么的架构决策都是基于我们不完美的现状做出的。这正是架构取舍的微妙之处,超越不论什么的方法论。