文字内容
3. 微服务文集 ThoughtWorks洞见
4. 目 录 [介绍篇] 微服务概述 我向HRMM介绍Microservices 技术雷达之微服务架构 给CxO的微服务指南 [进一步解读] 微服务和演进式架构 微服务即演进式架构 你以为是微服务或Docker?其实是组织架构! [实践篇] 基于微服务架构,改造企业核心系统之实践 微服务——大企业是如何在实践微服务中成长的 微服务的团队应对之道 服务拆分和架构演进
6. [介绍篇]
7. 微服务概述 文/姚琪琳 “微服务”这个术语在过去几年如雨后春笋般涌现,它是一 种构建可独立部署服务套件的软件设计方式。虽然这样的架构 风格没有明确的定义,但它们在组织方式、业务能力、自动化 部署、智能化终端以及对语言与数据的去中心化等方面具备共 同的特征。 以下内容摘自Martin Fowler的网站。
8. “微服务”,又一个出现在拥挤的软件架构街道的新名词。 虽然我们的第一反应是不屑一顾,但它的确是一个出镜率越来 越高的软件设计风格。在过去的几年中,我们已经看到很多的 项目使用了微服务,目前来看效果不错,我们很多同事已经将 它作为构建企业应用的默认方式。但很遗憾,并没有很多资料 解释微服务是什么以及如何实现微服务。 简而言之,微服务是一种将单个应用以许多微小服务所组 成的服务套件的形式来构建软件的方法,每个微服务拥有自己 的轻量级数据处理模块以及通信机制(通常是HTTP API的形 式)。微服务围绕业务能力和各自独立的自动化部署机制构建 而来。由于微服务需要极少的集中管理,因此各个服务可以使 用不同的编程语言以及存储技术。 为了解释微服务的设计风格,我们先来把它和单块架构风 格做一个比较。单块架构的应用只有一个单元。企业应用常常 包含三个主要部分:客户端用户界面(包括运行在用户计算机 浏览器中的HTML页面和JavaScript)、数据库(包括保存在常 见关系型数据库中的各种表)和服务器端应用程序。服务器端 应用程序处理HTTP请求,执行业务逻辑,在数据库中检索和更 新数据并选择和渲染HTML视图发送到浏览器。此服务器端应 用程序是一个完整的、 单一的逻辑可执行单元。任何对系统的 更改都需要构建和部署完整的服务器端应用程序的新版本。 这样的单块服务器是构建系统最自然的方式。所有处理请 求的业务逻辑都在同一个进程中,它允许你使用编程语言的特
9. 性来将整个应用划分为类、函数及命名空间。利用某些方法, 你可以在笔记本电脑中运行和测试应用程序,并使用部署流水 线确保新的更改通过了测试,并部署到了生产环境中。最后你 可以通过增加运行实例并进行负载均衡,对应用进行横向扩 展。 单块应用是可行的,但越来越多的人在使用的过程中受 挫,尤其是随着越来越多的应用被部署到云中。整个系统的更 新周期是被绑在一起的——对应用的一小部分进行了更改,就 需要整个系统重新构建和部署。随着时间的推移它往往很难保 持一个良好的模块化结构,继而难以保证新的更改只影响其所 在的模块。需要对应用进行扩展时,只能将整个应用一起进行 扩展,而不是扩展应用中的某个部分,这也消耗了更多的资 源。
10. 这些挫折导致了微服务的架构方式:以服务套件的形式构 建软件。微服务是独立部署和可扩展的,每个服务都有明确的 模块边界,甚至允许不同的服务使用不同的编程语言,它们甚 至可以由不同的团队管理。 我们不认为微服务架构是什么创新,它的历史可以追溯到 Unix年代的设计思想。但还没有足够多的人考虑过采用微服务 架构,如果他们使用微服务,很多软件开发过程会变得更好。 了解更多信息: 詹姆斯和马丁的文章接着罗列了九个微服务的特点来定义 什么是微服务架构,并探讨了其与面向服务的架构(SOA)的 关系,最后论述了这种风格是否是企业软件的未来。 请到这里继续阅读:
11. http://martinfowler.com/articles/microservices.html。 James Lewis是ThoughtWorks资深咨询师,也是技术顾问 委员会的成员。James的兴趣点在于整合企业级系统时采用小 型的相互协作的服务构建应用。他已经成功地构建了许多采用 微服务的系统,并且在最近的几年里一直是社区的活跃分子。 Martin Fowler是一位作家,演讲家和大名鼎鼎的软件开 发者。如何组件化软件系统的问题一直困扰着他,一些模棱两 可的答案并没有让他满意。他希望微服务不要辜负倡导者们所 提出的承诺。
12. 我向HRMM介绍Microservices 文/刘夏 一天我司招才猫姐(HR大人)对我说,“你给我解释一下 Microservicess是什么吧?”故成此文。一切都是从一个创业公 司开始的。 第一章:从集中到分权 最近的创业潮非常火爆,我禁不住诱惑也掺和进去创建了 一家公司。为了实现我的伟大抱负,我取“千秋万代,一统江 湖”之意,给公司定下了一个非常响亮的名字——一统。 故事 虽说叫做一统,但凡事都要从头开始,公司成立之初有五 个成员:罗密欧、朱丽叶、维克多、布拉伯还有老大——我。 我们五个人都是工程师出身,自身具备非常优秀的学习能力, 各个都是从业务到代码的好手,五个人一起做策划、搞市场、 写程序、做运维、面对客户;可谓你中有我,我中有你,努力 拼搏,好不热闹。为了吉利,我们找了一个车库作为机房和资 料室,上至合同,下至代码,全都放在里面。这就是一统最初 的样子。
13. 虽然创业艰难,大部分公司都在前两年倒下了,但是我大 一统不但没有倒掉,还意外地实现了增长:客户量从当初的一 家猛增到一百家。这样一来,即使我们的团队再出色也应付不 了这么多的客户。挣钱还是要命呢? 命得要,钱也得挣!怎么办呢?招人吧!我们绞尽脑汁搜 罗(挖角)市场上的人才,组成了巨型一统团队。我们认为团 队中的所有成员都应该跟初创时期的五个人一样,能攻能守, 内外兼修,但是……我们发现这是不可能的,有些人擅长写代 码而非面对客户,有些人善于做市场但是不喜欢做财务。后来 出现了更加让人挠头的事情,有一个财务流程,问了五六个人 竟然没有一个人能够完整地串起来。于是,我一个一个地问,
14. 最后才把整个流程从这些碎片知识里面串联起来。 这种团队的服务质量可想而知,不久就接到了数十件客户 投诉。竞争对手趁机抢占市场,一个欣欣向荣的公司瞬间就摇 摇欲坠了。 为了留住客户,我们必须在扩张的同时保证服务质量。我 发现目前最重要的问题就是职责不清晰,大家不知道自己应该 干什么、也不清楚该怎么干,于是我抽调了各个业务部分的精 干力量,总结流程,形成了客户\市场、财务\合同、技术运 维、管理团队四个独立的业务部分。采取内部招聘的方式将人 力分配到了这四个部门中。我期望将大家从纷繁的知识体系中 解脱出来,每个人不需要了解那么多的知识,集中力量关注自 己的问题以提升效率和服务质量。
15. 在此次结构调整之后,大家的工作效率明显提升了。抱怨 知识结构太复杂、无法短期适应工作的声音消失了。一个月之 后,我们做了一个抽样调查,发现大家对自己的工作范围和内 容都了如指掌。一些客户又重新和我们签订了合同。 正当我沾沾自喜的时候,发生了一个重大事件。由于我们 的资料室是对全公司开放的,任何成员都可以查看或修订其中 的信息。客户及市场部的一个员工平时非常好学,对财务方面 的知识掌握的非常系统。有一天,公司急需草拟一份财务清 单,但是这个任务非常耗时,财务部门的同事当时正在进行月 末审核,无暇抽身。这位热心的同学就凭借自己出色的能力从 资料室取来相应的材料完成了清单。三天后,财务部的罗密欧 准备细化这个清单。但是清单的内容让他着实吃了一惊——清
16. 单上的填写内容和他们部门内约定格格不入。罗密欧只得自己 重新完成了清单。一来一去让他的工作耽搁了一天,罗密欧向 我抱怨道。 无独有偶,其他部门也发生了同样的事情。这让我意识到 只是把人员的职责进行划分并不能彻底解决问题。我们不能再 继续混用一个资料室了,因为这样人人都可以任意修改各种资 料,安全性不好不说还会造成填写格式混乱。于是我把财务部 的资料放在了另一个独立的屋子里,并给罗密欧单独配了钥 匙。这样,任何想填写财务清单的人只能找财务部的人所要单 据,而当单据缴回的时候也必须经过财务部的审核。鉴于财务 部每个月底都会很忙,在那时我会临时抽调人手去帮忙。 我希望对其他部门做相应的整改,但这种动作幅度毕竟很 大,因此,一段时间内还会有多个部门共用资料室。经过一个 月的努力,我们最终还是淘汰了公用资料室。为每一个部门都 配备了独立资料室。虽然需要缴纳更多的房租,但是各部门再 也没有犯之前的错误。
17. 从故事到项目 大多数项目也会像我们的创业公司一样,一开始大家一起 干活,每一个人都是冲锋陷阵多面手。大家一起组成了应用程 序的全部,而我们的车库就是数据库。这种组织结构代表了典 型的 monolithic application。这种系统的逻辑架构是类似这样 的。 在项目的早期,业务简单、吞吐不大,这种结构清晰、易 于理解的架构非常实用。但是随着业务的增大,混在一起的代 码不易理解。而最容易想到的解决办法就进行职责的划分。一 统公司一开始在维持车库结构的情况下仅仅从人员上做了拆 分,这种情形在实际项目中也存在。系统进入了多个服务共享 一个数据库的阶段,集成点在数据库上。
18. 这种划分职责但又维持数据库集成的方式只应当作为过渡 阶段存在。程序永远都是逻辑+数据,而数据的混杂谈不上职 责的独立。长期维持这种数据集成的状态容易出现业务下行, 数据表达不一致等问题。从逻辑+数据的整体划分边界(称为 模块,或者服务)势在必行。而在边界划定之后,就需要考虑 独立的服务之间如何进行协作了。 第二章:协作 现在我们的资料室都独立了,再也没有办法像以前一样有 需要就去公共资料室里取资料了。那么我们应该如何进行协作 呢? 故事 一个非常自然的想法是把各部门用业务流程穿起来。例 如,在洽谈一个订单时,先由客户及市场部进行调查和谈判,
19. 然后由技术部制定解决方案,管理部审批之后由财务合同部拟 定合同,最终递交管理部签署。这种协作方式我们不妨叫他串 联协作。 为了将这一方案执行下去,我们对各个部门的人员进行了 培训。例如,对于技术部。在洽谈一个订单时,技术部需要给 出解决方案,完成之后需要将方案递交管理部审批。类似的业 务有很多,每一个业务各个部门任务都不同,而下游接收的部 门也不一样。但是我的同事们还是克服了困难,让它们烂熟于 胸。 业务变化是最平常的,一变就是一大把。现在对于洽谈订 单的业务,我们需要在给出技术方案之后先让财务部进行预算 审核,再将其递交给管理部。这需要重新培训三个部门的人, 洗脑一样的把他们之前的流程抹掉。一个业务变化还好,但是
20. 二三十个业务同时发生变化就让大家抓狂了。甚至有人说这和 之前一大坨人一起做所有事情没有什么本质上的差别。看来这 种业务串联的方式是行不通了。 所谓我不入地狱谁入地狱,这种情况下我挺身而出,入住 市场部——因为这个部门是直接为客户服务的。我对所有的流 程了如指掌,当业务来的时候,由我去对业务进行协调。例 如,当一个洽谈订单的业务到来时,我会先将它交给客户市场 部进行谈判;结束后市场部将需求和意向书交给我,我再把需 求交给技术部去制定解决方案;方案制定完毕之后技术部会把 方案返回给我,我再把结果交给财务部审核……如此进行。这 样,每一个部门都不需要由于业务变化重新接受培训了,也不 用记住他们的下游应该是谁。大家觉得,职责明确多了,工作 轻松多了。
21. 这种协作方式我们不妨称之为“业务调度员”式的协作。 现在我俨然成为了流程的中心,其他业务部门不需要关注 业务流程的变化。这给我们增加了很多灵活性,因为我一个人 的变化速度要比一群人的变化速度快得多(你是独裁者吗)。 但是我的大脑总是有限的,一年之后,经历了三四轮业务变 化,我已经无法准确回忆起某些业务细节。我不得不通过频繁 的查询业务笔记来确定我的下一步操作;此外,不停地往各部 门送信也令我不堪重负。
22. 这时候,我希望其他人能够为我分担。我决定化被动为主 动,不由我主动联络各个部门,而由各个部门主动接受任务。 我在公司安装了一个大喇叭,话筒就在我的办公室里。当一个 订单洽谈业务到来的时候我就朝着喇叭嚎:新订单来啦!客户 和市场部专门关注新订单,因为按照流程,订单到来之后市场 部要尽快投入谈判。于是他们会主动开始行动。当市场部工作 完毕之后,他们会将谈判的结果、需求以及意向书拿到我的办 公室里。我会再嚎:需求来啦。此时,技术部会从我这里拿走 这些资料并开始工作。如此往复,直到项目完成。 这种协作方式令我不必再操心信息在各部门之间的流转。 各部门知道他们应该何时介入,我只需要对着大喇叭喊,自然 会有相关的部门将活干完。这样,我作为业务的中转中心,工
23. 作量不会随着业务的增长显著的增大(只要喊话就行了,至多 就是增加喊话种类),而各部门也不用关心自己的下游到底是 谁,只需要关心我喊的话就行了。这种协作方式不妨称之为“公 司广播”。看起来这是一种非常方便的形式。但是这真的就又快 又省吗? 有一天,来了一个新的订单。在我接到意向书和需求之 后,我照例喊话:需求来啦!接着,我就出去吃饭了(真是资 本家啊你)。等我回到了办公室,发现文档已经被拿走了,而 结果还没有送过来。时间一天一天过去了,我手头的新订单越 积越多,需求文档和意向书源源不断的送过来。到了第三天我 实在是受不了了,想去查找文档的去向和任务的完成状况。这 时候我才发现我根本无从下手,因为我不知道文档是谁拿走 的,于是我便一个部门一个部门地去询问。可是由于业务的发 展,现在我们已经有20多个部门了,这种非常规的询问不仅让 我跑断了腿,而且为了查证,需要翻阅各部门成吨的业务日 志,各部门的部长对此也颇有微辞。我终于意识到——这种协 作方式在令结构松散灵活的同时也增加了监管的难度。必须采 取额外的投入来弥补这一短板。 于是,专门监视各部门动向的“纪检委”:监管部出现了。 一开始,我只是想确认一下各部门运作是否正常,有没有由于 天灾人祸而出现团灭的现象。出于不对各部门添加新的压力的 愿望,监管部会定期去各部门走一圈看看是否都在好好干活 (真是讨人嫌的部门啊),就像这样。
24. 但是随着业务的发展,我希望得到各个部门更加详尽的信 息,例如,各部门是否积压了大量任务并需要帮助,在处理过 程中是否由于流程不合理而无法继续下去等等。需要收集的数 据已经远远超过了监管部跑腿的速度。怎么办呢?如果我手头 没有什么钱,我可能会降低监管部工作的周期,例如之前是半 天一次,现在改成两天一次。但是我是土豪,于是我制定了监 管汇报单,强制各部门在状况出现问题的时候主动向监管部汇 报,就像这样。
25. 从故事到项目 我们真正开始考虑服务之间如何进行协作了。和一统公司 的做法一样,最容易想到的就是业务串联。业务首先由第一个 服务处理,之后再由第一个服务调用第二个服务继续处理,直 至业务全部处理完毕。于是我们就得到了这样的系统架构:
26. 正如故事中说的一样,这种业务的串联难以应对业务流发 生的变化。同时,由于服务之间互相直接耦合,集成点多,难 以做到独立进行部署。“业务调度员”的方式是一种很好的改 进。如果你还记得那位勤劳的调度员(我),那么你就一定认 识Composer这个特殊的服务:我们使用 它进行业务流的分发与 控制。这样,服务仅仅和Composer进行对接,不需要考虑业务 流的问题。既明确了职责又可以进行独立部署。以下就是这种 协作方式的架构:
27. 而最复杂的“公司广播”则是变直接调用为事件触发。使 用“事件”隔离了各自的模型。系统结构更加松散灵活。
28. 隔离和协作的矛盾 从踌躇满志的开始创业到现在,我感慨于业务的扩大和公 司规模的发展,也有一些会议例如 PCon希望我们能够去介绍结 构划分和协作模式。但是每当我在工作之余静静思考,却感到 一些厌倦。我们的协作方式真的好吗? 随着职责的划分,我们越来越专业化,互不影响的工作方 式极大地提高了我们的效率,良好的隔离让我们的失误不至于 扩散并能够横向扩展;而监控系统也告诉我们一切尽在掌握。 但是隔离同时也是壁垒。为了协作,我们在这些壁垒上开了些 小孔,为了严格控制进出,我们制定了越来越多的规条,例 如,信件应该怎么写,单据应该怎么填。回头看去,成百上千 的规约连我也不能尽数,当公司需要做出变化的时候,如果变 化仅仅发生在各个部门内部,这种结构的优势无可置疑。但是 如果涉及到部门之间的协作,甚至部门之间的拆分合并,就会 变得异常艰难。由于部门和规约的耦合是存在于脑内的,并不 显露在外,修改已经存在的规约和部门结构往往不现实,只能 花更多的钱去组建新的部门,逐步介入公司业务后淘汰旧有的 部门。而这种周期动辄是以月计算的。有的时候,可能宁可去 接受新的方式从头开始,卖掉旧的公司,创建新的公司,然后 继续轮回。 隔离既创造了灵活的单点变化也造就了整体的僵化。细小 的部门划分不能解决这个问题,因为部门越多,规约越多,实
29. 施成本越高(在例子中我们并没有考虑资料室的房租,监控的 支出,但是现实中这往往是一个决定性因素)。单个部门结构 的简化造就了整体的复杂。 因此,分部门就一定好吗?业务调度员就没有公司广播好 吗?答案应该来源于你的现实,而不是理论。如果让我重来一 次,我可能会慢一点,再慢一点。未来无法预计,针对当下的 痛点做出反应可能不是最优的,但是却是一个容易理解的思 路。 实际项目中也是一样。就像武侠小说中的一样,威力越大 的招数使用限制也就越多。一方面,系统结构越来松散越灵 活,变化变得容易;另一方面,系统越来越复杂,维护越来越 困难。当维护困难到一定程度不得不将其提上议事日程的时候, 专事监督与维护的工作就出现了,这种维护不同以往。维护者 既要有维护知识又必须了解这个复杂系统的运作方式。别忘 了,虚拟化、云、Devops,除了概念上的光鲜还复杂又花钱啊! 慢慢进化,慎重的考虑并决定是否选用Microservices,然 后做好维护吧。 第三章:Microservices 在前面的内容中,哪种方式可以称为Microservices架构 呢?故事里面公司组织结构演化分成了几个部分,并不是每一 个阶段代表的结构都可以称之为Microservices:
30. 第一个阶段是多个部门共用一个资料室,这种情况往往无 法摆脱数据库集成的事实(有些项目使用Schema对访问进行隔 离,不在此列),不能称为Microservices; 第二个阶段是各个部门有自己的资料室,这是一个非常重 要的改变,直到此时,各个部门才实现了完全的隔离,但是还 不足以称为Microservices; 第三个阶段分三类:首先是串联协作。在这种方式下,一 个部门的变化往往会影响其他部门,因为每一个部门都需要知 道业务的上游和下游,因此有比较紧密的耦合关系,无法独立 变化。因此不足以称为Microservices;其次是业务调度员方 式,此时部门自身的变化不会扩散到其他部门,因此是可以独 立决定和操作,只要部门足够小,这种结构可以称之为 Microservices了;第三是公司广播。这种方式下的部门耦合更 加松散,可以独立进行变化,在部门足够小的前提下可以称之 为Microservices。 我们的初衷是什么呢?构造一个系统能横向扩展以满足业 务伸缩性,提供灵活变化的能力,又希望变化的影响不要扩 散。因此,如果一个架构可以称之为Microservices架构,那么 意味着: • 每一个 Service 可以进行独立部署; • 每一个 Service 都足够小,完成完整的定义清晰的职责; 业务调度员和公司广播两个例子的组织结构都可以成为 Microservices架构。但是他们之间并没有绝对的优劣之分。选
31. 用哪一种应当取决于实际要求。 写在最后 Microservices不是一门科学,而仅仅是实践。就像是面向 对象编程一样。最终应当是需求、是人来决定架构而非架构决 定需求。Microservices是为Business Capability而建,是根据实 际(或者痛点)做出的抉择。他解决了一些问题,但是并不能 肯定这就是今后软件的发展方向。硬件的革新——不论是近期 的电池技术发展,还是近乎黑科技的量子态传输、量子计算都 有可能影响甚至颠覆今天形成的软件开发体系。就像是当年大 家为了追求极致的执行效率试图将代码塞进64K的代码段一 样,我们今天奉为经典的东西未来可能只是茶余饭后的谈资。 我们能做的只有保持开放的心态,坚持辩证的观点,坚持从实 际出发,寻找出最合适的解决方案。这也就是我们不称自己为 码农的理由之一吧。
32. 技术雷达之微服务架构 文/王健 最近几年,微服务架构异军突起,与容器技术相辅相成, 成为架构设计领域热议的话题。而《技术雷达》作为 ThoughtWorks出品的一份关于技术趋势的报告,在技术社区也 一直有着非常好的口碑。本篇文章就试图通过结合技术雷达与 微服务架构,从往期技术雷达中微服务架构的演变来审视一下 这个新兴架构的发展过程。 相信大家了解或者听说微服务架构也都是近两年的事情, 从Google Trends的搜索数据统计上看,微服务架构确实是从 2014年逐渐兴起、到目前才呈现出一个爆发的趋势。 但在技术雷达中,2012年3月份这一期就已经包含了微服 务架构相关的内容,当时它还处在评估(Assess)阶段,这就 说明技术雷达早在2012年初的时候就已经成功捕获到“微服务架 构”这个新的技术架构。
33. 微 服 务 2012年 第 一 次 出 现 在 技 术 雷 达 上 到底什么才是微服务架构,在Martin Fowler的那篇著名的 描述微服务架构的文章中第一次定义了“微服务架构”并阐述了 其九大特性。而我一开始接触微服务架构的时候也觉得这好像 不是一个新的概念,很早之前就有RPC和SOA这种面向服务的 分布式架构,现在又冒出一个新的微服务架构,他们到底有什 么区别?看到了Martin Fowler的定义后,才慢慢清楚他们的区 别,在Martin Fowler的定义中有几个关键字可以让我们甄别一 个分布式架构是传统的面向服务架构还是新的微服务架构:每 个服务是不是跑在独立的进程中?是不是采用轻量级的通讯机 制?是不是可以做到独立的部署?
34. 微服务架构的定义 时间来到了2012年的10月份,在这期的技术雷达中,微服 务架构已经从评估(Assess)阶段被移到实验(Trial)阶段。 什么叫实验阶段?我们ThoughtWorks内部有一个解释,就是这 项技术已经可以运用在实际项目中,但你仍要控制风险,也就 是说此项技术已经可以在风险比较低的项目中使用了。 一个项目要能被移到试验的阶段,还有一个必须要满足的 条件,就是必须在ThoughtWorks自己的项目中已经开始实际使 用。幸运的是,我当时所在的项目就是从2012年10月份左右开 始采用微服务架构的,结果非常好。我们在3个月完成一个新 的应用并成功上线,当时客户评价很高。 实际体验下来,微服务架构对我们来讲究竟有哪些好处? 这几点是我体会到的: 首先是组件化,作为一个软件开发人员,其实我们一直都
35. 有一个梦想,就是希望有朝一日可以把一堆的组件像乐高一样 通过直接拼装的方式快速构建我们的应用。无论是最早基于拖 拽的方式构建应用,还是利用现在大热的前端组件化,我们一 直都在试图寻找一种更好的组件化方式,微服务架构也是其中 之一。但构建软件本身还仍是一个非常复杂的过程,微服务架 构为我们提供了一种组件化的可能,但直到现在还不好说它能 不能达到我们作为整体组件化的目标,但是至少从我们的实际 体验来看,它确实能给我们带来组件化的很多好处。 然后是弹性架构,上几期技术雷达推荐了亚马逊的弹性计 算平台,如果我们的系统是由按业务划分的服务构成,结合容 器技术和云平台我们就可以构建一个极具弹性的架构。通过云 平台进行实时的监控,一旦发现资源紧张,立刻就可以通过云 平台和容器技术自动在瞬间扩展出成百上千的服务资源,在高 峰过去之后又可以立即把所有的服务注销掉,释放资源,整个 过程完全是自动化的。
36. 微服务架构的好处 去中心化和快速响应也是微服务架构给我们带来的好处。 在单体架构下,会非常依赖于项目一开始对技术的选择,一旦 选择了一个技术栈,之后几年都会被绑定在这样一个技术栈 下,很难应对变化。微服务架构则给我们提供了一个更细粒度 使用技术的可能,在不同的服务里可以使用完全不同的技术 栈、不同的语言、框架甚至数据库,真正做到用最适合的技术 解决最适合的问题,从而让我们可以更加敏捷地响应需求和市 场的变化,提高了竞争力。 从2012年10月份一直到2014年的7月份,这段时间里有大 量与微服务架构相关的工具、技术和框架出现在技术雷达上。 包含了很多领域:语言、测试、框架、CI、CD、持续交付、安 全等等。 从2012年的3月份微服务架构第一次出现在技术雷达上一
37. 直到2014年7月份,虽然微服务架构已经有比较大的发展,技 术雷达也推荐了大量相关的内容,但在当时社区中谈论微服务 架构的声音并不多,这也体现出了技术雷达的前瞻性。 技术雷达上微服务架构相关项目 从2014年7月份开始,微服务在社区就开始呈现出一种爆 发的趋势,但在紧接着的2015年1月刊的技术雷达中却出现一 个非常有意思的项目:Microservice Envy。通俗点儿讲就是“微 服务红眼病”,或者说是“微服务你有我也要”。 这意味着在社区刚刚爆发,对于微服务架构踩下油门的时 候,我们又踩下了一脚刹车。但这并不是代表我们不看好微服 务架构,而是认为需要认真思考我们是否真正需要以及何时以 何种方式使用微服务架构,不能看别的人都在使用也盲目切换 到微服务架构下。
38. 这是因为微服务架构并不是免费的午餐,使用微服务架构 是需要门槛和成本的。我们需要问自己:用微服务我们 够“个”吗?或是说用微服务我们够“”格”么?我们是否有这个能 力和足够的资源驾驭这个新的架构? Martin Fowler在他的《企业应用架构模式》中,就提到了 分布式对象设计的第一原则:“设计分布式对象的第一个原则就 是不要使用分布式对象”。因为分布式系统会给我们带来很大的 挑战,让系统复杂度大幅增加的同时,我们还需要面对开发环 境、测试、部署、运维、监控、一致性和事务等一系列的问 题。 Microservice Envy 所以说,微服务架构虽然看起来非常美好,但是也有很大 的附加成本。通过下面这张图可以看到,横轴是时间轴,纵轴
39. 是生产力。当软件的复杂度很低的时候,单体架构下的生产力 是要高于微服务架构的,但随着复杂度的不断增加,无论是单 体应用还是微服务应用的生产力都会下降,只是微服务架构的 下降会相对缓慢一些。 这也容易理解,因为微服务架构中我们的系统是由很多的 小的服务组成,每一个服务都很小,相对简单,技术栈也很独 立。这样做局部的变更也会更加容易,随着系统复杂度的不断 增加,微服务的优势也就慢慢地体现出来了。 那要如何应对呢?为了追求生产力的最大化,一开始我们
40. 可以选择从一个单体架构开始,然后争取在微服务架构生产力 超越单体架构的那个复杂度点时切换到微服务架构上来,这样 才能实现生产力的最大化。这就是Martin Fowler提出的单体应 用优先原则(MonolithFirst),以单体架构开始,通过演进式设 计逐渐重构到微服务架构。 MonolithFirst 为了保证从单体架构演进到微服务架构的重构过程安全可 控,还需要有一套良好的质量守护机制。下图描述的就是 Martin Fowler提出的微服务架构下的测试策略,我所在项目就 是按照这种方式来划分和设计我们的各种不同类型的测试,帮 助我们在对于服务的抽取合并分离的重构过程中做到安全可 控。
41. Testing Strategies in a Microservice Architecture 我们刚才提到了康威定律,康威定律说的是设计系统的组 织产生的设计和架构等价于组织间的沟通结构。而康威定律还 有一个逆定律:如果想改变一个设计架构方式,首先要改变组 织结构。我们经常发现推动技术架构的转型和演进很难,因为 我们在调整技术架构的同时却忽略了组织结构也要对应做相应 的调整以匹配技术架构的变化,当组织结构与技术架构不匹配 的时候,就会相互拉扯,这些都是在当时的技术雷达中不断着 重强调的。
42. 这篇文章所谈论的都还是2015年以前各期技术雷达里的内 容。在这之后直到现在,技术雷达也还在持续地推荐微服务架 构相关的内容。所以说踩下刹车并不是因为我们走错了路,只 是走的太快了,需要时刻提醒自己不要盲目,要清楚微服务给 我们带来了什么机遇和挑战,最终解决我们的问题。 及至最新的几期技术雷达,微服务架构还在不断的演进, 而且慢慢的与其他新兴技术融合形成了一整套不同以往的软件 构建解决方案。例如无服务器架构、Docker、PaaS等技术的发 展,会不会为微服务架构的演进提供更多可能?是否可以为微 服务架构早一天落地、改变我们的开发方式提供可能?让我们 大家一起拭目以待。
43. 给CxO的微服务指南 文/Jim Highsmith & Neal Ford 译者/禚娴静 这是技术雷达系列文章的第四篇。在这一系列的文章中, 技术雷达的作者们向企业领导者分享了他们对于那些推动业务 差异化的技术问题和解决方案的洞见和经验。ThoughtWorks技 术雷达由ThoughtWorks全球技术专家咨询委员会创建,它包含 了对软件开发和业务战略有显著影响的技术趋势组合,2016年 是技术雷达发布的第七年。 未来已经在这里,它只是分布不均。 ——威廉·吉布森 数字时代就在我们身边。将软件开发视为高成本开销而不 是竞争力的企业将会举步维艰。为了参与并在这个数字世界中 繁荣兴旺,企业必须学会适应我们这个时代的不确定性—更快 地将新产品推向市场,快速而有效地改进当前的产品,并为客 户提供有意义的数字体验。 为了实现这些目标,企业需要将敏捷性/适应性集成到三个 领域:人、流程和技术。 人们需要适应试验和改变。以“迭代”的形式推进这一过 程,并加强学习。技术,包括技术架构,需要支持快速地交付 产品与服务。
44. 技术的敏捷性不能被忽视——敏捷的团队和流程并不能弥 补笨重的技术所带来的缺陷。 但作为一个高级管理人员,在这样一个充满了新技术的世 界,你应该将注意力投注在哪里呢?? 这个问题的答案被那些不停地讨论着看似神秘话题的技术 人员们所掩盖。哪些神秘的话题需要得到管理层的注意呢?其 中最重要的话题之一是微服务。原因如下所述: 微服务影响人、流程和技术:包括团队组织结构,流程和 实践(如DevOps),以及重新调整架构以适应我们要解决的问 题,而并非纯技术层面。微服务促进了每个领域的适应性。它 值得管理层花时间去了解其潜在的贡献。 技术敏捷度 微服务架构风格的特性是由一组极小的服务组成,它们彼 此独立且单独部署。微服务由Netflix这样的公司推广开来。每 个服务包含一个离散的业务功能,它在技术上与其他服务相隔 离,产生了类似乐高积木的效果:开发人员可以将服务切换为 一个新的服务,而无需破坏其他服务。就像巨型的乐高模型可 以由75,000块乐高组成,大型的数字应用程序也可以由这些受 乐高思想启发的服务所构建。 这种架构有一些明显的好处。首先,每个服务与其他服务 高度解耦,这意味着它们是自包含的。因此,一个服务中的技
45. 术更改(例如数据结构更改)不会影响另一个服务。服务仍然 可以通过消息传递进行通信,但是任何一个服务都不允许修改 另一个服务的实现细节。 第二,因为开发人员不需要共享基础设施,他们可以选用 适合于该问题复杂度的技术栈来实现每一个服务。考虑到当今 技术栈的复杂性,在同一应用程序中,使用简单工具处理简单 问题和使用复杂工具处理复杂问题的能力使开发团队在增加了 灵活性的同时也降低了成本。领导者重视能将复杂问题简化的 技术专家。 第三,每个服务封装了业务功能,它更容易促成围绕特定 问题域的团队,而不是通过作业功能分割的团队。例如,服务 团队通常包括开发人员、业务分析师、DBA、运维人员和QA— 即构建和部署服务所需的一切角色。这样一来便降低了协调成 本。 “从功能性组织结构向产品或服务结构转变”是敏捷企业转 型的一个日益增长的趋势。而微服务架构支持了这种趋势的变 化。 最后,因为每个服务是相互隔离的,所以以服务组成的架 构既快速又灵活。同时因为服务的业务范围很小,对服务的更 改可以快速地发生,这为开发人员提供了新的高级功能。一旦 架构师设计了一个小型独立服务的系统,其中应用程序由部署 的多个服务之间的消息传递组成,多变量测试等操作就变得容 易了。
46. 例如,企业可能对他们网站的未来发展方向并不确定。因 此他们设计了具有相似性但功能不同的两种服务,并向不同的 用户组部署不同的版本,以获取结果从而推动未来的发展。像 Facebook这样的公司也是通过使用这种类型的A / B测试进行试 验来分析他们的用户。 标准化一直是IT组织降低成本的方式之一。不幸的是,它 也降低了灵活性—标准化越多,灵活性越少。通过采纳微服务 架构,架构师和开发人员可以使用更加多样化且能够紧密反映 问题复杂度的技术栈来设计应用程序。 微服务架构风格与许多企业部署软件和分配IT资源的方式 相反。许多架构风格的主要目标之一是有效地利用共享资源 (操作系统、数据库服务器、应用程序服务器等)。由于资源 的成本影响了底线,因此这些公司建立了软件架构以最大化共 享资源。 然而,共享资源有一个缺点。无论开发人员如何有效地构 建与这些服务器的隔离,都会出现对这些资源的竞争。有时组 件由于依赖管理而互相干扰,有时由于两个组件争用某些资源 (例如CPU)而产生问题。这就不可避免地会导致共享组件以 并不期望的方式进行交互。 容器和解耦 在软件交付中,有两个关键的技术“环境”:开发人员工作
47. 的开发环境,以及IT运维人员管辖范围的部署环境。传统情况 下,在这两个环境之间移动代码充满了技术错误,冗长的时间 延迟以及组织层面的沟通不畅。 几年前,一些有趣的事情发生了:Linux对于大多数企业足 够友好,Linux的变体在商业上免费—但是这不足以影响技术架 构。 接下来,开源的创新与敏捷开发技术的结合鼓励了开发人 员创建各种工具,将许多繁琐的运维手工操作自动化。这被许 多人称为DevOps革命。 这场革命使得开发团队和IT运维人员通过使用Puppet、Chef 和Docker等高级工具更加紧密地联系在一起。意外地,Linux的 变体允许免费操作,开发人员可以在不受干扰的情况下将其组 件部署到一个原始的操作系统。一整个可能的错误类别就突然 消失了,因为组件之间能够相互解耦。 如果开发人员可以构建他们自己的现实环境,他们必须减 少与运维部门的协调,也就减少了组织间的摩擦。用程序启动 类生产环境的能力消除了测试、集成、共享环境下的资源竞 争、以及一系列其他问题。 21世纪的架构敏捷度 在治理方面,微服务架构风格有其他的好处。传统的做法 是,企业架构师定义了组织的共享技术栈,以最大化项目间的
48. 资源使用,同时最大程度地减少支撑成本。例如,一个大型企 业可能将Java和Oracle标准化以作为其主要开发平台。如果每 个人都使用Oracle,那么该企业的一切都可以存储在一个工业 强度的数据库中。 规范化治理有一个缺点—通常,为了标准化的某一目的, 团队必须使用并不太理想的工具。与此同时,还有一个潜在的 更微妙的缺点。例如,考虑一个已经选择在特定消息队列上标 准化的大型企业。在评估需要此共享基础设施的所有项目时, 企业架构师会找出最复杂的场景,并选择一个适合这种复杂度 的工具来处理它们。 然而,许多项目并不具备这个最复杂的场景。但因为每个 项目必须共享相同的基础设施,所以每个团队都得承担其他团 队的最大复杂度。这种情况也发生在数据库层。许多项目只需 要几个记录的简单数据存储,并不需要复杂的查询功能,但最 终都使用了具有工业强度的数据库服务器,只因为这个企业的 标准如此。 容器化技术解决了这个问题,因为它远离了共享基础设施 —每个项目都部署在自己原始的、容器化的环境中。因为不存 在共享的动力去选择工具,所以每个项目刻意选择更适合自己 的工具。 当然,如果企业架构师允许每个项目选择自己的技术栈, 那么会存在一些严重的缺点。我们经常看到一个称之 为““Goldilocks治理”(企业架构师选择几个技术栈—简单、中
49. 等和复杂,并根据规模分配新项目)的实践,它适用于高度解 耦的环境。这些知识是可迁移的,该公司仍然可以从中受益, 但是却可以远离那些由于疏忽大意而将问题过于复杂化的行 为。 为什么我们会谈到这儿? Eric Evans的《领域驱动设计》一书对微服务架构发展产生 了巨大的影响。它介绍了一种将大问题空间分解为领域或重要 实体(如客户和订单)及其关系(客户下订单)和行为的技 术。领域定义的一部分是有关边界上下文的概念:每个领域形 成一个围绕实现细节的封装层。 例如,如果分析人员识别了一个Customer领域,那么它存 在于自己的边界上下文中。在Customer的上下文中,开发人员 知道所有的实现细节:类结构,数据库模式等。 但是,其他边界上下文(如Orders)不能看到这些实现细 节。虽然领域可以为了协调的目的互相发送消息,但是任何一 个领域都不能穿透另一个领域的边界上下文。因此,在一个边 界上下文中的开发人员可以自由地更改实现,而不必担心破坏 其他领域。 微服务中的容器是领域驱动设计(DDD)中边界上下文的 物理表现:每个容器代表了一层封装,以防止实现细节干扰系 统的其他部分。边界上下文提供的隔离展示了结构化软件架构
50. 的不同方式。 在过去,设计架构主要围绕技术架构:架构模式、库、框 架等。例如,分层架构在许多组织中是很常见的: 图 1: 传 统 的 分 层 架 构 在图1中,架构师沿技术层进行分离,使之在需要时可以 很容易地替换一整层的内容。例如,如果开发人员需要更改持 久机制,所有相关代码都会出现在持久层中。 那么开发人员多久更换一次整个持久层呢?几乎从不。但 你的团队多长时间基于像Customer这样的概念工作呢?每天! 在图1分层架构中,Customer处于哪一层呢?其中部分在表 示层、业务层、持久层等等。因此,项目架构上通用单元的变 化在分层架构中并没有得到很好的支持,原因是通用的变更影 响到了每一层。 如果不同层代表了开发团队的不同部分,其影响会更严 重。例如,对Customer的更改可能涉及到用户界面、业务逻
51. 辑、持久层和其他特性。如果你的组织由开发人员、DBA、用 户界面设计师和运维人员组成,而他们在相互隔离的HR部门 下,那么进行常见更改的协调成本是巨大的。 微服务强调解耦和容器化,翻转了图1中的传统做法,使 领域成为架构的主要元素,如图2所示。 图 2: 以 领 域 为 中 心 的 架 构 在图2中,分层结构仍然存在,但是其耦合边界是领域的 边界,它将技术架构归入实现细节,并用领域对其进行封装。 以技术为中心的组织单元中,员工与员工彼此隔离,要想在这 样的组织中构建以领域为中心的架构是很难的。 许多技术人员在构建数字化企业中会遇到这样的问题:想 要支持如移动应用等新举措,却被那些需要拆分的遗留系统所 拖累。如今,这些企业越来越多地引入微服务作为这种拆分过 程的关键战略。 Greenfield项目得益于DDD实践。通过DDD理解了他们的问
52. 题领域以及重要组件之间的接口所在。对于现有项目,更加模 块化的系统会促使开发者解开事务性的泥球,并且可以在那些 属于一起的组件和偶然耦合的组件之间做更清楚地区分。 团队 你还将遇到微服务对团队影响:一个架构风格是如何推动 开发团队重组的。 1968年,梅尔文·康威对软件开发做了一个很有预见性的观 察,被称为康威定律: 设计系统的组织,其产生的设计等价于这些组织间的沟通 结构。 康威定律对软件开发的意义是什么呢?你的设计反映了你 的团队结构。企业常见的团队结构是由人力资源部门推动的, 他们将职能类似的技术专家组织在一起。虽然这是一种符合逻 辑的排序算法,但这种结构在设计自包含服务时效果不佳。 如我们认为的康威逆定律,现在许多公司在围绕业务领域 组织跨职能团队,而不是围绕技术分层构建。例如,一个 Customer服务可能包括一个业务分析师、开发人员、QA、 UX、DBA和运维人员。 团队会在准备好之后再部署服务,而不是先构建一些东西 传递到运维人员,使之包含在下一个巨大的发布中。许多选择 微服务的公司使用持续部署,以尽快将变更投入生产环境中。
53. 总结 企业高管可能会认为微服务是最新流行词而不予考虑,但 那些了解这种架构影响的人可以获得实实在在的好处。微服务 可以提高交付速度,增强灵活性,并提高效率。他们将工作进 行重组,并与业务问题域保持一致,而不是技术域;从一组独 立,更易于开发和维护的服务中创建业务应用程序;更好地匹 配技术解决方案与业务问题的复杂程度;构建可以帮助重组现 有遗留系统以及创建能够快速响应不断变化的业务条件的新产 品和服务的自适应架构。 威廉·吉布森是正确的—许多公司已经将IT竞争力看作鲁棒 性一个新的度量。对于这些企业来说,未来已经在这里了。其 他还没有意识到这一点的公司可能会发现他们的未来已经受到 了影响。 原文链接: https://www.thoughtworks.com/cn/insights/blog/cxo-guidemicroservices
55. [进一步解读]
56. 微服务和演进式架构 文/Rebecca Parsons 译/占红来 在我们的软件开发流程中,经常会面临改动,有来自用户 需求的、来自市场的,以及为了一些潜在机会而做出的改动 等。当这些改动来临的时候,我们需要快速做出调整。但不幸 的是,事情并不总是如我们所愿。 那么我们之前是怎么做的呢? 资历较老的程序员应该都还记得一种基于可重用组件的设 计方法。在这种方法中,专门有一个架构团队,他们会识别出 整个组织中各个部门应该怎么使用某一组件。某些时候架构团 队的业绩甚至还会与其所设计的组件被使用的次数挂钩。但是 不幸的是,由于架构团队和组件使用团队缺少连接,因此架构 团队很难设计出一个有口皆碑、受使用者欢迎的组件。
57. 还记得另外一种利用数据库做集成的架构么?是的,我们 之前都是这么做的,在这种架构模式中,我们有一个巨型数据 库,所有的数据都囊括在其中。这个数据库的周围,有一圈各 种各样的应用,它们支配着这些数据。 此外还有一种曾经颇为流行的面向服务的架构,这种架构 理念声称它们可以达到我们想达到的目标。这种架构确实有其 做得不错的一些地方。首先,它让组织者知道并不是所有的东 西都必须是模块化的。与此同时,它也激发大家开始思考,将 多种功能更好的集成到一起,而不是紧耦合到一块,比如你可 以想想使用中间件、消息队列或者其他一些更松耦合的方法。 SOA(面向服务型架构)让最终一致性得到更加广泛的认
58. 同。一直以来,传统的(DBA)数据库管理员这个角色起着至 关重要的作用,因为最有价值的数据资源均由他们保护。在访 问数据库的时候,一切都是关系型的,都是事务处理。因此每 当你说我需要做持久化的时候,就会有人告诉你,放在一个关 系型数据库里就好了,大家对此都达成默契了,没有任何问 题。然后所有的操作都是完整的事务处理,我们可以使用关系 型数据库所能提供的所有功能。以前大家都是这么干的。而 SOA的出现至少启发了大家,使之开始讨论我们是不是可以用 另外的方式来取代之前的老路子,从这个方面来讲,SOA确实 有其正面意义。 但不幸的是,SOA也犯了一些错误。最主要的一个问题在 于其庞大的服务。你看看使用SOA模型做出来的这些服务,这 些海量服务作为一个全局组件,还是太大了,太难做出改动, 也太难部署了。其次,SOA倾向于提供方驱动的服务。我的意 思是,当你开始想我要写一个用户服务,我要给用户提供这些 信息,因为我是这些信息的提供方。假设我知道用户将会如何 使用这些信息。这其实和设计可重用组件的架构师差不多,我 们统称为信息提供方驱动。一般而言是由组织中的IT部门做完 之后移交给业务部门使用,这种设计中的想法大部分是从系统 的角度在想问题,而不是从应用的角度。 SOA的另外一个问题是充斥着大量的编配(orchestration), 注意这里我们说的是编配而不是编排(choreography)。在管弦 乐(也是orchestration这个词)中,有一个统一的指挥,由他来
59. 指挥整个乐团,他来设置节奏、音量等各种信息。整个乐团里 的个体都无一例外的听命于这个指挥。 我们设想一下,如果某个时候同时发生两件事,那么可能 就需要两个指挥。总而言之,在这种模型里面,有一个类似指 挥的角色来对整个系统全盘负责。而编排却不是这样,在编排 的时候,每个个体只需要关注自己周围的成员就行,并没有一 个统一的总指挥。当出现问题的时候,每个个体只要知道自己 应该怎么调整就行,同样也不需要一个所谓的总指挥来指挥。 SOA这种类似管弦乐团的组织方式,过分集中化了,从而导致 其本身通常难以测试。
60. SOA还有一个问题是工艺受阻。SOA需要我们有这样的供 应商,能满足业务部门的所有想法,然后业务部门只需要坐在 自己的办公室里面做一些自定义的配置就可以了。因此最后的 工具通常是我们将一些之前有人用过的系统稍作修改来供应另 外一群用户。 事实上,SOA搞出来的东西甚至比没有他们之前还要更难 以修改。讽刺的是SOA恰恰是为了让改动变得容易而诞生的。 不可避免的是,SOA也很难进行测试。
61. 好,现在我们来聊聊微服务(Microservices)。 简单来讲,你可以将微服务理解成正确的SOA模式。我们 的关注点还是服务,在微服务的架构里面,服务是作为一个基 础单元存在的。SOA本身即是面向服务的架构,所以我们这个 其实也可以叫SOA2,但是我们还是用了微服务这个名字,目的 就是提醒大家不要搞海量服务。这是一段从James Lewis和 Martin Fowler的文章中摘抄的一段关于微服务的定义: 一种将一组小型服务做成一个单独应用的开发方式,每一 个小型服务在其独自的进程中运行,使用诸如HTTP资源API等 其他轻量级方式进行通信。重点是要轻量级。 微服务有什么特点呢? 第一个显而易见的特点是,微服务中每个个体服务单元都 很小。这里的“小”并不是绝对的,其思想要点是,“与其搞一个 大而全的服务体,我们更倾向于小一些的单一服务。” 微服务的另外一个特点是,这些服务是按照业务能力构建 的。之前我们经常掉入一个陷阱,就是总是从系统的角度思考 问题,而不是从业务角度。现在我们不仅要有思考系统的能 力,更要具备思考业务的能力。除此之外,我们还需要按照业 务能力来组织工作。对于业务部门而言,如何实现并不重要, 他们所关心的是系统长什么样子,怎么能方便用户使用。业务 部门是这么思考的,我们也需要围绕业务能力进行设计。
62. 微服务中的服务个体都是可以单独部署的。也就是说,只 要没有动接口协议,在修改某一个服务个体的时候,完全不用 理会其他服务个体。在微服务中,只有很少一部分需要集中管 理,而由于各个服务个体之间是相对独立的,因此我们甚至可 以在不同的服务单元中采用不同的技术栈。比如某一部分的计 算逻辑比较复杂,我们选用clojure。另外一部分对应着很强的 对象模型,我们就可以用一些面向对象的编程语言等等。 在微服务中,我们主张“智能端点”和“傻瓜管道”。基本上 如果管道两边都按照一定的假设强制执行的话,重新配置时就 会简单许多,而并不需要时刻监控管道中的中间状态。当我们 尝试把现在这种模块拆分的时候,需要考虑的另一个问题是, 数据库的结构应该是什么样的?具体的问题还包括数据如何进 行维护,其他单元如何缓存等等。毫无疑问,在微服务中,数 据结构的形态会有很大不同。 使用微服务意味着什么呢? 首先粒度的问题是至关重要的,当你在思考微服务的边界 问题时,这应该是使用微服务架构需要做出的一个最重要的决 定。在这个过程中需要平衡好内聚和耦合的关系,一方面为了 加强内聚你可能需要将某一些服务合并到一起,另外一方面为 了解耦,需要对某些服务进行拆分。事实上在使用微服务架构 的整个过程中都充斥着来回往复的拆分和合并,直到你真的理
63. 解了服务的边界应该是什么为止。我们后面会继续回到这个问 题上。 微服务中的各个服务个体是可以独立扩展的,也就是说如 果某个服务上的需求量猛增,我们只需要扩展该服务即可,与 其他服务无关。相应的,对于各个服务的状态监控也非常重 要。如果你手头是一个单块,从定义来看,理论上你需要监控 的只有一个东西。而到了微服务里面,因为我们有大量的小型 服务,因此需要对所有这些服务进行监控才行,你需要清楚地 知道每一个服务是不是在工作,是不是在正常工作,为此光监 控就会需要更多的机器。 在微服务中,我们还需要考虑服务挂掉的情况,而这些情 况在传统单块架构里面一般不用怎么考虑。比如我们有一块业 务需要依赖数个独立的微服务,那么我们需要考虑的失败场景 就相当多了,基本上是把所有这些可能的失败进行排列组合, 而不得不说的一点是,在传统单块架构里面这些可能根本就不 称之为一个问题。 在微服务架构中,因为我们有很多独立的单元,它们需要 独自进行部署,因此我们真心离不开自动构建、自动化部署和 持续交付这些基础。在微服务中,虽然我们在不同的服务中可 以使用不同的技术栈,但是如果任其发展,最终也会完全不可 控,因此我们需要管理好这种灵活性。在我之前的一个项目里 面,光是XML解析就有11种不同的方法,是的你没听错,11种 之多。一般来讲我觉得两种XML解析器尚能接受,但是11种实
64. 在是难以理解。因此在微服务架构中,我们必须要避免引入所 有类型的编程语言以及所有种类的数据库,没什么原因,明眼 人都知道我们不能这么做。在系统的技术栈方面,我们必须在 某个层面进行控制,否则一发不可收拾了。 当然最终一致性也必须管理好。一旦我们开始将数据分散 到各个不同的服务单元里面,就必须考虑到这对于信息传播会 有什么影响。其中的一个结果就是,我们需要给业务人员讲清 楚,什么是最终一致性。一般而言我觉得业务人员会理解成“可 能会一致”,而不是最终会达到一致。我们必须时刻想到由于最 终一致性的存在所可能产生的各种后果。同样,如果我们用的 是一个大而全的关系型数据库,压根就不会存在这个问题。 好了,大家看看我们列出来的这些个问题,他们一个比一 个复杂,而在传统的单块模型中,这些问题我们根本不用想。 当我们回顾这些问题时,不由得会想到我们的初衷,如果我们 的初衷能够得以实现,最少能弥补解决这些问题时所带来的痛 处。我们的初衷是什么呢?让系统能尽可能快的响应变化!另 外一个方面,这些问题也在一定程度上警醒着你,微服务这个 东西不是你想象的那么简单,不是照着教程做一遍就可以大功 告成,然后出门跟人炫耀:哥在搞微服务哦,牛逼吧! 最后有一点差点忘了说,接口的改动也必须有个限度。在 定义清楚服务边界的时候,少不了要修改一些接口协议,在修 改的时候务必想清楚这个动作意味着什么。这个也深受团队成 员结构的影响,比如如果写另外一个服务的人就在你旁边,改
65. 起来三两句话就搞定了,但是如果团队成员咫尺天涯或者天各 一方,这个沟通过程本身就是一个巨大的成本。 好了,以上这些就是我认为的在准备使用微服务的时候, 需要想清楚的一些问题。 现在我们有两个选项。第一个是一片绿地,就好比我们拿 到一个空白的项目,没有任何的遗留代码。这种情况也有,但 是很少。另外还有一点,在马丁即将发表的一篇文章里提到, 我们并不建议在一个崭新的项目中一开始就使用微服务进行开 发。因为你很可能并不真的理解业务领域,也很难理解各个服 务的边界。因此在这种项目中,可以先做成单块的,进行适当 的模块化,加深理解之后再考虑演进成微服务。总而言之,你 迟早会走到这个点,就是我们怎么将一个单块系统拆解成微服 务架构。 首先,想清楚边界上下文。这其实是从《领域驱动设计》 一书中拿过来的概念。所谓的边界,指的是你可以将某些部分 用一个圈圈起来,圈里的内容代表了一定的业务面。这个所谓 的边界其实就是我们设计服务边界时的一个重要指示。再回到 我之前说的那个问题,你需要在对你的系统有一个全面透彻的 认知之后,才能做出这些决定。作为划分服务边界的第一个提 示便是:尝试按照领域驱动设计的方式来思考服务的边界应该 在哪里。 其次还是这一点:从业务能力的角度来思考服务的边界。 想想系统所提供的产品、服务是什么,从这个角度想想怎么样
66. 才算一个合理的服务边界。 想想调用者需要什么。与提供方驱动方式不同的是,你需 要想想这个服务的使用者会需要些什么信息。也就是说需要从 真实的需求开始想问题,而不是一些作为提供方揣测出来的需 求。 想想服务之间的通信模式。想想哪些服务、哪些系统可能 会用到同一组数据,不同的服务怎么合作来实现一个特殊的业 务产出。特别是当我们在犹豫是要将两个服务分开还是合并到 一块的时候,想想拆开之后可能产生的各种通信,以及通信失 败的情形等等。 想想数据结构。一般而言,大家不愿意花太多精力想怎么 保护数据的问题,也不会纠结太多最终一致性产生的影响。你 怎么设计数据,合适的数据结构应该是什么样的也可以作为一 个指示你如何设计服务边界的提示。因为服务是持有数据的。 我们想的不再是一个数据库周围围绕着一堆服务,而是每一个 服务有一个自己的持久化存储。
67. 想想联动变化模式。比如有两个业务部分需要一起改,其 实某种程度上是在提示你,是不是把这两块放到一个服务里面 更加合适。因此多想想未来可能产生的各种改动,对你做出决 定也会有所帮助。 做好出错的准备,你可能经常需要将一些服务进行合并, 而后搞不好又要重新再拆开。由于服务还牵扯到数据,如果两 个服务的关系是一个服务主要负责一部分数据,而另外一个服 务对这部分数据只是进行缓存的话,你或许还要考虑一些需要 进行数据迁移的情况。一般而言你不会想经常修改服务的边 界,因为这会带来一系列的应用程序,数据的改动。但是还是 那句话,做最坏的打算。
68. 最后的一点是:做一名有耐心的读者。这其实扯到演进架 构的内容了。首先是我们不能把build搞挂了。我们能做的是: 只有在没有别的选择的时候,我们才开始改。而做耐心的读者 就是为了确保他们改的确实是你所需要的。也就是说在正式确 定修改之前,需求本身的变动可能更大。 OK,那么微服务与演进式架构还有什么联系呢?其实当我 们谈论演进式架构的时候,是有很多不同原则的。这些原则都 很严格,而微服务某种程度上展现出了一些演进式架构的原 则。我们在谈微服务的时候,主要是想用它来快速应对频繁的 需求变更,因此微服务所承载的期望便是让我们能尽可能快地 适应变化。而演进式架构中所倡导的进化性与此不谋而合。可 进化型并不同于可维护性,但也不是说要怎么预测未来,而是 一种随时准备响应变化的状态,而不管你是否提前就设想好了 这些变化。以前关于可进化性的一个理解误区是,我要非常聪 明的想到所有可能出现的变化,并且为所有的这些可能的变化 写好代码,哪怕到头来根本就没变。因此微服务将“可进化 性”作为其首要目标。 耐心的读者,是的前面已经提到过一遍了。我们可以做出 任何改变,但这种改变必须是我们经过大量的沟通讨论之后得 出的统一结论。 遵从康威法则。我们需要关注怎么组织团队结构,以及不 同的团队结构可能影响到的最终系统形态。只有团队对服务有 很好的所有权意识,其做出来的微服务才是这种松耦合的独立
69. 服务。在某些采用了微服务的组织中,并没有一个专门的支持 维护团队,因此每个团队成员会不自觉地将他的那部分代码写 好,因为谁也不想大周末的还要跑到公司来修BUG。 适当耦合。我们在谈演进式架构的时候,其实总是在平衡 耦合与性能、复杂度等其他因素之间的关系。 协议。在微服务架构中,各个服务可以独立演进。那么必 不可少的一环就是相互之间的接口协议。通常而言,我们可以 借助于一些协议测试工具或者文档来确保相互之间正常工作。 作为服务提供方,同时还应该提供对应的接口测试给调用方, 而一旦调用方发现这个测试失败了,马上需要找到提供方确认 问题。测试的另外一重含义是,只要这个全面的接口测试是正 常通过的,那么无论提供方把代码改成什么样了,调用一方都 不用关心,因为大家都是独立的,链接着彼此的就是这些接口 协议,这也是为什么微服务中的接口协议显得如此重要的一个 重要原因。 最后,作为一名来自ThoughtWorks的员工,我不得不谈谈 测试相关的事情。我们发现如果你始终沿着方便测试的方向设 计架构,最后的架构会更加简洁。而且易于测试的系统一定是 有一个清楚的定义的,你甚至不需要颗粒度太细的测试,哪怕 只有一个非常顶层的端到端测试,只要这个测试能简单明了的 描述其行为就已足够。当你的架构设计得很好,边界划分得很 清楚,系统本身就应该是很好测试的。我们发现,一般而言, 不管是从代码层面还是系统层面,关注测试始终会让你的架构
70. 更加完善。而且一般而言,基于测试定义的边界,也让整个架 构更容易做出改变。 持续交付在这里扮演什么角色呢? 微服务相比于传统架构,增加了大量的运维负担。有更多 的东西需要部署,有更多的地方需要监控,出错的地方自然也 成倍增加,有更多的数据库,对应的需要更多的备份。在微服 务架构中,出现问题时如何快速恢复也是件很复杂的事,因为 服务数量众多,对应的排列组合情况更是数不胜数。 第二点是微服务需要很强的运维文化,这里我用了“不明 智”这个词,主要是强调运维文化对于微服务架构的重要性。如 果你的开发团队和运维团队之间有堵高墙,那么用微服务实施 下去必然是个灾难。这里面有大量的琐事需要做好做对,需要 理解清楚。如果没有一种强运维环境,你那个单独的运维团队 一定会被你搞疯掉的。 如果因为不能严格执行持续交付而选择了微服务也不是一 种明智之举。在程序出错的时候,我们需要赶紧进行调试,但 是如果你连现在的代码是哪个版本都没法准确知道,你告诉我 怎么调试?所以“严格执行持续交付”是微服务架构赖以成功之 根本。关于持续交付的内容,比如基础设置自动化,自动化部 署,自动化测试等等都缺一不可。拿自动化测试举例,与传统 架构相比,你的测试场景会更加复杂,甚至就连程序主路径这
71. 一个方面都要比原来负责很多,因此测试就显得至关重要了。 我应该从哪儿开始呢? 跟前面讲的一样,我们始终建议在完全透彻的理解业务背 景的前提下再尝试使用微服务。在一个崭新的项目上,始终建 议从一个单块架构开始,因为你不可避免地会犯一些边界划分 的错误,除非你真的是对于这个领域烂熟于胸。在开始的单块 架构中,你依然可以让代码保持整洁清晰,有完整的测试覆 盖。实施微服务的时候面临的一个最大问题是,大家容易把它 用错了,导致大量没有必要的反复更改,从这个意义上来讲, 从一个单件开始不失为一种较为安全的选择。
72. 微服务是一把尚方宝剑吗? 我们说它并不是。我们确实见证了不少使用微服务架构的 成功案例,但是就微服务本身而言还是有很多问题需要考虑。 比如我之前提到的最终一致性、错误的排列组合等问题。这些 问题也并不是我们完全不知道怎么解决,我们知道怎么管理开 发流程,我们知道该怎么沟通,只是在微服务中要稍微复杂一 些而已。但是面对这些问题的时候,不要害怕做出修改。你完 全可以重新设计某些部分。我们有严格的接口协议、全面的接 口测试覆盖,来使得你在修改业务流程、引入新功能、新的校 验方式时更加从容。 事实上这些东西也确实容易朝秦暮楚,现在只要谁在社交 媒体上秀了个新功能,马上大家一窝蜂地都想要这个新功能 了。用户的期待就是改变的这么快,业务生命周期也越来越 短,安全相关的问题也是日新月异,所有这些变更都驱使着我 们快速适应变化,而微服务便是在这样的大环境下应运而生 的,但是微服务并不是免费的蛋糕,也有其自身的成本消耗。
73. 微服务即演进式架构 文/禚娴静 微服务架构风格正在席卷全球。去年三月,O'Reilly举办了 他们的第一届软件架构大会,提交的话题中与微服务相关的占 绝大部分。那么为什么这种架构风格会突然如此流行了呢? 微服务是后DevOps革命时代出现的第一种全新架构风格。 它是第一个全面拥抱持续交付的工程实践,也是演进式架构家 族的一员。演进式架构以“支持增量的、非破坏的变更”作为第 一原则,同时支持在应用程序结构层面的多维度变化。不过, 微服务仅仅是支持某些演进行为的众多架构之一。本文分享了 演进式架构风格的一些特点和原则。 演进式架构 软件行业曾经有这样一个共识,架构一旦确定,“日后很难 改变”。演进式架构将支持增量式变更作为第一原则。由于历来 变更都是很难预测的,改造的成本也极其昂贵,所以演进式架 构听上去很吸引人。如果真的可以在架构层次做到演进式地变 更,那么变更就会更容易、成本更低,也能发生在开发实践、 发布实践和整体敏捷度等多个地方。 微服务满足这一定义,因为它遵循强边界上下文的原则, 从而使得Evan的领域驱动设计中描述的逻辑划分变成物理上的
74. 隔离。微服务能够通过采用自动化基础设施建构、测试、自动 化部署等先进的DevOps实践,获得这种分离。因为每个服务在 结构层面与其他服务都是解耦的,替换服务就像替换乐高积木 一般。 演进式架构的特点 不同的演进式架构展示了一些共同的特点,我们已经识别 了很多特点,并收录进即将出版的《演进式架构》一书里。本 文将分享其中的几个特点。 模块化和耦合 边界划分明确的组件,显然可以给希望做出非破坏性变更 的开发人员以更大的便利。而毫无架构元素的大泥球架构就无 法做到演进式变更,因为它缺少模块化。 在 一 个 大 泥 球 项 目 中 类 (图 中 圆 边 上 的 点 )与 类 之 间 的 耦 合 度 – 来 自 一 个 不 愿 透 漏 名 字 的 项 目
75. 不适当的耦合将变更导向难以预料的方向,从而阻碍演 化。而演进式架构都支持一定程度的模块化,这种模块化通常 体现在技术架构层面(例如经典的分层架构)。 围绕业务能力组织 受领域驱动设计的启发,越来越多的成功架构都以在领域 架构层的模块化为特色。基于服务的架构与传统的SOA主要区 别在于模块划分的策略,SOA是严格按照技术层进行模块划 分,而基于服务的架构则倾向于按业务领域划分。 试验 试验(experimentation)是演进式架构给商业交付带来的最 大价值之一。从操作角度来讲,可以采用A/B测试、金丝雀发 布等常见的持续交付实践对应用进行低成本的、微小的变更。 微服务架构常常是围绕服务之间的路由来定义应用程序的。通 常,微服务架构围绕服务之间的路由来定义应用程序,允许同 一个服务的多个版本同时运行。这反过来也使得试验和现有功 能的逐步替换成为可能。最终,这使得你的业务可以花更少的 时间去猜测待办故事项,从而投入到假设驱动开发中。 演进式架构的原则
76. 思考演进式架构的另一个方法就是考察它的原则。原则描 述了架构本身的不同特点或者设计架构的方法,其中一些原则 专注在特定的架构决策过程。 适应度函数 我们将浮现式和演进式架构区别对待,并且认为这种区分 是很重要的。就像在进化计算技术中的遗传算法一样,一个架 构级别的适应度函数指明了我们的目标架构是什么样子,其中 一些系统关注高运行时间,而其他一些系统则会更关注吞吐量 或者安全。 这张雷达图展示了适用于软件系统的几个重要的适应度函数 在项目前期思考一个特定系统的适应度函数,可以对决策
77. 的制定和决策的时机提供指导。适应度函数是对架构决策的衡 量,通过适应度函数,我们可以预见架构是否在向正确的方向 演进。 痛苦的事提前做 受极限编程社区的启发,许多持续交付和演进式架构的实 践都体现了“痛苦的事提前做”原则。在做一个项目的时候,如 果一些事情可能会很痛苦,那么你需要强迫自己更早更频繁地 去做这些事情。这反过来会鼓励你用自动化的手段消除这些痛 苦并能提前识别问题。那些基础的持续交付实践,如部署流水 线、自动化基础设施建构、数据库迁移,就是这一原则的应 用,它们会提早解决变更带来的常规问题,从而使架构的演进 更容易。 最后责任时刻 决策的时机是传统架构和演进式架构的最主要区别。这些 决策可以围绕应用程序的结构、技术栈、特定的工具或通信模 式。在传统的架构中,这些决策发生在早期写代码之前。而在 演进式的架构中,它们发生在最后责任时刻。延迟决策的好处 是有更多可用的信息来辅助决策。其成本体现在做出决定后任 何可能出现的重复工作中,这些工作可以通过适当的抽象得到
78. 减轻,但成本仍然是实打实存在的。相比而言,决定太早的成 本也是很明显的。比如一个通讯工具的选择,不同的工具有不 同的特性。如果我们选择一个可能最终也不会用到的重量级工 具,那就是在项目中引入了技术债。这个技术债是由于使用了 错误的工具导致开发进度延缓而出现的。你不能拿事先“抽象一 切”作为借口。我们仍然支持敏捷YAGNI(You Ain't Gonna Need It,你不会需要它)的原则,但会更倾向于在合适的时候做出决 策。 当然,我们在考虑最后责任时刻的一个最直接的问题就 是,什么时刻是最后责任时刻。适应度函数对这个问题提供了 指导建议。那些会对架构、设计选型或者项目的关键成功有重 大影响的决策,都必须尽早做出,延缓这些决策往往得不偿 失。 总结 软件架构师常常用画图的方式来解释系统之间的适配,然 而太多的架构师并没有意识到,一个静态的二维架构图的生命 是很短暂的。软件世界是不断变化的,它是动态、而不是静态 的存在。而架构也并不是一个等式,它是持续过程的快照。 持续交付和DevOps运动都诠释了一个问题,即由于忽略实 现架构并使之保持常新所要付出的精力。其实架构建模和付出 这些精力本没有什么问题,但是架构的实现仅仅是第一步。架
79. 构只是抽象,直到真正投入运维。换句话说,如果你没有实现 并升级过一个架构,甚至帮它渡过难关,那么你就无法真正判 断架构的长期生命力。 架构师的运维意识是演进式架构的关键。演进会影响具体 的实现,因此这些实现细节是不能忽略的。持续交付在架构层 面的要求,使得实现更可视化、演进更简单化。因此,持续交 付是所有演进式架构重要的助力。
80. 你以为是微服务或Docker?其实是组织架构! 文/肖然 It's Microservices …It's docker …It's organization structure 微服务和容器毫无争议地成为了这个时代的主旋律,大家 争先恐后地让自己的团队和企业去尝试这样的旋律,但往往发 现曲高和寡,难以在整个组织内形成共鸣。在本文中,我们尝 试揭开微服务和容器技术背后映射出的组织结构的变迁,以及 组织结构对落地微服务和容器化架构所带来的反向制约,最后 用INVEST原则来看看支撑这样松耦合架构的组织结构应有的特 质。希望能够帮助迷茫中的企业和组织重新思考自己的微服务 之路。 Microservices(微服务)和docker(容器)成了近一年来软 件行业的新宠,每次参加相关活动总会感到康威老先生站在背 后邪邪地笑着:“我早告诉你们了”。 尽管Martin Fowler在“定义”微服务时十分小心的警告了大 家所要付出的代价,但好像微服务的优点太过于吸引人,以至 于大部分软件开发组织和企业都把微服务这种架构方式作为了 未来的必选,大家都觉得我就是那个高个子(I'm that tall!)。
81. Martin Fowler对 伴 随 微 服 务 架 构 的 高 工 程 实 践 能 力 的 比 喻 。 随着容器技术到达生产应用的临界点,这种化学效应好像 一触即发,我们仿佛看到了未来一个不一样的软件微服务大集 市在逐步展开! 在这个集市里会有淘宝这样的平台,为中小服务卖家搭起 一个在线商城,买家可以根据自己的需要搜索及购买琳琅满 目、各式各样的服务,在线或是二进制、代码质量及自动化覆 盖率等指标成为同类服务评级的重要标准。 杀手级的服务如区块链或者量子加密可能成为皇冠销量服 务。最后掀起一大波程序猿开微服务店的热潮~ 很期待那是怎 样的卖家秀和买家秀啊! 这种几乎接近于科幻的描述可能只适合作为微信上的谈 资,但微服务和容器技术的流行却并非偶然。康威老先生用自
82. 己的定律揭示了一个更深刻的道理: 这不是一次技术架构或者基础设施的革命,而是为了保持 组织灵活性的必由之路。 换句话说,软件开发组织或企业开始意识到一切的管理和 技术实践都必须为保持尽可能高的组织灵活性服务。一定会有 人问为啥要保持“尽可能高”的灵活性呢?铁打的营盘流水的 兵、稳定的规章制度不也缔造出了历史上那么多成功的组织和 企业吗? 论尽可能高的组织灵活性 所以我在前面加了定语“软件开发”,当然现在我们有一个
83. 更广泛的提法:科技企业。通常我们认为产品或服务的技术含 量比较高,具有核心竞争力,能不断推出适销对路的新产品, 不断开拓市场的企业为科技企业。 在我们所处的软件时代,大量的科技企业都跟软件沾上了 边。但历史上我们可以回想大生产时代炼钢也曾是高科技,信 息时代发邮件也是高科技。前两波的“科技企业”给我们的印象 可不是灵活的:几大钢铁巨擘让人联想到的应该是当年国家呼 唤生产力全民建设的宏伟场景;信息时代佼佼者如Microsoft和 IBM让人联想到的应该是动辄千人的大型工业软件开发队伍, 一个部署都得来一个专家队伍。那么为啥现在咱们的科技企业 必须灵活,而且必须尽可能高呢? 这里我们再次使用康威老先生的定律来做推论,康威定律 说 “一个产品或系统的设计(架构)受到其生产组织自身交 流沟通结构的制约”。 换句话说如果你有一个前端展现团队、一个后端服务团队 和一个数据库团队,那么我们可以肯定,搞出来的系统会分前 后台和数据库的设计。这本身是一个悲观的定律,所以前面的 团队发现新需求来了必须沟通三次,前后台团队关心新需求对 自身架构的影响,数据库设计关心对现有数据结构的冲击,最 后总是会在各方的争执中得到一个别扭的解决方案。 很多团队早已经习惯了这样的痛苦,数字化时代的变化频 率将这样的痛苦逐渐推向了顶峰。举例感受一下:达到100亿
84. 产值,首钢用了71年,联想用了13年,这个时代的小米用了仅 仅3年!而今年的小米已经不是站在浪潮之巅的科技新贵了。 所以康威老先生说: 如果要保持产品的持续竞争力,就要保持组织的灵活性。 曾经有人跟我争辩说:“我们做的是数字化时代的后台系 统,不直接面对市场,需求很稳定,搞那么灵活成本反而 高。”于是我指着他们有着千万行代码的系统说:“你们至少有 30%代码是冗余的,这就是组织缺乏灵活性的另外一个恶果。” 这里我们先收缩范围到软件开发,非常有意思的是在咱们 这个行业里,针对同一份需求,没有两个开发人员实现出来的 代码是一样的(也许Hello World例外)。甚至,当我发现两个 程序员使用的变量命名一样的时候我会怀疑他们抄袭了。这说 明软件开发从需求提出到写代码实际都是在做设计,不同的人 设计出来的东西就会不同,像大家的签名一样。
85. 设计甚至延续到了后面的软件测试和部署,同样的应用在 不同的网络拓扑结构下表现可能是完全不一样的。那些追求稳 定的组织希望尽早结束设计这个高度不确定性的活动,从而能 够通过标准化来提高效率。 即使在敏捷开发主流化的今天,很多团队仍然是架构师“画 图”,码农堆砌代码。所以这样的组织很快发现自己深陷二进制 的泥潭,进退维谷。我经常跟这样的团队讲:你们缺乏“代码的 响应力”。而响应力对组织的要求就是灵活,能够从前到后驾驭 设计活动带来的不确定性。 小结一下:数字化时代的市场变化是迅猛的,康威老先生
86. 已经告诉我们,处在这样时代背景下的科技企业保持组织灵活 性是十分重要的。而软件(广义讲新科技领域)本身由于强设 计而带来的不确定性又加重了对组织灵活性的诉求。 于是在这个时代我们看到了如Google、海尔这样已然成功 的企业开始大刀阔斧地改革自己的组织结构,这种对灵活性的 极致追求成就了这些组织持续保持市场领先水平的核心竞争 力。毫无疑问,微服务架构的优点也正反向映射出了组织结构 的灵活性,而容器技术的运用降低了这种松散集市结构的运营 成本,就如同淘宝平台的出现给千千万卖家和买家搭建了一个 基础的交易平台。 弹性伸缩的容器化计算资源加上松耦合的微服务架构必然 会吸引追求组织灵活性的企业去打败康威定律,保持组织活 力。 组织结构的INVEST原则 前面咱们辩证了数字化时代科技企业保持组织灵活性的必 要,那么灵活的组织结构应该满足什么原则呢?下面我们就借 用敏捷开发中赫赫有名的需求管理原则INVEST来剖析一下怎样 的组织结构才能够真正落地微服务架构和容器技术带来的灵活 性优势,或者从另外一个角度看支撑微服务架构的运用。
87. 两种组织结构对比示意 独立的:Independent 按照微服务架构的团队应该对外提供一种或多种服务,服 务和服务之间应该是松耦合的,所以背后的团队也应该是相对 独立的。遵循康威定律,如果一个大型组织没有能够划分出服 务导向的相对独立团队,那么最后对外提供的产品或系统的内 部结构也不可能是简单的服务组装,而会是我们常说的“意大利 面”,内部结构纠缠不清以至于最后响应市场新需求越来越慢。 便于沟通的:Negotiable。 “小”服务团队的结构必然造成整个组织的集市化、社区 化。如果没有建立良好的团队间的沟通机制,很难想象这样的 组织里会有任何的产出。Amazon被认为是一个微服务架构运用 的成功典范,其2pizza团队的原则成为了业内的标杆。
88. 但这样服务导向小团队集合的底层是长期磨合形成的良好 团队间沟通机制,甚至当我们问到Amazon各个团队如何发现其 它服务或要求其它团队协助完成需求时,团队都说不出具体的 流程机制,一切都变得很自然,全然像我们走进自己熟悉的超 市一样,能够很自然的找到日常所需。 有价值的:Valuable 毫无疑问,每个团队必然是面向价值交付的。敏捷开发方 法的提出其实很早就指出了传统方式下按照功能部门划分的瀑 布交付模式的原罪,即每个功能部门都不对最终的价值交付负 责(Output over Outcome,输出大于结果)。这样的组织结构必 然造成对市场变化响应的滞后。 值得一提的是面向价值交付的团队往往也是跨职能的,按 照微服务的架构,团队需要负责服务从需求到部署运营的全生 命周期(Outcome over Output,结果大于输出)。这也是为什么 在基础的工程交付平台及实践上团队必须是一个“高个子”。 可估计的:Estimable 这样的服务团队交付周期应该是很短且可以准确估计的, 上线应该是家常便饭,而不是过去短则数月、长则一年的大爆 炸模式。持续交付在这样的组织里应该是标准实践,让软件系
89. 统时刻处于可发布状态是团队的共同责任。从Amazon和Netfliex 这样的现代科技企业身上我们已经看到了这样组织结构下逐步 形成的工程能力优势,并最终转换成了业务服务上的巨大成 功。 短小:Small 前面提到了Amazon的2pizza团队,人数10人以内,经典的 敏捷管理框架Scrum也建议5~9人的团队,可见小团队成为组织 灵活性的一个必要条件。中国俗语有“船小好调头”朴实地揭示 了小的灵活性,但为什么不再小一点呢?比如两个人结对一个 团队。 显然大家很容易发现软件开发本身的复杂性决定了要端到 端交付价值两个人的团队是搞不定的。从整个组织的健壮性来 讲,过小的团队也会增加企业形成单点依赖的风险。虽然没有 正式确认,但我们交流中发现Amazon这样的微服务组织里其实 也是存在服务冗余的,这样的重复保证了组织在切割成小团队 后风险得到适当的规避。 可测试的:Testable 在面对市场情况高度不确定性时,我们应该直面试错这件 事情。传统职能型的大组织结构往往是不能容错的,错误的代
90. 价就是整个企业走偏了方向,或者一个部门在企业里失去了话 语权。 在灵活性高的组织里我们却应该是能够很容易进行这样 的“测试”,企业更能够利用这样的结构进行动态的投资组合管 理,像Google著名的7:2:1投资比例,最后的一成就是利用组织 的灵活性进行创新的测试。测试的结果往往是失败的,但正是 这样的不断测试创造了Google历史上很多著名的“黑天鹅”。 打破康威定律 最近很多以精益(LEAN)为关键字的理论框架在咱们这 个领域冒了出来,也包括我前期撰文提到的精益企业(Lean Enterprise),于是有朋友揶揄说又开始炒概念了。我却很严肃 地澄清正是不希望炒概念,所以才回到了上个世纪就论证和发 展起来的理念:精益。 来源于丰田制造的精益总结出了很多的原则和实践,但有 意无意中丰田完成了自身组织持续灵活性打造这项超越同期其 它企业的伟业。其结果就是在响应需求多样化时展现出的更强 适应能力。 如果用我们前面的INVEST原则来看待精益组织,你会很快 找到对应的原则和实践,即使在传统的工业流水线上,丰田也 在形成一个个的小团队(cell,单元生产),也在通过员工的 多技能培养来完成小团队内部的“跨职能”。其持续改进
91. (Kaizen)的核心思想有力保证了团队面向价值的工作方式和 良好的跨团队沟通文化。 某种意义上讲精益在康威定律定义之前就打破了康威定 律! 微服务和容器技术无疑是这个时代工程架构方面支撑组织 灵活性的重要一步,然而我们不能忘记一个组织是五脏俱全 的,如精益企业提到的,组织的财务审计、人力资源、采购合 规等功能如何有效的“微服务”化和如何能够合力构建一个弹性 的“容器”支撑平台仍然需要诸君努力!
93. [实践篇]
94. 基于微服务架构,改造企业核心系统之实践 文/王磊 本文首发于InfoQ: http://www.infoq.com/cn/articles/enterprise-core-systemstransformation-practice 背景与挑战 随着公司国际化战略的推行以及本土业务的高速发展,后 台支撑系统已经不堪重负。在吞吐量、稳定性以及可扩展性上 都无法满足日益增长的业务需求。对于每10万元额度的合同, 从销售团队准备材料、与客户签单、递交给合同部门,再到合 同生效大概需要3.5人天。随着业务量的快速增长,签订合同的 成本急剧增加。 合同管理系统是后台支撑系统中重要的一部分。当前的合 同系统是5年前使用.NET基于SAGE CRM二次开发的产品。 一 方面,系统架构过于陈旧,性能、可靠性无法满足现有的需 求。另一方面,功能繁杂,结构混乱,定制的代码与SAGE CRM系统耦合度极高。由于是遗留系统,熟悉该代码的人早已 离职多时,新团队对其望而却步,只能做些周边的修补工作。 同时,还要承担着边补测试,边整理逻辑的工作。
95. 在无法中断业务处理的情况下,为了解决当前面临的问 题,团队制定了如下的策略: 1.在现有合同管理系统的外围,构建功能服务接口,将系 统核心的功能分离出来。 2.利用这些功能服务接口作为代理,解耦原合同系统与其 调用者之间的依赖; 3.通过不断构建功能服务接口,逐渐将原有系统分解成多 个独立的服务。 4.摒弃原有的合同管理系统,使用全新构建的(微)服务接口 替代。 什么是微服务 多年来,我们一直在技术的浪潮中乘风破浪、扬帆奋进, 寻找更好的方式构建IT系统。微服务架构通过将功能分解到多
96. 个独立的服务,以实现对解决方案或者复杂系统的解耦。 微服务的诞生并非偶然: 领域驱动设计指导我们如何分析 并模型化复杂的业务;敏捷方法论帮助我们消除浪费,快速反 馈;持续交付促使我们构建更快、更可靠、更频繁的软件部署 和交付能力;虚拟化和基础设施自动化( Infrastructure As Code) 则帮助我们简化环境的创建、安装;DevOps文化的流行以及特 性团队的出现,使得小团队更加全功能化。这些都是推动微服 务诞生的重要因素。 实际上,微服务本身并没有一个严格的定义。不过从业界 的讨论来看,微服务通常有如下几个特征: 小,且专注于做一件事情 每个服务都是很小的应用,至于有多小,是一个非常有趣 的话题。有人喜欢100行以内,有人赞成1000行以内。数字并 不是最重要的。仁者见仁,智者见智,只要团队觉得合适就 好。只关注一个业务功能,这一点和我们平常谈论的面向对象 原则中的”单一职责原则”类似,每个服务只做一件事情,并且 把它做好。 运行在独立的进程中 每个服务都运行在一个独立的操作系统进程中,这意味着 不同的服务能被部署到不同的主机上。 轻量级的通信机制
97. 服务和服务之间通过轻量级的机制实现彼此间的通信。所 谓轻量级通信机制,通常指基于语言无关、平台无关的这类协 议,例如XML、JSON,而不是传统我们熟知的Java RMI或 者.Net Remoting等。 松耦合 不需要改变依赖,只更改当前服务本身,就可以独立部 署。这意味着该服务和其他服务之间在部署和运行上呈现相互 独立的状态。 综上所述,微服务架构采用多个服务间互相协作的方式构 建传统应用。每个服务独立运行在不同的进程中,服务与服务 之间通过轻量的通讯机制交互,并且每个服务可以通过自动化 部署方式独立部署。 微服务的优势 相比传统的单块架构系统(monolithic),微服务在如下诸多 方面有着显著的优势: 异构性 问题有其具体性,解决方案也应有其针对性。用最适合的 技术方案去解决具体的问题,往往会事半功倍。传统的单块架 构系统倾向采用统一的技术平台或方案来解决所有问题。而微 服务的异构性,可以针对不同的业务特征选择不同的技术方 案,有针对性的解决具体的业务问题。
98. 对于单块架构的系统,初始的技术选型严重限制了将来采 用不同语言或框架的能力。如果想尝试新的编程语言或者框 架,没有完备的功能测试集,很难平滑的完成替换,而且系统 规模越大,风险越高。基于微服务架构,我们更容易在遗留系 统上尝试新的技术或解决方案。譬如说,可以先挑选风险最小 的服务作为尝试,快速得到反馈后再决定是否试用于其他服 务。这也意味着,即便对一项新技术的尝试失败,也可以抛弃 这个方案,这并不会给整个产品带来风险。 该 图 引 用 自 Martin Fowler的 Microservices一 文 独立测试与部署 单块架构系统运行在一个进程中,因此系统中任何程序的
99. 改变,都需要对整个系统重新测试并部署。 而对于微服务架构 而言,不同服务之间的打包、测试或者部署等,与其它服务都 是完全独立的。对某个服务所做的改动,只需要关注该服务本 身。从这个角度来说,使用微服务后,代码修改、测试、打包 以及部署的成本和风险都比单块架构系统降低很多。 按需伸缩 单块架构系统由于单进程的局限性,水平扩展时只能基于 整个系统进行扩展,无法针对某一个功能模块按需扩展。 而服 务架构则可以完美地解决伸缩性的扩展问题。系统可以根据需 要,实施细粒度的自由扩展。 错误隔离性 微服务架构同时也能提升故障的隔离性。例如,如果某个 服务的内存泄露,只会影响自己,其他服务能够继续正常地工 作。与之形成对比的是,单块架构中如果有一个不合格的组件 发生异常,有可能会拖垮整个系统。 团队全功能化 康威定律(Conway's law)指出:一个组织的设计成果, 其结构往往对应于这个组织中的沟通结构。传统的开发模式在 分工时往往以技术为单位,比如UI团队、服务端团队和数据库 团队,这样的分工可能会导致任何功能上的改变都需要跨团队 沟通和协调。而微服务则倡导围绕服务来分工,团队需要具备
100. 服务设计、开发、测试到部署所需的所有技能。 微服务快速开发实践 随着团队对业务的理解加深和对微服务实践的尝试,数个 微服务程序已经成功构建出来。不过,问题同时也出现了:对 于这些不同的微服务程序而言,虽然具体实现的代码细节不 同,但其结构、开发方式、持续集成环境、测试策略、部署机 制以及监控和告警等,都有着类似的实现方式。那么如何满足 DRY原则并消除浪费呢?带着这个问题,经过团队的努力, Stencil诞生了。 Stencil是一个帮助快速构建Ruby微服务应用的 开发框架,主要包括四部分:Stencil模板、代码生成工具,持 续集成模板以及一键部署工具。
101. Stencil模板 Stencil模板是一个独立的Ruby代码工程库,主要包括代码 模板以及一组配置文件模板。 代码模板使用Webmachine作为Web框架,RESTful和JSON 构建服务之间的通信方式,RSpec作为测试框架。同时,代码 模板还定义了一组Rake任务,譬如运行测试,查看测试报告, 将当前的微服务生成RPM包,使用Koji给RPM包打标签等。 除此之外,该模板也提供了一组通用的URL,帮助使用者 查看微服务的当前版本、配置信息以及检测该微服务程序是否 健康运行等。
102. [ { rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel: "index", path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path: "/diagnostic/" }, { rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel: "version", path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path: "/diagnostic/version" }, { rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel: "config", path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path: "/diagnostic/config" }, { rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel: "hostname", path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path: "/diagnostic/hostname" }, { rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel:'>rel: "heartbeat", path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path:'>path: "/diagnostic/status/heartbeat" }, {
103. rel: "nagios", path: "/diagnostic/status/nagios" } ] 配置文件模板主要包括NewRelic配置,Passenger配置、 Nagios配置、Apache配置以及Splunk配置。通过定义这些配置 文件模板,当把新的微服务程序部署到验收环境或者产品环境 时,我们立刻就可以使用Nagios、NewRelic以及Splunk等第三 方服务提供的功能,帮助我们有效的监控微服务,并在超过初 始阈值时获得告警。 代码生成工具 借助Stencil代码生成工具,我们能在很短时间内就构建出 一个可以立即运行的微服务应用程序。随着系统越来越复杂, 微服务程序的不断增多,Stencil模板和代码生成工具帮助我们 大大简化了创建微服务的流程,让开发人员更关注如何实现业 务逻辑并快速验证。 Create a project from the stencil template (version 0.1.27) --name, -n : New project name. eg. things-and-stuff --git-owner, -g : Git owner (default: which team or owner) --database, -d: Include database connection code
104. --triggered-task, -t: Include triggered task code --provider, -p: Is it a service provider? (other services use this service) --consumer, -c: Is it a service consumer? (it uses other services) --branch, -b : Specify a particular branch of Stencil --face-palm, -f: Overide name validation --help, -h: Show this message 如上代码所示,通过指定不同参数,我们能创建具有数据 库访问能力的微服务程序,或者是包含异步队列处理的微服务 程序。同时,我们也可以标记该服务是数据消费者还是数据生 产者,能帮助我们理解多个微服务之间的联系。 持续集成模板 基于持续集成服务器Bamboo,团队创建了针对Stencil的持 续集成模板工程,并定义了三个主要阶段: 1.打包:运行单元测试、集成测试,等待测试通过后生成 RPM包。 2.发布:将RPM包发布到Koji服务器上,并打上相应的 Tag。然后使用Packer在亚马逊 AWS云环境中创建AMI,建好的 AMI上已经安装了当前微服务程序的最新RPM包。 3.部署:基于指定版本的AMI,将应用快速部署到验收环
105. 境或者产品环境上。 利用持续集成模板工程,团队仅需花费很少的时间,就可 以针对新建的微应用程序,在Bamboo上快速定义其对应的持续 集成环境。 一键部署工具 所有的微服务程序都部署并运行在亚马逊AWS云环境上。 同时,我们使用Asgard对AWS云环境中的资源进行创建、部署 和管理。 Asgard是一套功能强大的基于Web的AWS云部署和管 理工具,由Netflix采用Groovy on Grails开发,其主要优点有: • 基于B/S的AWS部署及管理工具,使用户能通过浏览器直 接访问AWS云资源,无需设置Secret Key和Access Key; • 定义了Application以及Cluster等逻辑概念,更清晰、有效 地描述了应用程序在AWS云环境中对应的部署拓扑结构。 • 在对应用的部署操作中,集成了AWS Elastic Load Balancer、AWS EC2以及AWS Autoscaling Group,并将这些资源 自动关联起来。 • 提供RESTful接口,能够方便地与其他系统集成。 • 简洁易用的用户接口,提供可视化的方式完成一键部署 以及流量切换。 由于Asgard对RESTful的良好支持,团队实现了一套基于 Asgard的命令行部署工具,只需如下一条命令,提供应用程序
106. 的名称以及版本号,就可自动完成资源的创建、部署、流量切 换、删除旧的应用等操作。 asgard-deploy [AppName] [AppVersion] 同时,基于命令行的部署工具,也可以很容易的将自动化 部署集成到Bamboo持续集成环境。 通过使用微服务框架Stencil,大大缩短了团队开发微服务 的周期。同时,基于Stencil,我们定义了一套团队内部的开发 流程,帮助团队的每一位成员理解并快速构建微服务。 微服务架构下的新系统 经过5个月的努力,我们重新构建了合同管理系统,将之 前的产品、价格、销售人员、合同签署、合同审查以及PDF生 成都定义成了独立的服务接口。相比之前大而全、难以维护的 合同管理系统而言,新的系统由不同功能的微服务组成,每个 微服务程序只关注单一的功能。每个微服务应用都有相关的负 责人,通过使用Page Duty建立消息通知机制。每当有监控出现 告警的时候,责任人能立即收到消息并快速做出响应。
107. 由于微服务具有高内聚,低耦合的特点,每个应用都是一 个独立的个体。当出现问题时,很容易定位问题并解决问题, 大大缩短了修复缺陷的周期。另外,通过使用不同功能的微服 务接口提供数据,用户接口(UI)部分变成了一个非常简洁、轻 量级的应用,更关注如何渲染页面以及表单提交等交互功能。 总结 通过使用微服务架构,在不影响现有业务运转的情况下, 我们有效的将遗留的大系统逐渐分解成不同功能的微服务接 口。同时,通过Stencil微服务开发框架,我们能够快速地构建 不同功能的微服务接口,并能方便地将其部署到验收环境或者
108. 产品环境。最后,得益于微服务架构的灵活性以及扩展性,使 得我们能够快速构建低耦合、易扩展、易伸缩性的应用系统。 参考文献 1.http://martinfowler.com/articles/microservices.html 2.http://jaxenter.com/cracking-microservices-practices50692.html 3.http://microservices.io/patterns/microservices.html
109. 微服务——大企业是如何在实践微服务中成长的 文/贺思聪 我足够“高”了么? Martin Fowler描述过当组织在考虑实现微服务架构时,必 须要有的一组“能力基线”,但大企业通常有各种理由不太愿意 去尝试和成长以达到这样的能力。有很多的文字都提到,在成 长之路完成后便能收获微服务架构所能带来的各种好处。这篇 文章将描述一个大企业为达到Martin Fowler的能力基线,所经 历的挑战和决心。 开篇 在行业中,微服务有着众多不同的定义。某些定义认为它 是一种和Unix编程风格类似,以构建很多能够专注于做好一件 事情的、微小的、有自治进程的架构风格。某些定义认为它是 第一个后DevOps革命的架构。它从DevOps和持续交付中吸取 经验,并且对其进行了优化。
110. image by Fabio Pereira 我们采用微服务的初衷是提供一种能够扩大团队规模的途 径。我们从一个单体应用开始,康威定律启迪我们分解这个单 体应用。经过这个过程,我们最终变成了很多小而优的团队来 进行交付。 团队结构影响系统架构并不是一个新鲜事。Nygard总结得 很到位——“团队的工作分配方式就是架构的初稿”。这种最初 对团队伸缩性的需求是将一批最佳实践带入微服务和持续集成 的催化剂。 团队的工作分配方式就是架构的初稿。 拆分单体应用 当我们拆分单体应用时,我们面临的第一个挑战是找到系 统的接缝或者界限上下文。这种尝试带来了一个非常有意思的
111. 副作用,即我们可以通过识别系统中那些比起其他地方更不容 易变化的地方,来解耦我们的系统。这和重构代码以让你的代 码更经得起时间的考验类似,只不过是在架构层次上罢了。 从单体应用中分割出多个服务是很不简单的。包括创建单 独的代码仓库,构建管道和基础设施建设。这些都要消耗时 间。因为很多企业都对频繁构建新服务持悲观的态度,我们经 常会听到犹豫之声:“如果构建一个服务都用了这么多时间,我 们怎么做其他的服务呢?” 我们是在每个迭代中逐步攻克这个问题的。我们在构建管 道、工程的创建、环境设置和部署中作出改进。这是从微服务 架构中所获得的很大一部分益处——它不仅强制性的将质量和 成熟度构建进你的软件,而且也包含了开发流程和实践。 步入云端 在改进DevOps最佳实践的路上,配置环境成了绊脚石。如 果需要另一个部门花几周的时间,去配置好一个新的机器来托 管你的新服务,你就有麻烦了。幸运的是我们已经准备好步入 云端,并且已经在企业层面上准备好了支持云部署所必需的工 具链。 即便有这些工具,开发人员也必须开始拥有他们的软件, 包括生产环境的部署和支持。封闭的组织有一个趋势是将他们 的开发人员与真实地生产环境隔离开。“谁构建,谁拥有”这个
112. 思想非常的重要,它能促进最佳实践的成熟。亦即,如果开发 人员已经对生产环境的稳定性和支持有浓厚的兴趣,那么很有 可能是他们构建了这个系统。 消费者驱动的契约测试 我们已经拥有了很多已经部署到云端的RESTFul API,并 且由团队自己维护这些API。这就意味着团队可以不借助其他 人的力量进行独立的开发。不过,我们开始发现依赖的服务在 逐渐改变我们的行为。测试和利益相关者开始抱怨系统不稳定 ——当我们是单体应用时这根本不是问题。 我们使用集成测试来解决这个问题。服务提供者为其API
113. 的消费者维护一组测试,而不是消费者自己为契约写集成测 试。这样做有很多的好处:首先,如果服务提供者破坏了契 约,它会直接被告知;另外,如果消费者增加了新的测试场 景,但这个场景破坏了契约,那么构建也同样会失败。这些考 量驱动出更重要的事情,也即团队之间的交流以及尽快开始对 话。API始终可以进化,但它会有足够的约束来保证稳定性。 蝴蝶效应 解耦单体应用的另一个副作用是监控的工作量成倍增加。 之前一个应用中可能只有一个终端(endpoint),而现在你有很 多的服务。为了更好地保证应用正常工作,你必须要为支撑你 的服务基础设置上提供足够的监控。 在单体应用中,如果一个服务调用失败了,我们会清楚地 知道哪里出错了。但在一个经常变化的解耦架构中不再成立。 当一个服务失败了,真实的失败位置可能是在依赖树上的数个 服务。这就意味着平均修复时间(MTTR)会受影响——我们 必须要调查受影响的服务,也会调查这个服务所有的依赖。我 们使用PRTG监控工具来解决这个问题。PRTG给我们提供了一 个高级的仪表盘(dashboard)来图形化系统的不同的部件。 我们发现另外一种必要的监控是分布式的日志收集。这允 许我们从不同的服务器收集日志并且可以做联合查询。我们甚 至可以引入相关性ID来改进它。这样分布式的日志允许我们跟
114. 踪一个请求在系统不同服务中的跳转过程。 展望 当然我们还有一些需要在未来解决的困难问题。包括一些 棘手的组织变化,例如将交付与产品对齐而不是和工程对齐, 并且使开发人员能够在DevOps的环境中工作。这也包含了更多 的环境配置,包括更多的通过Ansible来进行基础设施自动化。 尽管还有未来的挑战,我们已经开始收获一些引入微服务先决 条件所带来的好处了。你的微服务的旅程是怎样的呢?
115. 微服务的团队应对之道 文/禚娴静 原文首发于InfoQ: http://www.infoq.com/cn/articles/micro-service-team-dealwith-problems 这两年,微服务架构火了。在国内,从消费级互联网应 用,到企业级应用;从金融领域,到电信领域;从新开发系统 到已经开发了十几二十年的遗留系统;一夜之间,好像所有的 团队都在谈微服务。 然而,我们为什么采用微服务呢? “让我们的系统尽可能快地响应变化” ——Rebecca Parson 是的,让我们的系统尽可能快地去响应变化。其实几十年 来我们一直在尝试解决这个问题。如果一定要在前面加个限制 的话,那就是低成本的快速响应变化。上世纪九十年代Kent Beck提出要拥抱变化,在同期出现了诸多轻量级开发方法(诸 如 XP、Scrum);2001年敏捷宣言诞生,之后又出现了精益、 看板等新的管理方式。如果说,这些是为了尽快的响应变化, 在软件开发流程和实践方面提出的解决方案,那么微服务架构
116. 就是在软件技术和架构层面提出的应对之道。 微服务是如何做到的? 微服务是一种架构模式,它提倡将单一应用程序划分成一 组小的服务,服务之间互相协调、互相配合,为用户提供最终 价值。每个服务运行在其独立的进程中,服务与服务间采用轻 量级的通信机制互相沟通(通常是基于HTTP协议的RESTful API)。每个服务都围绕着具体业务进行构建,并且能够被独 立地部署到生产环境、类生产环境等。另外,应当尽量避免统 一的、集中式的服务管理机制,对具体的一个服务而言,应根 据业务上下文,选择合适的语言、工具对其进行构建。 ——James Lewis and Martin Fowler 这是James和Martin2014年在《微服务》一文中提到的对于 微服务的定义。相对于单体架构和SOA,它的主要特点是组件 化、松耦合、自治、去中心化,体现在以下几个方面:
117. 1.一组小的服务 服务粒度要小,而每个服务是针对一个单一职责的业务能 力的封装,专注做好一件事情。 2.独立部署运行和扩展 每个服务能够独立被部署并运行在一个进程内。这种运行 和部署方式能够赋予系统灵活的代码组织方式和发布节奏,使 得快速交付和应对变化成为可能。 • 独立开发和演化 技术选型灵活,不受遗留系统技术约束。合适的业务问题 选择合适的技术可以独立演化。服务与服务之间采取与语言无 关的API进行集成。相对于单体架构,微服务架构是更面向业 务创新的一种架构模式。
118. 3.独立团队和自治 团队对服务的整个生命周期负责,工作在独立的上下文 中,自己决策自己治理,而不需要统一的指挥中心。团队和团 队之间通过松散的社区部落进行衔接。 我们可以看到整个微服务的思想就如我们现在面对信息爆 炸、知识爆炸是一样的:通过解耦我们所做的事情,分而治之 以减少不必要的损耗,使得整个复杂的系统和组织能够快速的 应对变化。 My First Law of Distributed Object Design: Don't distribute your objects (From P of EAA). ——Martin Fowler 然而谈到微服务,我们不能忽视的一点是:微服务仍然是 典型的分布式系统,它必然有分布式系统固有的问题:诸如怎 么部署,出错怎么办,怎么保证数据的最后一致性;与此同 时,还有服务要多微?业务变化后服务如何调整?服务规模化 后怎么办?如何避免一个服务改动导致的多个级联服务的失 败?如何进行测试等等问题。 “微服务不是免费的午餐”。从实战中我们清楚地认识到选 择任何架构都有利有弊,服务化也是一样。企业从微服务架构 获益的同时,必然要面对切换到由众多服务组成的分布式系统 后所带来的挑战。我们认为只有提升团队应对这些挑战的成熟
119. 度,才能真正使企业从这种微服务架构中获益. 那么对于即将和已经开始实施微服务的团队,应该如何应 对呢?结合我们项目的经验,我认为应从DevOps、服务构建、 团队和文化四点入手: • 首先需要考虑构建DevOps能力,这是保证微服务架构在 持续交付和应对复杂运维问题的动力之源; • 其次保持服务持续演进,使之能够快速、低成本地被拆 分和合并,以快速响应业务的变化; • 同时要保持团队和架构对齐。微服务貌似是技术层面的 变革,但它对团队结构和组织文化有很强的要求和影响。识别 和构建匹配架构的团队是解决问题的另一大支柱。 • 最后,打造持续改进的自组织文化是实施微服务的关键 基石。只有持续改进,持续学习和反馈,持续打造这样一个文 化氛围和团队,微服务架构才能持续发展下去,保持新鲜的生 命力,进而实现我们的初衷。 在本文中会针对第一点,并以我们项目微服务的发展历程 为例介绍我们遇到的各种坑和采取的相关措施,希望能够给正 在准备实施和已经实施微服务的团队一些借鉴。 背景
120. 我们于2012年在系统集成需求的驱动下走上了服务化之 路,通过将重复的业务能力封装在几个服务之间完成了系统集 成,并成功上线。最初只有8个服务支持我们的业务系统,服 务与服务之间采取基于HTTP的RESTful API的方式进行通信, 通过自动化脚本将应用部署到生产环境。 在随后的2年中我们的业务快速发展,增加到了60多个站 点和服务。服务的上线周期也越来越短,从两年到两周。而这 样的一套生产环境是由客户的2名运维人员手工维护的(包括 基础设施构建),每次发布都会存在大量的人工干预,比如对 部署结构和系统权限的修改等,给我们的整个生产部署和运维 带来了较大的问题: • 大量的人工干预,频频出错。 手工方式始终是易错和低效的,而且会导致各种难以重现 的环境问题(就如雪花服务器),这使得一些复杂点的运维工 作,包括技术平台的整体升级、灾备系统搭建等很难开展,往
121. 往要提前半年甚至一年来进行筹备。当我们服务规模化和发布 周期缩短之后,它带来的伤害又进一步明显起来。为了减小这 种伤害,业务部门不得不降低发布频率,从两周延迟到一个 月,因此也影响到了对最终用户的响应速度,并不得不采取 Hotfix的方式来修正发布速度的问题,实际上又增加了问题的 复杂度。 • 缺乏有效的监控和日志管理,产品环境定位困难。 没有监控,无法及时知晓服务的运行状态。很多问题直到 最终用户才能发现,问题反馈周期很长。同时,运维人员不懂 开发人员的服务设计和调用流程,开发人员不懂产品环境的配 置结构。当产品环境出错之后,往往要花费数小时才能定位到 问题根源。 另外,负载均衡和单点服务降级无法真正开展,当一个服 务出现问题时,需要关掉其所在的服务器。产品环境资源利用 率低,运维成本居高不下。 2015年初,当我们遇到了Powershell的bug和服务不能正常 启动的貌似随机问题时,就如遇到了那根压倒骆驼的最后一根 稻草,客户对我们明确地提出“不要再添加任何一个服务了”。 残酷的事实再一次向我们证明,在这样一个复杂系统下, 传统的手工运维方式必然要被淘汰,微服务的实施有一定的先 决条件:基础的运维能力(如监控、快速配置、快速部署)需 提前构建,否则就会陷入像我们一般如此被动的局面。而我们 也看到,当服务规模化后需要更多自动化和标准化的手段来提
122. 升效能和降低成本。 服务治理 随后的一段时间,我们的团队重新梳理了最后一公里和运 维的需求,如下图所示,并开始服务治理,从而构建支撑当下 架构的交付和运维能力。 1. 基础环境的准备 环境需要能够快速地创建并启用全新的服务,能够快速对 现有的环境进行自动更改等,以保持各环境的一致性。我们推 荐采用基础设施及代码的实践,通过代码来描述计算和网络基 础设施的方法,使得图案度i可以快速安全的搭建和处理由新的 配置代替的服务器,服务器之间可以拥有更高的一致性,降低
123. 了在“我的环境工作,而你的环境不工作”的可能,也是为后续 的发布策略和运维提供更好的支撑。 在技术层面,随着云平台技术的成熟,Docker和围绕 Docker生态圈的形成,开发和运维团队如虎添翼。组织可以根 据现状选择合适的方式逐步迁移到云平台。另外,对于目前不 能采用Docker技术的Windows平台,Chef、Ansible也是不错的 选择。 2. 发布部署 要求服务能够快速上线,能够快速部署到各个环境以便尽 快得到验证。面对如此庞大的服务及复杂的依赖关系,我们建 议分离产品、预发布环境及测试环境。采用部署流水线,由自 动化脚本实现全环境的快速部署,包括配置管理、版本管理 等。 3. 运行时监控与业务运营 当产品环境出错时,需要快速的定位问题,检测可能发生 的意外和故障。而监控是快速定位和预防的不二选择,在微服 务架构中更是至关重要。监控包括服务可用状态、请求流量、 调用链、错误计数等内容,以便发现问题及时修复,实时调整 系统负载,进行必要服务降级,过载保护等等,从而让系统和 环境提供高效高质量的业务服务。其中健康状态页面、结构化 的日志、实时服务依赖关系可视化、流量统计、事件机制等都
124. 是监控领域可采取的基础技术手段。 除此,随着服务越来越多,需要进一步考虑蓝绿部署、灰 度发布、服务安全、容器编排等问题和自动化标准化的手段, 从而更好地管理大规模下服务产生的运维需求。下图是最近几 期ThoughtWorks技术雷达中提到的相关内容,可供不同技术栈 和处于不同实施阶段的团队参考: 我们的选择和改进
125. 针对上面的几个痛点和我们项目所处的阶段,结合项 目.NET技术栈的生态系统,我们主要采用Chef自动化构建本地 构建的基础设施,与运维团队一起优化部署流程,提供服务健 康状态页面支持监控,使用Splunk进行集中式日志管理,并可 视化服务依赖关系等来进行全面服务治理,我们的部署时间从 原来的十几个小时缩短到三十分钟,成功率也大大提高。结合 业务部门的需求和现状的分析,对其方面地要求,如独立部 署、配置管理、服务发现、过载保护等的改进仍在继续中。 除此之外,我们还做了什么?
126. You build it, you own it. ——Amazon CTO 打造DevOps文化,将运维作为需求提前注入到开发流程 从上一节可以看出,微服务对开发人员和运维人员的工作 方式和技能都有新的要求,带来很强的冲击。在2014年随后的 一段时间,我们开始将运维的需求内建到整个开发流程。当新 业务需求提出的时候会同时交给开发人员和运维人员,后者将 整个运维环境的要求(包括监控和安全)进行分析,产出约束 规范或非功能需求递给开发人员;开发人员在做技术决策和开 发工作时遵循这些约束并满足这些非功能需求,最后将整个产 品以及监控的实现交付给运维团队。双方同时也重建了沟通计 划,互换技术架构和运维方面的知识,互相支持和深入合作。 在我们整个服务治理的过程中,花了大量的时间去理顺最 后一公里和运营监控的问题,与运维团队的合作一步步从无到
127. 有,从不信任不合作到逐渐改善,才使得微服务的实施顺利进 阶。可以说在企业内要成功实施微服务,最不能少的合作角色 就是企业的运维团队。微服务实施要想顺利进行,必须要打破 开发团队和运维团队之间的高墙,真正做到“开发自运维”,运 维自开发,互生互长。我们也向其他的组织推荐这样的方式, 打通DevOps的任督二脉,为微服务保驾护航。 扩展阅读: 1.http://martinfowler.com/microservices/ 2.http://martinfowler.com/bliki/MicroservicePrerequisites.html 3.http://martinfowler.com/bliki/InfrastructureAsCode.html 4.https://www.thoughtworks.com/insights/blog/microservicesevolutionary-architecture 5.http://liguanglei.name/blogs/2015/04/22/devops-chinesename/ 6.https://www.thoughtworks.com/insights/blog/macro-trendstechnology-industry
128. 服务拆分和架构演进 文/禚娴静 本文首发于InfoQ: http://www.infoq.com/cn/articles/service-split-andarchitecture-evolution “领域驱动设计和服务自演进能力是内功。” 前言 《微服务的团队应对之道》提到,微服务帮助企业提升其 响应力,而企业需要从DevOps、服务构建、团队和文化四点入 手,应对微服务带来的复杂度和各种挑战,从而真正获益。如 果说运维能力是微服务的加油站,服务则是其核心。 企业想要实施微服务架构,经常问到的第一个问题是,怎 么拆?如何从单体到服务化的结构?第二个问题是拆完后业务 变了增加了怎么办?另外,我们想要改变的系统往往已经成功 上线,并有着活跃的用户。那么对其拆分还需要考虑现有的系 统运行,如何以安全最快最低成本的方式拆分也是在这个过程 中需要回答的问题。 本文会针对以上问题,介绍我们团队在服务拆分和演进过 程中的实践和经验总结。
129. 我们项目架构的演化历程 该项目始于2009年,到现在已有7年的时间。在这7年中覆 盖的业务线不断扩大,从工单、差旅、计费、文件、报表、增 值业务等;业务流程从部分节点到用户端的全线延伸;7年间 打造多个产品,架构经历了多次调整,从单体架构、RPC、服 务化、规模化到微服务。 主要架构变迁如下图所示:
130. 在这7年架构演进路上,我们遇到的主要挑战如下: 1.如何拆?即如何正确理解业务,将单体结构拆分为服务 化架构? 2.拆完后业务变了增加了怎么办?即在业务需求不断发展 变化的前提下,如何持续快速地演进? 3.如何安全地持续地拆?即如何在不影响当下系统运行状 态的前提下,持续安全地演进? 4.如何保证拆对了? 5.拆完了怎么保证不被破坏? 问题1:如何将单体结构拆分为服务化架构? 就如庖丁解牛一样,拆分需要摸清内部的构造脉络,在筋 骨缝隙处下刀。那么微服务架构中,我们认为服务是业务能力 的代表,需要围绕业务进行组织。拆分的关键在于正确理解业 务,识别单体内部的业务领域及其边界,并按边界进行拆分。 1. 识别业务领域及边界。 首先需要将客户、体验设计师、业务分析师、技术人员集 结在一起对业务需求进行沟通,随后对其进行领域划分,确定 限界上下文(Boundary Context),也称战略建模。 以下我们经常使用的方法和参考的红蓝宝书: 1.Inception-> User Journey Scenarios,用于梳理业务流程,
131. 由粗粒度到细粒度逐一场景分析。 2.四色建模,用于提取核心概念、关键数据项和业务约 束。 3.领域驱动设计-战略设计,用于划分领域及边界、进行技 术验证。 4.Eventstorming,用于提取领域中的业务事件,便于正确建 模。 2.Inception与DDD战略设计的对比:
132. 一个业务领域或子域是一个企业中的业务范围以及在其中 进行的活动,核心子域指业务成功的主要促成因素,是企业的 核心竞争力;通用子域不是核心,但被整个业务系统所使用; 支撑子域不是核心,不被整个系统使用,该能力可从外部购 买。一个业务领域和子域可以包括多个业务能力,一个业务能 力对应一个服务。领域的边界即限界上下文,也是服务的边 界,它封装了一系列的领域模型。 一个业务流程代表了企业的一个业务领域,业务流程所涉 及的数据或角色或是通用子域,或是支撑子域,由其在企业的
133. 核心竞争力的角色所决定。比如企业有统一身份认证,决策不 同部门负责不同的流程任务,那么身份认证子域并不产生业务 价值,不是业务成功的促成因素,但是所有流程的入口,因而 为通用子域,可为单独服务;而部门负责的业务则为核心子 域。 举个例子 工单业务流程: 某企业为服务人员提供工单服务的业务流程简化如下。首 先搜索服务人员,选取服务人员购买的服务,基于目标国家的 工单流程,向服务人员收取资料,对其进行审计,最后发送结 果。
134. 识别的领域: 其中服务为其核心竞争能力,包括该企业对全球各国的政 策理解,即法律流程,服务资料(问卷),计算服务,资料审 计服务,相比其他竞争对手的服务(价位/效率等),这些都为 改企业提供核心的业务价值,自然也是核心子域。而其他用于 统计改企业员工工作的工单,组织结构和员工为支撑子域,并 不直接产生业务价值。 领域划分的原则 在划分的过程中,经常纠结的一个问题是:这个模型(概 念或数据)看起来放这个领域合适,放另一个也合适,如何抉 择呢?
135. • 第一,依据该模型与边界内其他模型或角色关系的紧密 程度。比如,是否当该模型变化时,其他模型也需要进行变 化;该数据是否通常由当前上下文中的角色在当前活动范围内 使用。 • 第二,服务边界内的业务能力职责应单一,不是完成同 一业务能力的模型不放在同一个上下文中。 • 第三,划分的子域和服务需满足正交原则。领域名字代 表的自然语言上下文保持互相独立。 • 第四,读写分离的原则。例如报表需有单独报表子域。 核心子域的划分更多基于来自业务价值的产生方,而非不产生 价值的报表系统。 • 第五,模型在很多业务操作中同时被修改和更新。 • 第六,组织中业务部分的划分也是一种参考,一个业务 部门的存在往往有其独特的业务价值。 简单打个比方,同一个领域上下文中的模型要保持近亲关 系,五福以内,同一血统(业务)。 领域划分的误区和建议 3.业务能力还是计算能力?在划分一些貌似通用的领域 时,其实只是用到了通用的计算能力而不是业务能力,只需采 用通用库的方式进行封装,而无需使用服务的方式。如我们系 统的模板服务,是构建通用的模板服务,服务于整个平台的服
136. 务;还是每个服务拥有独立的模板模块? 4.尽早识别剥离通用领域。如身份认证与鉴权领域,是企 业系统中最复杂、有相对多变的领域,需要及早隔离它对核心 业务的干扰。 5.时刻促成技术人员与客户、业务人员的对话。业务领 域的划分离不开对业务意图的真正理解。而需求人员和体验设 计师对于User Journey的使用更熟悉,而技术人员、架构师对领 域驱动设计、Eventstorming更熟悉。不管哪种方法都要求跨角 色的群体协同工作,即客户人员、业务分析师、体验设计师与 技术人员、架构师。而现实的情况中,User Journey更多的在 Inception,在需求阶段进行,而领域驱动设计、Eventstorming更 多的在开发设计阶段被使用,故而需求阶段经常缺失技术人 员,而开发设计阶段经常缺失客户、业务人员的参与。 另一个 常见的现象是,Inception的参与人员和真正的开发团队有可能 不是同一个群体,那么Inception中的业务沟通往往以UI的方式 作为传递,因此在开发中经常只能通过UI设计来理解业务的真 正意图。 所以要想将正确的理解业务,做对软件,需要时刻促 成技术人员与客户、业务人员的对话。 识别了被拆对象的结构和边界,下一步需要决定拆分的策 略和拆分的步骤。 2.拆分方法与策略 拆分方法需要根据遗留系统的状态,通常分为绞杀者与修
137. 缮者两种模式。 • 绞杀者模式 指在遗留系统外围,将新功能用新的方式构 建为新的服务。随着时间的推移,新的服务逐渐“绞杀”老的一 流系统。对于那些老旧庞大难以更改的遗留系统,推荐采用绞 杀者模式。 • 修缮者模式 就如修房或修路一样,将老旧待修缮的部分 进行隔离,用新的方式对其进行单独修复。修复的同时,需保 证与其他部分仍能协同功能。 我们过去所做的拆分中多为修缮者模式,其基本原理来自 Martin Fowler的branch by abstraction的重构方法,如下图所示: 就如我们团队所总结的16字重构箴言,我觉得十分的贴 切: “旧的不变,新的创建,一步切换,旧的再见”。
138. 通过识别内部的被拆模块,对其增加接口层,将旧的引用 改为新接口调用;随后将接口封装为API,并将对接口的引用 改为本地API调用;最后将新服务部署为新进程,调用改为真 正的服务API调用。 同时,拆分建议从业务相对独立、耦合度最小的地方开 始。待团队获取相应经验和基础设施平台构建完善后,再进行 核心应用迁移和大规模的改造。另外,核心通用服务尽量先 行,如身份认证服务。 3. 拆分步骤 对于模块的拆分包括两部分:数据库与业务代码,可以先 数据库后业务代码,亦可先业务代码后数据库。然而我们的项 目拆分中遇到的最大挑战是数据层的拆分。在2015年的拆分中 发现,数据库层由于当时系统性能调优的驱动,在代码中出现 了跨模块的数据库连表查询。这导致后期服务的拆分非常的困 难。因此在拆分步骤上我们更多的推荐数据库先行。 4.数据库拆分 我们借鉴了重构数据库一书中提到的方法,通过重复 schema同步数据,对数据库的读写操作分别进行迁移。如下图 所示:
139. 虽然技术上是可行的,然而这仍然占用了大量不必要的时 间,包括大量的数据迁移。这也是导致当时的拆分无法在给定 时间内完成的很大因素。 5. 我们的结果: 系统架构图:
140. 问题2:拆分后业务变了增加了怎么办? 随着客户业务的变化,我们的服务也在持续的增加,而其 中碰到了一个特大的服务。服务的大小如何衡量呢?该服务生 产代码7万行+,测试代码14万行+,测试运行时间2个小时。团 队中7个stream每天50%工作需要对这个服务进行更改,使得团 队间的依赖非常严重,独立功能无法单独快速前行,交付速度 及质量都受到了影响。 我们的总结: 客户的业务是在变化的,我们对业务的认知也是逐渐的过 程,所以Martin Fowler在他的文章中提出,系统的初期建议以 单体结构开始,随业务发展决定其是否被拆分或合并。那么这
141. 也意味着这样构建的服务在它的生命周期中必然会持续被拆分 或合并。那么为了实现这样一个目标,使系统拥有快速的响应 力,也要求这样的拆分必然是高效的低成本的。 因此,服务的设计需要满足如下的原则: • 服务要有明确的业务边界,以单体开始并不意味着没有 边界。 服务要有边界,即使以单体开始也要定义单体时期的边 界。我们系统中有一个名为“Monkey”的服务,是在中国虎年启 动的,由此它并不是一个业务概念。当这个服务的名字为 MonkeyAPI时,可以想象5年来它变成了什么?几乎所有和这个 产品相关的功能都放入了这个服务中。脱离平台来看这一个产 品的系统,其实它只是做了前后端分离而已。这个例子告诉我 们,没有边界就会导致大杂烩,之后对其进行整理和重造的代 价很大,可能需要花费“几代人”的努力。 • 服务要有明确清晰的契约设计,即对外提供的业务能 力。 • 服务内部要保持高度模块化,才能够容易地被拆分。 • 可测试。 问题3:如何安全地持续地拆? 就如前言中提到的,系统已经上线大量的用户正在使用, 如何在不影响当下系统运行状态的前提下,持续安全地演进? 其实持续演进就是一场架构层次的重构,在这样的路上同样需
142. 要: • 坏味道驱动,架构的坏味道是代码坏味道在更高层次的 展现,也就意味着架构的混乱程度同样反映了该系统代码层的 质量问题。 • 安全小步的重构。 • 有足够的测试进行保护——契约测试。 • 持续验证演进的方向。 真正有挑战的问题4:如何保证拆对了? 拆分不能没有目标,尤其在具有风险的架构层次拆分更需 谨慎。那么我们如何验证拆分的结果和收益?或许它可以提高 开发效率,交付速度快,上线快,宕机时间也短,还能提高开 发质量,可扩展性好,稳定,维护成本低,新人成长快,团队 容易掌握等等。然而软件开发是一个复杂的事情,拆分可以引 起多个维度的变化,度量的难度在于如何准确定位由拆分这一 单一因素引起的价值的变化(增加或降低)。 其实要回答这个问题,还是要回到拆分之初:为什么而 拆? 我所见过的案例中有因为政治原因拆的、业务发展需要 的、系统集成驱动的等等;有因之而成功的,也有因之而失败 的。拆并不是一件容易的事,有诸多的因素。我认为不管表象 是什么,拆之前需要弄清拆分的价值所在,这也是我们可以保 证拆分结果的源头。
143. 总结 系统可由单体结构开始,不断的演进。而团队需要对业务 保持敏感,与客户、业务人员进行业务对话,不断修炼领域驱 动设计和重构的能力。 在拆分的路上,我们的经验显示其最大的障碍来自意大利 面一样的系统。不管我们是什么样的架构风格,高内聚低耦合 的模块化代码内部质量仍然是我们架构演进的基石。具有夯实 领域驱动设计和重构功底的团队才可以应对这些挑战,持续演 进,保持其生命力。而架构变迁之前需要弄清背后的变迁动因 与价值,探索性前进,及时反馈验证,才是正解。那么我们如 何保证架构不被破坏呢?这个问题会在后续的文章中持续探 讨。 最后,勿忘初心,且行且演进。
144. 更多精彩洞见,请关注微信公众号:思特沃克 “ Follow us, give you more!”