在变革中前行【Changes Needed】
本文章参考自Migrating to Cloud-Native Application Architectures
- Stine M. Migrating to cloud-native application architectures[M]. O’Reilly Media, 2015.
作者:Matt Stine,Pivotal的技术产品经理,拥有15年企业IT和众多业务领域的经验。Matt 强调精益/敏捷方法、DevOps、架构模式和编程范例,他正在探究使用技术组合帮助企业IT部门能够像初创公司一样工作。云原生的推广者。
中文版:《迁移到云原生应用架构》
宋净超(Jimmy Song),Tetrate 布道师,云原生社区 及 ServiceMesher 创始人,CNCF Ambassador
All we are doing is looking at the timeline from the moment a cus- tomer gives us an order to the point when we collect the cash. And we are reducing that timeline by removing the nonvalue-added wastes.
—— Taichi Ohno
Taichi Ohno被公认为精益制造之父。虽然精益制造的实践无法完全适用于软件开发领域,但它们的原则是一致的。 这些原则可以指导我们很好地寻求典型的企业IT组织采用云原生应用架构所需的变革,并且接受作为这一转变所带来的部分的文化和组织转型
2.1 文化变革
企业 IT 采用云原生架构所需的变革从根本上来说不是属于技术性的,而是属于企业文化和组织的变革,而其致力于消除造成浪费的结构、流程和活动。 在本节中,我们将研究必要的文化转变。
2.1.1 From Silos to DevOps
企业 IT 通常被组织成以下许多职能部门(silos):
- 软件开发
- 质量保证
- 数据库管理
- 系统管理
- IT 运营
- 发布管理
- 项目管理
创建这些职能部门是为了让那些了解特定领域的人员来管理和指导执行该专业领域工作的人员。 这些职能部门通常具有不同的管理层次,工具集、沟通风格、词汇表和激励结构。这些差异启发了企业 IT 目标的不同范式,以及如何实现这一目标。
不过这里面也存在很多矛盾,例如开发和运维对软件变更(the view of change
)持有的不同观念就是个经常被提起的例子。开发的任务通常是通过开发软件功能为组织提供额外的价值。 而这些功能本身就是向 IT 生态系统引入变更。于是开发的使命可以被描述为 “交付变化”(delivering change
),同时通常根据变更次数来进行激励。
相反,IT 运营的使命可以被描述为 “防止变更”(pre- venting change
)。 IT 运营通常负责维护 IT 系统所需的可用性、弹性、性能和耐用性(availability, resiliency, performance, and durability
)。因此,他们经常以维持关键绩效指标(KPI)来进行激励,例如平均故障间隔时间(MTBF)和平均恢复时间(MTTR)。与这些措施相关的主要风险因素之一是在系统中引入任何类型的变更。 因此,与其寻找方法将发展所需的变更安全地引入到IT生态系统中,最原始的反应往往是将使变更变得苦难,从而降低变更速度。
这些不同的范式显然导致了许多额外的工作。项目工作中的协作、沟通和简单的交接变得乏味和痛苦,最糟糕的是导致绝对混乱(甚至是危险的)。 企业 IT 通常通过创建基于单据的系统和委员会会议驱动的复杂流程来尝试 “修复” 这种情况。
这样的环境是与云原生的速度理念背道而驰的。 专业的信息职能部门和流程往往是为了创造一个安全的环境。然而,他们通常提供很少的附加安全性,在某些情况下,反而会使事情变得更糟!
DevOps 代表着这样一种思想,这些信息职能部门构建成共享的工具集、词汇表和沟通结构,以服务于专注于单一目标的文化:快速、安全地交付价值。 然后创建激励结构,强制和奖励领导组织朝着这一目标迈进的行为。 官僚主义和流程被信任和问责所取代。
在这个新的世界中,开发和 IT 运营部门向共同的直接领导者汇报,并进行合作,寻找能够持续提供价值并获得期望的可用性、弹性、性能和耐久性水平的实践。今天,这些context-sensitive
的做法越来越多地采用云原生应用架构,为完成企业组织新的共享目标提供必要的技术支持。
2.1.2 From Punctuated Equilibrium to Continuous Delivery
从间断均衡到持续交付
企业经常采用敏捷流程(agile processes
),如 Scrum,但是只作为开发团队内部的本地优化。
在行业中,我们实际上已经相当成功地将个人开发团队过渡到更敏捷的工作方式。 我们可以从项目开始,编写用户故事,并进行敏捷开发的所有常规工作,如迭代计划会议、每日例会、回顾会议和客户展示演示。我们中富有冒险精神的人甚至可能冒险进入工程实践,如结对编程和测试驱动开发。持续集成,过去是一个相当激进的概念,现在已经成为企业软件词典的一个标准部分。事实上,我参加过几个企业软件团队,他们建立了高度优化的 "从故事到演示 "(story to demo
)的周期,其结果是每个开发迭代都能被客户热情地接受。
但是,这些团队会遇到可怕的问题:我们什么时候可以在生产环境中看到这些功能?
这个问题我们很难回答,因为它迫使我们考虑自己无法控制的力量:
- 我们需要多长时间才能浏览独立的质量保证流程?
- 我们什么时候可以加入生产发布的行列中?
- 我们可以让 IT 运营及时为我们提供生产环境吗?
在这一点上,我们意识到自己已经陷入了戴维・韦斯特哈斯(Dave Westhas)所说的waterscrumfall中了。 我们的团队已经开始接受敏捷原则,但我们的组织却没有。因此,与其说每次迭代都会导致生产部署(这是《敏捷宣言》中工作软件价值背后的初衷),不如说代码实际上被分批参与到更传统的下游发布周期中。
这种操作风格产生直接的后果。我们不是每次迭代都将价值交付给客户,并将有价值的反馈回到开发团队,我们继续保持 “间断均衡” 的交付方式。 间断均衡实际上丧失了敏捷交付的两个主要优点:
- 客户可能需要几周的时间才能看到软件带来的新价值。 他们认为,这种新的敏捷工作方式只是 “一切照旧”(
business as usual
),不会增强对开发团队的信任。 因为他们没有看到可靠的交付节奏,他们回到了以前的套路将尽可能多的要求尽可能多地堆放到发布版上。 为什么? 因为他们对软件能够快速发布没有信心,他们希望尽可能多的价值被包括在最终交付时。 - 开发团队可能会好几周都没有得到真正的反馈。虽然演示很棒,但任何经验丰富的开发人员都知道,只有真实用户参与到软件之中才能获得最佳反馈。这些反馈能够帮助软件修正,使团队去做正确的事情。反馈推迟后,错误的可能性只能增加,并带来昂贵的返工。
如果我们想要获得云原生应用架构的好处,就需要将间断均衡转变为持续交付。这样一个生命周期的模型是由 Mary 和 Tom Poppendieck 在Implementing Lean SoftwareDevelopment一书中描述的 “Concept to Cash” 的想法中提取出来的。 这种方法考虑了所有必要的活动,将业务想法从概念传递到创造利润的角度,并构建可以使人们和过程达到最佳目标的价值流。
我们在技术上支持这种与持续交付工程实践一起工作的方式,其中每次迭代(实际上,每次源代码提交)都被证明可以以自动化方式进行部署。 我们构建部署流水线,可以自动执行每次测试,如果该测试失败,将会阻止生产部署。 唯一剩下的决定是商业决策:现在部署可用的新功能有很好的业务意义吗? 我们已经知道它已经如广告中的方式工作,但是我们要现在就把它们交给客户吗? 因为部署管道是完全自动化的,所以企业能够通过点击按钮来决定是否采取行动。
2.1.3 Centralized Governance to Decentralized Autonomy
从集中治理到分散自治
企业通常采用围绕应用架构和数据管理的集中治理结构,负责维护指导方针和标准委员会,以及批准个人设计和变更。 集中治理旨在帮助解决以下几个问题:
- 可以防止技术栈的大范围不一致,降低组织的整体维护负担。
- 可以防止架构选型中的大范围不一致,从而形成组织的应用程序开发的共同观点。
- 整个组织可以一致地处理跨部门关切,例如合规性。
- 数据所有权可由具有全局视野的人来决定。
之所以创造这些结构,是因为我们相信它们将有助于提高质量、降低成本或两者兼而有之。然而,这些结构很少能够帮助我们提高质量节约成本,并且进一步妨碍了云原生应用架构寻求的交付速度。 正如单体应用架构导致了限制技术创新速度的瓶颈一样,单一的治理结构同样如此。架构委员会经常只会定期召集,并且经常需要很长的等待时才能发挥工作。即使是很小的数据模型的变化 —— 可能在几分钟或几个小时内完成的更改,即将被委员会批准的变更 —— 将会把时间浪费在一个不断增长的待办事项中。
采用云原生应用架构时通常都会与分散式治理结合起来。建立云原生应用的团队拥有他们负责交付的能力的所有方面。他们拥有和管理数据、技术栈、应用架构、每个组件设计和 API 协议并将它们交付给组织的其余部分。如果需要对某事作出决策,则由团队自主制定和执行。
团队个体的分散自治和自主性是通过最小化、轻量级的结构进行平衡的,这些结构在可独立开发和部署的服务之间使用集成模式(例如,他们更喜欢 HTTP REST JSON API 而不是不同风格的 RPC)来实现。这些结构通常会在底层解决交叉问题,如容错。激励团队自己设法解决这些问题,然后自发组织与其他团队一起建立共同的模式和框架。随着整个组织中的最优解决方案出现,该解决方案的所有权通常被转移到云框架 / 工具团队,这可能嵌入到平台运营团队中也可能不会。当组织正在围绕对架构共识进行改革时,云框架 / 工具团队通常也将开创解决方案。
2.2 组织变革
在本节中,我们将探讨采用云原生应用架构的组织在创建团队时需要进行的变革。这个重组背后的理论是著名的康威定律。我们的解决方案是在长周期的产品开发中,创建一个包含了各方面专业员工的团队,而不是将他们分离在单一的团队中,例如测试人员。
2.2.1 Business Capability Teams
业务能力团队
我们在From Silos to DevOps 一节中讨论了将 IT 组织成专门的职能部门的做法。我们很自然地创造了这些职能部门,并把个体放到这些团队中。但是当我们需要构建一个新的软件的时候会怎么样?
一个很常见的做法是成立一个项目团队。该团队向项目经理汇报,然后项目经理与各个职能部门合作,为项目所需的各个专业领域寻求 “资源”。正如康威定律所言,这些团队将很自然地在系统中构筑起各种孤岛,我们最终得到的是联合各种孤岛相对应的孤立模块的架构:
- 数据访问层
- 服务层
- Web MVC 层
- 消息层
- 等等
每一层都跨越多个可识别的业务功能,这使得在独立于其他业务功能之外的条件下创新和部署与某个业务功能相关的功能变得非常困难。
寻求迁移到将业务能力分离的微服务等云原生架构的公司经常采用 Thoughtworks 称之为的 “逆康威定律”(Inverse Conway Maneuver
)。他们没有建立一个与其组织结构图相匹配的架构,而是决定了他们想要的架构,并重组组织以匹配该架构。如果你这样做的话,根据康威定律,您所期望的架构终将出现。
因此,作为转向 DevOps 文化的一部分,我们组织了跨职能、业务能力的团队,开发的是产品而不再是项目。开发产品需要长期的付出,直到它们不再为企业提供价值为止。(直到你的代码不再运行在生产上为止!)构建、测试、交付和运营提供业务能力的服务所需的所有角色都存在于一个团队中,该团队不会向组织的其他部分交接代码。这些团队通常被组织为 “Inverse Conway Maneuver”,意思是如果不能用两个比萨饼喂饱,那就意味着团队规模太大了。
那么剩下的就是确定要创建的团队。如果我们遵循逆康威定律,我们将从组织的领域模型开始,并寻求可以封装在有限环境中的业务功能。一旦我们确定了这些功能,我们就可以创建为这些业务功能整个生命周期负责的团队。 业务能力团队掌握其应用程序从开发到运营的整个生命周期。
2.1.2 The Platform Operations Team
平台运营团队
业务能力团队需要依赖于我们前面提到的"Self-Service Agile Infrastructure"。
事实上,我们可以将一种特殊的业务能力定义为“开发、部署和操作业务能力的能力”。该功能由平台运营团队拥有。
平台运营团队运营自助敏捷基础架构平台,并交付给业务能力团队使用。该团队通常包括传统的系统、网络和存储管理员角色。如果公司正在运营云平台,该团队也将拥有管理数据中心的团队或与他们紧密合作,并了解提供基础架构平台所需的硬件能力。
IT 运营传统上通过各种基于单据的系统与客户进行互动。由于基于平台操作流来运行自助服务平台,因此必须提供不同形式的交互方式。正如业务能力团队之间通过定义好的 API 协议相互协作一样,平台运营团队也为该平台提供了 API 协议。业务能力团队不再需要排队申请应用环境和数据服务,而是采用更精简的方式构建按需申请环境和服务的自动化发布管道。
2.3 技术变革
现在我们将目光放到迁移到云中DevOps平台的一些技术实现问题。
2.3.1 Decomposing Monoliths
分解单体应用
传统的 n 层单体式应用部署到云中后很难维护,因为它们经常对云基础设施提供的部署环境做出不可靠的假设,这些假设云很难提供。 例如以下要求:
- 可访问已挂载的共享文件系统
- P2P 应用服务器集群
- 共享库
- 配置文件位于常用的配置文件目录
大多数这些假设都出于这样的事实:单体应用通常都部署在长期运行的基础设施中,并与其紧密结合。不幸的是,单体应用并不太适合弹性和短暂(非长期支持)生命周期的基础设施。
但是即使我们可以构建一个不需要这些假设的单体应用,我们依然有一些问题需要解决:
- 单体式应用的变更周期耦合,使独立业务能力无法按需部署,阻碍创新速度。
- 嵌入到单体应用中的服务不能独立于其他服务进行扩展,因此负载更难于优化。
- 新加入组织的开发人员必须适应新的团队,经常学习新的业务领域,并且一次就熟悉一个非常大的代码库。 这样会增加 3-6 个月的适应时间,才能实现真正的生产力。
- 尝试通过堆积开发人员来扩大开发组织,增加了昂贵的沟通和协调成本。
- 技术栈需要长期承诺。引进新技术太过冒险,可能会对整体产生不利影响。
细心的读者会注意到,该列表正好与 “微服务” 的列表相反。将组织分解为业务能力团队还要求我们将应用程序分解成微服务。只有这样,我们才能从云计算基础架构中获得最大的收益
2.3.2 Decomposing Data
仅仅将单体应用分解为微服务还是远远不够的。数据模型必须要解耦。如果业务能力团队被认为是自主的,却被迫通过单一的数据存储进行协作,那么单体应用对创新的阻碍将依然存在。
事实上,产品架构必须从数据开始的说法是有争议的。 Eric Evans(Addison-Wesley)在领域驱动设计(DDD)中提出的原理认为,我们的成功在很大程度上取决于领域模型的质量(以及支持它的普遍存在的语言)。要使领域模型有效,还必须在内部一致——我们不应该在同一模型内的一致定义中找到重复定义的术语或概念。
创建不具有这种不一致的联合领域模型是非常困难和昂贵的(可以说是不可能的)。Evans 将业务的整体领域模型的内部一致性子集称为有界上下文(bounded contexts
)。
最近与航空公司客户合作时,我们讨论了他们业务的核心概念,自然是 “航空公司预订” 的话题。该集团可以在其预定业务中划分十七种不同的逻辑定义,几乎不能将它们调和为一个。相反,每个定义的所有细微差别都被仔细地描绘成一个个单一的概念,这将成为组织的巨大瓶颈。
有界上下文允许你在整个组织中保持单一概念的不一致定义,只要它们在有界上下文中一致地定义。
因此,我们首先需要确定可以在内部保持一致的领域模型的细分。我们在这些细分上画出固定的边界,划分出有界上下文。然后,我们可以将业务能力团队与这些环境相匹配,这些团队将构建提供这些功能的微服务。
微服务提供了一个有用的定义,用于定义 12 因素应用程序应该是什么。12 因素主要是技术规范,而微服务主要是业务规范。通过定义有界上下文,为它们分配一组业务能力,委托业务能力团队对这些业务能力负责,并建立 12 因素应用程序。在这些应用程序可以独立部署的情况下,为业务能力团队的运维提供了一组有用的技术工具。
**我们将有界上下文与每个服务模式的数据库结合,每个微服务封装、管理和保护自己的领域模型和持久存储。在每个服务模式的数据库中,只允许一个应用程序服务访问逻辑数据存储,逻辑数据存储可能是以多租户集群中的单个 schema 或专用物理数据库中存在。**对这些概念的任何外部访问都是通过一个明确定义的业务协议来实现的,该协议的实现方式为 API(通常是 REST,但可能是任何协议)。
这种分解允许应用拥有多语言支持的持久性,或者基于数据形态和读写访问模式选择不同的数据存储。然而,数据必须经常通过事件驱动技术重新组合,以便请求交叉上下文。诸如命令查询责任隔离(CQRS)和事件溯源(Event Sourcing)之类的技术通常在跨上下文同步类似概念时很有帮助,这超出了本文的范围,不再讨论。
2.3.3 Containerization
容器化
容器镜像(例如通过 LXC、Docker 或 Rocket 项目准备的镜像)正在迅速成为云原生应用架构的部署单元。然后通过诸如 Kubernetes、Marathon 或 Lattice 等各种调度解决方案,实例化这样的容器镜像。亚马逊和 Google 等公有云供应商也提供一流的解决方案,用于容器化调度和部署。容器利用现代的 Linux 内核原语,如控制组(cgroups)和命名空间来提供类似的资源分配和隔离功能,这些功能与虚拟机提供的功能相比,具有更少的开销和更强的可移植性。应用程序开发人员将需要将应用程序包装成容器镜像,以充分利用现代云基础架构的功能。
2.3.4 From Orchestration to Choreography
从管弦乐编排到舞蹈编舞
不仅仅服务交付、数据建模和治理必须分散化,服务集成也是如此。企业服务集成传统上是通过企业服务总线(ESB)实现的。ESB 成为管理服务之间交互的所有路由、转换、策略、安全性和其他决策的所有者。我们将其称之为编排,类似于导演,它决定了乐团演出期间演奏音乐的流程。ESB 和编排可以产生非常简单和令人愉快的架构图,但它们的简单性仅仅是表面性的。在 ESB 中隐藏的是复杂的网络。管理这种复杂性成为全职工作,这成为应用开发团队的持续瓶颈。正如我们在联合数据模型所看到的,像 ESB 这样的联合集成解决方案成为阻碍幅度的巨大难题。
诸如微服务这样的云原生架构更倾向于舞蹈,它们类似于芭蕾舞中的舞者。它们将心智放置在端点上,类似于 Unix 架构中的虚拟管道和智能过滤器,而不是放在集成机制中。当舞台上的情况与原来的计划有所不同时,没有导演告诉舞者该怎么做。相反,他们会自适应。同样,服务通过客户端负载均衡和断路器等模式,适应环境中不断变化的各种情况。
虽然架构图看起来像一个庞杂的网络,但它们的复杂性并不比传统的 SOA 大。编排简单地承认并暴露了系统原有的复杂性。再次,这种转变是为了支持从云原生架构中寻求速度所需的自治。团队能够适应不断变化的环境,而无需承担与其他团队协调的开销,并避免了在集中管理的 ESB 中协调变更所造成的开销。
2.4 本章小结
本章中,我们探讨了大多数企业采用云原生应用架构所需要做出的变革。从宏观总体上看是权力下放和自治:
- DevOps:技能集中化转变为跨职能团队。
- 持续交付:发行时间表和流程的权力下放。
- 自治:决策权力下放。
我们将这种权力下放编成两个主要的团队结构:
- 业务能力团队:自主决定设计、流程和发布时间表的跨职能团队。
- 平台运营团队:为跨职能团队提供他们所需要运行平台。
而在技术上,我们也分散自治:
- 单体应用到微服务:将个人业务能力的控制分配给单个自主服务。
- 有界上下文:将业务领域模型的内部一致子集的控制分配到微服务。
- 容器化:将对应用包装的控制分配给业务能力团队。
- 编排:将服务集成控制分配给服务端点。
所有这些变化造就了无数的自治单元,辅助我们以期望的创新速度安全前行。
在最后一章中,我们将通过一组操作手册,深入研究迁移到云原生应用架构的技术细节。