微服务架构的责任困境

本文讲的是微服务架构的责任困境【编者的话】通过技术上的技巧(比如Docker利用了大家都是基于统一的操作系统接口)确实可以解决一些问题。但是技术再怎么升级,也无法解决所有问题。

【3 天烧脑式容器存储网络训练营 | 深圳站】本次培训以容器存储和网络为主题,包括:Docker Plugin、Docker storage driver、Docker Volume Pulgin、Kubernetes Storage机制、容器网络实现原理和模型、Docker网络实现、网络插件、Calico、Contiv Netplugin、开源企业级镜像仓库Harbor原理及实现等。

引言

创世记第11章1-9句记录了“巴别城”的故事。当时地上的人们都说同一种语言,当人们离开东方之后,他们来到了示拿之地。在那里,人们想方设法烧砖好让他们能够造出一座城和一座高耸入云的塔来传播自己的名声,以免他们分散到世界各地。上帝来到人间后看到了这座城和这座塔,说一群只说一种语言的人以后便没有他们做不成的事了;于是上帝将他们的语言打乱,这样他们就不能听懂对方说什么了,还把他们分散到了世界各地,这座城市也停止了修建。这座城市就被称为“巴别城”。《钦定版圣经》是这样描写的:

4、他们说,“来吧,我们要建造一座城和一座塔,塔顶通天,为了扬我们的名,免得我们被分散到世界各地。”
5、但是耶和华降临看到了世人所建造的城和塔。
6、耶和华说,“看哪,他们都是一样的人,说着同一种语言,如今他们既然能做起这事,以后他们想要做的事就没有不成功的了。”
7、让我们下去,在那里打乱他们的语言,让他们不能知晓别人的意思。
8、于是耶和华使他们分散到了世界各地,他们也就停止建造那座城。
9、因为耶和华在那里打乱了天下人的言语,使众人分散到了世界各地,所以那座城名叫巴别。——Genesis 11:4–9

愿景

每人都可以随时获取一个开发环境。在其中做开发。并且随时可以验证自己写的代码在整个系统里集成起来是否工作正常。我可以立即得到有效反馈,从而提高工作效率。

尝试一:书同文

最理想的情况是所有的开发者使用完全相同的技术。他们使用同样的编程语言,他们使用同样的开发框架。他们使用同样的操作系统。他们使用同样的IDE。他们使用同样的风格管理Git仓库。他们使用同一种语言来写构建脚本。如果这一些都是真的,想要获得一个开发环境,那会是非常简单的事情。

曾经尝试过各种方式把自己认为“最优”的开发环境兜售给同僚,给下级,甚至是给我的雇员。但是都失败了。让这帮geek们使用同样的方式工作,这个难题比我们这里要解决的问题更难。上帝来到人间后看到了这座城和这座塔,说一群只说一种语言的程序员以后便没有他们做不成的事了。于是神创造了Emacs和Vim。

打着提高开发效率的方式去强奸别人的开发环境是行不通的。无论你说你写的库再好,都不如我的库写得好。无论我今天写的库在好,也不如我明天想造的下一个轮子好。这个道理普世于各种IDE工具的执念,各种编程语言的执念。

不要只看到始皇帝做了书同文的伟业。还要看到人家焚书坑儒的本事。

尝试二:自动化脚本

退而求其次的办法是,不要求所有的组件都是同样的方式开发出来的。我们只要求你们各个模块的owner都提供一个共同的自动化脚本。当我们把这些脚本拼接到一起之后,整个系统就实现了自动化的部署。

这条道路演进的尽头就是一堆bash/python/msbuild脚本,加上一个cmdb数据库组成的怪兽。我已经在《闲谈集群管理模式》一文里描述了这个模式的问题。

  • 无法审查的脚本:给定一个 f(),你无法知道这个 f() 到底做了什么。这个是所有基于脚本组合的方式(函数套函数)做自动化的根本问题。最近这次 S3 的故障,就是因为误执行一个 saltstack 脚本导致的。而任何运行这个脚本的程序,是无法在加载脚本之后做任何事情来验证其权限和危害的。对于任何runner来说,f() 就是一个黑盒的 f()。
  • 状态漂移:开发环境脚本在一个新的开发机上可能运行,但是在一个已经安装模块A的机器上就可能执行失败。或者在安装了A,B的,但是没有装C的机器上会失败。脚本执行的起始状态可能有千千万万,不可能测试齐全。脚本执行完之后留下的系统的状态也千千万万。

这两点技术上的硬伤,导致了基于一堆脚本堆砌出来的自动化仿佛浮沙之上筑高台一般。

尝试三:Docker + 组网技术

