[TOC]
Introduction
软件架构
定义1:程序或计算系统的软件体系结构是系统的一个或多个结构,其中包括软件组件,这些组件的外部可见属性以及它们之间的关系。
定义2:系统的基本组织,体现在其组件,它们之间的相互关系以及环境以及支配其设计和演进的原则。
体系结构是关于软件设计的(software design)
- 所有的体系结构都是软件设计,但不是所有的软件设计都是体系结构
- 体系结构是设计过程的一个过程
体系结构是更高层的设计,是设计决策的组合
元素(Elements):部件(Components)和连接件(Connectors)
关系:静态(static)和动态(dynamic)的关系
【2019】Architecture,structure和Design的区别?
- Design 包含 Architecture,Architecture 包含 Structure
- 结构是静态的、逻辑的,是关于系统如何构成的,但是架构除了包含结构,还会增加组件的相互之间的关系接口,还会定义一些动态的行为
- 体系架构是关于软件设计的,所有体系架构都是设计,但是不是所有的设计都是体系架构,体系架构是软件设计的⼀个部分
- 体系结构将系统分解成部件/模块/子系统,降低每一部分的复杂度
- 体系结构定义
- 部件接口:部件可以做什么?
- 部件交流和依赖:部件可以怎么沟通交流?
- 部件职责:当我们询问它时,部件需要精确的知道自己将要做什么?
体系结构确定通信,包括:
- 数据通过机器传递,比如
- 函数调用
- 远程方法调用异步信息
- 控制流
- 组件间的信息流来满足需要的功能
- 序列化的
- 并发/并行
- 同步
非功能性需求 NFRs
- 非功能性需求(Non-functional requirements)定义了系统运行的有多好
- 当然也需要考虑功能性需求。
- 非功能性需求很少在功能性需求中很少被发现
- 又名体系结构需求 (aka. architecture requirements)
- 必须通过体系结构引出
- 非功能性需求包括
- 技术约束 Technical constraints
- 商业约束 Business constraints
- 质量属性 Quality attrilbutes
⭐通用设计决策
以前考了
- 分解:针对某⼀个系统关注点分解后处理,比如将整个系统分解或将某个模块分解。
- 抽象:使用抽象让设计师关注本身结构而不关心实现
- 分而治之:将每个模块分别处理
- 生成和测试:将⼀个特定的设计看作是⼀个假设;根据测试路径生成测试⽤例。
- 迭代:使用迭代的方法,ADD方法多次迭代直到满足所有ASR
- 重用元素:重用在设计过程中可以复用的元素或架构
⭐4+1 Views
以前考了
- 逻辑视图:描述了对架构而言重要的元素和他们之间的关系(功能需求)
- 过程视图:描述了元素之间的并发和交互。
- 物理视图:描述了主要过程和组件是如何被映射到硬件上的。
- 发展视图:描述了软件组件的内部组织联系(比如使用配置管理工具)。
- 用例场景(Use Case):捕获架构需求,与一个或多个特定视图相关。
软件架构师做了什么
- 联络人
- 在客户、技术团队和商业/需求分析师之间
- 包含管理和市场分析
- 软件工程:软件工程的最佳实践
- 技术知识:深入理解技术领域
- 风险管理:与设计、技术决策相关的风险
架构活动
- 创建系统的商业案例
- 理解需求
- 创建和选择体系结构
- 沟通体系结构(涉众,包括开发商)
- 分析或评估体系结构
- 整体的方法论
- 具体技术的质量
- 实现体系结构
- 保证和体系结构的一致性
⭐软件架构过程
以前考了
a) 通过 StackHolder 获取到 ASRs(架构攸关需求)
b) 通过分析得到 高优先级质量属性解决方案 和 需求和约束
c) 将上述部分,结合模式和策略,综合可以得到架构的设计
d) 根据架构的设计得到由模式决定的候选视图的示意图,之后完成文档化
e) 选择、组合视图,将文档进行进一步的评估,这一部分需要 StackHolder 的参与、也需要 高优先级质量属性解决方案 和 文档 等作为参考。
架构的角色和重要性
角色:
- 架构是代表决定如何实现需求的决策的第一批人工制品。作为早期设计决策的体现,架构代表了那些最难更改的设计决策,因此值得最仔细的考虑
- 架构是成功完成产品线工程,与独立开发每个系统相比,以较少的工作量,成本和风险来有序地开发一系列相似系统的关键要素
- 当有人开始在系统上工作时,架构通常是首先要检查的设计工件
- 软件架构为维护和修改决策提供了参考框架
重要性:
- 提供了沟通的工具
- 表现最早期的决策集合
- 表现早期设计决策
- 促进/阻碍质量属性实现
- 影响质量
- 引发潜在变更的讨论
- 将更改分为本地、非本地和架构三种类型
- 可迁移和可重用的抽象
- 产品通用性的基础
- 集成独立开发的组件
软件架构的来源
NFRs、ASRs、质量需求、涉众、组织、技术环境等等
质量属性
功能性需求
- 功能性需求定义了系统必须做什么并且强调了系统如何提供价值给涉众
- 功能性需求意味着系统的行为
- 功能是系统完成其预期工作的能力,例如,使学生能够在线注册。
- 通过使用许多可能的结构可以实现功能。
- 功能在很大程度上与结构无关,因为它可以作为单个整体系统存在而没有任何内部结构。
质量需求
- 质量需求是系统应在其功能要求之上提供的整个系统的合乎需要的特性(又称质量属性)
- 质量要求是功能要求或整个产品的资格。
- 如果质量属性很重要,软件架构便会约束功能向各种结构的分配(映射)。
非功能性需求
- 非功能要求或体系结构要求是用于质量属性的替代术语
- 不可能先实现功能正确,然后再试图兼顾非功能性需求(质量无法事后补装)。
- 在任何设计决策中都必须考虑非功能性要求
- ⭐非功能性需求分为两大类:
- 在执行过程中可观察(外部):系统满足其行为要求的程度如何?例如性能,安全性,可用性,易用性等。
- 执行期间不可观察(内部):系统的维护,集成或测试有多容易? 例如,可修改性,可移植性,可重用性,可测试性等。
约束
约束是具有零自由度的设计决策,是已经做出的预先指定的设计决策。通过接受设计决策并将其与其他受影响的设计决策进行协调来满足约束条件。
质量属性
$\to$质量需求、非功能性需求
为什么软件系统结构被认为是解决质量问题的最合适层次:
i. 开发完成后,质量不能被添加到软件密集型系统中,软件开发的所有阶段都需要解决质量问题:没有办法先实现功能,然后再尝试实现非功能性需求。
ii. 软件体系结构限制了各种质量属性的实现,例如性能、安全性和可用性等。
质量属性方案
确定质量属性:质量属性的精确定义对于在体系结构级别对其进行评估是必要的,使用质量属性方案用于定义所需的质量需求。
质量属性方案用于定义所需的质量属性,是具有一定结构的简单句子。方案的主要类别为通用方案与具体方案。
通用方案是与系统无关的方案,用于指导质量属性要求的规范。它提供了一个框架,用于生成大量通用的、独立于系统的、质量属性特定的方案。
具体方案是系统特定方案,用于指导特定系统的质量属性要求的规范,是通用方案的实例。
⭐⭐⭐质量属性建模(刺激-响应图)
- 刺激(Stimulus):到达系统时需要考虑的条件
- 刺激源(Source of Stimulus):产生刺激的实体(人,系统或任何促动器),可能是输入、消息等等,对当前的状态有一个变化。
- 应对(Response):刺激措施到来之后开展的活动
- 响应度量(Response Measure):对刺激的响应应以某种方式进行测量,以便可以测试需求。
- 环境(Environment):发生刺激时系统的状况,例如过载,运行等
- 工件(Artifact):需求适用的整个系统或系统的一部分。
从上到下:可用性、互操作性、可修改性、性能、安全性、可测试性、易用性
策略(Tactics)
策略是影响质量属性相应控制的设计决策,比如冗余。
策略的集合称为体系结构策略 (A collection of tactics is called an architectural strategy.)
样式(Style)或模式(Pattern)运用策略来提供预期的收益。
像模式一样,策略也可以由其他策略组成,例如,冗余可以由数据的冗余,计算的冗余组成。
策略 vs 模式
i. 策略比模式更简单,仅有单一的结构或机制来应对单一的架构驱动
ii. 策略是创建架构设计的重要组成块。
iii. 模式通常将多个设计决策组合到一个包中。
iv. 模式和策略共同构成了软件设计师的主要工具。
v. 大多数模式包含几种不同的策略,这些策略可能有共同的目的或者经常被选择来实现不同的质量属性。
可用性 Availability
可将可用性计算为在指定的时间间隔内它将在要求的范围内提供指定服务的概率,以所需的可用时间来度量。
- MTBF(平均无故障时间,mean time between failures)
- MTTR(平均维修时间,mean time to repair)
$\frac{MTBF}{MTBF+MTTR}$
互操作性 Interoperability
互操作性是指两个或多个系统可以在特定的上下文中通过接口有效交换有意义的信息的程度,包括语法可操作性(交换数据的能力)和语义可操作性(能够正确解释数据)。
可修改性 Modifiability
可修改性涉及到更改以及进行更改所需花费的时间或金钱,包括这种可变更性影响其他功能或质量属性的程度。
性能 Performance
性能与时间有关,和系统满足时序要求的能力有关(单位时间能做多少事情)。
安全性 Security
安全性衡量系统保护数据和信息免遭未授权应用的能力,同时仍提供对授权人员和系统的访问权限。
可测试性 Testability
可测试性是指可以使软件通过(通常是基于执行)测试来证明其故障的难易程度。
易用性 Usability
易用性与用户完成所需任务的难易程度以及系统提供的用户支持的类型相关。
质量设计决策
- 职责分配:将大的职责进行分配
- 协调模型:各部分之间的沟通、交互
- 数据模型:数据格式、存储方式(缓存等)
- 资源管理:CPU、网络、内存、时间(部分时间敏感的场景)等资源
- 架构元素之间的映射:将架构元素如何映射到软件的实现上
- 绑定时间决策:
- 设置时间点(也就是这个时间前,系统还是可以变化的,但是这个时间之后就不可以变化了)
- 比如选择安装环境是需要在一个时间点前完成的,技术是否添加、编译时间、初始化时间,运行时绑定,但运行时是弹性最大的
- 实际上我们希望绑定时间越往后越好,但是也就要付出相应的代价。
- 技术选择:前面的部分都确定后,我们可以选择的技术栈相对比较局限。
Architecturally Significant Requirements, ASRs
什么是ASR?列出提取和识别ASR的四种来源和方法。
架构攸关需求是对体系结构产生深远影响的需求(如果缺失了这个需求,架构就会变得截然不同)。
需求越困难和重要,就越可能显著影响体系结构,从而成为 ASR。
【2018】Software requirements, Quality attributes, ASRs 的区别和联系
软件需求包括功能性需求和非功能性需求(⼜称质量需求)
质量属性是由软件的业务目标所决定,在功能性需求的基础上提供的整个系统的合乎需求的特性,是非功能需求的⼀种反应。
ASRs架构攸关需求是对于体系结构有着深远影响的需求,肯定是软件需求的⼀部分。
⭐如何识别ASR和其他因素
- 从需求文档中收集ASR:可以使用“MoSCoW”样式或用户故事来收集需求(不过难以收集质量需求),但其中大部分的内容都不会影响体系结构,对架构师有用的部分甚至没有出现在需求文档中。
- 通过采访涉众来收集ASR:使用质量属性工作坊(QA Workshop)
- 通过了解业务目标来收集ASR
- 通过效用树来捕获ASR:使用方案量化描述需求后,逐渐对质量需求进行分解细化,直到含有量化指标为止。
架构驱动因素
架构驱动因素是塑造架构的需求的一个子集
- 功能性需求
- 质量属性需求
- 约束条件
其他驱动因素:系统类型、设计目标、关注点
这些是设计过程的输入
功能性驱动因素
常涉及主要功能,即直接支持业务目标的功能
质量属性驱动因素
用户和开发人员感兴趣的可度量特征
- 性能、可用性、可修改性、可测试性等
- 可以使用场景技术来指定
- 由客户按重要性排序(H/M/L),由架构师按技术风险排序(H/M/L)
约束
系统设计也有塑造架构的「约束条件」,就像盖房子,预算和土地面积限制设计。
- 时间与预算:3个月项目期限排除需要6个月开发的复杂模块。优先MVP功能。
- 技术限制:团队缺乏区块链知识?避免添加相关需求。技能差距可能导致实施延迟或失败。
- 业务规则与法规:电商系统必须遵守GDPR。在每个用户数据相关模块中嵌入合规检查。
系统类型
- 新颖领域的绿地系统:如 Google、Amazon、WhatsApp — 不太知名的领域,更具创新性
- 成熟领域的绿地系统:传统企业应用、标准移动应用 — 知名领域,创新性较低
- 棕地系统:对现有系统进行更改
设计目的/目标
在开始之前需要清楚为什么做设计。目标会改变设计的内容和方式。
- 对于售前方案:快速设计初始方案以产生估算
- 对于定制系统:具有既定时间和成本,发布后不太演变
- 对于持续演进系统的新增量或发布版本
架构关注点
需要作为架构设计一部分考虑的额外方面,但未表达为传统需求。
- 一般关注点:整体系统结构、功能→模块、模块→团队、代码库组织
- 特定关注点:日志记录、API版本管理等系统内部问题
- 内部需求:虽未明确来自客户但至关重要,它们会影响组件设计和交互
- 问题:安全风险、性能瓶颈需要架构变更
ADD 3.0
步骤1:审查输入
步骤2:通过选择驱动因素确立迭代目标
步骤3:选择系统中一个或多个待细化的元素
步骤4:选择一个或多个满足所选驱动因素的设计概念
步骤5:实例化架构元素、分配职责并定义接口
步骤6:绘制视图并记录设计决策
步骤7:分析当前设计,并回顾迭代目标及设计目的的达成情况
架构文档化
即使是最好的架构,如果需要它的人不知道它是什么、无法充分理解以使用/构建/修改它、或误解并错误应用它,也将毫无用处。架构团队的所有努力都将白费。
用途与受众
- 架构文档必须:足够透明和易于访问以便新员工快速理解;足够具体以作为构建蓝图;有足够信息作为分析基础。
- 架构文档既是规定性的也是描述性的。
- 理解利益相关者对架构文档的使用至关重要——这些使用决定了要捕获的信息。
架构文档的三种用途
- 教育:向新团队成员、外部分析师/评估者、新架构师介绍系统
- 利益相关者之间的主要沟通工具:尤其是架构师到开发人员,架构师到未来架构师
- 系统分析和构建的基础:架构告诉实施者要实施什么;作为注册和沟通未解决问题的基础;作为架构评估的基础
符号表示法(Notations)
- 非正式符号:使用通用图形工具描述视图,语义用自然语言表达,不能进行形式化分析
- 半形式化符号:标准化的符号规定图形元素和构建规则。UML是半形式化符号。
- 形式化符号:使用具有精确语义的符号描述视图,架构描述语言(ADL),通过相关工具支持自动化。
选择符号表示法
- 权衡:更形式化的符号需要更多时间和精力但减少歧义。非正式符号更容易创建和理解但提供较少保证。
- 不同符号更适合/不适合表达不同类型的信息。
- 根据你需要捕获和推理的重要问题来选择符号和表示语言。
视图
视图让我们将软件架构划分为若干有趣且可管理的系统表示。文档化架构就是文档化相关视图,然后添加适用于多个视图的文档。
选择哪些视图?
- 不同视图支持不同目标和使用。
- 你应该文档化的视图取决于你期望的文档用途。
- 每个视图都有成本和收益;确保维护视图的收益超过其成本。
模块视图
元素与关系
- 元素:模块,是提供一组连贯职责的软件实现单元
- 关系:Is part of(组成部分)、Depends on(依赖)、Is a(泛化/特化)
约束与用法
- 约束:不同模块视图可能施加特定拓扑约束(比如不同模块之间的可见性)
- 用法:代码构建蓝图、变更影响分析、增量开发规划、需求可追溯性分析、传达系统的功能及其代码库的结构、支持工作任务分配、实施进度安排和预算信息的定义、展示系统需要管理的信息结构
任何软件架构的文档几乎不可能没有模块视图就算完整。
C&C视图(组件与连接器)
元素与关系
- 组件:主要处理单元和数据存储,有一组端口
- 连接器:组件间交互的路径,有一组角色(接口)
- 关系:
- Attachments(附件。组件端口与连接器角色关联,从而产生组件和连接器的图形。)
- Interface delegation(接口委托。在某些情况下,组件端口与“内部”子架构中的一个或多个端口关联。连接器角色的情况类似。)
约束与用法
- 约束:组件只能附着到连接器;连接器只能附着到组件;附件只能在兼容的端口和角色之间建立;接口委托只能在两个兼容端口之间定义;连接器不能孤立出现;连接器必须附加到组件。
- 用法:展示系统如何工作;通过指定运行时元素的结构和行为来指导开发;帮助推理运行时系统质量属性
C&C 视图的符号
UML 组件是 C&C 组件的良好匹配。
C & C的符号表达法
UML 连接器不够丰富,无法表示许多 C&C 连接器。
- UML 连接器不能具有子结构、属性或行为描述。
使用 UML 连接器(一条线)表示一个“简单的”C&C 连接器。
许多常用的 C&C 连接器具有众所周知的、与应用无关的语义和实现,例如函数调用或数据读取操作。
可以使用构造型来表示连接器的类型。
连接器角色无法用 UML 连接器显式表示。
UML 连接器元素不允许包含接口。
为连接器端点添加标签,并使用这些标签来标识必须在别处记录的角色描述。
使用 UML 组件表示一个“丰富的”C&C 连接器,或者通过使用标签标注线条状的 UML 连接器,来解释该复杂连接器的含义。
分配视图
元素与关系
- 软件元素:有环境要求的属性
- 环境元素:有提供给软件的属性
- 关系:Allocated to(分配到)— 软件元素映射到环境元素
约束与用法
- 约束:因视图而异
- 用法:推理性能、可用性、安全性;推理分布式开发和将工作分配给团队;推理软件版本并发访问;推理系统安装的形式和机制
质量视图
质量视图可以为特定利益相关者量身定制或解决特定关注点。
通过提取结构视图的相关部分并打包在一起形成质量视图。
质量视图示例
安全视图:
- 展示具有某种安全角色或职责的组件,这些组件如何通信,用于安全信息的任何数据存储库,以及具有安全利益的数据存储库。
- 视图的上下文信息将展示系统环境中其他安全措施(例如物理安全)。
- 安全视图的行为部分
- 展示安全协议的运作方式,以及人类在何处以及如何与安全元素交互。
- 捕获系统如何响应特定威胁和漏洞。
通信视图:
- 对于全球分散且异构的系统尤其有帮助。
- 展示所有组件到组件的通道、各种网络通道、服务质量参数值以及并发区域。
- 用于分析特定类型的性能和可靠性(例如死锁或竞态条件检测)。
- 该视图的行为部分可以展示(例如)网络带宽是如何动态分配的。
异常/错误处理视图:
- 有助于阐明并引起人们对错误报告和解决机制的关注。
- 展示组件如何检测、报告和解决故障或错误。
- 这将有助于识别错误的来源,并针对每种错误采取适当的纠正措施。
可靠性视图:
- 对诸如复制和切换等机制进行建模。
- 描述时序问题和事务完整性。
性能视图:
- 展示架构中那些有助于推断系统性能的方面。
- 展示网络流量模型、操作的最大延迟等。
选择视图的方法
步骤1:构建利益相关者/视图表
- 行:列出项目利益相关者
- 列:枚举适用于系统的视图
- 填充:填写每个单元格,以描述利益相关者从该视图所需的信息量:无、仅概述、中等细节或高度细节。
某些视图(例如分解视图、使用视图和工作分配视图)适用于每个系统,而其他视图(各种C&C视图、分层视图)仅适用于某些系统
步骤2:合并视图以减少数量
- 查找边缘视图:只需要概述的视图,或者只为极少数利益相关者服务的视图
- 将边缘视图与具有更强支持者的视图合并
- 自然合并的视图:各种C&C视图、部署视图与SOA视图或通信进程视图、分解视图与工作分配视图、实现视图、使用视图或分层视图中的任意一个
步骤3:优先级排序和分阶段发布
- 分解视图是特别有帮助的早期发布视图
- 提供80%的信息已经很好,不用最大程度满足所有信息需求
- 不必在完成一个视图之后才开始另一个视图,广度优先的方法通常是最好的
构建文档包
【2017】【2019】典型的软件架构⽂档包中应该包含哪些内容?简要描述每个组件及其⽤途。What should be included in a typical software architecture documentation package? Briefly describe each component and its purpose.
文档包由以下组成:视图 + 视图之外的文档
文档化一个视图
第1节:主展示
主展示显示视图的元素和关系。主展示通常是图形化的。确保包含说明符号的图例——缺少图例是实践中最常见的错误。主展示偶尔会是文字型的,例如表格和列表。
第2节:元素目录
元素目录至少详细说明主展示中所描绘的元素及其属性、关系及其属性、元素接口、元素行为。
- 例如,如果一张图展示了元素A、B和C,那么元素目录就需要解释A、B和C分别是什么。
- 如果与此视图相关的元素或关系在主展示中被省略了,则应在目录中加以介绍和解释。
第3、4、5节
- 上下文图:展示视图中的系统或部分系统如何与环境关联。
- 可变性指南:展示如何运用变化点,告知可能出现的变化
- 基本原理(Rationale):解释设计为何如此。
文档化视图以外的信息
文档控制信息:列出发布组织、版本号、日期和状态、变更历史、提交变更请求的程序。
文档路线图:告诉读者文档中包含哪些信息(范围和摘要等),以及在哪里可以找到这些信息。
视图文档化方式:解释视图的标准组织方式
系统概述:用简短的文字描述系统的功能、其用户,以及任何重要的背景或约束。
视图间映射:帮助读者理解视图间的关联。可以用表格记录。
基本原理:记录适用于多个视图的架构决策
目录:参考资料,帮助读者快速找到更多信息:术语索引、词汇表、缩略语列表
微服务架构
微服务架构是把应用程序功能性分解为一组服务的架构风格,每一个服务都是由一组专注、内聚的功能职责组成。
主要特性
- 通过服务组件化
- 围绕业务能力组织
- 服务内高内聚和服务间低耦合
- 去中心化
- 基础设施自动化
- 服务高可用设计和演进式设计
其余特性:
高可伸缩、每个服务相对较小并容易维护、技术栈不受限、服务可以独立扩展、大型复杂程序可以持续部署和交付
模式和模式语言
模式:针对特定上下文中发生的问题的可重用解决方案
上下文(Context):问题特定的场景
问题(Problems):需要解决的问题
需求(Forces):需求、优先级和其他约束
方案(Solution):可重用的解决方案
结果(Consequences):采用模式后的后果
- 好处
- 弊端
- 问题
相关模式(Related patterns):与其他模式之间的关系
前导(Predecessor )
后续(Successor )
替代(Alternative )
泛化(Generalization)
特化(Specialization)
微服务架构模式语言就是一组模式,帮助解决微服务架构设计问题,包括应用相关模式组,应用基础设施相关模式组,基础设施相关模式组
微服务拆分
问题:如何将应用拆分为合适粒度的微服务?或如何划分合适的微服务边界?
需求:
- 高内聚
- 低耦合
- 单一职责原则
- 共同封闭原则
- 双披萨团队开发
- 团队自洽
- ……
关键步骤
- 定义系统操作:将需求提炼为系统关键请求
- 定义微服务:根据业务能力或子域或动静态调用关系进行服务拆分
- 定义服务API和协作方式:将标识的系统操作分配给服务,独立或与其他服务协作
⚠️ 以下部分考虑设计题
定义系统操作
输入:需求,用户故事/相关用户场景/源代码恢复等
流程:
- 步骤1:创建领域模型
- 关键概念/类组成
- 关键类是用户故事中的名词
- 从输入中提取
- 领域专家沟通或事件风暴
- 关键概念/类组成
- 步骤2:确定系统操作
- 用户故事中的动词
- 操作行为指对领域对象的影响及之间关系
- 创建/删除/更新领域对象,创建/破坏关系
定义微服务
根据业务能力拆分
业务能力:业务架构建模的术语
- 为企业产生价值的商业活动,较为稳定
- 示例
- 保险公司:承保、理赔服务、账务和合规等
- 在线商店:订单管理、库存管理和发货等
- ……
- 业务能力的实现方式相对不稳定
- 示例:银行“兑现支票” — 纸质/ATM机/手机等
- 获取方式
- 通过分析组织目标、结构、商业流程得到
- 特征
- 一个业务能力往往对应特定的业务对象
- 能力可分解为子能力
- 示例:订单获取和履行的5个子能力
业务能力到服务
- 顶级能力或子能力映射到服务
- 顶级能力直接映射
- 用户服务
- 会计记账服务(统一处理支付和计费)
- 子能力分解映射
- 供应商管理2个服务(两个不同的供应商)
- 订单获取和履行3个服务(3个阶段)
- 顶级能力直接映射
- 映射具有一定的主观性
- 分解方式可能会变化(组合或进一步拆分)
- 通信效率
- 变更频率
- ……
- 结果-优点
- 架构稳定(业务能力相对稳定)
- 开发团队跨职能、自治,围绕交付业务价值而非技术特性进行组织
- 服务高内聚和松耦合
- 结果-问题
- 如何分析业务能力:分析组织的目的、结构、业务流程
- 相关模式
- 根据子域拆分、动静态调用关系进行服务拆分
根据子域拆分
子域:领域驱动设计方法论的核心
领域驱动设计(DDD)
- 解决复杂软件业务领域范围/业务边界划分的问题
- 业务出发,以面向对象和领域模型为核心
领域
- 描述问题域,一种特定的范围,电商、外卖、保险…
- 子域是领域的细分,电商(订单、商品、物流)
- 核心域、通用域、支撑域
核心思想和流程
- 将问题域逐级细分,降低理解和实现的复杂度
- 从业务需求中提炼统一语言
- 战略设计
- 构建领域模型,识别限界上下文,确定领域边界
- 上下文映射建立领域间关系
- 划分(微)服务的逻辑和物理边界
- 战术设计
- 限界上下文内领域建模,指导程序设计、编码和重构
通用语言(Ubiquitous Language)
- 定义领域内相关团队的词汇表
- 统一、简单、清晰、准确描述业务规则和业务
- 理解不一致问题,如账户
- 身份和访问管理上下文,身份验证和授权的凭证
- 客户管理上下文,人口统计和联系人属性
- 财务会计上下文,付款和历史交易的特定信息
领域模型 (Domain Model)
- 以解决具体问题的方式包含一个领域的知识
- 为每一个子域定义单独的领域模型
限界上下文(Bounded Context)
- 领域模型的边界
- 包括实现模型的代码集合
- 对应微服务架构中一个或一组服务
结果-优点
- 高内聚和松耦合
- 子域和限界上下文与微服务边界匹配
- 架构稳定(子域相对稳定)
- 领域模型由团队独立开发、支持团队自治
- 子域用于自己的领域模型,消除上帝类和优化拆分
结果-问题
- 如何识别子域:分析业务及其组织结构并识别不同的专业领域
相关模式
- 根据业务能力、动静态调用关系进行服务拆分
根据动静态调用关系拆分
- 收集单体应用动静态调用信息
- 静态:用例分析、字节码解析、API接口
- 动态:调用链路、数据流图、控制流图
- 构建有向带权图(调用频率、变更频率等)
- 基于聚类算法拆分
- 结果
- 棕地开发场景的拆分(遗留系统)
- 自动化、效率高
- 受限于遗留系统的分析和数据收集难度
- 相关模式
- 根据业务能力、子域进行服务拆分
API定义、实现
- 服务API操作的存在原因
- 某些操作对应于系统操作(外部客户端/其他服务调用)
- 存在其他操作支持服务间协作(其他服务调用)
- 通过事件发布支持协作
- API定义流程
- 将系统操作分配给服务
- 确定支持协作的API
步骤1:将系统操作分配给服务
- 确定请求的初始入口服务
- 映射不清晰的服务
- 其他情况将分配给具有处理它所需信息的服务
步骤2:确定支持协作的API
某些操作可以由单个服务处理
verifyConsumerDetails()
某些操作跨越多个服务(数据分散)
createOrder()调用多个服务:验证前置条件并使后置条件成立acceptOrder()调用配送服务安排送餐员并交付订单
进程间通信技术
重构策略
微服务架构通信
应用层服务发现模式
问题:基于 RPI 的客户端如何在网络上发现服务实例的位置?
自注册:服务实例调用服务注册表的注册API来注册其网络位置(服务注册表定期调用心跳API)
客户端发现:客户端查询服务注册表以获取服务实例的列表(缓存+负载均衡,提高性能)
- 结果
- 处理多平台部署的问题
- 服务发现机制与具体的部署平台无关,Eureka vs. K8s
- 需要为使用的每种编程语言(可能还有框架)提供服务发现库
- Spring Cloud仅支持
- 开发者负责设置和管理服务注册表,分散精力
- 处理多平台部署的问题
- 相关模式
- 前序模式:同步远程过程调用
- 替代模式:平台层服务发现模式
平台层服务发现模式
第三方注册:由第三方负责(注册服务器,通常是部署平台的一部分)处理注册,而不是服务本身向服务注册表注册自己
服务端发现:客户端无需查询服务注册表,而是向DNS名称发出请求,对该DNS名称的请求被解析到路由器,路由器查询服务注册表并对请求进行负载均衡
- 结果
- 完全交给部署平台,服务端、客户端代码减负
- 多语言支持度较高
- 存在平台约束
- 相关模式
- 前序模式:同步远程过程调用
- 替代模式:应用层服务发现模式
API网关模式
问题:如何处理外部客户端与服务之间的通讯?
- 需求:支持多种客户端的API
- 细粒度API,客户端与多项服务交互请求效率低
- 不同客户端需要不同的数据,性能要求亦有区别
- 缺少封装,影响可修改性(服务划分方式变化)
- 服务的实例数量与位置(地址和端口)动态变化
- 对客户端不友好的进程间通信(防火墙内外协议不同)
- 模式:API Gateway模式
- 实现一个服务,外部API客户端进入基于微服务应用的入口点
- 针对不同客户端提供不同的API
- 结果
- 封装应用程序内部结构,减少交互(请求往返)次数
- 确保客户端不受服务实例位置影响
- API组合、协议转换和边缘功能,身份验证等
- 问题:性能和可扩展性、局部故障等
- 相关模式
- 替代模式:后端前置模式
- 后续模式:断路器模式、服务发现模式
断路器模式
问题:同步通信中如何避免由于服务故障或网络中断所引起的故障蔓延到其他服务?
- 模式:断路器(Circuit Breaker)
- 闭合状态:对程序的请求能够直接引起方法的调用
- 断开状态:对程序的请求会立即返回错误响应
- 半断开状态:允许对程序的一定数量的请求可以调用服务,如调用成功,可认为之前导致调用失败的错误已经修正,熔断器切换到闭合状态;如调用失败,则认为问题仍存在,熔断器切回到断开状态
- 结果
- 防止不断地尝试执行可能会失败的操作
- 使程序能够诊断错误是否已经修正,进而再次尝试调用操作
- 相关模式
- 前序模式:同步远程过程调用模式
微服务架构部署模式
将服务部署到容器
将服务打包为 (Docker) 容器镜像并将每个服务实例部署到容器
容器是一种更现代、更轻量级的部署机制,操作系统级的虚拟化机制
容器由在隔离的沙箱中运行的一个或多个进程组成,多个容器通常在一台机器上运行,容器共享操作系统
从在容器中运行的进程的角度来看,它就好像在自己的机器上运行一样,有独立IP、可消除端口冲突
优点
- 通过更改容器实例的数量可以直接扩展和缩减服务
- 容器封装了用于构建服务的技术细节,所有服务都以完全相同的方式启动和停止
- 每个服务实例都是隔离的
- 容器对服务实例消耗的 CPU 和内存施加限制
- 容器的构建和启动速度非常快
- 将应用程序打包为 Docker 容器比将其打包为 AMI 快 100 倍
- Docker 容器启动速度明显快于 VM (仅启动应用程序进程而非整个操作系统)
缺点
- 大量的容器镜像管理工作(操作系统补丁、基础设施)
- 部署容器的基础设施不如部署虚拟机的基础设施丰富
相关模式
- 替代模式:将服务部署到虚拟机
- 泛化模式:单主机部署单个服务实例
微服务架构可观测模式
日志聚合模式
使用集中式日志记录服务聚合来自每个服务实例的日志,用户可搜索和分析日志,可配置当某些消息出现在日志中时触发的警报
- 缺点
- 处理大量日志需要大量的基础设施
- 相关模式
- 分布式追踪、异常跟踪
审计日志模式
向业务逻辑中添加审计日志代码,创建审核日志条目并保存在数据库中
- 优点
- 提供用户操作的记录
- 缺点
- 审计代码与业务逻辑交织,使业务逻辑复杂化
- 相关模式
- 后续模式:事件溯源(实施审计的可靠方式)
应用程序指标模式
检测服务以收集有关各个操作的统计信息,在集中式指标服务中聚合指标,提供报告和警报。聚合指标两种模型:
1)push - 服务将指标推送到指标服务
2)pull - 指标服务从服务中提取指标
- 优点
- 提供对应用程序行为的深入洞察
- 缺点
- 指标代码与业务逻辑交织在一起,使其更加复杂
- 聚合指标可能需要大量的基础设施
- 相关模式
- 其他可观测性模式
分布式追踪模式
记录单次请求范围以内的信息,为每个外部请求分配一个唯一的外部请求ID,并在提供可视化和分析的集中式服务器中记录请求如何从一个服务流向下一个服务。
在所有日志消息中包含外部请求ID,记录在集中服务中处理外部请求时执行的请求和操作的信息(例如开始时间、结束时间)
- 优点
- 提供了对系统行为的有用洞察,包括延迟的来源
- 使开发人员能够通过在聚合日志中搜索其外部请求 ID来查看单个请求是如何处理的
- 缺点
- 聚合和存储追踪数据可能需要大量的基础设施
- 相关模式
- 日志聚合 - 外部请求 ID 包含在每个日志消息中
异常跟踪模式
向集中式异常跟踪服务报告所有异常,该服务聚合和跟踪异常并通知开发人员。
- 优点
- 更容易查看异常并跟踪其解决方案
- 缺点
- 异常跟踪服务是额外的基础设施
- 相关模式
- 日志聚合 - 应记录异常并报告给跟踪服务
健康检查API模式
使用 Spring Boot 和 Spring Cloud 作为微服务框架,提供健康检查端点,配置调用/health可扩展健康检查逻辑的 HTTP 端点。
- 优点
- 定期测试服务实例的健康状况
- 缺点
- 不够全面
- 服务实例可能在健康检查之间失败
- 相关模式
- 前置模式:服务注册与发现模式、部署相关模式
架构模式
说实话上面都是祖传理论就算了,这个一眼AI-generated的理论我无法绷住,老师和学生之间的双向糊弄
主机/终端
迁移原因
上一代模式在新约束下的问题:
- 无法支撑大量用户持续在线访问同一数据
- 缺少统一的事务、权限与审计控制
- 数据共享与并发访问一多,批处理思路就会失灵
因此系统必须从执行任务转向服务一群用户
架构结构
- 主机承担几乎全部事务处理、数据存储与权限控制
- 终端主要负责输入、显示、不承载复杂业务逻辑
- 安全、审计和一致性都被集中到中心系统
本质通过“强中心+弱终端”换取一致性、安全性与治理能力
核心思想
通过事务中心化,把“多人共享”从混乱访问变成可治理的制度化系统
- 统一事务:同一份核心数据由中心系统负责一致性
- 统一安全:权限、审计与访问路径集中控制
- 统一资源共享:昂贵算力服务更多终端用户
- 统一运维治理:关键系统更容易被制度化管理
解决的是“很多人如何共享核心事务系统”;但是交互灵活性依然很弱
对质量属性的影响
由于越来越多的用户要共享同一套核心事务与核心数据,因此要优先保障一致性、安全性、可靠性、可审计性,而相对牺牲易用性、交互响应性和局部可修改性。
具体业务系统
C/S
迁移原因
PC与GUI普及,用户要求桌面交互
上一代模式:
- 终端太“瘦”,难以支持复杂GUI与本地交互
- 所有变化都压到中心系统,部门级快速建设很难
- PC算力已可用,完全不下放逻辑变得不经济
系统开始把交互迁移到客户端,把共享数据留在服务器
架构结构
- 客户端负责UI与部分本地逻辑,提升响应性与体验
- 服务器负责共享数据与部分公共逻辑
- 前后端通过网络协作,形成分布式桌面计算
本质:把“富交互”从中心系统迁移到桌面端
核心思想
通过客户端做交互、服务器保数据的分工,第一次把企业软件真正贴近了桌面用户
- 界面前移:GUI与本地状态处理让体验显著改善
- 响应更快:一部分逻辑直接在本地完成
- 建设更快:部门级系统能较快上线
- 共享仍存在:核心数据依旧保留在服务器端统一管理
解决的是怎样做富交互,但把部署和版本复杂度也搬到了客户端
对质量属性的影响
由于用户开始要求更丰富、更即时的桌面交互,因此要优先保障易用性、响应性、交互体验,而相对牺牲可部署性、可维护性、兼容性、统一治理。
具体业务系统
三层/分层
迁移原因
Web成为统一入口,要降低部署复杂度,并把系统内部职责整理清楚
上一代模式:
- 客户端安装、升级、兼容成本随着规模上升而爆炸
- 客户端直接或强耦合访问数据层,不利于统一治理
- 一个系统里混杂了太多展示、业务和数据处理
重心从“前后分工”进一步转向“服务端内部清晰分层”
架构结构
- 表示层负责接入与界面呈现,统一用户入口
- 业务层承载业务规则、流程控制与领域逻辑
- 数据层负责持久化与数据访问,形成清晰职责边界
本质通过职责分层控制变化影响,而不是只做客户端瘦身
核心思想
通过统一入口和职责分层,把部署问题和维护问题同时压了下来
- 浏览器统一接入:客户端安装与升级成本明显下降
- 逻辑集中到服务端:业务规则更容易统一修改与治理
- 分层控制变化:界面变化、业务变化、数据变化尽量局部化
- 安全更清晰:数据访问不必暴露到大量客户端
解决的是系统内如何更清楚,但没有解决系统间如何协同
对质量属性的影响
由于既要统一入口,又要降低维护成本并把系统内部职责整理清楚,因此要优先保障可维护性、可修改性、安全性、可部署性,而相对牺牲极致性能、跨系统协同灵活性、快速局部自治。
具体业务系统
SOA
迁移原因
系统数量激增,企业需要跨系统复用业务能力,并打通端到端流程
上一代模式:
- 系统之间依旧割裂,集成靠大量点对点接口
- 同一业务能力在不同系统中重复实现
- 跨系统流程一变动,协调成本就会迅速上升
企业需要从应用视角上升到服务能力视角
架构结构
- 能力通过服务契约暴露,不再只藏在某个应用内部
- ESB / 中间件负责路由、转换、编排与集成
- 治理体系负责版本、规范、注册、权限与生命周期
本质把系统功能提升为可复用的服务能力
核心思想
它通过“契约 + 总线 + 编排 + 治理” ,把企业从孤岛系统集合拉向了能力网络
- 契约标准化:能力接口与系统内部实现脱钩
- 服务复用:各个能力不必每个系统重写
- 流程编排:跨系统业务流程可以串起来
- 异构整合:不同技术栈也能进入统一企业流程
解决的是全企业协同,代价是治理体系更重、中心中间件更强
对质量属性的影响
由于系统数量激增后企业需要跨系统复用能力并打通端到端流程,因此要优先保障互操作性、可复用性、可组合性、可治理性,而相对牺牲简单性、响应性能、轻量部署、局部演进速度。
具体业务系统
课件没有
微服务
迁移原因
交付频率大幅提升;团队要更快迭代,但 SOA 的重治理与粗粒度服务拖慢了速度
上一代模式:
- 服务边界偏粗,不易与快速变化的产品边界对齐
- 中心治理与总线容易形成变更瓶颈
- 跨团队依赖多,难以实现真正的独立发布
因此服务必须更贴近业务能力、团队边界和发布节奏
架构结构
系统围绕相对独立的业务能力拆成多个小服务
每个服务由相对独立的团队负责其开发、部署与运维
接口协作替代共享实现,数据尽量跟随服务边界自治
本质让系统边界、团队边界、发布边界尽量对齐
核心思想
通过更小的业务边界与独立部署,把交付链条显著缩短
- 边界更小:单次改动影响范围更可控
- 团队自洽:一支团队可以端到端拥有一块能力
- 部署更独立:不必每次都整体发布整套系统
- 扩展更局部:热点能力可以单独扩容
微服务不是服务更多,而是演进单位更小、交付链更短
对质量属性的影响
由于产品迭代太快,团队需要围绕业务能力独立开发与发布,因此要优先保障可部署性、可扩展性、可修改性、演进速度,而相对牺牲一致性、运维简单性、故障定位性、全局可理解性。
具体业务系统
事件驱动/云原生
迁移原因
系统规模与流量波动持续放大,同步链路过长、扩缩容困难、人工运维不可持续
上一代模式:
- 全同步调用链会放大尾延迟和级联故障
- 服务变多后,发布、扩容、恢复、观测仍高度依赖人工
- 运行能力如果不平台化,规模效应无法形成
系统既要改变写作方式,也要改变运行方式
架构结构
- 事件驱动:生产者发布事实,消费者按需订阅并处理
- 消息 / 流平台承担传递、缓冲、削峰与异步解耦
- 云原生平台承担编排、扩缩容、恢复、配置与观测
本质:事件驱动解决如何协作,云原生解决如何运行
核心思想
通过异步事件与平台化运行能力,让分布式系统更弹性、更韧性、更自动化
- 异步解耦:生产者不必强依赖消费者
- 削峰与缓冲:流量波峰不再直接压垮下游
- 自动化运行:扩容、恢复、调度尽量交给平台处理
- 可观测性前置:运行状态必须被显式监控和追踪
把系统运行能力正式拉进了架构主体,而不再只是运维附属
对质量属性的影响
由于系统规模和流量波动放大,同步链路过长,人工运维不可持续,因此要优先保障弹性、韧性、可扩展性、可用性、自动化运维能力,而相对牺牲可理解性、可调试性、时序可预测性、强一致性。
具体业务系统
LJ.skill整理的核心思想速记
主机/终端:
- 组织核心事务
- 事务、数据、权限集中在主机,终端主要输入与显示
C/S:
- 组织交互能力
- 客户端承担UI与部分逻辑,服务器管理共享数据
三层/分层:
- 组织职责边界:
- 表示层、业务层、数据层分离,降低系统内部解耦
SOA:
- 组织企业服务能力
- 通过服务契约暴露可复用能力,支撑跨系统整合
微服务:
- 组织独立演进单元
- 围绕业务能力拆服务,使团队、代码和发布边界对齐
事件驱动 / 云原生:
- 组织运行时协作:
- 事件负责异步协作,平台负责部署、扩缩容、恢复和观测。
LJ.skill整理的迁移原因速记
主机/终端:
- 交互能力弱,终端灵活性低
C/S:
- 客户端安装升级重,版本与兼容难治理
三层/分层:
- 单系统可维护性提升,但跨系统复用不足
SOA:
- 企业级整合增强,但治理与总线较重
微服务:
- 局部发布更快,但分布式复杂度上升
事件驱动 / 云原生:
- 更适合高波动运行时,但时序与排障更难
LJ.skill整理的质量属性取舍速记
| 架构 | 优先保障 | 相对牺牲 / 新复杂性 |
|---|---|---|
| 主机 / 终端 | 一致性、安全性、可靠性、可审计性 | 易用性、交互响应性、局部修改灵活性 |
| C/S | 易用性、响应性、桌面交互体验 | 可部署性、可维护性、版本一致性、统一治理 |
| 三层 / 分层 | 可维护性、可修改性、安全边界、部署治理 | 极致性能、跨系统复用、团队自治速度 |
| SOA | 互操作性、可复用性、可组合性、可治理性 | 简单性、响应性能、轻量部署、局部演进速度 |
| 微服务 | 可部署性、可扩展性、可修改性、演进速度 | 强一致性、运维简单性、故障定位、全局理解 |
| 事件 / 云原生 | 弹性、韧性、可扩展性、可用性、自动化运维 | 可理解性、可调试性、时序可预测性、强一致性 |