Microservice Anti-patterns

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

  如果您不知道Microservice是什么,请首先阅读我的另一篇文章《Microservice简介》。

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

Distributed Monolith

  不知道大家是否喜欢看看各公司所办的各种会议。现在不像10年前只有微软,Intel等几家公司办的TechED,IDF等会议了。越来越多的公司喜欢举办会议、论坛等活动,以吸引越来越多的优秀开发人员一起讨论最新技术和业界发展趋势。因此我先说点题外话,希望如果大家感兴趣请自己寻找一下自己觉得有趣的会议。我相信大家都是喜欢技术的人。这样一方面能提高自己的能力,另一方面也对国内的技术环境有帮助,利人利己。

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

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

  在从原有服务上剥离时,我们常常会选择让新创建的子服务使用原有的技术,以减少创建子服务的工作量。这其实并没有太多的问题,毕竟这种剥离在原有服务的基础上提高了各子服务的独立性。虽然说此时我们所使用的技术并不是最合适的,但是的确是最有效率的创建子服务的方式。

  而新建一个Microservice子服务就不一样了。在创建一个新的子服务时,软件开发人员常常需要自行编写该子服务所包含的所有代码。因此此时我们应该尽量选择最合适的技术,以获取最高的开发效率。

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

  在这些共有的技术越积越多的情况下,我们的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


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/329278.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

css 图片换行_好程序员web前端学习路线分享CSS浮动-文档流篇

1、纯文本的排列。文档流就像我们的文本内容一样,所有的文字都会紧挨着,一个个排列下来,如果到了边界,就会换一行排列。当然如果敲回车或者按下空格键一般都会认为是一个词间距,因为英文中每个单词之间是有距离的&…

京东购物车的 Java 架构实现及原理

转载自 京东购物车的 Java 架构实现及原理 今天来写一下关于购物车的东西, 这里首先抛出四个问题: 1)用户没登陆用户名和密码,添加商品, 关闭浏览器再打开后 不登录用户名和密码  问:购物车商品还在吗? 2)用户登陆了用户名密…

程序员求职面试三部曲之三:快速适应新的工作环境

新进一家公司总有各种的不适应,或兴奋, 或紧张,或不安,或迷茫各种情绪兼而有之。曾经有个家伙好不容易进了A公司,本来是要替代另一位即将离职的小伙伴的,结果,走得比那位兄弟还快,只…

问的书写规则是什么意思_化学式的定义及其书写规则

化学式的定义及其书写规则化学式是用元素符号表示纯净物组成及原子个数的式子。分子晶体的化学式叫做分子式,可以表示这种物质的分子构成。下面是百分网小编给大家整理的化学式的简介,希望能帮到大家!化学式的定义用元素符号表示纯净物组成及原子个数的式…

微软企业应用开发三大方向:跨平台、开放/开源与DevOps

软件和互联网正在改变传统企业,软件的职能逐渐从管理内部员工变成核心的商业竞争能力,在今天这种大环境下,我们应该用的新开发技术和方法。微软公司全球资深副总裁、开发平台事业部潘正磊(Julia)认为,把IT托…

Java程序员最常犯的 10 个错误

转载自 Java程序员最常犯的 10 个错误 这个列表总结了Java开发人员经常犯的10个错误。一 、把数组转成ArrayList 为了将数组转换为ArrayList,开发者经常会这样做: List list Arrays.asList(arr); 使用Arrays.asList()方法可以得到一个ArrayList&…

mysql5.1升级5.5_mysql数据库迁移,由版本5.1升级至5.5.29,需要注意哪些

caching_sha2_password认证插件提供更多的密码加密方式,并62616964757a686964616fe59b9ee7ad9431333433636131且在加密方面具有更好的表现,目前MySQL 8.0选用caching_sha2_password作为默认的认证插件,MySQL 5.7的认证插件是MySQL_native_pas…

dotnetConf 2016 线上虚拟大会

为期三天(6月7日-9日)的Channel9 免费.NET线上虚拟大会,微软产品团队及.NET社区精英一起徜徉在.NET的世界! 与大咖Scott Hunter, Miguel de Icaza (Xamarin CTO) , ScottHanselman及其他.NET大牛一起学习如何利用.NET开发跨…