在发现了脚本自动化的缺陷之后,我陷入了对Docker技术的痴迷。Docker的技术上的好处显而易见。它完美地把业务代码封装到了一个容器里,无论你是什么语言写的,什么框架开发的,最终都是一个Docker执行命令。放佛巴别塔问题解决了,只要有了Docker,什么东西都是一样部署的。Docker镜像由模块owner提供,他们怎么弄出来是他们自己的事情。你想用Node.js,还是Haskell,随便。而且Docker完美解决了基于脚本技术的状态累积漂移问题。所谓immutable infrastructure。

Docker还稍微有一些问题,那就是还需要把多个服务通过网络组装到一起。这个也不是什么大问题。虽然通过服务发现这样的方式推广起来有难度,但是我们还有网络代理的大招。比如指定100.64.0.1代表MySQL,100.64.0.2代表Redis。通过网络层拦截这些IP的请求,我们可以不修改业务代码的情况下,把这些Docker容器给组装起来。

Docker基于了Linux ABI,代理版本的服务发现基于了TCP/IP。这两个东西在巴别塔的时代就是一个bug级别的存在,但是本质上还是书同文。上帝留了一个口子,给我们钻了漏洞。于是我们又可以把这些乱七八糟的东西攒一起了。

Docker 也无法解决书同文的问题

这种方式完美了吗?我们再次发现了巴别塔问题。实际上的软件是这样工作的:

某种程度上来说,我们通过Docker,通过组网,构建出来的系统只是一个空壳而已。它只是一门开发语言,它通过各种配置界面提供了自己的开发工具。PM 通过产品配置,配置出了产品,而运营再基于产品,配置出了真正运行起来可以赚钱的系统。

Docker可以利用Linux ABI 这个“书同文”的接口,整合了后台服务。网络代理利用 TCP/IP 这个“书同文”的接口把这些服务串联了起来。但是对于各个模块自己提供的产品配置和运营配置,我们就没有这么幸运了。有的模块使用了CSV,有的使用了Json,有的使用了数据库。当你要重现一个“环境”的时候。它不仅仅是意味着进程的启动,意味着网络的连接。它还需要把各种配置数据灌入到系统。而搞清楚有哪些配置,让这些模块使用完全相同的方式来定义和使用配置,我们就又回到了第一步,书同文的路数里了。书同文的成功实施,来自于强大的中央权威。如果拥有强大的中央权威,完全可以从一开始就强推书同文的开发模式(比如都是Java,比如都是Finagle)。这就形成悖论了。

微服务架构的责任困境

过去的开发模式是这样的。我负责一个服务,它从DB往上都是我的。产品经理的需求,我全部负责。中间会有少量的调用外部接口进行支付,邮件群发之类的事情。但是这些调用一般处于流程的末端,不参与主要的业务逻辑并且接口清晰。

这个年代的测试非常清楚,mock掉外部依赖(支付,短信网关,ftp接口),启动真实的数据库,从用户的接口测试我的服务。我直接向用户负责。这种工作模式,我至今认为是效率最高的方式。

现在的微服务的模式是叠罗汉式的。我负责了B,上面有A,下面还有C。A依赖B和C才能跑起来,B依赖A和C才能和客户端完整交互。

在这种拆分下,我们强调了每个团队的自主性。而且大家共同承担了最终的业务敏捷性和稳定性的要求。对于生产环境,确实是这样的。如果C挂了,C会立即去修,因为影响了生产环境。如果B挂了,B也会立即去修。

但是把这个问题改成线下和线下分开呢?如果是在服务B的开发环境里,服务C出问题了,有一个设置没有配置对。或者这个设置改了,B没有更新代码。你认为C会积极地帮B解决问题么?你认为B会进入到C的代码目录下,看他们打的日志么,然后自己就知道怎么修复问题了?即便可以解决,B也会遇到巨大的相应延迟的问题。C可能在开会,C可能在忙别的事情。

那么解法是什么?线下环境直接利用生产环境的部署脚本?一套脚本,可随时复制环境?前面已经讨论过这些自动化部署脚本,以及Docker等模式的技术缺陷了。事实上,部署两套一模一样的环境是相当困难的。而且引入复杂的部署工具,以及专职的团队还有一个更加有趣的现象,它把两方的关系,变成了三方的互动:

这三方的关系是互相不信任的,因为代码不是自己写的。服务消费方遇到了困难,去找服务集成方。集成方会认为可能是提供方的代码有问题。于是把提供方拉进来定位问题。提供方会觉得我的服务在线上是好好的, 为什么在线下就不行了呢?是不是你部署得有问题,GCC版本是不是不对。这种责任的链式传导很快就会让环境的使用方觉得,能用就用,不能用我也没法推动去定位问题。

从根本上来说,这个困境在于模块的owner,只对生产环境负责,不对别人使用的开发环境里自己的服务负责。花时间帮别人解决问题,提高团队的整体效率,对于模块的owner来说不是最优解。因为他花费了额外的时间去帮别人完成KPI,而不是专注于领导布置的下一个任务。

