免费下载!由 O’Reilly 出版的《NGINX 完全指南》中文版已正式上线 了解详情
写点什么

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

  • 2019-05-20
  • 本文字数:4882 字

    阅读完需:约 16 分钟

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

微服务作为架构风格几乎成为云时代企业级应用的事实标准,构成微服务的技术元素本身却并非革命性。跨平台的分布式通信框架、地址无关的服务注册与发现、智能路由与编排等技术早已在 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。好在那些架构和实践背后的原则是经久不变的。从操作系统到移动应用都会需要高内聚低耦合的架构,任何软件开发都需要版本控制、自动化构建等实践。谨记这些核心原则、谨记软件被创造出来是为了解决有价值的问题,可以帮我们更好的借鉴历史的经验,理解和采纳新的技术。

作者简介

刘尚奇是活跃在技术前线的咨询师,区块链实践负责人,ThoughtWorks 技术顾问委员会成员。刘尚奇曾先后为国内外医疗、金融、通信、汽车等行业的客户提供软件咨询和交付服务。作为技术顾问参与和主导了多个系统架构设计、技术评估、大型遗留系统重构规划和实施、微服务架构转型。并作为技术负责人带领团队交付软件,技术攻关和构建工程能力。刘尚奇主要关注在区块链、分布式计算、微服务架构、领域建模、遗留系统重构等技术方向,致力于去中心化一切。


原文链接


https://6up7.com/a-retrospective-for-enterprise-distributed-application/


2019-05-20 08:005369
用户头像

发布了 85 篇内容, 共 21.1 次阅读, 收获喜欢 232 次。

关注

评论

发布
暂无评论
  • SOA != Web 服务

    许多人认为SOA和Web服务是一码事——但是它们不是。在最近的一篇文章中,Zapthink的分析师试图为此查找些原因,并称到了更清楚地区分这些术语的时候了。

  • 内聚对 SOA 是否重要?

    Jim Webber重新点燃了关于SOA里是否需要内聚的服务(Cohesive Services)的一些讨论。一篇本无冒犯之意的文章,却引起了激烈的争论。

  • 微博 Service Mesh 实践之路(上)

    对于一个已经上线运行多年的业务系统来说,要想从经典的微服务架构走上Istio这条看似完美的道路其实并不容易。

    2018-11-10

  • REST 会是 SOA 的未来吗?

    在本中文,Boris Lublinsky探讨了SOA和REST之间的架构差别并对使用REST机制实施SOA做了评估。

  • 微服务的历史与陷阱

    微服务是近几年非常火热的架构设计理念

  • 从单体应用到 Service Mesh 的曲折历程

    微博架构是如何从一开始的单体应用一步步成长为今天的庞大规模?微博为什么要选择做 Service Mesh?

    2018-03-18

  • SOLID 仍然与现代软件架构相关吗?

    SOLID 原则适不适用于微服务?

  • 分布式计算编程模型之 RPC

    RPC机制的出现可以追溯到40年之前。时至今日,它仍是在编写分布式应用时使用率最高的一种编程模型。只是近些年来,人们对于RPC技术的质疑与批评声逐渐多了起来。尽管面临着这些尖锐的批评,但RPC的历史地位是不容置疑的,而它在现代化的应用中仍能够占据一席之地,成为分布式计算中一种重要的编程模型。Christopher Meiklejohn近来开设了一系列博客文章以讲解分布式计算中的各种编程模型与语言,在其中一篇文章中对RPC进行了详尽的回顾与展望。

  • 微服务架构该如何落地?

    在实际项目中,如何让一个中小团队把我们所学的微服务架构落地呢?

    2018-10-16

  • SOA:我们从这里走向何处?

    “关于SOA是否已死,还是生机勃勃,又或根本未曾存在,还是消逝在新墨西哥的罗斯韦尔,争论已经足够了。不容争辩的事实是,许多组织正朝着至少将他们的业务应用产品的一部分面向服务化而努力,而这还会增长。”Joe Mckendrick谈到,那么从这里出发我们将奔向何处?

  • SOA 实现中的 4 个最差实践

    在铺天盖地的SOA宣传文章中,最佳实践是出现频率最高的词汇之一。相比起来,最差实践就没那么风光了。但是,俗话说得好“吃一堑,长一智”,看看别人犯过的错,未尝对自己没有帮助。最近,Information Builders的市场副总裁Jake Freivald就撰文介绍了SOA实现中常见的4种最差实践,并针对每个实践给出了解决方案。

  • Web 风格起过作用吗?

    大约七年前,Tim Bray 宣称SOA已经离死期不远,而Web风格才是未来的趋势。但是在最近的一篇博客文章里,Jean-Jacques Dubray回顾了这几年来Web风格的发展趋势,并且断定Web风格从未起到过作用,不仅如此,在可编程的Web目录里还涌现出了大量的非Web风格的服务,而从这种趋势看来,实际上是Web风格要灭亡了。他还就这一现状对于计算技术和应用开发的未来意味着什么进行了考虑。

  • 采访 ServiceStack 的项目领导 Demis Bellot——第 1 部分

    ServiceStack是一个开源的、支持.NET与Mono平台的REST Web Services框架。InfoQ有幸与Demis Bellot深入地讨论了这个项目。在这篇两部分报道的第1部分中,我们主要谈论了ServiceStack项目建立的原动力,以及项目中的各种设计方案选择。

  • SOA 吸纳 WOA?

    Dion Hinchcliffe讲述了为何SOA与WOA是互补而不是竞争的关系。根据Dion的说法,采用一种基于WOA的方法,不仅给开发者降低了门槛,而且较传统SOA方法更具优势。Dion认为WOA并不是REST的同义词,反WOA的争论主要归咎于SOA供应商和专家们“保护自己的地盘”。

  • 01|定义:到底什么是 Serverless?

    Serverless可分为狭义和广义。

    2020-04-15

  • 我们高呼的下一代微服务 Service Mesh 到底是什么?

    考虑到有的同学之前可能没有接触过 Service Mesh 这个概念,所以这里我先对 Service Mesh 做一个简单介绍,作为后续内容的基础。

    2018-03-17

  • SOA 与云计算有多大关联?

    在最近的ebizQ的云QCamp大会上有一个分会场讨论了云计算的当前状态以及它与SOA之间的关系等话题。与会成员达成的共识是云能够加强SOA所承诺的那些优势,并促使其为业务提供更坚实的基础。

  • 面向数据的架构

    在面向数据的架构中,单体数据存储是系统中状态的唯一来源,并由松耦合无状态的微服务对其进行操作。

  • 破除误解:企业架构真的做不做都行吗?

    如果不了解企业架构,你或许能帮助企业实现一些很不错的数字化创新点,但是无法帮企业实现整体转型。

    2021-04-20