mysql的on和in用法_数据库中in、on、with的用法及示例。

with用法:创建一个表:create table regr (pid integer,id integer, name char(20))alter table regr alter id set not null add primary key(id)insert into regr values(-1,1,library),(1,2,news),(2,3,world news),(2,4,politics),(2,5,bussiness)(2,…

文档数据库RavenDB-介绍与初体验

不知不觉,“.NET平台开源项目速览“系列文章已经15篇了,每一篇都非常受欢迎,可能技术水平不高,但足够入门了。虽然工作很忙,但还是会抽空把自己知道的,已经平时遇到的好的开源项目分享出来。今天就给大家介…

双机热备的原理

转载自 双机热备的原理夜半惊魂 上次的文章《负载均衡的原理》中讲到,张大胖在Bill的指导下,成功地开发了一个四层的负载均衡软件, 把流量“均匀地”分发到了后面的几个服务器中, 获得了老板的1000块钱奖励。但是张大胖心中隐隐不…

c# 向mysql插入数据_C#连接mysql数据库 及向表中插入数据的方法

mysql 语句操作:创建数据库:create database hotelATMDb;use hotelATMDb;C#连接mysql1、引用 dll MySql.Data.dll 下载地址:http://download.csdn.net/detail/chen504390172/67461312、引用 using MySql.Data.MySqlClient;连接语句&#xff1…

微软CEO纳德拉开讲,2016微软开发者峰会在京召开

6月1日,2016微软开发者峰会在京召开。 来自微软总部的高层、技术大拿, 以及来自微软亚洲研究院、微软亚太研发集团、Xamarin 总部团队、微软中国开发体验及平台合作事业部的技术专家对各平台的开发进行技术探讨,向开发者展示了一系列引人入胜…

Linux下如何避免误操作执行 rm

转载自 Linux下如何避免误操作执行 rm最近IT圈子流行着一个段子:某个蠢萌的程序员,不小心在公司的服务器上输入了 rm -rf/ 指令,结果......现在还没出狱呢。当然,绝大部分程序员不可能犯下如此低级的错误,更何况也没有…

Consul入门

简介 为什么要用consul,这里就不详细介绍了,本文重点是Consul的搭建和使用过程。 Consul搭建 参考文献:http://tonybai.com/2015/07/06/implement-distributed-services-registery-and-discovery-by-consul/ 下载consul和consul UI 官方地址&…

Java Socket编程----通信是这样炼成的

转载自 Java Socket编程----通信是这样炼成的 Java最初是作为网络编程语言出现的,其对网络提供了高度的支持,使得客户端和服务器的沟通变成了现实,而在网络编程中,使用最多的就是Socket。像大家熟悉的QQ、MSN都使用了Socket相关的…

mysql级联复制转换成一主两从_一主两从转级联复制

一主两从 转 级联复制 示意图如下M ---> S1\ > M ---> S1 ---> S2\ --> S2如果有开启GTID操作起来方便多,GTID是唯一的,直接操作即可。如果使用file_name、position可以使用如下办法(现在还没开启gtid真的是无力吐槽)# 步骤1、# 现将S2的…

细说ASP.NET Core与OWIN的关系

前言 最近这段时间除了工作,所有的时间都是在移植我以前实现的一个Owin框架,相当移植到到Core的话肯定会有很多坑,这个大家都懂,以后几篇文章可能会围绕这个说下,暂时就叫《Dotnet Core踩坑记》吧,呵呵。 接…

mysql 外键和事务_Mysql (五)事务和外键

一、 什么是事务:简单说,所谓事务就是一组操作,这组操作要么都成功执行,要么都不执行。二、 事务的使用流程1. 第一步:开启事务,start transaction;2. 第二步:正常操作SQL语句&#…

微软发布正式版SQL Server 2016

微软于6.2 在SQL 官方博客上宣布 SQL Server 数据库软件的正式发布版本(GA),历时一年多,微软为该软件发布了多个公共预览版和候选版本,而今天最终版本终于上线了。在博客中,微软数据集团的企业副总裁 Josep…