本文介绍了越来越受欢迎的微服务架构模式。微服务背后的大思路在于将大型的、复杂的、长期运行的应用程序构建为一组相互配合的、可随时间不断改进的服务。微服务一词意味这每个服务都应该足够小。
有些人甚至主张建立10-100LOC服务。然而虽然需要小型服务,但这不应是主要目标。相反,你应该将系统分解为服务,来解决下文讨论的各种各样的开发和部署问题。一些服务可能确实很微小,然而其他的却可能很大。
微服务架构的本质并不新颖。分布式系统的概念是非常陈旧的。微服务架构也类似于SOA。
它甚至曾被称为轻型或细粒度SOA。事实上,有一种方式就是把微服务看作不涉及商品化及沉重的WS*和ESB的SOA。尽管不是全新的思路,但微服务架构仍然值得进行一番讨论,因为它与传统的SOA不同,更重要的是它可以解决很多组织目前遇到的许多问题。
在这篇文章中,你将了解使用微服务架构的动机以及它与更传统的巨石架构的不同之处。讨论微服务的优点和缺点,你将了解如何解决运用微服务架构包括内部服务通讯和分布式数据管理时遇到的一些关键性技术难题。
整体架构(有时很差)
从最早为Web系统开发应用开始,最为广泛使用的企业应用架构就是将应用所有的服务端组件打包成一个单元。很多的企业级Java应用由一个WAR或EAR文件组成。用其他语言(如Ruby甚至C++)所编写的应用也是同样的情况。
比如,你正在构建一个在线商店,它会接受顾客的订单、检查库存以及可用的额度,然后完成运送。你很可能会把这款应用构建成图1的样子。
图1——整体架构
应用由多个组件构成,包括StoreFront UI,它实现了用户界面,以及用来管理产品目录、处理订单和管理用户账户的服务。这些服务共享一个包含了各个实体(如Product、Order和Customer)的域模型。
尽管有一个逻辑上的模块化设计,但应用还是会作为一个整体进行部署。例如,如果你使用Java的话,那么应用会由一个WAR文件组成,它会在Web容器中运行,如Tomcat。如果应用是Rails版本的话,它会由一个目录结构组成,如果使用Apache/Nginx的话,可以使用Phusion Passenger部署,或者使用Tomcat的时候,利用JRuby进行部署。
这种所谓的整体架构有很多的优点。整体架构开发起来较为容易,因为IDE和其他的开发工具都是面向单个应用开发的。它们测试起来很容易,因为你只需要启动一个应用。整体架构的应用也很容易进行部署,因为你只需要将部署单元(一个文件或目录)复制到运行对应种类服务器的机器上就可以了。
这种方法适用于相对小的应用程序。但对复杂应用来讲,整体架构就会变得很笨重了。对开发者来说,大型的整体架构应用会很难理解和维护。对频繁部署来说,这也是一个障碍。要部署某个应用组件的变更,你必须要构建和部署整个庞大的应用,这会很复杂、有风险、耗时,并且需要与众多的开发人员协调从而导致很长的测试周期。
此外,整体架构会给试验和采用新技术带来困难。例如:如果不重写整个应用的话,很难去尝试使用新的基础框架,而重写整个应用是有风险且不现实的。因此,你经常被迫接受你在项目一开始做出的技术选择。换句话说,整体架构不能进行扩展来支持大型的、长期运行的应用程序。
将应用程序分解为服务
幸运的是,有其他架构模式可支持可扩展性。在《可扩展性的艺术》一书中,描述了一个很有用的三维可扩展性模型:扩展性立方,如图2所示。
图2 – 扩展性立方
在这个模型中要对应用进行扩展,最常用的方式就是在负载均衡器后面运行多个完全相同的应用,这也就是所谓的X轴扩展。对于提升应用的处理能力以及可用性来讲,这是一种很好的方式。
当使用Z轴扩展时,每个服务器均运行相同的代码。在这方面,它与X轴扩展类似。最大的区别在于每个服务器只负责数据的一个子集。系统中有些组件负责将每个请求路由到对应的服务器。一个常用的路由条件就是请求的属性,如要访问实体的主键标,这也就是所谓的sharding。另外一个常见的路由条件是客户类型。例如,相对于免费客户,应用可能会为付费客户提供更高的SLA,这就需要将付费客户的请求路由到具有更高处理能力的不同服务器上面。
Z轴扩展,类似于X轴扩展,提升应用的处理能力和可用性。但它们都无法解决越来越复杂的开发和应用这一问题。为了解决这些问题,我们需要Y轴扩展。
扩展的第三个维度称为Y轴扩展或功能分解。与Z轴扩展中对事情进行拆分类似,Y轴扩展会将不同的事情进行拆分。在应用层,Y轴扩展会将整体应用拆分为一组服务。每个服务实现一组相关的功能,如订单管理、客户管理等。
决定如何将系统拆分为一组服务在很大程度上来讲是一门艺术,不过有一些策略可以提供帮助。拆分服务的一种方式是按照动词(verb)或者是用例来进行拆分。例如,稍后你会看到拆分后的在线商店应用包含了Checkout UI服务,它实现了结账用例的UI功能。
另外一种拆分方式就是将系统按照名词或资源进行拆分。这种服务负责既定类型实体/资源的所有操作。例如,稍后你会看到如何使在线商店具有一个Catalog服务,它会管理产品目录。
理想情况下,每个服务应该只有很小的一个责任集合。Bob Martin(叔叔)曾经提出过使用单一责任原则(SRP)设计类[PDF]。SRP将类的职责定义为变更的原因,而且只有一个原因会导致某个类产生变更。当设计服务时,使用SRP也是很有价值的。
服务设计时,另外一个可以提供帮助的类比对象就是Unix工具列表的设计。Unix提供了大量的工具集,如grep、cat和find。每个工具只执行一件事情,通常会做的特别好,而且可以通过shell脚本与其他工具联合起来执行复杂的任务。遵循Unix系统工具的方式对服务进行建模是很好的,这种方式会创建出单一功能的服务。
要强调的很重要的一点就是分解的目标并不在于片面追求微小(如:有些人所主张的10-100代码行)的服务。与之相反,它的目标在于解决上文中所提到的整体架构所面临的问题和局限性。有些服务很微小是非常合适的,不过其他的会更大一些。
如果对样例应用使用Y轴分解的话,我们得到的架构如图3所示。
图3 – 微服务架构
分解后的应用包含了各种实现用户界面不同部分的前端服务以及多个后端服务。前端服务包括Catalog UI,它实现了产品搜索和浏览,还包括Checkout UI,它实现了购物车和结账过程。后端服务包括相同的逻辑服务,这些已经在本文开始的时候进行了说明。我们已经将应用中的每个主要组件转换成了单独的服务。让我们看一下这样做的结果是什么。
微服务架构的优点和缺点
优点
这种架构有很多优点。首先,每个微服务相对比较小。对开发人员来说,代码更易于理解。很小的代码基并不会拖慢IDE,因此开发人员会更有效率。同时每个服务在启动方面也比大型的整体应用快得多,这同样也会使开发人员更有效率并加速部署。
第二,每个服务可以独立于其他服务进行部署。如果负责某个服务的开发人员需要部署一个变更,这个变更仅仅涉及到这个服务本地的内容,那么他们没有必要协调其他的开发人员。他们可以只部署自己的变更就可以了。微服务架构使持续部署变得可行。
第三,每个服务可以独立于其他服务使用X轴克隆和Z轴分区进行扩展。此外,每个服务可以部署到最适合其资源需求的硬件上。这与使用整体架构时有很大的区别,在整体架构中,具有严重资源需求差异的组件(如CPU密集与内存密集)必须部署在一起。
微服务架构使开发的扩展也变得更为容易。你可以围绕多个小团队(如两个披萨原则)组织研发。每个团队只需负责开发和部署一个服务或一组相关的服务。每个团队能够独立于其他的团队开发、部署和扩展他们的服务。
微服务架构同时也能改善故障隔离。例如,某个服务中的内存泄露只会影响到服务本身。其他服务能够继续正常处理请求。相比之下,整体架构中如果有一个不合格的组件,整个系统就会被拖垮。
最后但同样重要的一点是:微服务架构消除了对某个技术栈的长期依赖。原则上,当开发新的服务时,开发人员可以任意选择最适合该服务的语言和框架。当然,在很多组织中限制可选的技术方案是有一定的道理的,不过关键的一点在于,你不再受制于过去做出的决策。
此外,因为服务比较小,使用更好的语言和技术进行重写是可行。这也意味着,如果对一项新技术的尝试失败的话你尽可以抛弃这个成果而不会给整个项目带来风险,这与采用整体架构有很大的区别。在整体架构中,初始的技术选择严重限制你将来使用不同语言和框架的能力。
缺点
没有什么技术是完美的,微服务架构有一些明显的缺点和问题。首先,开发人员必须要处理创建分布式系统时遇到的额外复杂性。开发人员必须要实现进程间的通信机制。要实现跨多个服务的用例的话,如果不使用分布式事务是很难完成的。IDE以及其他开发工具关注于开发整体应用,并没有为开发分布式应用提供明确的支持。编写涉及多个服务的自动化测试用例也是很有挑战的。在开发整体架构时,你无需处理这样的问题。
微服务架构同样引入了明显的运维复杂性。在这种架构下,有了更多正在运行中的不同部件,也就是不同类型服务的多个实例,在生产环境下必须对它们进行管理。为了成功做到这一点,你需要一个高度自动化的工具,要么是自己编写的代码,要么是类似于PaaS的技术,如Netflix Asgard及其关联组件,或者是现成的PaaS,如Pivotal Cloud Foundry。
同时,部署跨多个服务的特性时你需要认真地协调不同的开发团队,需要根据服务间的依赖关系创建服务如何按顺序部署的规划,这与整体架构有着很大的差异。在整体架构模式下,你可以很容易地一次性更新多个组件。
使用微服务架构的另外一个挑战就是要决定在应用生命周期的哪个时间点上采用这种架构。当开发应用的第一个版本时,你通常还不会遇到这种架构所能解决的问题。另外,使用复杂的、分布式的架构将会延缓开发。
对于初创公司来讲,这可能是一个两难的困境,最大的挑战通常在于如何快速地演化业务模型以及相关的应用。使用Y轴分解可能会使快速迭代更为困难。当挑战变成如何扩展的话,你需要进行功能分解,此时混乱的依赖关系可能让你很难将整体应用分解为一组服务。
鉴于这些问题的存在,不应轻易采用微服务架构。但对于需要进行扩展的应用,如面向客户的Web应用或SaaS应用,这通常是正确的选择。知名站点如eBay[PDF]、Amazon.com、Groupon以及Gilt都已经从整体架构转移到微服务架构上来了。
微服务分解应用程序今天我们先了解到这里,下一篇将为大家带来微服务架构中几个关键的设计问题,一起期待明天的分享吧!