Microservice Anti-patterns

  在最近的一次Microservices Practitioner Summit中,原Netflix工程师介绍了一种愈来愈常见的对Microservice的误用。简单地说,你们在搭建一个基于Microservice的服务时经常依赖同一套类库,进而使得Microservice中的各个子服务没法选择最适合的技术。html

  若是您不知道Microservice是什么,请首先阅读个人另外一篇文章《Microservice简介》。数据库

  在本文中,咱们就将以该演讲的内容做为引子,介绍一下当前业界对于Microservice的一系列误用方式。浏览器

 

Distributed Monolith缓存

  不知道你们是否喜欢看看各公司所办的各类会议。如今不像10年前只有微软,Intel等几家公司办的TechED,IDF等会议了。愈来愈多的公司喜欢举办会议、论坛等活动,以吸引愈来愈多的优秀开发人员一块儿讨论最新技术和业界发展趋势。所以我先说点题外话,但愿若是你们感兴趣请本身寻找一下本身以为有趣的会议。我相信你们都是喜欢技术的人。这样一方面能提升本身的能力,另外一方面也对国内的技术环境有帮助,利人利己。安全

  好,让咱们回到原题。在该工程师的演讲中,他提出了近期较为常见的一种对Microservice的误用:不少公司或我的都认为将一个Monolith的服务拆分红一系列子服务,就可以被称为是基于Microservice的服务了。的确,这种变化引入了Microservice的一系列优势:因为各个子服务之间拥有了确切的边界,所以它们将可以更容易地独立发展,并且咱们也能够更容易地对该子服务进行扩容:框架

  可是这种子服务组织方式并不能彻底地称为Microservice:其丢掉了Microservice的技术灵活性。在Microservice中建立一个子服务的方式主要分为两种:从原有的服务上剥离,以及新建服务。性能

  在从原有服务上剥离时,咱们经常会选择让新建立的子服务使用原有的技术,以减小建立子服务的工做量。这其实并无太多的问题,毕竟这种剥离在原有服务的基础上提升了各子服务的独立性。虽说此时咱们所使用的技术并非最合适的,可是的确是最有效率的建立子服务的方式。测试

  而新建一个Microservice子服务就不同了。在建立一个新的子服务时,软件开发人员经常须要自行编写该子服务所包含的全部代码。所以此时咱们应该尽可能选择最合适的技术,以获取最高的开发效率。htm

  可是误用就出如今这里。在建立一个新的Microservice子服务时,软件开发人员经常偏向于使用以前所使用的各类技术。这是软件开发人员对已使用技术所保留的一种惯性:软件开发人员在以前对这些类库的使用中知晓了其能够用来完成某些功能,而并无过多地关注实现这些功能的复杂程度。就像我在《Cassandra简介》一文中说的那样,技术选型是一个很是严谨的过程。该过程经常须要进行大量的研究,并根据开发的难易程度,用户基数,活跃程度以及成功案例来决定是否使用该技术。而软件开发人员的这种技术惯性则经常是致使项目最终失去控制的一个缘由。blog

  在这些共有的技术越积越多的状况下,咱们的Microservice服务就愈来愈容易引入刚刚Netflix工程师所提到的错误:在Microservice中普遍使用类库特有技术。咱们知道,某些类库会提供一系列特有的功能,以用来提升执行效率,提供更高的安全性等。可是这些技术经常并非行业规范,所以也会致使其没法与其它类库兼容。这会致使Microservice中的各个子服务之间存在着一种隐式的契约:为了有效地在各个子服务之间进行通信,Microservice中的各个子服务须要使用特定的技术。

  若是咱们在Microservice中引入这种特定的技术,那么该技术将会逐渐扩展到Microservice的全部子服务中:

  这样Microservice中的全部子服务最终将使用同一个技术集,进而限制了其它子服务所可以选择的技术。若是咱们任由这种状况发展,那么到最后Microservice中的全部子服务都将绑定于一整套固定的技术集之上,并没有法再选用最为合适的技术。而最终的结果就是,咱们的Monolith服务的确转化为基于Microservice的服务,可是其使用的技术集仍是原来的技术集。这种服务组织方式并无提升开发效率,反而增长了在各个Microservice子服务之间相互沟通的成本,下降了整个服务对单一请求的响应速度。整体来讲,得不偿失。

  而真正应该在Microservice子服务之间存在的,是明确指定的契约和协议,而不该该是如何实现这些子服务。

  其实一个决策经常是在权衡各方面优劣才作出的。Microservice的优点无非就是具备更好的横向扩展能力(Scalability),更灵活的技术选择,更简单的子服务实现逻辑,更清晰的子服务边界以及更好的子服务复用性。可是缺点也同样明显:子服务之间相互通信所致使的单一请求执行效率下降,子服务边界所带来的代码组织灵活性下降等。若是咱们丢掉了灵活的技术选择,那么更简单的子服务实现逻辑所带来的高效开发及更好的维护性就将无从提及。最终所致使的结果就是:使用Microservice组织子服务不会为咱们带来额外的好处。

  这里还有一个悬而未决的问题,那就是从Monolith剥离出来的各个子服务经常使用同一个技术集。是的。在这种状况下,咱们要尽可能控制这些技术集的扩散,并在须要时逐渐移除对这些技术集的依赖。

 

