精华内容
下载资源
问答
  • 溯源微服务企业分布式应用的一次回顾原创:刘尚奇ThoughtWorks洞见微服务作为架构风格几乎成为云时代企业应用的事实标准,构成微服务...本文是对企业分布式应用的一次回顾,与前微服务时代相比,我们究竟哪些...

    溯源微服务:企业分布式应用的一次回顾

    原创: 刘尚奇 ThoughtWorks洞见 

    微服务作为架构风格几乎成为云时代企业级应用的事实标准,构成微服务的技术元素本身却并非革命性。跨平台的分布式通信框架、地址无关的服务注册与发现、智能路由与编排等技术早已在CORBA、SOA时代实现了一遍又一遍,我们不禁好奇,微服务有什么不同?本文是对企业分布式应用的一次回顾,与前微服务时代相比,我们究竟在哪些领域吸取了教训,哪些方面持续搞砸。

    我们在重新界定抽象边界上取得了进展...

    架构的关键在于构造合理的封装抽象。良好的抽象构造如进程,由操作系统接管CPU调度、内存地址空间分配和I/O,程序员的心智从此解放,得以聚焦在业务逻辑上。糟糕的抽象往往引向万丈深渊,大量精力被浪费在抽象泄露带来的问题上。

    在分布式系统中我们关注组件、组件间的通信以及伴随的工程实践,微服务在企业应用的上下文中就技术约束和业务价值间达成了更好的平衡点。


    RPC?不,是API!

    让我们从组件间的通信开始,最初人们认为这只是需要被解决的技术要素。

    72c2eae049ed503cc9e414328919ce1c.png

    (图片来自:维基百科)

    关于如何实现跨平台的分布式通信,30年前诞生的CORBA架构在今天来看仍然非常漂亮:通过定义IDL/ORB/API我们可以将内存对象任意分布于网络中。只要共享IDL,对象可以由C++/Java等不同的语言实现,其互相调用就像本地方法一样简单。然而实践经验告诉我们,分布式系统总是会出现本地调用不会发生的各种问题:网络的开销、传输的延迟、消息的超时和丢包、远端系统的崩溃……物理世界的技术约束是无法被忽略的,我们没有办法把分布式调用抽象成简单的本地方法。因此Martin Fowler在他的里提出了著名分布式对象第一定律:“不要分布式你的对象”。相反,你应该把尽可能多的操作置于进程之内,通过replicate整个应用的方式来实现系统的scale。

    由分析师们发起的SOA运动从另一个角度看待这个问题,Web Service应该是对企业资产和业务能力的封装。我们开始站在更高的维度,远过程调用不再只是技术意义上的集成。WSDL不仅是通信调用的接口,更是服务间的契约;UDDI不仅是服务描述、发现、集成的中心,更是企业业务与服务的黄页。WS-*在厂商的裹挟下发展成包罗万象,却也没几个人能掌握。开发者们抱怨花了太多时间写冗余的XML制定所谓的规范,WSDL生成的客户端也将不同服务耦合在一起。是否有更加轻量敏捷的方式,让我们快点开始写第一行生产代码?

    于是我们看到REST的兴起。起初是作为反叛,用更加轻量级的方式(http+json)使用Web。然后我们发现"企业级"应用并非需要ESB这样昂贵的专有中间件,由"消费级"技术组成的万维网是世界上最大规模的分布式网络,我们应该向其学习如何构建健壮、可演化的系统。Roy Fielding那篇论文所提出的无状态、可缓存等特征已经深入人心,而狭义上的REST API(基于资源的URI、HTTP动词和状态码的标准接口)也成为API设计的最佳实践。

    既然API和网站一样都是基于通用Web技术,API是否可以像网站一样作为产品提供呢(APIs as product)?于是越来越多的企业开始将自己的业务能力封装成API,提供给消费者,随之而来的是更弹性的商业应用和更灵活的计费方式。很多组织也着手构建自己的API市场,把内部IT能力整合、复用,并为孵化外部产品做准备。API已经成为商业价值主张的一部分。

    我们从聚焦实现细节的rpc出发,来到了更具价值导向的REST API。即使构建内部系统,以消费者驱动的方式,也总是能帮助我们设计出更加松耦合和易于演进的API。


    技术组件?不,是业务服务!

    编程语言中的组件构造(如Java中的jar, C#中的dll)是软件架构师们封装可复用单元的最常用武器。组件作为理论上的最小部署单元,在工程实践中却并不容易独立变更。一般应用程序需要讲多个组件打包成一个部署单元(如war包),链接在内存地址中进行调用。对单个组件的热更新往往对组件间耦合和对象状态管理有很高的要求,重新部署整个应用一般是默认选项。以进程为边界构建可独立部署的服务成为架构师的另一项选择。

    早期的服务只是单纯的技术构件,大多数组织从纯粹的技术实现角度考虑服务的划分。SOA的推动者们指出企业的信息资产应该被复用,信息孤岛应该被打通。通过将不同的服务编排组合,我们应该能够实现IT对业务更加灵活的支撑。

    1a54116297077447e4f5675294461126.png

    (图片来自:0SOA in practice, Nicolai Josuttism, 2009)

    SOA的服务建模一般采用业务流程驱动的方式。一个典型的SOA设计是由业务分析师自顶向下地对企业现有业务流程进行分析,通过BPM引擎对流程进行建模,向下分解成组合服务,并进一步拆分成数据访问服务(很多可怜的SOA实现中数据的访问被拆分成不同的读服务和写服务)。然而这带来的问题是,服务跟服务间的耦合非常严重。当我的业务发生了变化,可能会需要修改很多不同的服务,涉及到多个团队的沟通和协调。在运行时层面,服务器间的通信非常频繁,用户在界面上的一次点击按钮,对应的后台多层服务间的级联通信。这给系统性能和稳定性也带来了巨大的挑战。SOA式的服务建模从分析型思维出发,却往往低估了分布式系统和跨团队协调的复杂度,导致服务拆分粒度过细。

    微服务的名字常常让人误解,但实施正确的微服务粒度可能并不"微"。Martin Fowler与James Lewis在开创微服务定义的一文中已经指出微服务应该围绕完整的业务能力。今天我们在做微服务设计时,常常利用领域驱动设计中的Bounded Context来进行服务边界的划分。假设你的库存管理是一个独立的业务子域,针对库存的维护和操作应该被放到通过一个上下文和微服务中,由一个团队进行开发维护。多数业务变更都发生在上下文内部,不涉及跨团队协调。单个codebase内的重构和部署让发布更加容易。维护库存所需要的信息查询的调用多发生在进程内,更好的性能,同时无需处理额外的一致性问题。

    08e6ecfc28aa256e462f50e960c327dc.png

    微服务的另一个特点在于Product over Project,这需要不同于传统投资组合的预算管理与团队组建。传统的项目制将预算分配在相对短期的服务开发过程中,项目团队关注的是如何将业务范围(scope)实现,开发结束后服务转交运维团队进行维护,项目团队则被解散进行其他项目的开发。将微服务作为产品运营则需要建立业务结果导向的稳定产品团队。服务的设计不只聚焦于当下需求,更需要考虑价值定位和产品愿景。工程团队则需要思考如何用有限成本支撑非线性的业务接入增长。

    846eae9338f75f099d853a974f147cee.png

    (图片来自:Enterprise Architecture as Strategy, Ross et al, 2006)

    如今我们对服务的定义已经超越了技术组件,领先的组织已经在尝试将design thinking, business operating model应用到微服务设计中。


    解耦服务就足够了吗?我们需要去中心化一切!

    即使有了设计合理的服务于API,我们仍然需要与之匹配的工程实践才能将其顺利实施。

    今天仍有很多企业使用集中式的应用服务器部署应用:开发团队将软件包构建出来,再统一安装到应用服务器中。对应用团队来说,这往往意味着漫长的反馈周期和痛苦的自动化。我们很早就推荐用Jetty这样内嵌式的应用容器部署软件,启动更快,测试环境更接近生产。one Tomcat per VM的部署方式虽然运行时开销较大,却是前容器时代隔离性最好的服务部署模式。Docker将这个实践更进一步,除了更轻量级的隔离,我们第一次可以将软件和所依赖的环境本身打包成版本化的artifact,彻底统一开发和生产环境。容器技术的成熟让我们可以将部署去中心化,开发团队可以独立部署一个服务。

    数据库耦合是影响服务独立变更的另一重要因素。相比代码构成的应用软件,数据库schema更加难以变动。因为难以测试、难以兼顾性能优化和耦合的发布周期等因素,服务间以数据库集成成为臭名昭著的反模式。服务间的集成应该依赖封装好的显示接口,而不是数据库这种实现细节。我们应该在兼顾数据一致性的情况下,为每个微服务分配独立的db schema甚至db instance。如果说十年前数据几乎等同于关系数据库。如今数 据则可能呈现出各种形态:键值、文档、时间序列、图...我们完全可以采用更加合适的技术,以去中心化的方式进行微服务的数据治理。

    即使将这一切都解耦,如果将交给一个集中的团队去实施,很有可能最终还是得到一个耦合的架构。这就是是著名的康威定律。康威定律告诉我们“设计系统的架构受制于产生这些设计的组织的沟通结构”。但同样我们可以将康威定律反转应用:如果你想达成一个目标架构,则必须对团队结构进行调整,使之和目标架构对齐。相比单体系统,微服务在运行时监控和运维所带来的挑战更大。"you build it, you run it"的DevOps文化成为必须。监控运维不再是Ops部门的事情,产品团队必须对微服务的整个生命周期负责。授权的去中心化自治团队是实施微服务的必要条件。


    我们干得还不错,但也在持续搞砸一些事情...

    我们在很多方向的确取得了进展。但即使在微服务时代,很多问题仍然在轮回发生着,似乎我们总是无法吸取历史的教训。让我们看一看那些挥之不去的反模式阴云。

    一个例子是开发者对强类型RPC代码生成的依恋。尽管历史经验已经证明同步的rpc无法为分布式通信提供足够好的封装,伪装成本地方法调用的客户端往往鼓励程序员做出糟糕的接口设计:细粒度的频繁调用、缺少缓存和容错处理。IDL生成客户端也会导致服务间耦合,每次变更接口都需要升级数个相关服务。如果用可演进的REST API(如HATEOS)和tolerant reader模式,则可以优雅地解决这个问题。然而新一代的开发者们还是经常“重新”发现rpc的这些能力并陷入依赖——更快的序列化反序列化、类型安全和来自IDE的智能提示、通过spec反向生成代码...分布式计算先驱Vinoski不禁感叹“开发人员的便利性是否真的胜过正确性,可扩展性,性能,关注点分离,可扩展性和意外复杂性?”

    另一个挥之不去的阴影是ESB。ESB在将异构的应用wire在一起有着关键的作用。然而当越来越多的职责被加入:数据报文的裁剪转换、难以测试和版本控制的编排(orchection)逻辑、服务发现智能路由监控治理分布式事务等All in One的solution将ESB变成了一个可怕的单点梦魇。所以微服务发出了“智能终端哑管道”的呐喊:我们只是需要一个不那么智能的代理处理可靠消息传输,将灵活的逻辑交给服务本身去编配(choreography)吧。

    于是在典型的微服务架构里,负载均衡、服务注册发现、分布式追踪等组件以Unix way的方式各司其职。然而在利益诱惑和特性竞争压力之下,很多厂商不断将更多的功能放进他们的中间件,其中为代表的Overambitious API gateways俨然要重新实现占据中心的ESB。如果API gateway只是处理鉴权、限流等横切层逻辑没有问题,如果API gateway开始处理数据转换和业务逻辑编排,你应该提高警惕!

    尽管行业在不断发展,但很多时候人们仍然沿用旧的思维,用新的技术去一遍遍重新实现这些旧的反模式。


    如何更进一步

    你总是可以在技术雷达里追踪微服务的state of art,如今这个领域的前沿方向是什么,Service Mesh, Chaos Engineering, 还是Observability as Code?然而历史告诉我们,新的技术在解决一些问题的同时,也可能会产生新的问题。更糟糕的是,我们永远无法记住历史,用新的工具更高效地重现旧日问题。

    Technologies come and go, Principles stay forever。好在那些架构和实践背后的原则是经久不变的。从操作系统到移动应用都会需要高内聚低耦合的架构,任何软件开发都需要版本控制、自动化构建等实践。谨记这些核心原则、谨记软件被创造出来是为了解决有价值的问题,可以帮我们更好的借鉴历史的经验,理解和采纳新的技术。


    微服务架构下的质量迷思——混沌工程

    原创: 梁真 ThoughtWorks洞见 

    从2005年Peter Rodgers博士提出微web服务,到2014年ThoughtWorks首席科学家Martin Fowler与James Lewis共同提出微服务概念至今已多年,这期间也是互联网及互联网+发展的高速期,消费市场变化莫测,消费者也变得越来越挑剔,很多公司和产品由于无法跟上市场的快速变化而纷纷倒下。越来越多的互联网巨头甚至传统行业都开始对自己的遗留系统进行微服务改造,通过把系统拆分为更加灵活、有业务边界上下文、松散耦合、可独立部署的服务来应对快速变化的消费市场。


    微服务架构面临的挑战

    通常情况下,对于复杂业务或遗留系统,我们可以通过领域驱动设计(DDD:Domain-Driven Design)有效的解决限界上下文划分、服务边界定义以及组织结构调整等问题。除了这些,我们的开发团队还面临着其他的挑战:复杂的分布式系统、数据一致性、容错设计、限流设计、舱壁设计等问题。那么如此复杂的系统如何来保证系统“质量”呢?

    长久以来,“测试金字塔”都是敏捷开发团队保证项目交付质量的守则,而“测试金字塔”也确实从不同的维度涵盖了方法调用、业务逻辑、用户行为等方面。为了确保在进行复杂的调用和被调用时,服务之间能有一定程度上的一致性和快速反馈,我们会第一时间想到“契约测试”,“测试金字塔”也演化成了另一个样子。

    fe631dbd67a56e86bed4d2bd0fbf9c37.png

    下图,我们聚焦于微服务架构的业务服务层,在API测试之外在基础服务的调用方和提供方之间增加了契约测试:

    fbb2b63178786ca35a07790042e89341.png

    在微服务和前后端分离日趋流行的今天,契约测试的确可以在系统频繁演进、重构的情况下保证服务间调用的可用性,而在“聚合服务层”通过API测试,可以暴露服务的组合过程中的问题。“尽早测试”可以让团队在初期发现更多的问题,降低后期修复成本,同时让服务与服务之间具有“感知力”,任何与契约不符的业务变更都能被测试所感知。但是,既然契约测试是保证服务调用方和提供方的一致性,更直接说,是另一种对API的验证,那么契约测试只能覆盖到业务逻辑维度,如果想更好开发或改造微服务系统,就需要相对深入的了解微服务有哪些特性:

    050eb75f5bade3593f2c7bf1239d8833.png

    我们可以看到,这个简单的图中提到了一些微服务的特性(基于Spring Boot):客户端负载均衡、微服务容错保护、API服务网关、分布式链路跟踪等,我们不对这些进行解释,但毫无疑问,契约测试无法覆盖和测试到这些特性,同时也无法模拟例如网络延迟、CPU满载、请求异常、依赖故障、硬件故障等场景。对于一个不具备容错能力的脆弱系统,即使我们可以对服务解耦、独立部署,可对于用户来说,体验到的可能是一次又一次的“灾难”。我们在质量活动中,总会听到这样的声音:“不要动这个功能,会弄坏其他功能”、“客户根本不会这么操作“、”这个缺陷没有意义,你这样会把系统弄挂”。我们总是担心系统某些脆弱的环节挂掉,担心某次操作让整个系统宕机。遗憾的是,墨菲定律告诉我们,“如果事情有变坏的可能,不管这种可能性有多小,它总会发生。

    之前一个发生在身边的项目经历大概是这样的:一个团队提供基础服务,并承诺服务的功能、性能、弹性都没有问题。在集成联调时,由于对认证服务的调用超过负荷,对整个服务系统造成阻塞,导致雪崩效应,几乎所有客户端应用大面积瘫痪;另一个案例,由于没有对一个内容服务进行熔断保护,导致整个网站首页无法加载。而发生在世界各地的IT灾难也不少,某航空公司,由于调度和跟踪系统出现问题,导致去年6月份七天内将近3000个航班取消,损失3500万美金;“信息灾难总是普遍而没有偏见地发生在各个领域和任何时候”。

    既然我们没有办法避免灾难的发生,最好的办法就是“探索系统故障边界,验证系统灾难恢复能力”。以往的“机房”时代的一些故障演练一般通过断网、断电模拟单点故障,来测试系统的恢复能力,而新型的分布式服务时代消除了单点故障,但也引入了更多复杂的问题,我们需要可靠性更强、容错性和扩容性更高的系统。一种解决方案就是,我们需要一种有策略的、有方法的实践方案对系统进行一定程度的“随机破坏”,通过让系统”感染“,来提升系统的”免疫力“。Netflix开发出Chaos Monkey来对系统进行随机试验来了解系统是否具有高可用性和容错性,而由此便诞生出”混沌工程“。


    什么是混沌工程?混沌工程原则是什么?

    混沌工程是一种可试验的、基于系统的方法来处理大规模分布式系统中的混乱问题。通过不断试验,了解系统的实际能承受的韧性边界并建立信心,通过不同的试验方法和目的,观察分布式系统的行为和反应。一句话——以试验的方法尽早揭露系统弱点

    混沌工程类似于“故障演练”,不局限于测试,而更像是工程实践。为什么这么说,通常的测试用例会有“期望结果”和“实际结果”,通过将两个结果比较,或者对用户行为的预期,来判断测试通过或失败。而混沌试验类似于”探索性测试“,试验本身没有明确是输入和预期结果,通过对系统和服务的干预,来观察系统的”反应“。我们将混沌工程原则融入在试验过程中:在生产环境小规模模拟系统故障并定期自动化执行试验,通过试验结果与正常结果进行比对,观察系统”边界“。

    dc84c9921227596c589c1a00b2dba865.png

    通过“测试金字塔”和混沌试验,从业务逻辑和系统高可用性两个维度对微服务系统进行观察和测试,两种方案结合形成了一种更全面的实践,我称之为“服务级质量内建实践”(BQIS——Build Qualify in Services)。不论企业是在微服务改造期还是中台战略部署期,混沌实践能够有效避免生产环境灾难,提升系统的容错率和可用性。


    如何引入混沌工程?

    在众多服务化改造案例中,Netflix无疑是最成功的公司之一,该公司的很多试验工具也都集成在Spring Cloud中,成为微服务框架的标准。而Chaos Monkey就是Netflix进行混沌试验一个重要工具。作为国内的电商巨头,服务化和中台战略的先行者阿里,近期也开源了他们自己的混沌试验注入工具ChaosBlade。

    “混沌工程”的引入受限于组织文化的接受程度,任何一种工程实践和方法论的落地都无法一蹴而就。但是我们依然可以通过裁剪,在组织的安全范围内进行逐步尝试。不管是在线上环境还是测试环境,我们都需要先搞清楚,目前的混沌工具都为我们提供了哪些方法。

    Spring Cloud是时下最流行的分布式微服务架构下的一站式解决方案之一,它方便快速的将Spring Boot的微服务有效的管理起来,并提供了包括负载均衡、全链路监控、服务网关以及众多基于Netflix的开源工具。除此之外,鉴于Netflix在服务化演进中的成功案例,我们来了解下Netflix开源的混沌工程试验框架Chaos Monkey究竟是什么?

    在Spring Boot工程中,对需要进行试验的服务application.yml文件的Chaos Monkey进行配置:

    5d055a346de29407da2924c7ba0b216a.png

    从配置文件中我们可以很容易看到,Chaos Monkey的三种袭击方式——延时、异常和进程终止,同时我们也可以设置一个数值范围,在对服务进行延时攻击时生成随机延时。默认攻击方式为延时攻击,当同时开启异常攻击时,进程攻击则不会发生。Level:N表示第N个请求将被攻击,N=1时,表示每个请求都会被攻击,当同时开启异常攻击时,与N值无关,表示每个请求都将被攻击。

    ChaosBlade提供的攻击也很丰富,使用方式对开发人员来说更友好:

    f4d9a4970111ffd81de655e07d2f17f0.png

    通过命令行对CPU、硬盘、网络进行试验,也可以对相应的服务进行类似的例如延时攻击试验:

    449888a68e4ed574f7c8e43d97df3830.png

    利用性能测试工具例如Jmeter或Gatling,对于API进行测试,例如POST /product?des=phone,通过性能测试报告对比API性能指标以及Hystrix监控分析相关服务“反应”,同时也可以通过Grafana和CloudWatch监控各个系统参数来和“稳定基线数据”进行比较和观察。


    混沌试验示例

    试验一:

    1.确定目标和范围,观察CPU利用率基线(CPU平均利用率低于20%)

    932140ce3ca7c6b01ddaee0fd2acb8e3.png

    观察API延时基线:(可以看到API-1和API-2平均延时低于300ms,API-3在300ms-700ms之间)

    cf01d984c6e6dabdab6cc60df3bc08ec.png

    2.设计实验数据和方案,我们对几个实例进行CPU满载攻击:

    48f5ad56beefeeef9d7d9ce33d98d33f.png

    观察CPU利用率:

    d7f8177aae9996dbdc425db8b24643d8.png

    观察API延时:(API请求延时变化明显,API-3延时更加严重)

    d29d32d940232624e4b769be943ee2ac.png

    试验二:测试服务熔断机制

    示例项目架构:Eureka服务发现注册,一个PROVIDER-SERVICE且有两个实例,一个CONSUMER-SERVICE,也可以通过zipkin之类的分布式跟踪系统也可以看到服务调用关系。

    d27fc9a49bebf9de3f23eb4ad227be9a.png

    1.对PROVIDER-SERVICE的实例2进行延时攻击

    a29dfe61ee2489b50582aff0260b7ce6.png

    2.查看PROVIDER-SERVICE instance 2的延时是否生效通过postman测试,可以看到API响应为30s:

    b23498b7d8adc4294dbb68658ba7f6af.png

    3.客户端请求相同的API

    60c47934caca34ac334d7fafaf2c1167.png

    观察结果:负载均衡生效,请求成功,熔断器关闭

    4.杀掉instance 1之后请求相同API

    a6baa3b065f9bf176697322cf46eff96.png

    观察结果:请求超时,熔断器关闭

    5.连续且请求相同API

    2dd496b8590f4b0c12a6cdc8337d7dd9.png

    观察结果:部分请求被立刻拒绝,加速服务失败的判定,熔断器开启

    6.杀掉instance 2请求API:

    773d9bf5782e22093de117751aa5b6d0.png

    观察结果:fallback机制生效,返回相应逻辑。

    这些只是混沌工程的简单使用方法,在实际项目中需要根据项目架构、业务复杂度、调用场景等设计试验细节。


    总结

    从业务的横切面到对微服务系统的纵切面观察,“契约测试”固然重要,但并不能代表微服务质量保证的全部。“蛮力”可以从某种意义上解决很多问题,但并不能催化出更高阶解决方案。同样,也只有了解到微服务的实现方式和原理才能够更好的理解系统并实施更有效的质量解决方案。

    Netflix对混沌工程的成熟度从“复杂度”和“接受度”两个方面给出了定义,可以看到,混沌工程或试验不单单是方法论的引入,更是实践上的渗透。用“Immersion”解释更加确切,与敏捷实践类似,这样的“服务级质量内建试验”对团队来说开始无疑是一种挑战,但随着越来越多的问题更快、更早的可视化给团队,使组织和客户对我们构建和改造中的系统越来越有信心。通过小规模实践到大规模改造,混沌工程不是为了测试,更不是为了引入工具, 混沌工程会像一种文化,将扩散于范围更广的团队和组织。

    0e159a71b155b8393532a5ea7a363f63.png

    先进制造业+工业互联网


    产业智能官  AI-CPS

    加入知识星球“产业智能研究院”:先进制造业OT(自动化+机器人+工艺+精益)和工业互联网IT(云计算+大数据+物联网+区块链+人工智能)产业智能化技术深度融合,在场景中构建“状态感知-实时分析-自主决策-精准执行-学习提升”的产业智能化平台;实现产业转型升级、DT驱动业务、价值创新创造的产业互联生态链。

    产业智能化平台作为第四次工业革命的核心驱动力,将进一步释放历次科技革命和产业变革积蓄的巨大能量,并创造新的强大引擎;重构设计、生产、物流、服务等经济活动各环节,形成从宏观到微观各领域的智能化新需求,催生新技术、新产品、新产业、新业态和新模式;引发经济结构重大变革,深刻改变人类生产生活方式和思维模式,实现社会生产力的整体跃升。产业智能化技术分支用来的今天,制造业者必须了解如何将“智能技术”全面渗入整个公司、产品、业务等商业场景中,利用工业互联网形成数字化、网络化和智能化力量,实现行业的重新布局、企业的重新构建和焕然新生。

    3d1db9e2448ba57fb13ccf1b5b0b00f8.png

    版权声明产业智能官(ID:AI-CPS)推荐的文章,除非确实无法确认,我们都会注明作者和来源,涉权烦请联系协商解决,联系、投稿邮箱:erp_vip@hotmail.com。

    展开全文
  • 微服务作为架构风格几乎成为云时代企业...本文是对企业分布式应用的一次回顾,与前微服务时代相比,我们究竟哪些领域吸取了教训,哪些方面持续搞砸。我们重新界定抽象边界上取得了进展…架构关键在于构造合理...

    微服务作为架构风格几乎成为云时代企业级应用的事实标准,构成微服务的技术元素本身却并非革命性。跨平台的分布式通信框架、地址无关的服务注册与发现、智能路由与编排等技术早已在CORBA、SOA时代实现了一遍又一遍,我们不禁好奇,微服务有什么不同?本文是对企业分布式应用的一次回顾,与前微服务时代相比,我们究竟在哪些领域吸取了教训,哪些方面持续搞砸。

    我们在重新界定抽象边界上取得了进展…

    架构的关键在于构造合理的封装抽象。良好的抽象构造如进程,由操作系统接管CPU调度、内存地址空间分配和I/O,程序员的心智从此解放,得以聚焦在业务逻辑上。糟糕的抽象往往引向万丈深渊,大量精力被浪费在抽象泄露带来的问题上。

    在分布式系统中我们关注组件、组件间的通信以及伴随的工程实践,微服务在企业应用的上下文中就技术约束和业务价值间达成了更好的平衡点。

    RPC?不,是API!

    让我们从组件间的通信开始,最初人们认为这只是需要被解决的技术要素。

    5ee0d1c64bca8f3cd69b7a2995486c56.png

    (图片来自:https://upload.wikimedia.org/wikipedia/en/thumb/f/f0/Orb.svg/802px-Orb.svg.png)

    关于如何实现跨平台的分布式通信,30年前诞生的CORBA架构在今天来看仍然非常漂亮:通过定义IDL/ORB/API我们可以将内存对象任意分布于网络中。只要共享IDL,对象可以由C++/Java等不同的语言实现,其互相调用就像本地方法一样简单。然而实践经验告诉我们,分布式系统总是会出现本地调用不会发生的各种问题:网络的开销、传输的延迟、消息的超时和丢包、远端系统的崩溃……物理世界的技术约束是无法被忽略的,我们没有办法把分布式调用抽象成简单的本地方法。因此Martin Fowler在他的< 企业应用架构模式>里提出了著名分布式对象第一定律:“不要分布式你的对象”。相反,你应该把尽可能多的操作置于进程之内,通过replicate整个应用的方式来实现系统的scale。

    由分析师们发起的SOA运动从另一个角度看待这个问题,Web Service应该是对企业资产和业务能力的封装。我们开始站在更高的维度,远过程调用不再只是技术意义上的集成。WSDL不仅是通信调用的接口,更是服务间的契约;UDDI不仅是服务描述、发现、集成的中心,更是企业业务与服务的黄页。WS-*在厂商的裹挟下发展成包罗万象,却也没几个人能掌握。开发者们抱怨花了太多时间写冗余的XML制定所谓的规范,WSDL生成的客户端也将不同服务耦合在一起。是否有更加轻量敏捷的方式,让我们快点开始写第一行生产代码?

    于是我们看到REST的兴起。起初是作为反叛,用更加轻量级的方式(http+json)使用Web。然后我们发现”企业级”应用并非需要ESB这样昂贵的专有中间件,由”消费级”技术组成的万维网是世界上最大规模的分布式网络,我们应该向其学习如何构建健壮、可演化的系统。Roy Fielding那篇论文所提出的无状态、可缓存等特征已经深入人心,而狭义上的REST API(基于资源的URI、HTTP动词和状态码的标准接口)也成为API设计的最佳实践。

    既然API和网站一样都是基于通用Web技术,API是否可以像网站一样作为产品提供呢(APIs as product)?于是越来越多的企业开始将自己的业务能力封装成API,提供给消费者,随之而来的是更弹性的商业应用和更灵活的计费方式。很多组织也着手构建自己的API市场,把内部IT能力整合、复用,并为孵化外部产品做准备。API已经成为商业价值主张的一部分。

    我们从聚焦实现细节的rpc出发,来到了更具价值导向的REST API。即使构建内部系统,以消费者驱动的方式,也总是能帮助我们设计出更加松耦合和易于演进的API。

    技术组件?不,是业务服务!

    编程语言中的组件构造(如Java中的jar, C#中的dll)是软件架构师们封装可复用单元的最常用武器。组件作为理论上的最小部署单元,在工程实践中却并不容易独立变更。一般应用程序需要讲多个组件打包成一个部署单元(如war包),链接在内存地址中进行调用。对单个组件的热更新往往对组件间耦合和对象状态管理有很高的要求,重新部署整个应用一般是默认选项。以进程为边界构建可独立部署的服务成为架构师的另一项选择。

    早期的服务只是单纯的技术构件,大多数组织从纯粹的技术实现角度考虑服务的划分。SOA的推动者们指出企业的信息资产应该被复用,信息孤岛应该被打通。通过将不同的服务编排组合,我们应该能够实现IT对业务更加灵活的支撑。

    5ca8f7e4731ec7dc524075596c013b50.png

    (图片来自:0SOA in practice, Nicolai Josuttism, 2009)

    SOA的服务建模一般采用业务流程驱动的方式。一个典型的SOA设计是由业务分析师自顶向下地对企业现有业务流程进行分析,通过BPM引擎对流程进行建模,向下分解成组合服务,并进一步拆分成数据访问服务(很多可怜的SOA实现中数据的访问被拆分成不同的读服务和写服务)。然而这带来的问题是,服务跟服务间的耦合非常严重。当我的业务发生了变化,可能会需要修改很多不同的服务,涉及到多个团队的沟通和协调。在运行时层面,服务器间的通信非常频繁,用户在界面上的一次点击按钮,对应的后台多层服务间的级联通信。这给系统性能和稳定性也带来了巨大的挑战。SOA式的服务建模从分析型思维出发,却往往低估了分布式系统和跨团队协调的复杂度,导致服务拆分粒度过细。

    微服务的名字常常让人误解,但实施正确的微服务粒度可能并不”微”。Martin Fowler与James Lewis在开创微服务定义的一文中已经指出微服务应该围绕完整的业务能力。今天我们在做微服务设计时,常常利用领域驱动设计中的Bounded Context来进行服务边界的划分。假设你的库存管理是一个独立的业务子域,针对库存的维护和操作应该被放到通过一个上下文和微服务中,由一个团队进行开发维护。多数业务变更都发生在上下文内部,不涉及跨团队协调。单个codebase内的重构和部署让发布更加容易。维护库存所需要的信息查询的调用多发生在进程内,更好的性能,同时无需处理额外的一致性问题。

    522c5ddff5d89aba82180a58cfc3667b.png

    微服务的另一个特点在于Product over Project,这需要不同于传统投资组合的预算管理与团队组建。传统的项目制将预算分配在相对短期的服务开发过程中,项目团队关注的是如何将业务范围(scope)实现,开发结束后服务转交运维团队进行维护,项目团队则被解散进行其他项目的开发。将微服务作为产品运营则需要建立业务结果导向的稳定产品团队。服务的设计不只聚焦于当下需求,更需要考虑价值定位和产品愿景。工程团队则需要思考如何用有限成本支撑非线性的业务接入增长。

    9fbb5304105791051aa3933d91988e5f.png

    (图片来自:Enterprise Architecture as Strategy, Ross et al, 2006

    如今我们对服务的定义已经超越了技术组件,领先的组织已经在尝试将design thinking, business operating model应用到微服务设计中。

    解耦服务就足够了吗?我们需要去中心化一切!

    即使有了设计合理的服务于API,我们仍然需要与之匹配的工程实践才能将其顺利实施。

    今天仍有很多企业使用集中式的应用服务器部署应用:开发团队将软件包构建出来,再统一安装到应用服务器中。对应用团队来说,这往往意味着漫长的反馈周期和痛苦的自动化。我们很早就推荐用Jetty这样内嵌式的应用容器部署软件,启动更快,测试环境更接近生产。one Tomcat per VM的部署方式虽然运行时开销较大,却是前容器时代隔离性最好的服务部署模式。Docker将这个实践更进一步,除了更轻量级的隔离,我们第一次可以将软件和所依赖的环境本身打包成版本化的artifact,彻底统一开发和生产环境。容器技术的成熟让我们可以将部署去中心化,开发团队可以独立部署一个服务。

    数据库耦合是影响服务独立变更的另一重要因素。相比代码构成的应用软件,数据库schema更加难以变动。因为难以测试、难以兼顾性能优化和耦合的发布周期等因素,服务间以数据库集成成为臭名昭著的反模式。服务间的集成应该依赖封装好的显示接口,而不是数据库这种实现细节。我们应该在兼顾数据一致性的情况下,为每个微服务分配独立的db schema甚至db instance。如果说十年前数据几乎等同于关系数据库。如今数 据则可能呈现出各种形态:键值、文档、时间序列、图…我们完全可以采用更加合适的技术,以去中心化的方式进行微服务的数据治理。

    即使将这一切都解耦,如果将交给一个集中的团队去实施,很有可能最终还是得到一个耦合的架构。这就是是著名的康威定律。康威定律告诉我们“设计系统的架构受制于产生这些设计的组织的沟通结构”。但同样我们可以将康威定律反转应用:如果你想达成一个目标架构,则必须对团队结构进行调整,使之和目标架构对齐。相比单体系统,微服务在运行时监控和运维所带来的挑战更大。”you build it, you run it”的DevOps文化成为必须。监控运维不再是Ops部门的事情,产品团队必须对微服务的整个生命周期负责。授权的去中心化自治团队是实施微服务的必要条件。

    我们干得还不错,但也在持续搞砸一些事情…

    我们在很多方向的确取得了进展。但即使在微服务时代,很多问题仍然在轮回发生着,似乎我们总是无法吸取历史的教训。让我们看一看那些挥之不去的反模式阴云。

    一个例子是开发者对强类型RPC代码生成的依恋。尽管历史经验已经证明同步的rpc无法为分布式通信提供足够好的封装,伪装成本地方法调用的客户端往往鼓励程序员做出糟糕的接口设计:细粒度的频繁调用、缺少缓存和容错处理。IDL生成客户端也会导致服务间耦合,每次变更接口都需要升级数个相关服务。如果用可演进的REST API(如HATEOS)和tolerant reader模式,则可以优雅地解决这个问题。然而新一代的开发者们还是经常“重新”发现rpc的这些能力并陷入依赖——更快的序列化反序列化、类型安全和来自IDE的智能提示、通过spec反向生成代码…分布式计算先驱Vinoski不禁感叹“开发人员的便利性是否真的胜过正确性,可扩展性,性能,关注点分离,可扩展性和意外复杂性?”

    另一个挥之不去的阴影是ESB。ESB在将异构的应用wire在一起有着关键的作用。然而当越来越多的职责被加入:数据报文的裁剪转换、难以测试和版本控制的编排(orchection)逻辑、服务发现智能路由监控治理分布式事务等All in One的solution将ESB变成了一个可怕的单点梦魇。所以微服务发出了“智能终端哑管道”的呐喊:我们只是需要一个不那么智能的代理处理可靠消息传输,将灵活的逻辑交给服务本身去编配(choreography)吧。

    于是在典型的微服务架构里,负载均衡、服务注册发现、分布式追踪等组件以Unix way的方式各司其职。然而在利益诱惑和特性竞争压力之下,很多厂商不断将更多的功能放进他们的中间件,其中为代表的Overambitious API gateways俨然要重新实现占据中心的ESB。如果API gateway只是处理鉴权、限流等横切层逻辑没有问题,如果API gateway开始处理数据转换和业务逻辑编排,你应该提高警惕!

    尽管行业在不断发展,但很多时候人们仍然沿用旧的思维,用新的技术去一遍遍重新实现这些旧的反模式。

    如何更进一步

    你总是可以在技术雷达里追踪微服务的state of art,如今这个领域的前沿方向是什么,Service Mesh, Chaos Engineering, 还是Observability as Code?然而历史告诉我们,新的技术在解决一些问题的同时,也可能会产生新的问题。更糟糕的是,我们永远无法记住历史,用新的工具更高效地重现旧日问题。

    Technologies come and go, Principles stay forever。好在那些架构和实践背后的原则是经久不变的。从操作系统到移动应用都会需要高内聚低耦合的架构,任何软件开发都需要版本控制、自动化构建等实践。谨记这些核心原则、谨记软件被创造出来是为了解决有价值的问题,可以帮我们更好的借鉴历史的经验,理解和采纳新的技术。

    853cb534dc9c2f3cd4f0597f18acbbea.png

    文/ThougtWorks刘尚奇

    本文首发于刘尚奇个人网站:溯源微服务:企业分布式应用的一次回顾

    更多精彩洞见请关注微信公众号:ThougtWorks洞见

    展开全文
  • 微服务作为架构风格几乎成为云时代企业应用...本文是对企业分布式应用的一次回顾,与前微服务时代相比,我们究竟哪些领域吸取了教训,哪些方面持续搞砸。 我们重新界定抽象边界上取得了进展... 架构关键在于...

    微服务作为架构风格几乎成为云时代企业级应用的事实标准,构成微服务的技术元素本身却并非革命性。跨平台的分布式通信框架、地址无关的服务注册与发现、智能路由与编排等技术早已在CORBA、SOA时代实现了一遍又一遍,我们不禁好奇,微服务有什么不同?本文是对企业分布式应用的一次回顾,与前微服务时代相比,我们究竟在哪些领域吸取了教训,哪些方面持续搞砸。

    我们在重新界定抽象边界上取得了进展...

    架构的关键在于构造合理的封装抽象。良好的抽象构造如进程,由操作系统接管CPU调度、内存地址空间分配和I/O,程序员的心智从此解放,得以聚焦在业务逻辑上。糟糕的抽象往往引向万丈深渊,大量精力被浪费在抽象泄露带来的问题上。

    在分布式系统中我们关注组件、组件间的通信以及伴随的工程实践,微服务在企业应用的上下文中就技术约束和业务价值间达成了更好的平衡点。

    RPC?不,是API!

    让我们从组件间的通信开始,最初人们认为这只是需要被解决的技术要素。

    (图片来自:https://upload.wikimedia.org/wikipedia/en/thumb/f/f0/Orb.svg/802px-Orb.svg.png)

    关于如何实现跨平台的分布式通信,30年前诞生的CORBA架构在今天来看仍然非常漂亮:通过定义IDL/ORB/API我们可以将内存对象任意分布于网络中。只要共享IDL,对象可以由C++/Java等不同的语言实现,其互相调用就像本地方法一样简单。然而实践经验告诉我们,分布式系统总是会出现本地调用不会发生的各种问题:网络的开销、传输的延迟、消息的超时和丢包、远端系统的崩溃……物理世界的技术约束是无法被忽略的,我们没有办法把分布式调用抽象成简单的本地方法。因此Martin Fowler在他的< 企业应用架构模式>里提出了著名分布式对象第一定律:“不要分布式你的对象”。相反,你应该把尽可能多的操作置于进程之内,通过replicate整个应用的方式来实现系统的scale。

    由分析师们发起的SOA运动从另一个角度看待这个问题,Web Service应该是对企业资产和业务能力的封装。我们开始站在更高的维度,远过程调用不再只是技术意义上的集成。WSDL不仅是通信调用的接口,更是服务间的契约;UDDI不仅是服务描述、发现、集成的中心,更是企业业务与服务的黄页。WS-*在厂商的裹挟下发展成包罗万象,却也没几个人能掌握。开发者们抱怨花了太多时间写冗余的XML制定所谓的规范,WSDL生成的客户端也将不同服务耦合在一起。是否有更加轻量敏捷的方式,让我们快点开始写第一行生产代码?

    于是我们看到REST的兴起。起初是作为反叛,用更加轻量级的方式(http+json)使用Web。然后我们发现"企业级"应用并非需要ESB这样昂贵的专有中间件,由"消费级"技术组成的万维网是世界上最大规模的分布式网络,我们应该向其学习如何构建健壮、可演化的系统。Roy Fielding那篇论文所提出的无状态、可缓存等特征已经深入人心,而狭义上的REST API(基于资源的URI、HTTP动词和状态码的标准接口)也成为API设计的最佳实践。

    既然API和网站一样都是基于通用Web技术,API是否可以像网站一样作为产品提供呢(APIs as product)?于是越来越多的企业开始将自己的业务能力封装成API,提供给消费者,随之而来的是更弹性的商业应用和更灵活的计费方式。很多组织也着手构建自己的API市场,把内部IT能力整合、复用,并为孵化外部产品做准备。API已经成为商业价值主张的一部分。

    我们从聚焦实现细节的rpc出发,来到了更具价值导向的REST API。即使构建内部系统,以消费者驱动的方式,也总是能帮助我们设计出更加松耦合和易于演进的API。

    技术组件?不,是业务服务!

    编程语言中的组件构造(如Java中的jar, C#中的dll)是软件架构师们封装可复用单元的最常用武器。组件作为理论上的最小部署单元,在工程实践中却并不容易独立变更。一般应用程序需要讲多个组件打包成一个部署单元(如war包),链接在内存地址中进行调用。对单个组件的热更新往往对组件间耦合和对象状态管理有很高的要求,重新部署整个应用一般是默认选项。以进程为边界构建可独立部署的服务成为架构师的另一项选择。

    早期的服务只是单纯的技术构件,大多数组织从纯粹的技术实现角度考虑服务的划分。SOA的推动者们指出企业的信息资产应该被复用,信息孤岛应该被打通。通过将不同的服务编排组合,我们应该能够实现IT对业务更加灵活的支撑。

    (图片来自:0SOA in practice, Nicolai Josuttism, 2009)

    SOA的服务建模一般采用业务流程驱动的方式。一个典型的SOA设计是由业务分析师自顶向下地对企业现有业务流程进行分析,通过BPM引擎对流程进行建模,向下分解成组合服务,并进一步拆分成数据访问服务(很多可怜的SOA实现中数据的访问被拆分成不同的读服务和写服务)。然而这带来的问题是,服务跟服务间的耦合非常严重。当我的业务发生了变化,可能会需要修改很多不同的服务,涉及到多个团队的沟通和协调。在运行时层面,服务器间的通信非常频繁,用户在界面上的一次点击按钮,对应的后台多层服务间的级联通信。这给系统性能和稳定性也带来了巨大的挑战。SOA式的服务建模从分析型思维出发,却往往低估了分布式系统和跨团队协调的复杂度,导致服务拆分粒度过细。

    微服务的名字常常让人误解,但实施正确的微服务粒度可能并不"微"。Martin Fowler与James Lewis在开创微服务定义的一文中已经指出微服务应该围绕完整的业务能力。今天我们在做微服务设计时,常常利用领域驱动设计中的Bounded Context来进行服务边界的划分。假设你的库存管理是一个独立的业务子域,针对库存的维护和操作应该被放到通过一个上下文和微服务中,由一个团队进行开发维护。多数业务变更都发生在上下文内部,不涉及跨团队协调。单个codebase内的重构和部署让发布更加容易。维护库存所需要的信息查询的调用多发生在进程内,更好的性能,同时无需处理额外的一致性问题。

    微服务的另一个特点在于Product over Project,这需要不同于传统投资组合的预算管理与团队组建。传统的项目制将预算分配在相对短期的服务开发过程中,项目团队关注的是如何将业务范围(scope)实现,开发结束后服务转交运维团队进行维护,项目团队则被解散进行其他项目的开发。将微服务作为产品运营则需要建立业务结果导向的稳定产品团队。服务的设计不只聚焦于当下需求,更需要考虑价值定位和产品愿景。工程团队则需要思考如何用有限成本支撑非线性的业务接入增长。

    (图片来自:Enterprise Architecture as Strategy, Ross et al, 2006

    如今我们对服务的定义已经超越了技术组件,领先的组织已经在尝试将design thinking, business operating model应用到微服务设计中。

    解耦服务就足够了吗?我们需要去中心化一切!

    即使有了设计合理的服务于API,我们仍然需要与之匹配的工程实践才能将其顺利实施。

    今天仍有很多企业使用集中式的应用服务器部署应用:开发团队将软件包构建出来,再统一安装到应用服务器中。对应用团队来说,这往往意味着漫长的反馈周期和痛苦的自动化。我们很早就推荐用Jetty这样内嵌式的应用容器部署软件,启动更快,测试环境更接近生产。one Tomcat per VM的部署方式虽然运行时开销较大,却是前容器时代隔离性最好的服务部署模式。Docker将这个实践更进一步,除了更轻量级的隔离,我们第一次可以将软件和所依赖的环境本身打包成版本化的artifact,彻底统一开发和生产环境。容器技术的成熟让我们可以将部署去中心化,开发团队可以独立部署一个服务。

    数据库耦合是影响服务独立变更的另一重要因素。相比代码构成的应用软件,数据库schema更加难以变动。因为难以测试、难以兼顾性能优化和耦合的发布周期等因素,服务间以数据库集成成为臭名昭著的反模式。服务间的集成应该依赖封装好的显示接口,而不是数据库这种实现细节。我们应该在兼顾数据一致性的情况下,为每个微服务分配独立的db schema甚至db instance。如果说十年前数据几乎等同于关系数据库。如今数 据则可能呈现出各种形态:键值、文档、时间序列、图...我们完全可以采用更加合适的技术,以去中心化的方式进行微服务的数据治理。

    即使将这一切都解耦,如果将交给一个集中的团队去实施,很有可能最终还是得到一个耦合的架构。这就是是著名的康威定律。康威定律告诉我们“设计系统的架构受制于产生这些设计的组织的沟通结构”。但同样我们可以将康威定律反转应用:如果你想达成一个目标架构,则必须对团队结构进行调整,使之和目标架构对齐。相比单体系统,微服务在运行时监控和运维所带来的挑战更大。"you build it, you run it"的DevOps文化成为必须。监控运维不再是Ops部门的事情,产品团队必须对微服务的整个生命周期负责。授权的去中心化自治团队是实施微服务的必要条件。

    我们干得还不错,但也在持续搞砸一些事情...

    我们在很多方向的确取得了进展。但即使在微服务时代,很多问题仍然在轮回发生着,似乎我们总是无法吸取历史的教训。让我们看一看那些挥之不去的反模式阴云。

    一个例子是开发者对强类型RPC代码生成的依恋。尽管历史经验已经证明同步的rpc无法为分布式通信提供足够好的封装,伪装成本地方法调用的客户端往往鼓励程序员做出糟糕的接口设计:细粒度的频繁调用、缺少缓存和容错处理。IDL生成客户端也会导致服务间耦合,每次变更接口都需要升级数个相关服务。如果用可演进的REST API(如HATEOS)和tolerant reader模式,则可以优雅地解决这个问题。然而新一代的开发者们还是经常“重新”发现rpc的这些能力并陷入依赖——更快的序列化反序列化、类型安全和来自IDE的智能提示、通过spec反向生成代码...分布式计算先驱Vinoski不禁感叹“开发人员的便利性是否真的胜过正确性,可扩展性,性能,关注点分离,可扩展性和意外复杂性?”

    另一个挥之不去的阴影是ESB。ESB在将异构的应用wire在一起有着关键的作用。然而当越来越多的职责被加入:数据报文的裁剪转换、难以测试和版本控制的编排(orchection)逻辑、服务发现智能路由监控治理分布式事务等All in One的solution将ESB变成了一个可怕的单点梦魇。所以微服务发出了“智能终端哑管道”的呐喊:我们只是需要一个不那么智能的代理处理可靠消息传输,将灵活的逻辑交给服务本身去编配(choreography)吧。

    于是在典型的微服务架构里,负载均衡、服务注册发现、分布式追踪等组件以Unix way的方式各司其职。然而在利益诱惑和特性竞争压力之下,很多厂商不断将更多的功能放进他们的中间件,其中为代表的Overambitious API gateways俨然要重新实现占据中心的ESB。如果API gateway只是处理鉴权、限流等横切层逻辑没有问题,如果API gateway开始处理数据转换和业务逻辑编排,你应该提高警惕!

    尽管行业在不断发展,但很多时候人们仍然沿用旧的思维,用新的技术去一遍遍重新实现这些旧的反模式。

    如何更进一步

    你总是可以在技术雷达里追踪微服务的state of art,如今这个领域的前沿方向是什么,Service Mesh, Chaos Engineering, 还是Observability as Code?然而历史告诉我们,新的技术在解决一些问题的同时,也可能会产生新的问题。更糟糕的是,我们永远无法记住历史,用新的工具更高效地重现旧日问题。

    Technologies come and go, Principles stay forever。好在那些架构和实践背后的原则是经久不变的。从操作系统到移动应用都会需要高内聚低耦合的架构,任何软件开发都需要版本控制、自动化构建等实践。谨记这些核心原则、谨记软件被创造出来是为了解决有价值的问题,可以帮我们更好的借鉴历史的经验,理解和采纳新的技术。


    文/ThougtWorks刘尚奇

    本文首发于刘尚奇个人网站:https://6up7.com/a-retrospective-for-enterprise-distributed-application/

    更多精彩洞见请关注微信公众号:ThougtWorks洞见

    转载于:https://juejin.im/post/5cd2402cf265da03973ac540

    展开全文
  • 微服务好像是这两年突然火起来,其实和很...这些年来,我们帮助一些客户分布式/微服务架构方面进行了一些尝试与实践,这个过程中碰到了以前单体应用下很少需要特意关注问题。比如数据一致性、比如statelesss
  • 本篇文章从企业分布式应用架构层面介绍了云原生计算架构带来的变化,希望能够帮助更多企业的 IT 转型,利用云计算技术推动其成为市场竞争中的敏捷力量。 进入 21 世纪以来,我们见证了企业分布式应用架构从 SOA ...

    阿里妹导读:从十余年前的各种分布式系统研发到现在的容器云,从支撑原有业务到孵化各个新业务,企业的发展离不开统一的、与时俱进的技术架构。本篇文章从企业分布式应用架构层面介绍了云原生计算架构带来的变化,希望能够帮助更多企业的 IT 转型,利用云计算技术推动其成为市场竞争中的敏捷力量。

    进入 21 世纪以来,我们见证了企业分布式应用架构从 SOA (Service-oriented Architecture),到微服务架构,再到云原生应用架构的演化。

    为了说明企业架构演化背后的思考,我们先谈一些玄学。

    • 第一,企业 IT 系统的复杂性(熵)符合热力学第二定律。随着时间的推演,业务的变化,企业 IT 系统的复杂度会越来越高;
    • 第二,在计算机交互设计中有一个著名的复杂性守恒定律[1]。应用交互的复杂性不会消失,只会换一种方式存在。这个原理也同样适用于软件架构。引入新的软件架构,不会降低IT系统的整体复杂性。

    听到这里,是否让生命不息、折腾不止的我们感到一丝凉凉?

    现代软件架构的核心任务之一就是定义基础设施与应用的边界,合理切分复杂性,减少应用开发者需要面对的复杂性。换句话说,就是让开发者专注在核心价值创新上,而把一些问题交给更合适的人和系统来解决。

    我们就从下面这张图开始,探究企业分布式应用架构演进背后的逻辑。

    蜕变之痛:SOA

    2004 年,IBM 建立 SOA 全球设计中心,我作为研发 TL 和架构师参与了一系列全球客户的 pilot 项目,帮助 Pepboys, Office Depot 等国际企业利用 SOA 优化企业内部和企业间的业务流程,提升业务敏捷性。

    当时的大背景是:随着经济全球化逐渐深入,企业面对的竞争加剧,商业变革也开始提速。在大型企业内部的 IT 系统已经经过了数十年的演化,整个的技术体系变得异常复杂,并存着诸如主机系统上的 CISC/COBOL 交易应用,小型机 AS400 中的 RPG 业务系统,和 X86/Power 等分布式系统的 C/JEE/.Net 应用。

    大量应用系统由三方供应商提供,一些系统甚至已经无人维护。而且随着业务迭代,一些新的业务系统被持续构建出来,由于缺乏合理的方法论指导,系统之间缺乏有机的链接,形成了若干的孤岛,持续加剧了 IT 架构的复杂性,无法支撑业务的发展诉求。这就仿佛各派高手为了帮助受伤的令狐冲,把异种真气输入体中,虽然短时间可以缓解伤势。可是多道真气无法融合,互相激荡,长时间下来会伤上加伤。

    因此,企业 IT 所面临的首要挑战就是整合企业中大量竖桶型(silo-ed)的 IT 系统,支撑日益复杂的业务流程,进行高效的业务决策和支撑业务快速变化。

    在这种背景下,IBM 等公司提出了 SOA(面向服务的架构)理念,将应用系统抽象成一个个粗粒度的服务,构建松耦合服务架构,可以通过业务流程对服务进行灵活组合,提升企业 IT 资产复用,提高了系统的适应性、灵活性和扩展性,解决“信息孤岛”问题。

    SOA 提出了一系列构建分布式系统的原则,这些思考直到今天也依然适用:

    • 服务具备明确定义的标准化的接口。通过服务定义描述,将服务消费者(Service Consumer)和服务提供者 (Service Provider) 的实现进行解耦,并且服务应该采用 contract-first 而非 code-first 方式进行开发。服务间通信采用面向文档的消息而非特定语言 RPC 协议,一方面可以解决服务与实现语言的解耦,另一方面可以灵活选择同步或者异步的通信实现,提升系统可用性和可伸缩性;
    • 服务应该是松耦合的,服务之间不应存在时间、空间、技术、团队上的依赖;
    • 服务应该是无状态的,使得服务调用与会话上下文状态实现解耦;
    • 服务应该是自治和自包含的,服务的实现是可以独立进行部署、版本控制、自我管理和恢复;
    • 服务是可发现、可组合的。比如可以通过 Service Registry 进行服务发现,实现了服务消费者和服务提供者的动态绑定。业务流程中可以对来自不同系统的的业务服务进行编排组装。

    在初始构建 SOA 系统的时候,大多采用点对点的通信连接,服务调用和集成逻辑被内嵌在应用实现中。这种方式在服务数量比较少的时候,确实是一种简单和高效的开发方式。但其最大的问题是,随着服务规模的增长,服务之间通信愈发复杂,连接路径和复杂性会剧增,给服务治理带来巨大的挑战。

    为了解决上述挑战,企业服务总线 (Enterprise Service Bus,ESB) 开始被引入。企业服务总线提供了服务之间的连接(connection),转换(transformantion), 以及中介处理(mediation)的能力。可以将企业内部和各种服务连接到服务总线上,实现信息系统之间的松耦合架构,屏蔽了系统集成的复杂性,提高了 IT 系统架构的灵活性,降低企业内部信息共享的成本。

    SOA 方法论的目标就像易筋经可以帮助梳理、归聚不同的真气,融会贯通,为我所用。然而修炼过程却绝非易事。大量雄心勃勃的 SOA 项目并未取得预期的效果,其背后的原因是什么?

    任何 IT 架构的成功,都离不开与业务目标、技术基础和组织能力的相互配合。

    在业务上,当时 SOA 重点解决的是企业 IT 的存量市场的问题。这使得 SOA 方法论很大程度被窄化为 Enterprise Application Integration (EAI 企业应用集成)。

    在 SOA 理念中,打通信息系统间的经络只是第一步,还需要勤修内功,持续重构迭代企业 IT 架构,这样才能保持企业 IT 架构的敏捷、柔性,持续支撑业务的发展和变化。

    在组织结构上,由于当时在大部分企业的 IT 部门仍然是成本中心,是业务的附属支撑部门,大多数企业缺乏长远的 IT 战略规划,IT 团队也缺乏成长认同,SOA 沦为项目制运作而没有组织化保障和持续投入。

    即使当时成功的项目也会在复杂性日积月累的侵蚀下,逐渐失去活力。去年在美国生活的朋友发过来照片,15 年前我们为客户构建的业务系统还在支撑其现有全国门店的业务。这是技术项目的成功,却反映了企业技术战略的缺失。

    在技术上,ESB 架构虽然实现了业务逻辑与服务集成的解耦,可以更好地进行中央化的服务治理,也暴露出一些严肃问题:

    • 由于过度强调业务系统的可复用性,而不是对企业 IT 架构的治理和重构。大量服务集成的实现逻辑被下沉到 ESB 内部(如上图最右侧所示),这些逻辑非常难以维护,难以移植和扩展,成为 ESB 不可承受之重。我们必须在合适的地点合理地处理复杂性,而非将其简单转移;
    • ESB 基于一个中心化的消息处理系统,但随着互联网的高速发展,ESB 已经无法应对企业IT规模化成长的挑战;
    • ESB 这样的 Smart Pipes, Dumb endpoints 的系统架构是一个无法适应快速变化和大众创新的一个架构。

    类比一下,电信运营商曾经希望将视频通信,电话会议等复杂功能纳入电信基础设施,只需一个 Dummy 电话终端就可以享受丰富的通信服务。然而随着智能电话的普及,微信和钉钉这样的分布式协同工具创新彻底颠覆了人们沟通交流的方式,而电信网络重回管道的宿命。

    羽化之美:微服务

    随着互联网的发展,尤其是移动互联时代的到来,整个世界的经济形态发生了巨大的变化改变。企业 IT 的重点从传统的 System of Record(交易系统,如 ERP、SCM 等)演化到 System of Engagement(互动系统,如全渠道营销)。

    这些系统需要能够应对互联网规模的快速增长,并且能够快速迭代,低成本试错。企业 IT 已经成为创新驱动的引擎之一,技术拓展商业边界的理想也帮助 IT 团队更有使命感,进一步加速推动了企业 IT 的进化。

    以 Netflix、阿里为首的一系列互联网公司主导了企业架构新的变革 - 微服务架构。Apache Dubbo, Spring Cloud 等微服务框架得到了广泛应用。

    微服务的核心思想便是应用功能拆分与解耦,降低业务系统实现复杂性。微服务强调将应用功能拆解为一组松耦合服务,每个服务遵守单一责任原则(Single Responsibility Principle)。微服务架构解决了传统单体式架构存在的几个固有问题:每个服务可以独立部署和交付,大大提升了业务敏捷性;每个服务可以独立横向扩展/收缩,应对互联网规模的挑战。

    原图来自于 Martin Fowler 对微服务架构的定义[3]

    当然,将大型的单体应用拆解为多个微服务,也一定会增加 IT 系统研发协同、交付、运维的复杂性。这时候微服务架构与 DevOps 和容器自然走到了一起,构成了云原生应用架构的雏形。

    微服务架构继承了 SOA 的架构原则,但是在实现层面,它倾向于通过构造智能端点和哑管道的去中心化分布式架构风格来替代 ESB。

    微服务架构首先要面对分布式架构的内生复杂性,请参考分布式计算的误区[4]。微服务框架需要能够解决服务通信和服务治理的复杂性,比如服务发现、熔断、限流、全链路追踪等挑战。

    微服务框架,如 HSF/Dubbo 或 Spring Cloud 以代码库的方式来封装这些能力。这些代码库被构建在应用程序本身中,随着应用一起发布和维护。

    服务通信和治理本质是横向的系统级关注,是与业务逻辑正交的。但在微服务架构中,其实现方式和生命周期与业务逻辑耦合在一起的。

    微服务框架的升级会导致整个服务应用的重新构建和部署。此外由于代码库通常与特定语言所绑定,难以支持企业应用的多语言(polyglot)实现。

    进化之光:云原生

    SOA 采用中心化的服务总线架构,解耦了业务逻辑和服务治理逻辑;微服务架构回归了去中心化的点对点调用方式,在提升敏捷性和可伸缩性的同时,也牺牲了业务逻辑和服务治理逻辑解耦所带来的灵活性。

    为了解决上述挑战,社区提出了 Service Mesh(服务网格)架构。它重新将服务治理能力下沉到基础设施,在服务的消费者和提供者两侧以独立进程的方式部署。

    这样既达到了去中心化的目的,保障了系统的可伸缩性;也实现了服务治理和业务逻辑的解耦,二者可以独立演进不相互干扰,提升了整体架构演进的灵活性。同时服务网格架构减少了对业务逻辑的侵入性,降低了多语言支持的复杂性。

    Google, IBM,Lyft 主导发起的 Istio 项目就是服务网格架构的一个典型的实现,也成为了新的现象级“网红”项目。

     

    上图是 Istio 的架构,逻辑上分为数据平面和控制平面:

    • 数据平面由一组以 sidecar 方式部署的智能代理组成,负责截获应用网络流量,收集遥测数据并且执行服务治理策略;
    • 控制平面中,Galley 负责配置管理,Pilot 负责下发配置,Mixer 负责策略检查和遥测数据聚合,Citadel 负责通信中安全证书管理。

    Istio 提供了一系列高阶的服务治理能力,比如:服务发现和负载均衡,渐进式交付(灰度发布),混沌注入与分析,全链路追踪,零信任网络安全等,可以供上层业务系统将其编排到自己的 IT 架构和发布系统之中。

    但是 Service Mesh 不是银弹,其架构选择是通过增加部署复杂性(sidecar)和损失性能(增加两跳),来换取架构的灵活性和系统的可演化性。

    为了解决部署复杂性的挑战,社区和云服务商都在共同进行努力:

    • 一方面简化服务网格自动化运维水平(比如阿里云通过 operator 大大简化了 Istio的升级运维和跨 K8s 集群部署的复杂度);
    • 另一方面提供托管的服务网格服务,帮助用户关注在业务层面的服务治理而非基础架构实现。

    关于性能问题:

    • 一方面 Service Mesh 需要降低自身控制平面和服务平面的性能开销,比如尽可能 offload mixer 负载,将治理策略执行下沉到数据平面完成;
    • 另一方面还需要重新思考整个通信栈中应用与网络基础设施的边界。

    为了实现容器应用之间的互联互通,Kubernetes 社区提出 CNI 网络模型,将容器网络连通性与底层网络实现的进行解耦,同时 K8s 提供了 Service, Ingress, Network policy 等基本元语来支持应用层的服务通信和访问控制。但是这些能力远不能满足应用对服务治理的需求。

    服务网格在 L4/L7 增加了流量管理、全链路可观测性、安全互联等新功能,这些是通过引入运行在用户空间的 Envoy 代理实现的,在提升灵活性的同时也不可避免地增加了性能开销。

    为了系统化解决这个问题,社区在进行有趣的探索。比如在 Cillium 容器网络中,可以利用 eBPF/XDP 等操作系统和底层网络能力,将应用层的服务控制能力(如 Kube-Proxy 提供的 service, network policy)下沉到操作系统内核和网络层解决,并优化了 Service Mesh 数据链路,减少上下文切换和数据拷贝,有效地减少了性能开销。

    目前 Service Mesh 技术还处在技术成熟度曲线的初期,除了在 L4/L7 层提供灵活的服务通信功能,社区也在探索通过网络 Service Mesh[6] 实现灵活的 L2/L3 组网能力。我们相信其会成为未来企业分布式应用通信基础设施。

    在这个过程中会有一些新的理念和项目被持续创造出来,我们需要能够理性地分析其业务价值和技术局限性。我们要避免将 Service Mesh 作为万灵药,不要将应用集成、应用侧安全等业务逻辑下沉到服务网格中,避免我们重蹈复杂性覆辙。可以参考 Application Safety and Correctness Cannot Be Offloaded to Istio or Any Service Mesh[7]。

    回望历史

    天下大势,分久必合,合久必分。企业分布式应用架构也走过一条分分合合的进化道路。在新技术迭起的今天,我们既要拥抱新技术带来的架构变化,更加要关注其背后的演进逻辑和核心价值,系统化地控制复杂性。


    原文链接
    本文为云栖社区原创内容,未经允许不得转载。

    展开全文
  • 微服务在企业中可以带来积极影响。 因此,如何处理微服务体系架构(MSA)和一些微服务设计模式以及微服务体系架构一般目标或原则是很有必要。 以下是微服务架构实现中要考虑四个目标。降低成本 — MSA将降低...
  • 如果不年初规划好IT建设,那么年底双十一就可能顶不住,”这已经是业界尤其是电商相关产业共识。2019年,上云和数字化热潮仍继续,与电商紧密结合快递行业已然走了众多传统产业前面。专注“大件快递”...
  • 微服务平台架构是一项云中部署应用和服务新技术。大部分围绕微服务的争论都集中容器或其他技术是否能很好实施微服务微服务系统可以“自己程序”中运行,并通过“轻量级设备与HTTP型API进行沟通”。...
  • 当今,企业”上云”节奏正在加速,特别是以人工智能技术为代表新一波技术浪潮推动下,企业一方面通过云技术增强了自身数据存储连接、计算以及智能应用能力;另一方面,利用基于云计算之上大数据、人工智能等...
  • 微服务架构现在是谈到企业应用架构时必聊的话题,微服务之所以火热也是因为相对之前的应用开发方式有很多优点,如更灵活、更能适应现在需求快速变更的大环境。 本文将介绍微服务架构的演进、优缺点和微服务应用的...
  • 微服务架构的应用如何测试?

    千次阅读 2018-08-12 20:00:34
    最近几年,微服务架构越来越火爆,逐渐被...微服务架构是一种架构模式,它提倡将单一应用程序划分成一组小服务,每个服务运行其独立进程中,服务间采用轻量级通信机制互相沟通(通常是基于HTTP协议RESTful ...
  • 这种分布式应用程序架构为企业带来了更大优势——改进对性能控制、高可用性、更好灾难恢复和更深层次可见性——但基于微服务构建分布式应用远比传统应用复杂,因此这种构建可以说既是一门艺术,也是一门...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,009
精华内容 803
关键字:

微服务在企业的应用