发现更多内容

设计千万级学生管理系统的考试试卷存储方案

小虎

架构训练营

Java引用类型(class、interface)用法总结详解

共饮一杯无

Java 11月月更 Java引用类型

第九期-模块五

wuli洋

Verilog语法入门

向阳逐梦

Verilog 11月月更 组合逻辑电路

架构误区系列1:简单依靠扩容解决容量问题

agnostic

架构误区

架构实战营模块四

Geek_408c99

模块四 -- 作业

李某人

架构训练营 #架构训练营

披荆斩棘成功上岸美团、字节、华为,分享Java面经及答案

程序知音

Java java面试 后端技术 Java面试八股文

极客时间架构训练营模块四作业

李晨

架构

夜幕下的湖畔音乐派对,华为音乐之夜为HDC 2022划上“聚”号

最新动态

零基础入门网络安全,收藏这篇不迷茫【2022最新】

网络安全学海

黑客 网络安全 信息安全 渗透测试 WEB安全

2022-11-06:给定平面上n个点,x和y坐标都是整数, 找出其中的一对点的距离,使得在这n个点的所有点对中,该距离为所有点对中最小的。 返回最短距离,精确到小数点后面4位。

福大大架构师每日一题

算法 rust 福大大

python的类的定义和使用

乔乔

11月月更

Go语言入门14—Channel

良猿

Go golang 后端 11月月更

小白入门:什么是CURD?

wljslmz

数据库 sql crud 11月月更

【云原生】Nacos-TaskManager 任务管理的使用

石臻臻的杂货铺

云原生 nacos 11月月更

猿创征文|点亮JAVA技术之灯(线程篇)

叶秋学长

Java 线程 教学 11月月更

架构误区系列(Architecture Pitfall)

agnostic

构架师

使用TSDB自动检测时序数据的异常情况

CnosDB

IoT 时序数据库 开源社区 CnosDB infra

对象可达性状态流转分析、显式地影响软引用垃圾收集

共饮一杯无

Java 11月月更 引用类型扩展

设计模式之美-面向对象

GalaxyCreater

设计模式

数据库系统的组成

阿泽🧸

数据库 11月月更

Github已经54k个star的Docker,到底是什么?

Jackpop

纯css爱心代码-最近超级火的打火机与公主裙中的爱心代码(简易版)

肥晨

11月月更 跳动的爱心 代码爱心 爱心代码

如何在论文中画出漂亮的插图?

Jackpop

千万级学生管理系统试卷存储方案设计

π

架构实战营

【愚公系列】2022年11月 微信小程序-app.json配置属性

愚公搬代码

11月月更

漏洞扫描的种类

穿过生命散发芬芳

漏洞扫描 11月月更

强引用、软引用、弱引用、幻象引用有什么区别和使用场景

共饮一杯无

Java 引用类型 11月月更

溯源微服务:企业分布式应用的一次回顾_架构_Thoughtworks洞见_InfoQ精选文章