功能边界不清

  我相信有些读者已经对Microservice有些研究了,甚至尝试过在服务实现中使用它。最容易遇到麻烦的一点即是对单个请求进行处理时的性能问题。

  不管是浏览器仍是JS类库,都拥有一个请求超时的概念。在发送一个请求以后,若是服务长时间没有对该请求进行响应,那么浏览器或JS类库都会将该请求识别为超时。并且从用户使用的角度来说,他也并不但愿一个请求长时间没有响应。所以在一个基于Microservice的服务中,咱们经常须要让整个服务可以快速有效地响应用户的请求。

  一个提高性能的方法就是合并请求。若是说用户对一个服务的使用须要固定顺序的一系列调用,那么咱们就能够经过将这些调用合并到一块儿,从而减小反复通信所形成的损耗:

  上图展现了这种经过合并调用提升性能的方法。在用户尝试找到特定种类下的全部商品时,咱们须要经过查找全部的商品种类以肯定该商品种类的ID,进而经过该商品种类的ID获得该商品种类下的各类商品。为了可以合并调用,咱们须要提供一个新的API,以容许软件开发人员经过商品种类名称直接完成调用,而对商品ID的查询等执行逻辑都放在服务端去执行。这样用户就只须要发送一个请求,而不是三个请求,进而缩短了整个流程的运行时间。

  可是这样仍是有问题,那就是咱们所新引入的API已经将商品种类以及商品这两个概念包含在同一个子服务中了。这种包含了过多概念的子服务经常成长为一个包含了过多功能的子服务,也便是Microservice中的Monolith。

  而一个较为正确的解决方案则是:就像我在《Microservice简介》一文中已经提到过的那样,咱们在必要时应该提供一个Gateway,并在Gateway中添加合并在一块儿的API。这样因为Gateway经常和与其关联的各个子服务处于同一个数据中心中,所以其内部通信效率经常比用户经过浏览器访问快不少。这样咱们既保证了各个子服务能够独立地发展,又能提升用户的访问效率:

  并且在该Gateway中,咱们也经常能够经过缓存等一系列技术手段来提升运行效率。

  反过来啊,咱们也别走到另一个误区里面,那就是创建太多的层次。我能理解一个数据库做为一个独立的层次的必要性,毕竟数据库经常与其它服务实例处于不一样的服务实例上。可是若是在纵向上添加太多的层次,那么在处理用户所发出的一个请求时就须要通过过多的消息转发,从而使得对消息的处理时间变长:

  固然,Gateway也是其中的一个层次,所以不要为每一个子服务添加一个Gateway,而是要有一个总体的规划:

  总之,在如何切割子服务时咱们经常须要在脑中保持是否用户的请求能被快速响应这一个问题。在Microservice中,API的粒度过细,以及内部调用过可能是最具备杀伤力,也最容易出现的问题。

 

过于强调Microservice

  的确Microservice这个词在国外很火。不少公司都将本身的产品是基于Microservice来组织的做为一个卖点。这的确可以帮助不少销售人员解释公司产品所具备的一系列优点。可是做为一个开发人员,咱们不要被这个观点所迷惑。缘由就是由于,直接开发基于Microservice的服务所须要的初始开发成本较Monolith的开发成本高不少。直到产品的规模达到必定程度,Microservice的优点才可以发挥出来:

  而一个产品经常须要经由PoC才能变成真正的版本,并且在产品的初期,咱们所须要解决的经常不是这个产品须要具备多大的扩展性,而是咱们须要有足够的钱来支撑这个产品的持续研发。所以在产品演变的过程当中,功能性需求经常在开发的初期占首要地位,而像横向扩展能力等非功能性需求在后期才会变得愈来愈重要。因此在开发一个全新产品时,若是咱们过于注重经过Microservice来组织各个子服务,那么软件开发人员在整个项目的初始阶段的开发效率将很是低下。相反地,咱们须要在开始实现时尽可能注意各个组成之间的隔离。这样一旦须要从Monolith转化为Microservice,咱们只须要将这些代码根据其所在的包进行剥离便可。

  固然,若是咱们已经开发过按照Microservice组织的服务,并且有一系列子服务能够被重用,那么咱们彻底能够经过重用以前Microservice服务所使用的框架来开始这个服务的开发。此时Microservice服务的开发效率并不会低多少,甚至还可能在很是短的时间以内拥有比Monolith开发更高的效率:

  因此说,咱们的第一要务并非使用Microservice,而是经过它来为业务目标服务。将Microservice置于业务目标以前,反而经常在项目初期成为一块绊脚石。

 

没有使用Continuous Delivery

  由于我一直在外企,因此对Continuous Delivery平台的使用仍是相对较多的。可是从国内某些厂商,甚至是较大的厂商使用Microservice搭建服务时,经常会出现不使用Continuous Delivery平台的状况出现。这样就会致使一个问题,搭建测试环境及生产环境会很是麻烦。

  Microservice的一个重要优点就是提升了开发效率。反过来,若是软件开发人员和测试人员天天须要为如何搭建一个开发及测试环境发愁,那么使用Microservcie开发又获得了什么好处呢?

  固然啊,工做上的事情有些说不清,因此我们也很少说什么。只能说,Continuous Delivery可以提升咱们的开发效率。若是您是个决策者,并且恰好看到这篇文章,那么请您必定认真地考虑这一点。其实搭建一个Jenkins环境也并非很是困难,所须要的物理机也并非不少。并且您还可以在灾难恢复等众多非功能性需求上得到一系列好处。

 

  对,最后提一句,这篇文章和InfoQ上最近的一篇文章有关:http://www.infoq.com/news/2016/03/microservices-anti-patterns。熟悉个人读者可能知道我喜欢攒文章,隔几个月再发布,由于这样能够根据一段时间的经验对本身所写的内容进行一次校验。只不过我看这篇文章一样提到了这个演讲,因此为了不没必要要的解释,就提早发了

 

 

转载请注明原文地址并标明转载:http://www.cnblogs.com/loveis715/p/5315860.html

商业转载请事先与我联系:silverfox715@sina.com

公众号必定帮忙别标成原创,由于协调起来太麻烦了。。。

相关文章
相关标签/搜索