而服务的集成方,既不知道服务是如何消费的,也不知道服务是如何提供的。他不可能有足够的精力,时间与动机去深入了解所有的模块的工作细节。即便有意愿把这个集成工作做好,也没有能力在脱离模块owner的情况下把工作真正做好。

解法一:可复制的环境列入KPI

一种解法是把环境的可复制性变成每个人的KPI。这样每个模块不仅仅负责一个环境(生产环境)的工作正常。他还要负责保持这种可复制性。如果你的业务模式恰好依赖于这一点,则可以努力推动。比如你要去加拿大运营一套独立的系统,而能够一键部署一套环境给加拿大的运营使用,则变成了一件有业务收益的事情。

这种做法就是要把全流程的持续集成列为所有人的KPI。如果在线下环境集成失败,亮红灯,所有人负责来定位问题。就和生产环境出告警了一样来对待。如果做不到这一点,所谓可复制的环境就是镜花水月了。

解法二:生产环境自检

如果大家都只认同我只需要为生产环境负责,那就把生产环境变得更强大好了。复杂的机器都有“自检”的功能。我们要做的就是让生产环境可以跑测试的流量实现自检,类似于Windows “打印测试页” 这样的功能。四色建模里的party/place/thing/moment interval,大部分要测的行为都是moment interval。通过把party这个主体给换掉,把 place/thing 这两个维度的代码加以改造(比如一些分城市统计逻辑),可以实现moment interval的重放。

这种方式的实质是仍然是推动全流程的集成。因为全流程持续集成在线下推行失败,而退而求其次,选择在生产环境来做。

解法三:基于接口契约的开发

强化接口契约的作用。通过Mock掉所有的外部依赖,单独测试我自己负责的模块。通过线上Tcpdump的方式,方便构造这些mock的请求和响应,减少Mock的工作量,以及让Mock真实可信。避免查了半天问题,结果发现是Mock接口和线上实际行为不一致,这样的乌龙问题。

同时进行接口的形式化定义,并且通过consumer driven contract的方式把调用方的Mock,变成提供方的测试。

这种做法就是承认微服务架构的实质是利用组织边界来强化软件架构的边界。既然人为构建了组织墙,与其忽视其存在,还不如对它好好对待。既然我调用对方,对方不愿意帮我解决环境问题,我也没有能力独立把对方的代码跑起来。那不如我们就划界而治吧。大家把接口约定好,我用假的实现来替代你的真实实现来做开发。这种做法和我们调用国企银行的接口,双方联调的方式并无本质不同。

刻度尺

在中央威权强的场景,书同文的方式是最经济的方式。无论是统一开发语言,还是统一RPC框架,还是统一服务发现。本质上来自于书同文带来的收益大于威权推进的成本。

在越松散的组织下,越会趋向于面向接口开发。

后记

从统一的自动化脚本,Puppet/Chef/SaltStack到Docker + 网络代理到线上Tcpdump线下流量回放,基于接口契约的开发,技术难度逐步升级。通过技术上的技巧(比如Docker利用了大家都是基于统一的操作系统接口)确实可以解决一些问题。但是技术再怎么升级,也无法解决所有问题。毕竟,所谓环境问题,所谓测试问题,所谓我的代码跑不起来的问题,都是人与人之间如何整体地高效协作的问题。技术的尽头,是政治。

原文链接:微服务架构的责任困境(作者:陶文)

原文发布时间为:2017-06-28

本文作者:陶文

原文标题:微服务架构的责任困境

时间: 2024-08-01 20:27:10

微服务架构的责任困境的相关文章

微服务架构如何实现网站服务垂直化拆分

3月10日,2017阿里云网站行业热点问题和解决方案线下研讨会在上海举行.阿里云产品专家银时为大家带来<微服务架构如何实现网站服务垂直化拆分>精彩演讲.主要从服务化的缘起.微服务架构的形成,以及在大规模的服务化过程中所面临的一些挑战以及解决方案,跟大家分享整个微服务.   以下内容根据现场分享和讲师PPT整理而成.   关于讲师:   倪超,阿里花名银时,阿里巴巴企业互联网架构平台产品专家.国家认证系统分析师.IT畅销书作者,著有<从Paxos到ZooKeeper>一书,2015年

深度剖析微服务架构的九大特征

微服务架构这个术语在过去几年渐成热门,它把一种特定的软件应用的设计方法描述为能够独立部署的服务的套件.尽管缺乏对这一架构类型的准确定义,但是在业务能力.自动化部署.智能端点.语言和数据的去中心化控制等方面,已经形成了某些普遍特征. 微服务,另一个在软件架构领域津津乐道的新词.尽管我们本能上倾向于对它不屑一顾,然而这一专业术语描述了一种目前越来越吸引人的软件系统的风格.我们已经看到近年来有许多项目使用了此类型,结果很鼓舞人心;因而对于我的诸多同事来说,这也就成为他们构建企业级应用时候的首选.然而,

