22、软件架构设计决策与案例分析

软件架构设计决策与案例剖析

软件架构设计决策与案例分析

1. 通信方式选择原则

在软件架构设计中,同步通信在设计、实现和调试方面面临的挑战较少。因此,架构师应尽可能默认使用同步通信,仅在必要时采用异步通信。

2. 设计输出要素

架构设计过程的输出是架构拓扑,这需要考虑架构师选择的架构风格(及其混合形式)、架构决策记录(关于设计中架构师投入最多精力的部分)以及架构适配函数(用于保护重要原则和操作架构特性)。

3. 单体架构案例:Silicon Sandwiches
  • 架构特性与选择 :在对 Silicon Sandwiches 进行架构特性研究后,发现单个量子足以实现该系统。而且这是一个预算有限的简单应用,单体架构的简洁性颇具吸引力。
  • 组件设计 :为 Silicon Sandwiches 创建了两种不同的组件设计,一种是按领域划分,另一种是按技术划分。鉴于解决方案的简单性,将分别进行设计并探讨权衡。
  • 模块化单体架构
    • 架构特点 :模块化单体架构围绕领域构建组件,使用单个数据库,并作为单个量子部署。Silicon Sandwiches 的模块化单体设计如图 18 - 1 所示,它是一个具有单个关系数据库的单体架构,采用单一的基于 Web 的用户界面(同时考虑移动设备的设计)以降低总体成本。架构师之前确定的每个领域都作为组件出现。
    • 数据库设计考虑 :如果时间和资源允许,架构师应考虑像领域组件一样对表和其他数据库资产进行分离,以便在未来需求需要时更轻松地迁移到分布式架构。
    • 定制化设计 :由于架构风格本身并不天然支持定制化,架构师必须确保该功能成为领域设计的一部分。例如,设计一个 Override 端点,开发人员可以上传单个定制项。相应地,架构师必须确保每个领域组件针对每个可定制特性引用 Override 组件,这将是一个理想的适配函数。
  • 微内核架构
    • 架构特性与选择依据 :架构师在 Silicon Sandwiches 中确定的一个架构特性是可定制性。从领域/架构同构的角度看,架构师可能会选择使用微内核来实现,如图 18 - 2 所示。
    • 核心系统设计 :核心系统由领域组件和单个关系数据库组成。与之前的设计一样,领域和数据设计之间的仔细同步将允许核心在未来迁移到分布式架构。
    • 定制化实现 :每个定制项以插件形式出现,常见的定制项放在一组插件(带有相应数据库)中,一系列本地定制项各自拥有自己的数据。由于插件之间无需耦合,它们可以各自维护自己的数据,从而实现插件的解耦。
    • BFF 模式应用 :另一个独特的设计元素是利用 Backends for Frontends(BFF)模式,使 API 层成为一个薄的微内核适配器。它从后端提供通用信息,BFF 适配器将通用信息转换为前端设备适用的格式。例如,iOS 的 BFF 将获取后端的通用输出并为 iOS 原生应用进行定制,包括数据格式、分页、延迟等因素。构建每个 BFF 适配器可以实现最丰富的用户界面,并在未来支持其他设备扩展,这是微内核风格的优势之一。
  • 通信方式 :Silicon Sandwiches 架构内的通信可以是同步的,因为该架构不需要极端的性能或弹性要求,且所有操作都不会很长。
