多年以来,我们一直在寻找更好的方法来构建应用系统。我们一直在学习已有的技术,尝试新技术,也目睹过不少新兴技术公司使用不同的方式来构建IT 应用系统,从而提高了客户满意度和开发效率。 Eric Evans 的《领域驱动设计》一书帮助我们理解了用代码呈现真实世界的重要性,并且告诉我们如何更好地进行建模。持续交付理论告诉我们如何更有效及更高效地发布软件产品,并指出保持每次提交均可发布的重要性。基于对Web 的理解,我们寻找到了机器与机器交互的更好方式。Alistair Cockburn 的六边形架构理论 (http://alistair.cockburn.us/Hexagonal+architecture)把我们从分层架构中拯救出来,从而能够更好地体现业务逻辑。借助虚拟化平台,我们能够按需创建机器并且调整其大小,借助基础设施的自动化我们也很容易从一台机器扩展到多台。在类似Amazon 和Google 这样成功的大型组织中,有很多小团队,他们各自对某个服务的全生命周期负责。最近,Netflix 分享了构建大型反脆弱系统的经验,而这种构建方式在10 年前是很难想象的。 随着领域驱动设计、持续交付、按需虚拟化、基础设施自动化、小型自治团队、大型集群系统这些实践的流行,微服务也应运而生。它并不是被发明出来的,而是从现实世界中总结出来的一种趋势或模式。但是没有前面提及的这些概念,微服务也很难出现。在本书接下来的内容中,我会尝试把这些概念整合起来,从而给出一个涉及如何构建、管理和演化微服务的全景图。 很多组织发现细粒度的微服务架构可以帮助他们更快地交付软件,并且有更多机会尝试新技术。微服务在技术决策上给了我们极大的自由度,使我们能够更快地响应不可避免的变化。 1.1 什么是微服务 微服务就是一些协同工作的小而自治的服务。让我们详细地分析一下微服务的定义,看看它有什么不同之处。 1.1.1 很小,专注于做好一件事 随着新功能的增加,代码库会越变越大。时间久了代码库会非常庞大,以至于想要知道该在什么地方做修改都很困难。尽管我们想在巨大的代码库中做到清晰地模块化,但事实上这些模块之间的界限很难维护。相似的功能代码开始在代码库中随处可见,使得修复bug或实现更加困难。 在一个单块系统内,通常会创建一些抽象层或者模块来保证代码的内聚性,从而避免上述问题。内聚性是指将相关代码放在一起,在考虑使用微服务的时候,内聚性这一概念很重要。Robert C. Martin 有一个对单一职责原则(Single Responsibility Principle, http://programmer.97things.oreilly.com/wiki/index.php/The_Single_Responsibility_Principle)的论述:“把因相同原因而变化的东西聚合到一起,而把因不同原因而变化的东西分离开来。”该论述很好地强调了内聚性这一概念。 微服务将这个理念应用在独立的服务上。根据业务的边界来确定服务的边界,这样就很容易确定某个功能代码应该放在哪里。而且由于该服务专注于某个边界之内,因此可以很好地避免由于代码库过大衍生出的很多相关问题。 经常有人问我:代码库多小才算小?使用代码行数来衡量是有问题的,因为有些语言的表达力更好,能够使用很少的代码完成相同的功能。还有一个需要考虑的因素是,一个服务的代码可能有多个依赖项,而每个依赖项又会包含很多代码。此外,一个不可避免的事情是你的领域对象本身很复杂,所以需要更多的代码。澳大利亚RealEstate.com.au 的JonEaves 认为,一个微服务应该可以在两周内完全重写,这个经验法则在他所处的特定上下文中是有效的。 我可以给出的另一个比较老套的答案是:足够小即可,不要过小。当我在会议上做演讲的时候,几乎每次都会问听众:谁认为自己的系统太大了,想把它拆成更小的。几乎所有人都会举手。看起来大家都能够意识到什么是“过大”,那么换句话说,如果你不再感觉你的代码库过大,可能它就足够小了。 另外一个帮助你回答服务应该多小的关键因素是,该服务是否能够很好地与团队结构相匹配。如果代码库过大,一个小团队无法正常维护,那么很显然应该将其拆成小的。在后面关于组织匹配度的部分会对该话题做更多讨论。 当考虑多小才足够小的时候,我会考虑这些因素:服务越小,微服务架构的优点和缺点也就越明显。使用的服务越小,独立性带来的好处就越多。但是管理大量服务也会越复杂,本书的剩余部分会详细讨论这一复杂性。如果你能够更好地处理这一复杂性,那么就可以尽情地使用较小的服务了。 1.1.2 自治性 一个微服务就是一个独立的实体。它可以独立地部署在PAAS(Platform As A Service, 平台即服务)上,也可以作为一个操作系统进程存在。我们要尽量避免把多个服务部署到同一台机器上,尽管现如今机器的概念已经非常模糊了!后面会讨论到,尽管这种隔离性会引发一些代价,但它能够大大简化分布式系统的构建,而且有很多新技术可以帮助解决这种部署模型带来的问题。 服务之间均通过网络调用进行通信,从而加强了服务之间的隔离性,避免紧耦合。 这些服务应该可以彼此间独立进行修改,并且某一个服务的部署不应该引起该服务消费方的变动。对于一个服务来说,我们需要考虑的是什么应该暴露,什么应该隐藏。如果暴露得过多,那么服务消费方会与该服务的内部实现产生耦合。这会使得服务和消费方之间产生额外的协调工作,从而降低服务的自治性。 服务会暴露出API(Application Programming Interface,应用编程接口),然后服务之间通过这些API 进行通信。API 的实现技术应该避免与消费方耦合,这就意味着应该选择与具体技术不相关的API 实现方式,以保证技术的选择不被限制。本书后面会讨论选择好的解耦性API 的重要性。 如果系统没有很好地解耦,那么一旦出现问题,所有的功能都将不可用。有一个黄金法则是:你是否能够修改一个服务并对其进行部署,而不影响其他任何服务?如果答案是否定的,那么本书剩余部分讨论的那些好处对你来说就没什么意义了。为了达到解耦的目的,你需要正确地建模服务和API。后面会针对这个话题做更多讨论。