在2014年,Sam Newman,Martin Fowler在ThoughtWorks的一位同事,出版了一本新书《Building Microservices》。该书描述了如何按照Microservice架构模式设计及搭建一个具备良好扩展性并可持续开发的系统。除此以外,该书还将基于该模式的系统演化流程与Continuous Delivery等当前甚为流行的开发流程结合在了一块儿,使得Microservice架构模式看起来很是具备吸引力。基于这些缘由,该架构模式迅速被业界所熟知,并在多个产品中被尝试着使用。这其中就包含了咱们公司的产品vRA。html
在这一年多的时间里,咱们不但真正地体会到了Microservice所具备的一系列优势,也犯过一系列错误。所以在这篇文章里,我会对Microservice架构模式进行简单地介绍,并将咱们所获得的经验和教训介绍给你们。前端
Monolith数据库
网上对Microservice进行介绍的文章经常以Monolith做为开头,我也不会例外。缘由是,知道了Monolith的不便以后才能更容易地理解Microservice架构模式所具备的各类优势。浏览器
首先请回想一下咱们所开发的服务是什么样子的。一般状况下,这个服务所对应的代码由多个项目所组成,各个项目会根据自身所提供功能的不一样具备一个明确的边界。在编译时,这些项目将被打包成为一个个JAR包,并最终合并在一块儿造成一个WAR包。接下来,咱们须要将该WAR包上传到Web容器中,解压该WAR包,并从新启动服务器。在执行完这一系列操做以后,咱们对服务的编译及部署就已经完成了:缓存
这种将全部的代码及功能都包含在一个WAR包中的项目组织方式被称为Monolith。在项目较小的状况下,这种代码组织方式仍是能够接受的:更改完代码后,软件开发人员能够趁着编译器编译代码的时候冲杯咖啡,并在回到座位后花费一分钟部署刚刚编译出来的WAR包以便测试本身刚刚所作的更改。但随着项目的逐渐变大,整个开发流程的时间也会变得很长:即便在仅仅更改了一行代码的状况下,软件开发人员须要花费几十分钟甚至超过一个小时的时间对全部代码进行编译,并接下来花费大量的时间从新部署刚刚生成的产品,以验证本身的更改是否正确。安全
若是应用的部署很是麻烦,那么为了对本身的更改进行测试,软件开发人员还须要在部署前进行大量的环境设置,进而使得软件开发人员的工做变得繁杂而无趣:服务器
从上面的示意图中能够看到,在应用变大以后,软件开发人员花在编译及部署的时间明显增多,甚至超过了他对代码进行更改并测试的时间,效率已经变得十分低下。网络
在变得愈来愈大的同时,咱们的应用所使用的技术也会变得愈来愈多。这些技术有些是不兼容的,就好比在一个项目中大范围地混合使用C++和Java几乎是不可能的事情。在这种状况下,咱们就须要抛弃对某些不兼容技术的使用,而选择一种不是那么适合的技术来实现特定的功能。架构
除此以外,因为按照Monolith组织的代码将只产生一个包含了全部功能的WAR包,所以在对服务的容量进行扩展的时候,咱们只能选择重复地部署这些WAR包来扩展服务能力,而不是仅仅扩展出现系统瓶颈的组成:框架
可是这种扩展方式极大地浪费了资源。就以上图所展现的状况为例:在一个服务中,某个组成的负载已经达到了90%,也就是到了不起不对服务能力进行扩容的时候了。而同一服务的其它三个组成的负载尚未到其处理能力的20%。因为Monolith服务中的各个组成是打包在同一个WAR包中的,所以经过添加一个额外的服务实例虽然能够将须要扩容的组成的负载下降到了45%,可是也使得其它各组成的利用率更为低下。
能够说,全部的不便都是因为Monolith服务中一个WAR包包含了该服务的全部功能所致使的。而解决该问题的方法就是Microservice架构模式。
Microservice架构模式
简单地说,Microservice架构模式就是将整个Web应用组织为一系列小的Web服务。这些小的Web服务能够独立地编译及部署,并经过各自暴露的API接口相互通信。它们彼此相互协做,做为一个总体为用户提供功能,却能够独立地进行扩容。就如下图所示的WikiPedia服务架构为例:
从上图中能够看到,WikiPedia包含了一系列服务,如数据访问服务Databases,搜索服务Search等。这些服务都包含了数量不等的服务实例,以确保能在不一样负载的状况下为用户提供优质的服务。在用户的请求到达时,它们将协同工做,一块儿完成对用户请求的响应。
在使用Microservice架构模式的状况下,软件开发人员能够经过编译并从新部署单个子服务的方式来验证本身的更改,而再也不须要从新编译整个应用,从而节省了大量的时间。同时因为每一个子服务是独立的,所以各个服务内部能够自行决定最为合适的实现技术,使得这些子服务的开发变得更为容易。最后若是当前系统的容量不够了,那么咱们只须要找到成为系统瓶颈的子服务,并扩展该子服务的容量便可:
Microservice经验谈
以上就是对Miscroservice架构模式的介绍,是否是很简单?实际上,这是一个正在发展的架构模式。在众多讨论中,关于该模式的标准实现,以及最佳实践等众多话题并无彻底达成一致。所以我在这里介绍的,是各个论坛讨论中基本达成一致意见的一系列经验。而各位在实现本身的Microservice架构模式时,一方面能够借鉴这些经验,另外一方面也能够根据项目自己需求调整Microservice架构模式的实现方法。
转变你的视角
不管是在编写一个服务,仍是在编写一个桌面应用,咱们经常会首先尝试将须要实现的功能分割为一系列组件,并围绕着这些组件设计完成业务逻辑所须要的工做流及数据流。这种设计方法将致使实现业务逻辑的全部组件都运行在同一个进程以内,而且各个业务逻辑的实现也在同一个进程以内运行:
可是在Microservice架构模式中,咱们须要更高一层的分割:在尝试将须要实现的功能分割成为一系列组件以前,咱们首先须要考虑如何将须要实现的功能交由彼此相互独立的一系列服务来完成。例如在一个电子商务网站中,对用户购买商品这一业务流程的支持就能够交由三个服务来完成:在用户浏览商品的时候,其使用的是商品浏览服务;在用户将商品添加到购物车并生成订单的时候,其使用的是订单服务;而在用户进行网上支付的时候,其使用的则是付款服务。根据这种分割思路,咱们的应用将运行在三个独立的进程之中:
同时这三种服务各自的侧重点并不相同:商品浏览服务中,对数据库的读操做比写操做多得多,所以对读操做进行优化将很是显著地提升服务的运行性能;而订单服务则是写操做居多,所以咱们须要对订单的写入性能进行优化;付款服务涉及到用户的财产,所以其对安全要求会偏高一些。这种差别可能致使最适合实现这三个服务的技术各不相同。因为这些服务是彻底独立的,所以咱们彻底能够根据子服务的需求来决定所须要使用的技术,而再也不须要考虑这些类库是否与已有系统兼容。
使用最合适的技术所带来的优势就是,服务的代码会变得很是清晰明了,甚至在有些状况下能够达到简洁优雅的程度。在一些讨论中,有些人甚至建议一个服务只须要10到100行代码(他们经常使用简写LoC,即Lines of Code)。再加上服务已经独立出来,而再也不与其它服务混合在一块儿,所以正确地使用Microservice架构模式大大提升了代码的维护性以及新人上手的速度,也有助于技术人员在平常工做中进行技术集的更新及转换。
可是这种对于服务的分割和组件之间的分割并不相同。最重要的一点就是在各个服务之间进行通信的消耗相对于在同一个进程中而言是很是大的。在设计一个组件的时候,咱们须要考虑该组件所给出的接口可以尽量地知足当前及从此的一系列能够预见的需求,这便要求该组件所提供的API具备必定的前向兼容性,并拥有一系列其它特性,如灵活性,扩展性等等。这经常致使该组件所提供的API具备较细的粒度。在程序运行时,对该组件所提供的API的调用就在当前进程中进行,速度很是快,所以频繁地对该细粒度API进行调用并无太大的问题。可是一个跨服务调用所须要的时间则比进程内调用的时间长不少。若是在处理一个请求的时候须要太多的跨服务调用,那么整个应用的性能将变得没法忍受。所以咱们在执行服务分割时定义的API须要是粗粒度的API。
就让咱们以一个电子商务网站为例。在为用户生成订单时,电子商务网站经常须要列出各个商品的主要信息,商品的价格,优惠幅度,并经过库存系统检验该商品的库存,从而获得整个订单的内容。若是每次与其它服务沟通都须要100毫秒,并且整个订单包含了20件货物,那么系统准备订单的时间就会达到8秒(100ms * 4次调用 * 20件商品)。这从用户的角度来讲是不能够接受的性能。并且随着订单中所包含商品数量的增多,系统准备订单的时间会线性增加,进而使得系统的性能更加不可忍受。
究其缘由,实际上仍是由于准备订单所调用的API的粒度太细了。若是订单系统可以一次性地把一件商品的主要信息,价格,优惠幅度以及库存信息从商品服务中取回来,那么其效率就将提升四倍。若是订单系统不须要为每件商品依次发送请求,而是能够经过一次性地服务间调用就能取回全部须要的信息,那么系统准备订单的时间将不会再随着订单的增大而增加。所以在Microservice架构模式中,各个服务应该提供能够被灵活使用的粗粒度API,以减小各类跨服务调用的消耗。
除了各个服务所提供的API的粒度,服务分割的粒度也是在服务分割过程当中须要考虑的因素。若是一个服务的粒度过小,那么它所提供的API的粒度也不会高。一个较为广泛的见解是,在Microservice架构模式中,一个服务须要可以独立地完成特定的业务逻辑,至少是某个独立资源的CRUD操做。例如在电子商务网站中,咱们须要一个服务可以独立地完成对商品相关信息的读取,如商品的主要信息,商品的价格,参与的优惠活动等。
这里有一个例外,那就是公共功能的处理。试想在一个应用中,咱们经常须要一个权限管理组件来管理用户所具备的各个权限。权限管理组件经常实现了一种公用的安全模型(Security Model),如ACL(Access control list),RBAC(Role-based access control)等。在每次访问一个子服务的时候,这些服务都须要检查用户所具备的权限:
发现问题了么?是的,每次对一个产品系统及订单系统的调用都须要从权限系统中获得当前用户的权限,才能决定用户是否可以访问特定信息。若是这样的公共服务不少,那么该系统的性能将会变得很是差。
解决该问题的一种方法就是在各个系统中将下次还可以使用的信息缓存起来,也就是在这些系统中为用户建立一个会话。因为每一个系统可能由多个服务实例所组成,为了可以重复利用会话中所储存的信息,减小向公共服务发送请求的次数,咱们须要经过负载平衡技术让系统中的同一个服务实例处理同一个用户的请求。有关如何实现该功能,请见个人另外一篇文章《企业级负载平衡简介》。
除了性能问题以外,公共服务还会与各个服务产生一种逻辑上的依赖关系。让咱们继续经过权限系统这个例子进行讨论。当权限管理的组成存在于各个服务中的时候,咱们能够直接经过传入用户的信息以及须要访问的资源就能判断出到底用户是否可以访问特定资源。也就是说,从权限管理组成所返回的实际上就是一个布尔类型的数据。但若是权限管理再也不是一个组成,而是一个服务,那么为了不每次都调用权限管理服务,咱们须要在用户的会话中记录用户所具备的权限。在用户下次访问该服务的时候,咱们能够经过直接检查该用户所具备的全部权限就能决定其是否可以访问特定资源了。这些在用户会话中记录的权限经常具备其特定的表现方式,例如特定形式的字符串,而这种字符串表示须要同时被服务和权限管理服务所理解,从而形成了这两个服务之间的耦合:
可是这种方式为子服务加强了对权限系统的依赖性。和组件之间的耦合同样,增大的耦合性会致使服务的重用性降低。
因此说,如何对服务进行分割其实是Microservice架构模式中最须要技巧的事情。在分割过程当中,服务的整体性能是相当重要的,而各个服务的独立性也是你们所最为关心的特性。固然,Microservice架构模式仍在逐渐发展中,所以相信会有愈来愈多的实践经验被你们所发掘出来,进而指导咱们更好地对服务进行分割。
共享服务
在前面一节中,咱们已经提到了公共服务。实际上,这是Microservice架构模式中最须要技巧的一部分。
实际上,Microservice架构模式实现中经常须要一系列公有服务以辅助整个应用的运行。除了咱们刚刚提到的权限管理服务,咱们还须要可以监控各个服务实例的服务状态,服务实例的添加删除升级管理等等。这些服务在各个子服务的服务实例之间共享,甚至能够在其它应用中被重用。
只是不少人拥有一个这样的误区,那就是Microservice架构模式可让服务的开发变得更容易。而实际状况则刚好相反。在刚开始使用Microservice架构模式开发应用的时候,其效率是明显低于经过Monolith进行开发的:
从上图中能够看到,在刚开始的阶段,使用Microservice架构模式开发应用的效率明显低于Monolith。可是随着应用规模的增大,基于Microservice架构模式的开发效率将明显上升,而基于Monolith模式开发的效率将逐步降低。
为何呢?这是由于Microservice是一个架构模式,而不是一个特定的技术解决方案。其并不会将开发中的各个难点所有转移,而只是容许经过更为合适的技术来适当简化单个子服务的开发,或者绕过开发中可能遇到的部分难点。可是为了支持各个子服务的运行,咱们还须要建立一系列公共服务。这些公共服务须要在编写第一个子服务的同时进行。这是致使Microservice架构模式在开发初期会具备较低效率的一个缘由。
然而使用特定技术并不会绕过开发中所能遇到的全部难点。因为在Microservice架构中,各个子服务都集中精力处理自己的业务逻辑,而全部的公共功能都交由公共服务来完成,所以公共服务在保持和各个子服务的松耦合性的同时还须要提供一个足够通用的,可以在必定程度上知足全部当前和将来子服务要求的解决方案。而这也是致使Microservice架构模式在开发初期会具备较低效率的另一个缘由。
而在开发的后期,随着Monolith模式中应用的功能逐渐变大,增长一个新的功能会影响到该应用中的不少地方,所以其开发效率会愈来愈差。反过来,因为Microservice架构模式中的各个子服务所依赖的公共服务已经完成,并且子服务自己能够选择适合本身的实现技术,所以子服务的实现一般只须要关注自身的业务逻辑便可。这也是Microservice架构模式在后期具备较高效率的缘由。
当咱们再次经过Microservice架构模式搭建应用的时候,其在开发时的效率劣势也将消失,缘由就是由于在前一次基于Microservice架构模式开发的时候,咱们已经建立过一次公共服务,所以在这个新的应用中,咱们将这些公共服务拿来并稍事改动便可:
从上图中能够看到,虽然咱们仍然须要花一些时间来对公共服务进行一些修改,可是此时所致使的效率降低已经再也不那么明显了。也就是说,就算是在前期,咱们已经拥有了较高的开发效率。
并且随着Microservice架构模式的不断流行,在网络上会有愈来愈多的用户共享本身的公共服务解决方案。那么第一次按照Microservice架构模式编写应用所致使的性能降低也会逐渐变得愈来愈小。
模型匹配
OK。在介绍了共享服务以后,咱们就能够讨论Microservice架构模式中的另一个问题:模型匹配了。在Microservice中,各个服务是彼此独立的,并且是关注于自身业务逻辑的。所以在看待一个事物的时候,Microservice可能拥有不一样的视角,进而形成了各个子服务中的对应模型并不匹配。
例如在一个IaaS云中,一个用户所具备的角色可能会根据他所拥有的职责来划分:云上拥有一系列用于监控的用户,用来完成对云的总体运行监控等工做(不包含查看用户数据,这是个安全问题)。同时云上的用户又能够分为账号管理员,Tenant管理员,资源管理员以及普通用户等。而在其上运行的应用即服务(AaaS,Application as a Service)中,其用户的职责划分多是另外一个样子:在AaaS上定义应用的是应用架构师,负责应用部署及维护的则是运维人员。在应用架构师设计一个应用的时候,其并须要拥有IaaS云上访问资源的权限,却并不须要分配资源的权限,可是运维人员须要拥有该权限以对应用进行部署和维护。
也就是说,IaaS云中的权限划定和AaaS服务中的权限划定并不同。一般状况下,咱们经常在业务集成时执行一次对权限的匹配:
从上图中能够看出,因为AaaS服务是运行在IaaS之上的,所以为了可以操做IaaS中所包含的各个资源,AaaS服务须要将本身的用户角色匹配到IaaS所定义的角色上。例如应用架构师须要可以在定义应用的时候须要知道IaaS上所具备的资源,并须要可以指定到底哪些人可使用这些应用,所以其须要拥有IaaS的Tenant管理员,资源管理员及普通用户三种角色。而AaaS上的运维人员则只须要在部署和维护时察看IaaS上所拥有的资源,所以其只须要资源管理员及普通用户两种角色。
可是这么作有两点很差的地方:若是Microservice中只包含了几个服务,并且这种服务之间的依赖关系并非不少,那么这种服务匹配还可以解决,可是若是整个系统之间各个子服务的沟通不少,那么在各个子服务之间进行角色匹配将变成一个噩梦:
解决该问题的方法就是使用咱们上节所介绍的公共服务对它们进行管理。在提供一个集中的公共服务的状况下,咱们就再也不须要处理这么多的模型转化了:
除此以外,仅仅简单地对角色进行匹配实际上并不那么合适:就应用架构师而言,其须要的是查看当前的已有资源,却不须要对资源进行分配。所以其须要的是对资源的读权限。而运维人员则不只仅须要可以读取资源信息,更须要对资源进行分配,所以其须要的是资源的读写权限。若是仅仅像上面那样在IaaS层为应用架构师赋予对资源的读写权限,那么应用架构师就可能拥有了错误的权限,进而执行了错误的操做。而相对地较为合适的方式则是对这些权限进行细分,即在权限中区分读写权限等:
所以在集中的公共服务中,咱们须要使用较为细粒度的模型。该细粒度模型须要具备较高的灵活性,以可以无损地表示各个服务中的相应模型。
相信您如今已经可以看出,虽说Microservice架构模式将单个子服务的实现简化了,可是复杂化了数据的处理。所以相较于咱们以往所编写的应用,Microservice架构模式会在数据相关的一些特性上遇到一系列麻烦。
一个较为常见的麻烦就是保持多个子服务之间数据的一致性。咱们知道,在服务中,保持一致性的工做经常是由事务来完成的。而若是但愿在Microservice架构模式实现中保持子服务之间数据的一致性,咱们可能就须要使用分布式事务了。可是分布式事务自己就是一个很是复杂而且难以操做的东西,所以就如今而言,这种问题其实是很是难以解决的。可是反过来说,事务自己也是表示一种逻辑上的强耦合,所以咱们须要真正反思的则是这些须要使用事务来保持数据一致性的子服务是否应该属于同一个服务。固然,咱们能够在某种程度上借鉴NoSQL数据库中的一些作法。例如在一个服务更新了数据之后,咱们使用一种异步机制来保持数据的一致性,就好像不少NoSQL数据库不保证用户的数据当即可读同样。
另外一个较为常见的麻烦就是粒度的问题。咱们在前面已经说过,在Microservice的各个子服务之间进行服务间调用效率是十分低下的。为了减小屡次服务间调用,各个子服务所提供的API的粒度须要尽可能地粗,却须要尽可能地保持灵活性。最好的状况就是能够经过一次服务间调用来获得全部想要的信息。
项目管理
除了上面所讨论的一系列技术因素以外,Microservice架构模式的开发还存在着一系列项目管理上的难题。
首先,因为Microservice架构模式中的各个子服务可能使用了不一样的技术搭建,例若有些子服务是由Java开发的,有些则是由Python开发的,并且它们所使用的Servlet容器并不相同,所以由Microservice架构模式所搭建的应用可能须要很是复杂的环境设置。这对于传统的运维人员来讲是很是困难的一个任务。而相对于这些运维人员而言,负责各个子服务开发的开发人员才是有关该服务运行及部署的专家。所以在Microservice架构模式中,开发及运维的职责均发生了变化:开发人员不只仅须要负责子服务代码的编写,还须要考虑该子服务的平常运维。而运维人员须要向开发人员给出一些运维相关的建议,并在总的方向上掌控产品的平常运维。
这样作的好处则在于:开发人员会直接接触到生产环境,能够快速地跟踪并解决问题,而再也不须要经过客户及运维人员的转述等步骤才开始处理问题,也避免了在转述过程当中出现的误差。除此以外,开发人员也能更清楚地了解用户究竟是如何使用他们所建立出来的产品的,进而建立出来更容易被使用及管理的子服务。
可是这也会致使项目管理出现一些困难。首先,不管是开发人员仍是管理者都须要了解并处理一系列运维相关的问题。这会分散他们的注意力,使得开发效率的下降。其次,因为一个子服务经常同时包含前端,后台,数据库,测试,甚至运维相关的一些任务,所以子服务的开发人员经常须要了解服务开发的大部分组成。这种人才在中国市场上并很少见,所以比较抢手。并且因为一个开发人员须要接触太多的功能和技术,所以不少时候没有办法深刻地研究它们。由此所致使的问题则是,在遇到较为困难的问题时,软件开发人员须要花费较多的时间来分析并解决该问题。若是该问题较为严重,那么它将会严重影响整个组的开发进度。从项目管理的角度来说,这其实是一件很是危险的事情。
一个理想的解决方案就是,当前子服务所使用的各个技术都有一个专家。可是一个全栈开发人员,还须要是某一方面的技术专家,雇佣该人的成本可想而知。
除此以外,咱们还须要在按照Microservice架构模式开发的时候使用一系列标准化的开发及测试流程。其中和Microservice最天然契合的就是如今最为流行的Continuous Delivery,或被称为是DevOps。在这些自动化流程的帮助下,软件开发人员能够快速地完成一次迭代:在对代码更改完毕之后,软件开发人员能够直接开始对本身的更改进行编译,运行单元测试及功能测试。接下来,系统将会把刚刚编译好的代码自动进行部署,并在整个系统中执行集成测试。在集成测试完毕以后,质量管理人员或软件开发人员本身会在该系统中进行一次测试,并在完成测试后进行复杂的性能测试,并在经过性能测试后进行部署。
全部这一切实际上都和使用Monolith开发时所使用的流程相似。惟一不一样的是,在基于Microservice架构模式的开发中,这种自动化的流程变得更为重要了。由于基于Microservice架构模式所搭建的应用经常使用了不一样的逻辑,所以部署一个完整的环境就会变得很是复杂。因此由这些自动化流程来负责测试环境的部署则大大地减轻了软件开发人员的负担,也是提升软件开发人员工做效率的基础。
同时因为软件开发人员须要随时执行应用程序的部署来测试本身刚刚所作的更改,所以其须要可以随时分配到其所须要的各个资源,如部署应用所须要的计算资源,内存以及存储等。而这种功能则正是云这种商业模式所提供的功能。所以在开发基于Microservice架构模式的应用时,咱们则尽可能基于某些云来开展咱们的持续开发流程。
Microservice实现
在本节中,咱们将对实现Microservice架构模式时所经常使用的一些方法进行讲解。
相信你们的第一个问题就是,Microservice架构模式中各个子服务应该如何相互协做以向用户提供服务的呢?按照上面咱们的讲解,Microservice架构模式中各个子服务应该是独立的,不然它们之间将产生耦合,进而带来一系列问题:这些子服务彼此不独立,须要使用分布式事务保持其数据一致性,子服务不易被重用等。可是若是这些子服务绝对独立,甚至不包含一点点逻辑上的耦合,那么它们之间也将没法进行协做。所以在论坛讨论中经常出现的问题就是,这些子服务之间哪里能够出现耦合?能够出现什么程度的耦合?
这个问题实际上很是简单,那就是UI。咱们知道,在一个BS服务中,服务端和客户端之间存在着必定程度的耦合。二者经过服务所暴露的API进行沟通。而基于Microservice架构模式的服务也不例外:
既然运行在用户浏览器中的UI须要与其它各个子服务进行交互,那么它彻底能够做为一个中介者来完成各个子服务之间的交互。例如在显示产品页面的时候,该页面逻辑会向产品服务及库存服务同时发送请求,以并行地获得产品的详细信息以及该产品的当前库存。
所以在一个基于Microservice架构模式的服务中,经常会出现一个前端服务。该服务所提供的页面会与各个服务沟通。可是它实际上与各个子服务之间却不须要通信:
或许您会说,在这种状况下,咱们的各个子服务就没有UI了。而UI服务不只仅须要处理全部的前端业务逻辑,并且随着时间的推移,其可能会变成另一个庞然大物。除此以外,若是但愿整个平台可以容许第三方服务接入,那么这种打包在一块儿的UI服务将变成整个平台扩展性的阻碍。
是的。若是须要解决这个问题,那么您就须要在应用中尝试借鉴Service Locator模式。此时咱们须要的则是一个UI框架,其容许用户经过特定方式在应用中插入各个子服务所提供的UI,并容许您经过一些机制来发现已经在平台中注册的具备特定功能的API,并容许您对该API进行调用。我相信,随着Microservice架构模式的不断发展,会有愈来愈多的支持这种扩展方式的UI类库出现。
另一种模式则是Message Broker。简单地说,Message Broker就是一个消息的中转平台。该平台容许其它组成向其中注册消息,也容许其它组成侦听消息。当一个组成将一个消息发送到了Message Broker之上后,其它侦听该消息的各个组成则会根据消息中所包含的信息更新本身的状态。
反过来,若是您的服务须要支持移动设备,如手机,iPad等,咱们就不能让这些移动设备一个一个地访问子服务了。这是由于这些移动设备的带宽通常来讲都很是小,并且用户经常处于信号不是很好的地方,所以在向这些子服务一个个地发送请求将快速消耗掉它们所拥有的有限的带宽。为了解决这个问题,咱们经常须要在这些子服务前搭建一个代理服务。该代理服务会将用户请求根据业务逻辑拆分为对各个子服务的请求,并将各个子服务所返回的结果概括为一个响应返回给用户:
固然,上面所介绍的仅仅是当前论坛讨论中所经常提到的一种搭建基于Microservice架构模式应用的方式。或许在不久的未来,您会看到设计得愈来愈精巧的各类模式出现。
在讲解完这些子服务该如何展示给用户以后,咱们就来说解一下如何建立各个子服务所须要的公共服务。以前咱们已经提到过,因为对公共服务的调用是一个跨进程调用,所以其相较于进程内调用效率很是低下。在这种状况下,咱们须要尽可能避免对该公共服务的重复调用。为了达到该目标,咱们须要尽可能使用户访问同一个子服务实例,而且在该用户的会话中缓存从公共服务中所获得的信息。
所以在同一个子服务的各个服务实例上,咱们须要尽可能使用负载平衡服务的Sticky Session的功能,并在一次公共服务调用中取得多项信息。例如在查看用户的权限时,咱们不是返回用户是否具备特定权限,而是该用户拥有哪些权限。固然,这不只仅须要从Microservice这种架构模式的方面来考虑,还须要同时兼顾安全,维护性等一系列问题。
简单地说,在兼顾其它方面的状况下,咱们须要将公共服务API的粒度定得粗一些,同时也须要具备必定的灵活性,从而经过减小服务间调用来避免整个服务的性能瓶颈。
既然说到了API的粒度,那咱们就须要讨论一下各个子服务所提供的API了。和公共服务同样,各个子服务所暴露的API也应该具备较粗的粒度以及较大的灵活性。除此以外,咱们还须要让这些子服务所暴露的API具备尽可能一致的样式,如定义一系列RESTful的API。在这种状况下,与这些服务进行交互的组成,如网页的UI,才能具备能够接受的维护性。
一个经验性的观点则是,Microservice架构模式中的“开”是各个服务的内部实现,而其中的“闭”则是各个服务之间相互沟通的方式。
若是您须要从头开始搭建一个服务,那么您须要首先考虑如何对这些服务进行划分,并在建立第一个服务的时候开始搭建出各个公共服务的雏形,同时肯定各个服务之间沟通所须要遵照的协议。当愈来愈多的子服务被建立出来以后,您须要逐渐丰富各个公共服务所提供的功能,使其逐渐变为功能强大的,可重用的服务。
若是您已经拥有一个Monolith服务,而且但愿经过采用Microservice架构模式来缓解当前Monolith模式服务所具备的一系列问题,那么您首先须要建立一个独立的服务,并经过一个粘合层来与该Monolith服务交互。在该过程当中,您可能须要将Monolith服务的内部接口逐渐暴露出来,以供这个新的服务使用。而这就是在抽象公共服务的过程。
接下来,您就须要根据上一步中所获得的接口来逐步将Monolith服务中的公共服务剥离。在剥离过程当中,您脑中须要记得的一句话仍是:粗粒度,灵活的API。而其内部实现究竟是什么样的,实际上并不会影响到您的剥离结果。
最后就是再从Monolith中剥离其它服务了。此时咱们最须要考虑的就是在服务中具备鲜明特色的各个服务,如对资源的要求与整个Monolith服务格格不入,或者使用了和Monolith很难兼容的技术等。
最后一种状况就是多个服务集成的状况。在产品的逐渐迭代过程当中,咱们经常会遇到须要将多个产品集成成为一个产品以提升总体竞争力的状况。这经常发生在盈利产品和其它非盈利产品之间。而这正是实践Microservice架构模式的绝佳机会。此时咱们仅仅须要暴露一系列Monolith服务中的接口并建立粘合层便可。
Microservice的优势与劣势
好,在前面咱们已经讲解了不少有关Microservice架构模式的经验性方法和相关知识。那咱们如今回顾一下Microservice所具备的一系列优势和劣势,以使您可以在采用Microservice架构模式以前全面地衡量该方案所可能获得的好处及遇到的困难。
首先,因为Microservice架构模式中的每一个子服务均可以独立于其它服务执行,所以其经常具备更好的服务边界。而这个明确的服务边界则会带来一系列好处:在Microservice架构模式中,各个子服务执行所须要的业务逻辑都相对集中于子服务内。所以其实现代码相对容易理解,而且便于维护。另外各个子服务所具备的结构,运行流程及数据模型都可以更贴近于子服务所表示的业务逻辑,所以在代码的开发速度和维护性上获得了大大地加强。同时各个子服务能够选择最适合实现业务逻辑的技术,进而使得各个服务的开发变得更为容易。同时在出现新的更适合的技术时,咱们能够较为容易地在各个子服务内部对原有的实现技术进行替换。
独立性也意味着扩展性的加强。在Microservice架构模式中,各个子服务能够根据自身的负载独立地进行扩容,如Scale Up或Scale Out等。不只如此,咱们还能够根据子服务自身的特性为其准备特定的硬件设备,使得其运行在更适合的服务器上。同时这种独立性还可使得各个子服务能够被重用。
同时这种独立性也能够增长整个服务的容错能力。例如若是一个子服务因为种种缘由没法继续提供服务,其它子服务仍然能够独立地处理用户的请求。
另外,各个子服务的独立部署能力也能够大大地提升Continuous Delivery的运行效率。毕竟在这种状况下,软件开发人员只须要从新部署更改过的子服务就能够了。
因为Microservice架构模式中的各个子服务不管是在代码量方面仍是最终生成的WAR包方面都较Monolith架构所搭建的服务小,所以在IDE支持,启动速度方面都具备至关的优点。同时,这种小粒度的服务已经能够由一个几我的所组成的小组来完成,而再也不须要经过来自世界各地的不一样小组协同开发,进而大大下降了沟通成本,提升了开发的效率。
可是反过来,Microservice架构模式中各个子服务的独立性也会致使一系列问题。最明显的就是须要多个子服务相互配合的状况。因为这些子服务是不一样的进程,所以在这些进程之间保持数据的一致性,或添加一个新的跨子服务的用户用例实际上都是一件很是麻烦的事情。并且对这些独立服务在整个系统中是否可以工做的测试须要运行大量的集成测试。而若是须要快速地对这些子服务进行开发和迭代,那么咱们就须要每一个开发人员都可以专业并高效地使用一系列自动化工具。这实际上也是一个不低的要求。
除此以外,基于性能考虑,各个子服务所提供的接口将是粗粒度的,却具备较高灵活性的API。可是这种API拥有一个较明显的缺陷,那就是越灵活的API,其使用起来的难度就越大。所以对于服务的用户而言,其上手的难度则相对增长了。
另外,如何规范化各个子服务之间的沟通协议也是一个很是具备挑战性的事情。由于在Microservice架构模式中,咱们经常须要建立一系列公共服务。这些公共服务经常暴露特定样式的接口以供其它服务调用。所以咱们须要在这些接口上保持一致性,进而才可以更天然地编写各个子服务的内部逻辑并暴露适当的接口。可是反过来,一致的接口样式经常会致使各个服务的天然实现须要向这些标准进行妥协。所以咱们经常须要在二者之间平衡。
这些平衡方法包括标准化各个服务所暴露的接口,使用固定的几种方式对子服务进行集成,保持数据模型格式的一致性等。这些实际上都是咱们自由编写各个子服务的障碍。对此采起多么严格的规范其实是须要经过经验累积来完成的,所以这大大提升了使用Microservice架构模式失败的几率。
转载请注明原文地址并标明转载:http://www.cnblogs.com/loveis715/p/4644266.html
商业转载请事先与我联系:silverfox715@sina.com