4. 分布式架构案例:Going, Going, Gone
  • 架构挑战 :Going, Going, Gone(GGG)案例带来了更具挑战性的架构问题。根据组件分析,该架构的不同部分需要不同的架构特性。例如,拍卖师和投标人等角色在可用性和可扩展性等架构特性上存在差异。
  • 架构特性要求 :GGG 的需求明确提出了一定程度的规模、弹性、性能和其他复杂的操作架构特性。架构师需要选择一种能够在架构内进行细粒度高度定制的模式。在候选的分布式架构中,低级别事件驱动架构或微服务架构最符合大多数架构特性。其中,微服务架构更能支持不同的操作架构特性,因为纯事件驱动架构通常不会因这些操作架构特性而分离组件,而是基于通信风格(编排与协作)。
  • 微服务实现
    • 服务与组件对应 :GGG 的微服务实现如图 18 - 3 所示,每个确定的组件都成为架构中的服务,组件和服务的粒度相匹配。
    • 用户界面 :GGG 有三种不同的用户界面,分别是众多在线拍卖的投标人界面、每个拍卖一个的拍卖师界面以及负责向投标人流式传输视频和投标流的流服务界面(这是一个只读流,允许进行更新时无法实现的优化)。
    • 服务列表
      | 服务名称 | 功能描述 |
      | — | — |
      | BidCapture | 捕获在线投标人的输入,并异步发送到 Bid Tracker。该服务无需持久化,仅作为在线投标的通道。 |
      | BidStreamer | 以高性能只读流的方式将投标信息返回给在线参与者。 |
      | BidTracker | 跟踪来自 Auctioneer Capture 和 Bid Capture 的投标。它是统一两个不同信息流的组件,尽可能实时地对投标进行排序。该服务的两个入站连接都是异步的,允许开发人员使用消息队列作为缓冲区来处理不同速率的消息流。 |
      | Auctioneer Capture | 捕获拍卖师的投标。由于 Auctioneer Capture 和 Bid Capture 具有不同的架构特性,架构师将它们分开。 |
      | Auction Session | 管理单个拍卖的工作流程。 |
      | Payment | 第三方支付提供商,在拍卖会话完成后处理支付信息。 |
      | Video Capture | 捕获现场拍卖的视频流。 |
      | Video Streamer | 将拍卖视频流式传输给在线投标人。 |
  • 通信方式选择 :架构师仔细确定了该架构中的同步和异步通信方式。选择异步通信主要是为了适应服务之间不同的操作架构特性。例如,如果 Payment 服务每 500 毫秒只能处理一笔新支付,而大量拍卖同时结束,服务之间的同步通信将导致超时和其他可靠性问题。通过使用消息队列,架构师可以为架构中脆弱的关键部分增加可靠性。
  • 量子分析 :最终分析表明,该设计确定了五个量子,如图 18 - 4 所示,包括 Payment、Auctioneer、Bidder、Bidder Streams 和 Bid Tracker,大致对应于服务。图中用容器堆栈表示多个实例。在组件设计阶段使用量子分析使架构师能够更轻松地确定服务、数据和通信边界。需要注意的是,这并不是 GGG 的“正确”设计,也不是唯一的设计,甚至不能说是最佳设计,但它似乎是权衡后较优的选择。选择微服务架构,然后明智地使用事件和消息,使架构能够充分利用通用架构模式,同时为未来的开发和扩展奠定基础。
graph LR
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;

    A[Silicon Sandwiches]:::process --> B[模块化单体架构]:::process
    A --> C[微内核架构]:::process
    B --> B1[按领域划分组件]:::process
    B --> B2[单一关系数据库]:::process
    B --> B3[Web 用户界面]:::process
    C --> C1[核心系统]:::process
    C --> C2[插件定制]:::process
    C --> C3[BFF 模式]:::process
    D[Going, Going, Gone]:::process --> E[微服务架构]:::process
    E --> E1[BidCapture 服务]:::process
    E --> E2[BidStreamer 服务]:::process
    E --> E3[BidTracker 服务]:::process
    E --> E4[Auctioneer Capture 服务]:::process
    E --> E5[Auction Session 服务]:::process
    E --> E6[Payment 服务]:::process
    E --> E7[Video Capture 服务]:::process
    E --> E8[Video Streamer 服务]:::process