微服务架构强化的实时通信

本文讲的是微服务架构强化的实时通信[编者的话]本文探讨了微服务架构模式是如何强化实时通信的,比如数据同步.动态RPC.发布/订阅消息传递.许可信息等以及相关的框架. 一个强大的后端支撑可以产生更加动态.可扩展和易于管理的部署策略,它可以用于实时通信和协作. 前不久,这篇文章已经开始了一个关于微服务的盛大宣言:化整为零!分而治之!"......企业IT架构师知道该怎么做.尽管如今几乎没有必要了.事实上,大多数企业架构以低耦合.高内聚节点集群的模式来构建后端都是可能的. 但是这种灵活性是有代价的:企

成小胖学习微服务架构·基础篇

看到最近"微服务架构"这个概念这么火,作为一个积极上进的程序猿,成小胖忍不住想要学习学习.而架构师老王(不是隔壁老王)最近刚好在做公司基础服务的微服务化研究和落地,对此深有研究. 于是成小胖马上屁颠屁颠的跑过去向老王请教:"王哥,我看微服务架构这么火,我也想学,您给我讲讲啥是微服务架构呗?" 老王笑了笑说:"要想知道什么是微服务架构,你得先知道什么系统架构设计." 成小胖的理想是成为一名架构师,平时积累了不少知识,因此对"系统架构设计&

微服务架构核心:专注执行同一件事并做好

微服务有且仅有一种非常专项的功能,通过远程API来提供系统其余功能.举个例子:试想一下仓库的管理系统,这样的系统中微服务可能提供的一些功能有: 接收库存 计算新的库存该存到什么地方 计算在仓库内将库存运往正确放置点的路线 为仓库员工分配运送路线 接收订单 计算仓库内指定一组订单的拣货路线 为仓库员工分配拣货路线 以上这些功能(可能还会有更多)都是由单个微服务实现的.每个微服务都有单独的运行线程,并且可以独立于其他微服务进行部署.同样每个微服务都有自己的专用数据库,尽管每个微服务都会与其他微服务协

通过Ruby on Rails和docker构建微服务架构之入门教程

说到时下的架构,免不了会涉及到微服务.而谈到微服务架构,又跟容器和Docker技术脱不了关系.虽然容器和Docker并不完全是一回事,但两者是密不可分的,而且二者之间也有共同之处:在大型复杂应用的构建和运营方面,二者都可以大大提高企业的效率.   微服务可不像一般的应用,可以通过apt-get工具进行安装,大家可能会问了:我们该如何才能像安装应用一样实现这种服务呢?在很大的程度上,这个问题的答案是否定的,我们无法轻松实现这种服务.更准确的说,至少目前我们还无法实现.在一个系统中,最难修改的就是架

12年互联网产品开发人眼中的微服务架构云端应用

微服务架构很热,讨论的文章非常多.但如果提到微服务架构的云端应用,可以深入分析的还比较少.本篇来自中生代技术群(FreshmanTechnology)第二期,好雨云创始人兼CEO刘凡的分享.其曾任澳客网 CTO和CEO职位.拥有超过12年互联网产品开发和管理经验,专注于互联网技术架构设计,对产品设计.敏捷开发.安全.OKRs.大数据等领域有深入研究.现推崇反应式编程(http://www.reactivemanifesto.org/),并在多个产品中成功应用. 下为正文: 微服务架构(Micro

基于Nginx搭建一个安全的、快速的微服务架构

本文讲的是基于Nginx搭建一个安全的.快速的微服务架构[编者的话]本文改编自Chris Stetson发表在nginx.conf 2016上的一个有关如今的微服务以及如何使用Nginx构建一个快速的.安全的网络系统的演讲,大家可以在YourTube上回看此次演讲. 0:00 - 自我介绍 Chris Stetson:Hi,我的名字是Chris Stetson,我在Nginx带领专业服务部门,同时也领导微服务实践. 今天我们要谈论微服务以及如何使用Nginx构建一个快速的.安全的网络系统.在我们

《Spring Cloud与Docker微服务架构实战》配套代码

不才写了本使用Spring Cloud玩转微服务架构的书,书名是<Spring Cloud与Docker微服务架构实战> - 周立,已于2017-01-12交稿.不少朋友想先看看源码,现将代码放出. 本次放出的代码: 共计70+个DEMO 覆盖Eureka.Ribbon.Feign.Hystrix.Zuul.Spring Cloud Config.Spring Cloud Bus.Spring Cloud Sleuth.Docker.Docker Compose等. 1-11章代码地址: ht