微服务(Microservices)说在前面好久没写博文了,心里痒痒(也许是换工作后,有点时间了吧)。最近好像谈论微服务的人比较多,也开始学习一下,但是都有E文,看起来半懂不懂的。Martinfowler的《微服务》,也算是入门必读了。有人翻译过,但是只有一半。还是自己练练手吧。微服务“微服务架构”一词在过去几年里广泛的传播,它用于描述一种独立部署的软件应用设计方式。这种架构方式并没有非常准确的定义,但是在业务能力、自动部署、端对端的整合、对语言及数据的分散控制上,却有着显著特征。“微服务”----只不过在满大街充斥的软件架构中的一新名词而已。尽管我们非常鄙视这样的东西,但是这玩意所描述的软件风格,越来越引起我们的注意。在过去几年里,我们发现越来越多的项目开始使用这种风格,以至于我们身边的同事在构建企业应用时,把它理所当然的认为这是一种默认开发形式。然而,很不幸,微服务风格是什么,应该怎么开发,关于这样的理论描述却很难找到。简而言之,微服务架构风格,就像是把小的服务开发成单一应用的形式,每个应用运行在单一的进程中,并使用如HTTP这样子的轻量级的API。这些服务满足某需求,并使用自动化部署工具进行独立发布。这些服务可以使用不同的开发语言以及不同数据存储技术,并保持最低限制的集中式管理。开始介微服务风格前,先介绍整体风格:即把一个完整的应用当成一开发单元。企业应用通常包含三个部分:客户端界面(由HTML、Javascript组成,使用浏览器进行访问)、数据库(由许多的表组件构成一个通用的、相互关联的数据管理系统)、服务端应用。服务端应用处理HTTP请求、执行领域逻辑、检索并更新数据库中的数据、使用适当的HTML视图发送给客户端。服务端应用是完整的----由单一的逻辑层次执行。系统中任务变更都会导到服务端的应用重新编辑并发布一个新的版本。这样的整体服务是这样的构建系统的很自然的方式。虽然利用开发语基础特性会把应用封装成类、函数、命名空间,但是业务中所有逻辑都要在单一的进程中处理完成。在某些场景中,开发者可能在的笔计本中开发、测试应用,然后利用部署通道来保证经过正常测试、发布的修改内容正确的发布的产品中。也可以使用横向扩展,通过负载均横系统将事个应用部署到多台服务器上。整体风格的应用也是相当成功的,但是越来越多的人感觉到有点不妥,特别是在云中进行应用的发布时。变更发布周期被绑定了----原来可以划分成小的应用、小的需要的变更,需要统一的进行编译和发布。随着时间的推移,人们通常难于维护一种优美的模块化的结构,使得一个模块的变更很难不会影响到其它的模块。进行扩展,也需要进行整体的扩展,而不能根据进行部分的扩展。图1:整理架构与微服务架构这些原因导致了微服务架构风格的出现:以服务构建应用。因为服务可以独立部署、独立扩展,服务也可以提供模块化的边界,并且不同的使用也可以使用不同的开发语言。服还可以以不同的周期进行管理。微服务风格关不是我们发明的,也不是一个新的东西,它至少起源于Unix时代的设计原则。之所以这样,我们认为只是当时很少人考虑过这种风格,并认识到把软件使用这种的风格可以带来更多的好处。微服务风格的特性我们没有办法对微服务风格进行准确的定义,但是我们可以偿试着描述一下微服务风格所应该具有的觉特性,这样就可以对它打上相应的标签了。正如其它定义中对特性的描述一新,并不是所有的微服务风格都要所有的特性,但是我们认为常见的微服务都应该有这些特性。尽管我们是相当松散的社区核心成员,但是我们也计划偿试描述我们工作中或者在其它我们了解的组件中所理解的微服务。当然,我们并不依赖于那些已经明确过的定义。组件与服务自从我们从事软件行业以来,一直希望能够构建由组件组成的系统,就像我们所看到的实现世界由物件构成的一样。在过去的几十年里,我们已经看到了大部分语言平台的公共库的进行了精简,并取得可观的进展。当我们谈论组件的时候,有可能会因为组件的不同定义引起混乱。因此我们申明,这里谈到的组件是指软件中独立的单元,它能独立替代和独立更新。微服务架构也使用组件库,但是它把软件拆分成服务,并认为这是主要的组织形式。我们把组件库定义为程序中相互关系、并使用内存中调用的组件,把服务定义为进程间使用如Web请求服务或者远程调用来相互通信的组件。(这种定义的方式与其它面向对象程序中服务对象的概念是不一样的。)把服务当成组件(而不是组件库)一个主要的原因是服务可以独立的部署。如果你的应用由多个组件库组成并跑在一个进程中,那么任何组件的变更都将导致整体应用的重新发布。但是如果由许多服务构成的应用,你可以想像的到每个服务的变更仅需要发布相应的服务。当然,这也不是绝对的,比如导致服务接口的变更的更新就需要相应服务的变化,但优秀微服务构架,会尽量避免这种服务间的耦合并完善服务的交互接口。把服务当成组件的另一个考虑是这将拥有更新清晰的接口。许多开发语言并没有良好的定义公共接口的机制。通常只有文档和规范说明,让用户避免组件间会导致组件耦合的过度的依赖。不过服务由是是通过明确的远程接口调用,这个问题就很容易解决了。使用服务也有它的不足之处。远程调用比进制内部调用更消耗性能,而且远程的API比较粗糙,难以使用。如果由于对组件的职责进行变更,影响到跨进程间的交互,那么这操作起来也比较困难。第一个可能的特性,我们看到每个服务是运行在独立的进程上的。注意,这只是第一个可能的特性。服务也可以由多个进程组成,它们是同时开发和部署的,例如服务可能用到一个应用进制和一种数据禀。围绕业务功能进行组织当寻找把一个大的应用拆分成小的部分时,主管通常注意在技术层面,拆分成UI组、服务逻辑组和数据库组。当使用这种标准对团队进行划分时,甚至小小的更变都将导致跨团队间项目协作,从而消耗时间和预算审批。一个高效的团队会针对这种情况进行改善,关注它们所涉及的应用逻辑,并从中做出较好的选择。换句话说,逻辑无处不在。Conway'sLaw的实践就是一个例子。[plain]viewplaincopy任何组织设计一个系统(广义上的系统)都会产生一种设计,其结构为其组织通信结构的复本。--MelvynConway,1967图2:Conway'sLaw的实践微服务更倾向于围绕业务功能对服务结构进行划分、拆解。这样的服务,是针对业务领域有着关完整实现的软件,它包含使用接口、持久存储、以及对旬的交互。因此团队应该是跨职能的,包含完整的开发技术:用户体验、数据库、以及项目管理。图3:通过团队边界强调服务边界就采用这种组织形式。不同职能的团队同时为各自的产品构建和运营负责,同时每个产品又拆分成多个通过消息引擎通信的单独服务。大型的整体型应用也可以按照业务功能进行模块化的,尽管这种例子不常见。当然,我们敦促一个大型的团队将一个构建成整体型的应用依照业务功能进行拆分。我们能看到主要问题在于,这种组件形式会导致很多的上下文依赖。如果在大量的模块边界上都存在这种大量的调用,对于团队的每个成员来说,短期内是很难记住的。此外,我们发现模块化方式需要大量的规范去强制执行,当然,大量明确的拆分也让服务组件在团队的边界中更加清晰。产品不是项目大部分的软件开发者都使用这样的开发模式:至力于提供一些被认为是完整的软件。一旦开发完成,软件将移交给维护部门,然后,开发组就可以解散掉了。微服务的支持者认为,这种做法是不可取的,并提议开发组应该负责产品的整个生命周期。一个常见的证明是:Amazon的“你编译,你运维(youbuild,yourunit)”的理念,它要求开发团队对软件产品的整个生命周期负责。这要求开发者每天都关注软件产品的运行情况,并与用户联系的更紧密,同时承担一些售后支持。成熟的产品会与业务功能进行绑定。除了把软件看成既定功能的集合外,会进一步关心“软件如何帮助用户实现业务功能”这样的问题。采用整体型的架构并不是没有原因的,但是越小的服务粒度越容易促进用户与服务提供商之前的关系。强化终端及弱化通道当构建不同的进程间通信机制的时候,我们发现有许多的产品和方法能够把更加有效方法强加入的通信机制中。比如企业服务总线(ESB),这样的产品提供更有效的方式改进通信过程中的路由、编码、传输、以及业务处理规则。微服务倾向于做如下的选择:强化终端及弱化通道。微服务的应用致力松耦合和高内聚:采用单独的业务逻辑,表现的更像经典Unix意义上的过滤器一样,接受请求、处理业务逻辑、返回响应。它们更喜欢简单的REST风格,而不是复杂的协议,如WS或者BPEL或者集中式框架。有两种协议最经常被使用到:包含资源API的HTTP的请求-响应和轻量级消息通信协议。最为重要的建议为:[plain]viewplaincopyBeoftheweb,notbehindtheweb(善于利用网络,而不是限制使用网络。)----IanRobinson微服务团队采用这样的原则和规范:基于互联网(广义上,包含Unix系统)构建系统。这样经常使用的资源几乎不用什么的代价就可以被开发者或者运行商缓存。第二种做法是通过轻量级消息总线来发布消息。这种的通信协议非常的单一(单一到只负责消息路由),像RabbitMQ或者ZeroMQ这样的简单的实现甚至像可靠的异步机制都没提供,以至于需要依赖产生或者消费消息的终端或者服务来处理这类问题。在整体工风格中,组件在进程内执行,进程间的消息通信通常通过调用方法或者回调函数。从整体式风格到微服务框架最大的问题在于通信方式的变更。从内存内部原始的调用变成远程调用,产生的大量的不可靠通信。因此,你需要把粗粒度的方法成更加细粒度的通信。分散治理集中治理的一种好处是在单一平台上进行标准化。经验表明这种趋势的好处在缩小,因为并不是所有的问题都相同,而且解决方案并不是万能的。我们更加倾向于采用适当的工具解决适当的问题,整体式的应用在一定程度上比多语言环境更有优势,但也适合所有的情况。把整体式框架中的组件,拆分成不同的服务,我们在构建它们时有更多的选择。你想用Node.js去开发报表页面吗?做吧。用C++来构建时时性要求高的组件?很好。你想以在不同类型的数据库中切换,来提高组件的读取性能?我们现在有技术手段来实现它了。当然,你是可以做更多的选择,但也不意味的你就可以这样做,因为你的系统使用这种方式进行侵害意味着你已经有的决定。采用微服务的团队更喜欢不同的标准。他们不会把这些标准写在纸上,而是喜欢这样的思想:开发有用的工具来解决开发者遇到的相似的问题。这些工具通常从实现中成长起来,并进行的广泛范围内分享,当然,它们有时,并不一定,会采用开源模式。现在开源的做法也变得越来越普遍,git或者github成为了它们事实上的版本控制系统。Netfix就是这样的一个组织,它是非常好的一个例子。分享有用的、尤其是经过实践的代码库激励着其它的开发着也使用相似的方式来解决相似的问题,当然,也保留着根据需要使用不同的方法的权力。共享库更关注于数据存储、进程内通信以及我们接下来做讨论到的自动化等这些问题上。微服务社区中,开销问题特别引人注意。这并不是说,社区不认为服务交互的价值。相反,正是因为发现到它的价值。这使得他们在寻找各种方法来解决它们。如TolearantReader和Consumer-DrivenContracts这样的设计模式就经常被微服务使用。这些模式解决了独立服务在交互过程中的消耗问题。使用Consumer-DrivenContracts增加了你的信心,并实现了快速的反馈机制。事实上,我们知道澳大利亚的一个团队致力使用Consumer-DrvienContracts开发新的服务。他们使用简单的工程,帮助他们定义服务的接口。使得在新服务的代码开始编写之前,这些接口就成为自动化构建的一个部分。构建出来的服务,只需要指出这些接口适用的范围,一个优雅的方法避免了新软件中的'YAGNI'困境。这些技术和工具在使用过程中完善,通过减少服务间的耦合,限制了集中式管理的需求。也许分散治理普及于亚马逊“编译它,运维它”的理念。团队为他们开发的软件负