5. 架构决策相关内容
  • 架构决策的核心要点 :架构师的核心职责之一是做出架构决策。架构决策通常涉及应用程序或系统的结构,也可能涉及技术决策,特别是当这些技术决策影响架构特性时。一个好的架构决策应有助于指导开发团队做出正确的技术选择。做出架构决策包括收集足够的相关信息、为决策提供理由、记录决策并将决策有效地传达给相关利益相关者。
  • 架构决策反模式
    • Covering Your Assets 反模式
      • 问题描述 :这是在尝试做出架构决策时出现的第一个反模式。当架构师因害怕做出错误选择而避免或推迟做出架构决策时,就会出现这种反模式。
      • 解决方法 :一是等到最后负责时刻做出重要的架构决策,即等到有足够信息来证明和验证决策,但又不至于拖延太久导致阻碍开发团队或陷入分析瘫痪反模式。二是持续与开发团队合作,确保做出的决策能够按预期实现。例如,架构师决定将所有产品相关的参考数据(产品描述、重量和尺寸)使用只读复制缓存缓存在所有需要该信息的服务实例中,主副本由目录服务拥有。这样做的理由是减少服务之间的耦合并有效共享数据,而无需进行服务间调用。然而,开发团队在实现过程中发现,由于某些服务的可扩展性要求,该决策需要的进程内内存超过了可用内存。通过与开发团队密切合作,架构师可以迅速意识到问题并调整决策。
    • Groundhog Day 反模式
      • 问题描述 :当架构师克服了 Covering Your Assets 反模式并开始做出决策后,会出现第二个反模式——Groundhog Day 反模式。当人们不知道决策的原因时,决策会被反复讨论。该反模式得名于电影《土拨鼠之日》,片中每天都是 2 月 2 日。
      • 解决方法 :架构师在做出架构决策时,必须同时提供技术和业务理由。例如,架构师决定将单体应用拆分为多个独立服务,以解耦应用的功能方面,使应用的每个部分使用更少的虚拟机资源并可单独维护和部署。这是一个很好的技术理由,但缺少业务理由,即企业为何要为这种架构重构付费。一个好的业务理由可能是更快地交付新的业务功能,从而缩短上市时间,或者降低开发和发布新功能的成本。提供业务价值对于任何架构决策都至关重要,也是判断是否应该做出该架构决策的重要标准。常见的业务理由包括成本、上市时间、用户满意度和战略定位。在考虑这些业务理由时,需要考虑业务利益相关者的关注点。
    • Email - Driven Architecture 反模式
      • 问题描述 :当架构师做出决策并充分说明理由后,会出现第三个架构反模式——Email - Driven Architecture 反模式。当人们丢失、忘记或根本不知道架构决策已经做出,从而无法实现该决策时,就会出现这种反模式。该反模式主要涉及如何有效地传达架构决策。电子邮件是一种很好的沟通工具,但不适合作为文档存储系统。
      • 解决方法
        • 避免在邮件正文中包含决策内容 :在邮件正文中包含架构决策会导致该决策有多个记录系统。很多时候,重要细节(包括理由)会在邮件中缺失,从而再次引发 Groundhog Day 反模式。而且,如果架构决策发生更改或被替代,有多少人会收到修订后的决策呢?更好的方法是在邮件正文中只提及决策的性质和背景,并提供实际架构决策及相应细节的单一记录系统的链接(可以是维基页面或文件系统中的文档链接)。
        • 仅通知相关人员 :一种有效的技巧是在邮件正文中这样写:“Hi Sandra,我做出了一个关于服务间通信的重要决策,该决策直接影响到你。请通过以下链接查看决策……”注意第一句的措辞,提到了决策的背景,但没有提及实际决策内容。更重要的是“直接影响到你”,如果架构决策不会直接影响到某人,就无需让其知晓该决策。这是确定哪些利益相关者(包括开发人员)应直接收到架构决策通知的重要标准。第二句提供了架构决策的位置链接,确保决策只有一个记录系统。
  • 架构重要性决策
    • 决策定义 :许多架构师认为,如果架构决策涉及特定技术,那它就不是架构决策,而是技术决策。但事实并非总是如此。如果架构师决定使用特定技术是因为它直接支持特定的架构特性(如性能或可扩展性),那么这就是一个架构决策。Michael Nygard 提出了“架构重要性决策”的概念,即那些影响结构、非功能特性、依赖关系、接口或构建技术的决策。
    • 决策要素分析
      • 结构 :指影响所使用的架构模式或风格的决策。例如,决定在一组微服务之间共享数据,这会影响微服务的边界上下文,从而影响应用程序的结构。
      • 非功能特性 :是指对正在开发或维护的应用程序或系统至关重要的架构特性(如“-ilities”特性)。如果技术选择影响到性能,而性能是应用程序的重要方面,那么这就是一个架构决策。
      • 依赖关系 :指系统内组件和/或服务之间的耦合点,会影响整体的可扩展性、模块化、敏捷性、可测试性、可靠性等。
graph LR
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;

    A[架构决策]:::process --> B[Covering Your Assets 反模式]:::process
    A --> C[Groundhog Day 反模式]:::process
    A --> D[Email - Driven Architecture 反模式]:::process
    B --> B1[等待最后负责时刻]:::process
    B --> B2[与开发团队合作]:::process
    C --> C1[提供技术理由]:::process
    C --> C2[提供业务理由]:::process
    D --> D1[不在邮件正文包含决策]:::process
    D --> D2[仅通知相关人员]:::process

软件架构设计决策与案例分析

6. 架构决策反模式总结与应对流程

为了更清晰地理解架构决策反模式及其应对方法,我们可以总结成以下表格:
| 反模式名称 | 问题描述 | 解决方法 |
| — | — | — |
| Covering Your Assets 反模式 | 架构师因害怕犯错避免或推迟决策 | 1. 等到最后负责时刻决策;2. 与开发团队持续合作 |
| Groundhog Day 反模式 | 人们不知决策原因,决策反复讨论 | 提供技术和业务理由 |
| Email - Driven Architecture 反模式 | 人们不知决策内容,无法实现决策 | 1. 邮件只提决策背景,提供单一记录系统链接;2. 仅通知相关人员 |

同时,我们可以用 mermaid 流程图来展示应对架构决策反模式的整体流程:

graph LR
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;

    A[开始决策]:::process --> B{是否有 Covering Your Assets 倾向}:::process
    B -- 是 --> C[采用对应解决方法]:::process
    B -- 否 --> D{是否出现 Groundhog Day 情况}:::process
    D -- 是 --> E[提供技术和业务理由]:::process
    D -- 否 --> F{是否有 Email - Driven Architecture 问题}:::process
    F -- 是 --> G[遵循邮件通知规则]:::process
    F -- 否 --> H[决策完成]:::process
    C --> D
    E --> F
    G --> H
7. 案例中的架构决策应用分析

在前面的两个案例中,架构决策的应用十分关键。
- Silicon Sandwiches 案例
- 通信方式决策 :选择同步通信是基于架构对极端性能和弹性要求不高,操作时间短的特点。这一决策减少了设计、实现和调试的复杂度,符合默认使用同步通信的原则。
- 架构风格选择 :考虑到系统简单且预算有限,选择单体架构(模块化单体和微内核)。模块化单体架构通过领域划分组件,使用单一数据库和 Web 界面降低成本;微内核架构则利用插件和 BFF 模式实现定制化和未来扩展。这些决策都是为了满足系统的功能和非功能需求。
- Going, Going, Gone 案例
- 架构模式选择 :面对不同角色对架构特性的不同要求以及高规模、弹性和性能需求,选择微服务架构。微服务架构能够更好地支持不同的操作架构特性,通过将组件拆分为服务,实现了细粒度的定制。
- 通信方式决策 :部分服务采用异步通信,如 Payment 服务与其他服务之间,是为了适应服务间不同的操作架构特性,避免同步通信带来的可靠性问题。

8. 架构决策的最佳实践建议

基于上述案例和反模式分析,我们可以总结出以下架构决策的最佳实践:
- 信息收集与分析
- 全面了解系统的功能和非功能需求,包括性能、可扩展性、可靠性等方面。
- 分析不同架构模式和技术对需求的支持程度,进行充分的调研和评估。
- 决策过程管理
- 遵循“默认同步,必要异步”的通信方式选择原则。
- 避免架构决策反模式,如及时决策、提供充分理由、有效传达决策等。
- 在组件设计阶段进行量子分析,明确服务、数据和通信边界。
- 团队协作与沟通
- 与开发团队密切合作,确保决策的可实现性。
- 仅将决策通知给直接相关的利益相关者,提高沟通效率。

9. 未来架构决策的趋势与挑战

随着技术的不断发展,软件架构决策将面临新的趋势和挑战。
- 趋势
- 云原生技术的广泛应用 :云原生架构(如容器、Kubernetes 等)提供了更高的弹性和可扩展性,架构师需要考虑如何将其融入到架构决策中。
- 人工智能与机器学习的融合 :在软件系统中引入人工智能和机器学习功能,对架构的性能和数据处理能力提出了更高要求。
- 边缘计算的兴起 :边缘计算可以减少数据传输延迟,架构师需要考虑边缘节点与中心节点的架构设计。
- 挑战
- 技术更新换代快 :新的技术和架构模式不断涌现,架构师需要不断学习和更新知识,以做出合适的决策。
- 安全与隐私问题 :随着数据泄露事件的增多,架构决策需要更加注重安全和隐私保护,确保系统的可靠性和合规性。
- 跨团队协作难度增加 :大型项目往往涉及多个团队的协作,架构决策需要协调各方利益,确保架构的一致性和可维护性。

10. 总结

软件架构决策是一个复杂而关键的过程,涉及到通信方式选择、架构风格确定、技术选型等多个方面。通过对案例的分析和反模式的研究,我们了解到架构决策需要遵循一定的原则,避免常见的错误。同时,架构师需要不断关注技术发展趋势,应对未来的挑战。在实际工作中,按照最佳实践进行架构决策,与团队有效协作,才能设计出满足需求、具有良好扩展性和可靠性的软件架构。

graph LR
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;

    A[架构决策]:::process --> B[信息收集与分析]:::process
    A --> C[决策过程管理]:::process
    A --> D[团队协作与沟通]:::process
    B --> E[了解系统需求]:::process
    B --> F[分析技术支持]:::process
    C --> G[遵循通信原则]:::process
    C --> H[避免反模式]:::process
    C --> I[量子分析]:::process
    D --> J[与开发团队合作]:::process
    D --> K[有效通知相关者]:::process
    E --> G
    F --> G
    G --> H
    H --> I
    J --> K
    I --> K

通过以上内容,我们对软件架构设计决策有了更深入的理解,希望这些知识能够帮助架构师在实际工作中做出更明智的决策。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值