本文要点
近年来,诸如微服务、云计算和容器化之类的技术趋势一直在迅速发展,其中大多数技术现在已成为高级IT工程师、架构师和管理层日常工作的一部分。
我们生活在一个云技术已然普及的世界中。但是,转向云计算并不意味着成为云原生形态。实际上,在没有实现云原生形态之前就转向云计算可能是很危险的举动。
我们要研究这些趋势,并探讨企业应该实施怎样的架构和组织变革才能充分利用云计算的优势;但在此之前,重要的是要了解我们的过去,我们的现状以及我们前进的方向。
了解历史上范式转型过程中的弊端和陷阱,应该使我们能够从以前的错误中吸取教训,并使组织能够在最新的技术浪潮中蓬勃发展。
我们会简要介绍这一演变过程,其中会探索反模式的概念;所谓反模式,指的是在应对重复出现的问题时,习惯使用的措施往往无效甚至可能适得其反。
这个文章系列将具体论述上面提到的反模式。
在过去大约50年中,软件架构和应用程序托管模型经历了从大型机到微服务和无服务器的重大转变。
图1显示了架构模型的演化及其所推动的范式。
图1:从大型机到云和微服务的架构演变
上世纪70到80年代,大型机统治了计算领域。大型机基于中心化数据存储和计算模型,而客户端终端只具备基础功能,用来在早期的屏幕上输入和显示数据。
最早的大型计算机使用打孔卡,并且大多数计算都在批处理流程中进行。由于没有任何事物是实时处理的,因此也没有在线处理能力,并且延迟为100%。
随着在线处理和用户界面终端的诞生,大型机范式发生了一些变化。但是,安装在组织大型机房中的大规模中央处理单元,其整体范式仍然采用“不变应万变”的方法,并且只能提供大多数业务应用所需功能的一部分。
客户端/服务器架构将大多数逻辑放在服务端,只将某些处理过程放在客户端上。客户端/服务器是分布式计算的首次尝试,意图取代大型机作为业务应用的主流托管模型的地位。
在这一架构诞生的最初几年中,开发社区仍在使用与大型机应用开发相同的流程和单层原则来为客户端/服务器编写软件,从而产生了诸如意大利面条代码和胖球之类的反模式。软件的这种有机成长也产生了其他一些反模式,例如大泥球。业界必须找到一些方法,阻止团队遵循这些不良实践;为此人们需要研究,编写良好的客户端/服务器代码必需哪些内容。
这项研究工作找出了几种反模式,以及设计和编码模式的最佳实践。它引入了一项称为面向对象程序设计(OOP)的重大改进,其具有继承、多态性和封装功能,以及处理分散数据的范式(相比之下大型机只有一个真相版本),并提供了行业应如何发展以应对新挑战的指南。
客户端/服务器模型基于三层架构,包括表示(UI)、业务逻辑和数据层。但是,大多数应用程序是用两层模型编写的,其中一个胖客户端将所有表示、业务和数据访问逻辑封装在一起,并直接访问数据库。尽管彼时业界已经开始讨论将表示层与业务和数据访问分离的必要性,但这种做法直到基于互联网的应用问世,才真正显示出了自己的必要性。
总的来说,这种模型是对大型机范式局限的一种改进,但是业界很快也撞上了前者的围墙和局限,例如需要在每台用户计算机上安装客户端应用,并且无法作为业务函数进行细粒度的扩展等。
90年代中期发生了互联网革命,随即诞生了一个全新的范式。Web浏览器成为了客户端软件,而Web和应用程序服务器负责托管所有的处理和逻辑。万维网(www)范式在Web服务器上托管表示(UI)代码,在应用服务器上托管业务逻辑(API),并在数据库服务器中存储数据,从而塑造了真正的三层架构。
开发社区开始从胖(桌面)客户端迁移到瘦(Web)客户端上,这主要是由面向服务架构(SOA)之类的理念所推动的,这种理念加强了对三层架构的需求,并从客户端技术的改进及Web浏览器的快速发展中汲取了动力。这一运动加快了产品上市速度,并且不需要安装客户端软件。但是开发人员仍在使用紧密耦合的软件设计,结果带来了混乱(Jumble)等许多反模式。
作为回应,业界提出了改进的三层架构和实践,诸如领域驱动设计(DDD)、企业集成模式(EIP)、SOA和松散耦合技术等。
21世纪的前十年见证了应用托管模式的重大转变,此时托管开始成为以云计算的形式提供的一种服务。与传统基础架构相比,云托管能以合理的成本,更容易地提供应用程序用例所需的托管、分布式计算、网络、存储和计算等功能。此外,消费者也在利用资源的弹性来按需扩大或缩小规模。他们只需要为所使用的存储和计算资源付钱即可。
IaaS和PaaS中引入的弹性功能允许单个服务实例按需扩展,从而避免了为了扩展性而复制实例的麻烦。但是,这些功能无法避免因其他目的(例如具有多个版本)或作为单体部署副产品而导致的实例复制。
基于云的托管的吸引力在于,开发和运营团队用不着再操心服务器基础架构了。它提供了三种托管选项:
PaaS成为了几种云托管选项中的甜点,因为它使开发人员可以托管自己自定义的业务应用,而不必操心基础架构的准备或维护工作。
尽管云托管鼓励模块化的应用设计和部署,但许多组织发现,提供商会引诱客户将尚未针对弹性分布式架构设计的老式应用直接迁移到云中,从而产生了一种称为“单体地狱”的现代反模式。
为了应对这些挑战,业界提出了新的架构模式,例如微服务和12要素应用。
迁移到云还给行业带来了新的挑战,那就是管理应用对第三方库和技术的依赖关系。开发人员陷入了无穷无尽的选择困境中,缺乏可靠的标准参照来选择第三方工具,并且我们开始看到一些依赖地狱。
依赖地狱可以发生在许多层面上:
基于库的依赖关系是一个打包挑战,后两个则是设计挑战。本系列的后续文章将更详细地研究这些依赖地狱的场景,并提供一些设计模式以避免产生意料之外的后果,防止技术膨胀。
诸如DDD和EIP之类的软件设计实践自2003年左右就已诞生,一些团队从那时起就将应用程序开发为模块化服务了,但是传统的基础架构(如用于Java应用程序的重量级J2EE应用程序服务器和用于.NET应用程序的IIS)对模块化部署并无助益。
随着云托管的出现,尤其是诸如Heroku和Cloud Foundry之类的PaaS产品的面世,开发人员社区拥有了真正的模块化部署和可扩展业务应用所需的一切。微服务变革由此兴起。微服务为细粒度、可复用的功能性和非功能性服务创造了可能性。
微服务在2013-2014年间开始愈加流行。微服务功能强大,可以使较小的团队主导特定业务和技术功能的整个开发周期。开发人员可以随时部署或升级代码,而不会对系统的其他部分(客户端应用程序或其他服务)产生不利影响。还可以根据需求在单个服务级别上按需缩放服务。
需要使用特定业务函数的客户端应用程序将调用合适的微服务,而无需开发人员从头开始编写解决方案,或将解决方案打包为应用程序中的库。微服务方法鼓励服务提供商和服务消费者之间以合约驱动开发工作。这样可以缩短开发时间,并减少团队之间的依赖性。换句话说,微服务使团队之间的联系更加松散,并加速了解决方案的开发进程,这对组织,尤其是商业初创公司而言是至关重要的。
微服务还有助于在业务流程和领域(如客户、订单和库存等)之间建立明确的界限。它们可以在被称为组织中“限界上下文”的垂直模块内独立开发。
这种变革还加快了其他良好实践(如DevOps)的演进,并在组织级别提供了敏捷性和更快的面市时间。每个开发团队将在其领域中拥有一个或多个微服务,并负责设计、编码、部署到生产环境,以及生产后支持和维护的整个过程。
但是,就像之前的架构模型那样,微服务方法也遇到了自己的问题。
人们开始敲打那些没有从头开始针对微服务设计的传统应用,试图迫使它们进入微服务架构,从而导致了被称为单体地狱的反模式。其他一些尝试则强行将单体应用拆分为几个微服务,结果拆分出来的这些微服务在功能上不是相互孤立的,仍然严重依赖从同一单体应用中分解出来的其他微服务。这是称为微晶石(microlith)的反模式。
重点在于,我们要注意单体和微服务是两种不同的模式,后者并不总是可以替代前者。如果我们不够小心的话,最后可能会创建出一堆互相之间紧密耦合、混杂在一起的微服务。正确的选择取决于针对应用程序功能的业务和可扩展性需求。
微服务爆发式发展过程中,另一个人们没能料到的副作用是所谓的“死星”反模式。在服务交互和服务到服务的安全性(身份验证和授权)方面,如果缺乏治理模型,微服务的泛滥通常会导致任何服务都可以随意调用其他服务的状况。想要找出有多少服务正在被各种客户端应用程序以混乱的调用方式使用,这也是一项挑战。
图2显示了像Netflix和Twitter这样的组织如何陷入这种噩梦,并且不得不想出新的模式来应对“死星的死亡”问题。
图2:由于缺乏治理的微服务爆炸式增长而导致的死星架构
尽管图2中描述的示例看起来像是只发生在巨头身上的极端情况,但不要低估了云反模式的指数级破坏力。业界必须学习如何操作一种史上最庞大的武器。富兰克林·罗斯福曾说:“巨大的权力伴随着重大的责任。”
诸如服务网格(service mesh)、边车(sidecar)、服务编排和容器之类的新兴架构模式可以有效地阻止基于云的世界中出现的错误实践。
组织应该了解并采用这些模式,宜早不宜迟。
随着云平台的面世,特别是出现了像Kubernetes这样的容器编排技术后,服务网格就开始引起人们的关注了。服务网格是应用程序服务之间的桥梁,它带来了许多附加功能,如流量控制、服务发现、负载平衡、弹性、可观察性和安全性等。它使应用程序可以从应用程序级库中卸载这些功能,并允许开发人员专注于业务逻辑。
诸如Istio之类的某些服务网格技术还支持诸如混沌注入之类的功能,以便开发人员可以测试他们的应用程序,以及多达数十种相互依赖的微服务的弹性和健壮性。
服务网格非常适合放在平台即服务(PaaS)和容器即服务(CaaS)之上,并通过这些通用平台服务提升推行云计算过程的体验。
之后的文章将深入探讨基于服务网格的架构,并讨论特定的用例,对比有无服务网格的不同解决方案。
在过去的几年中,另一个备受关注的趋势是无服务器架构,也称为无服务器计算。无服务器比PaaS模型更进一步,因为它将服务器基础架构从应用程序开发人员那里完全抽象出来了。
在无服务器中,我们将业务服务编写为函数,并将这些函数部署到云基础架构中。无服务器技术的一些例子包括Amazon Lambda、Spring Cloud Function、Google Cloud Functions和Microsoft Azure Functions等。
无服务器模型位于云托管范围内的PaaS和SaaS之间,如下图所示。
图3:云计算、容器、服务网格和无服务器
与对比单体服务与微服务时的结论相似,并非所有解决方案都应作为函数来实现。另外,我们不应使用无服务器函数替换所有微服务,就像我们不应替换所有单体应用,或将其分解为微服务一样。只有诸如用户身份验证或客户通知之类的细粒度业务和技术功能,才应该设计为无服务器函数。
根据我们应用程序的功能性和非功能性需求(例如性能和可伸缩性以及事务边界等),我们应该为每个特定用例选择适当的单体、微服务或无服务器模型。常见的情况是,我们可能需要在一个解决方案架构中使用所有这三种模式。
如果设计不当,无服务器解决方案最终将变成纳米片,其中每个函数都与其他函数或微服务紧密结合,并且无法独立运行。
容器技术等辅助性技术趋势与微服务同时出现,以帮助人们在微服务器环境中部署服务和应用,从而真正隔离各个业务服务和每个服务的可扩展性。Docker、contained、rkt和Kubernetes等容器技术可以作为微服务开发的很好补充。如今,我们提到微服务或容器其中之一时,肯定就要谈到另一种技术了。
如前所述,了解这三种架构风格的优缺点是很重要的:也就是单体应用、微服务和无服务器函数。一项对比单体与微服务的案例研究报告详细描述了一个避免使用微服务的场景。
表1重点展示了这三种选项之间的高阶差异。
架构风格 | 何时使用 | 何时避免使用 | 使用场景案例 |
---|---|---|---|
单体 | 应用程序具有不同的模块,这些模块在事务上下文中完全相互依赖。所有数据操作都需要实时一致。 | 应用程序模块可以拆分为原子业务或技术函数。 | ERP或CRM系统。 |
微服务 | 应用程序模块在其运行时生命周期和事务管理中彼此独立。能够以无状态方式执行每个模块中的数据操作。即使模块之间存在任何依赖关系,它们仍然可以与最终的一致性支持松散地结合在一起。 注意:有时,团队会人为地将相关函数分解为微服务,并会遇到微服务模型的局限性。 | 如果不严格依赖其他模块,则无法独立部署和使用应用程序模块。 | 客户支持服务;订单管理服务;库存管理服务。 |
无服务器 | 具有完全独立性和单独可伸缩性策略的应用程序模块可以分解为业务或技术的单个函数。 没有流量时,应用程序将完全关闭。 开发团队不必关心基础架构。 | 长时间运行的作业、CRUD服务或有状态服务。 | 验证;通知;事件流。 |
表1:服务架构模型以及何时使用或避免使用它们
我们务必要注意,随着时间的流逝,我们的软件架构和代码中可能会形成很多反模式。反模式不仅会造成技术债务,而且更重要的是它们可能会将主题专家赶出组织。组织最后可能会充斥着那些不关心架构偏差或反模式的员工。
回顾以上简短的历史后,我们来重点讨论在匆忙推行微服务的过程中可能会出现的稳定性鸿沟和反模式。
诸如组织中的团队结构、业务领域以及团队中的技能组等特定因素,决定了哪些应用程序应实现为微服务,哪些应保留为单体解决方案。我们选择将解决方案设计为微服务时,还可以参考一些一般性的注意事项。
Eric Evans的著作《领域驱动设计(DDD)》改变了我们开发软件的方式。Eric提出了从领域的角度,而不是从基于技术的角度来审视业务需求的理念。
这本书认为微服务是聚合模式的一个变体。但是,许多软件开发团队会尝试将其所有现有应用都转换为微服务,结果将微服务的设计概念推向了极致。这导致了许多反模式,例如单体地狱、微晶石等。
以下是架构和开发团队需要注意的一些反模式:
在下一篇文章中,我们将详细介绍这些反模式。
为了弥补在不同的应用程序托管模型中发现的众多稳定性鸿沟和反模式,业界开发出了许多不断发展的架构模式和最佳实践来填补缺陷。
下表总结了这些架构模型、稳定性鸿沟和模式。
托管模型 | 描述 | 稳定性鸿沟/反模式 | 模式 |
---|---|---|---|
中心化 | 中央数据存储和计算模型。客户终端仅用于数据输入和数据显示。 | ||
去中心化 | 客户端/服务器架构,其中大多数应用程序逻辑在服务端处理。基本验证和某些处理在客户端上进行。 | 意大利面条代码,混乱 | 面向对象编程 |
连接/共享 | Web应用程序通过在Web服务器上托管的表示逻辑(UI)、在应用程序服务器上托管的业务逻辑(API)和数据库服务器中的数据来形成三层架构。 | 混乱 | 领域驱动设计,企业集成模式,SOA |
云托管 | 云计算模型改变了托管和扩展应用程序的方式。除了旧的“购买还是构建”选项之外,还为我们提供了“在云上托管”的第三个选项。 | 单体地狱,依赖地狱 | 微服务 |
微服务 | 细粒度的服务模型将特定的业务函数封装到轻量级应用程序(微服务)中,并在业务领域之间建立清晰的边界。 | 单体地狱,微晶石,死星 | 服务网格,边车,服务编排 |
表2:应用程序托管模型、反模式和模式
图4总结了所有这些架构模型、反模式形式的稳定性鸿沟及不断发展的设计模式和最佳实践。
图4:架构演变和应用程序托管模型
图5列出了架构演进的步骤,初始阶段中人们尚未探索出新范式中的最佳实践,这会加重技术债务。随着行业开发出新的设计模式来弥补稳定性鸿沟,团队开始在其架构中采用新的标准和模式。
图5:架构模型和新模式的推行
IT领导者必须在不断发展和优化的技术基础上提供稳定业务应用的同时,保护其投资免受无止境的技术快速变革的影响。全球范围内的IT主管正在越来越频繁地面对这类问题。
他们和我们都应该拥抱技术的发展,但不应该为此让支持业务的应用陷入持续不稳定的状态。
纪律严明的系统架构应该能够做到这一点。可以将本系列文章中讨论的模式看作有利于技术快速发展,并保护业务应用免受变化影响的策略。我们会在下一篇文章中探讨如何做到这一点。
从大型机到最新的云原生架构,各种托管模型都会影响我们开发、部署和维护业务应用的方式。业界每发现一种新的托管模式时,团队为了获取这种架构的全部优势,都会面临相应的挑战。这会导致意想不到的后果,例如架构偏差和反模式,从而带来了沉重的技术债务。随着时间的流逝,新的设计模式会不断涌现,以解决新托管模式所带来的稳定性问题。
技术债务管理在整个系统以及团队的健康发展中发挥着至关重要的作用。如果IT管理层不及时处理技术债务,可能会造成与软件相关的损害,并伤害组织本身。技术债务可以自我增殖,产生更多债务,同时导致不良实践制度化,还会排挤顶尖人才。
如果出现这些迹象,请立即停止当前的工作并开始评估,然后采取坚定的行动。
你一定要授权团队解决所有形式的技术债务。
本系列的后续文章将研究我的组织在采用微服务架构期间开发的一个通用服务平台。我们还将讨论公司如何利用不同的云原生架构组件,如容器、PaaS和服务网格等。
下一篇文章将深入探讨团队应注意的反模式,以及应在架构中采用的云原生设计模式。我们将讨论企业采用云原生服务网格战略的细节,这一战略将助力文中提到的众多能力。最后,我们将分享一些针对架构和组织的建议。
作者介绍
Srini Penchikala是位于德克萨斯州奥斯汀的通用汽车公司全球制造IT部门的高级IT架构师。他在软件架构、设计和开发方面拥有超过25年的经验,目前专注于云原生架构、微服务和服务网格、云数据管道以及持续交付领域。Penchikala是在组织中实施企业云原生服务网格解决方案的共同创建者和首席架构师。Penchikala撰写了《用Apache Spark处理大数据》一书,并与Manning合著了《Spring Roo in Action》。他经常在各种会议上发表演讲,是一位大数据培训师,并在各种技术网站上发表了多篇文章。
Marcio Esteves是位于得克萨斯州休斯敦的Tokyo Marine HCC的应用开发总监,负责领导解决方案架构、质量保证和开发团队在公司和企业IT领域协作,推动通用技术的普及,重点工作是在全球范围内部署基于云的创收系统。之前,Esteves是通用汽车IT全球制造部的首席架构师和云原生工程师,负责利用机器学习、大数据、IoT和AI/云优先微服务架构等技术进行数字转型。Esteves制定了愿景和战略,并领导了GM的企业云原生服务网格解决方案的实施,该解决方案具有可自动缩放的微服务,供几个关键业务应用使用。他还担任奥斯汀市中心VertifyData的董事会技术顾问。
原文链接:
Adoption of Cloud-Native Architecture, Part 1: Architecture Evolution and Maturity
领取专属 10元无门槛券
私享最新 技术干货