软件架构设计原则

软件架构设计原则

本文档使用AI工具将原始的手工笔记进行了整合, 并由AI进行评审后统一修正、重组与补全。

本文档整合 12 份原始设计原则材料,修正错误并补充现代架构要点。遵循"精简为主,难点注解"原则。


1. 基础理论

1.1 CAP 定理

分布式系统最多同时满足以下两项:

特性 含义
Consistency(一致性) 所有节点同一时刻看到相同数据
Availability(可用性) 每个请求都能收到响应(不保证数据最新)
Partition Tolerance(分区容错) 网络分区时系统仍能运行

注解:网络分区(P)在分布式系统中必然发生(网络不可靠),所以实际是在 C 和 A 之间做选择。微服务通常选 AP + 最终一致性(如电商订单),金融核心系统可能选 CP(如银行转账)。

1.2 BASE 理论

CAP 的延伸,强调基本可用、软状态、最终一致

  • BAsically Available:系统出现故障时允许损失部分可用性(如降级为只读)
  • Soft state:允许数据存在中间状态
  • Eventually consistent:不保证实时一致,但最终会一致

1.3 PACELC 定理

CAP 的扩展,强调**延迟(Latency)**的权衡:

如果存在分区(P),在可用性(A)和一致性(C)之间选择;
否则(E,即正常运行),在延迟(L)和一致性(C)之间选择。

注解:例如 DynamoDB 选 PA/EL(分区时保可用,正常时保低延迟),MongoDB 选 PC/EC(分区时保一致,正常时也保一致)。

1.4 康威定律(Conway’s Law)

“设计系统的组织,其产生的设计等同于组织之内、组织之间的沟通结构。”

实践意义:团队结构决定系统架构。微服务团队应为"两个披萨团队"(6~10 人),每个团队端到端负责一个服务。


2. 12-Factor App

原始材料对 12-Factor 的翻译偏口语化,以下用精简技术语言重述。

原则 核心要求 实践
代码库 一份代码库,多份部署 Git 单仓库,通过分支/标签区分环境
依赖 显式声明依赖 package.jsonpom.xmlgo.mod,禁止隐式依赖系统包
配置 配置与代码分离 环境变量、配置中心(Nacos/Consul/ConfigMap),禁止硬编码
后端服务 将数据库/缓存等视为附加资源 通过 URL 连接,可随时替换(如 MySQL → PostgreSQL)
构建-发布-运行 严格分离三个阶段 构建(CI 产出制品)→ 发布(绑定配置)→ 运行(启动进程)
进程 以一个或多个无状态进程运行应用 状态外置(Redis/DB),实例可任意启停和替换
端口绑定 通过端口暴露服务 自包含 HTTP 服务,不依赖外部 Web 服务器
并发 通过进程模型扩展 水平扩展(加实例)而非垂直扩展(升配置)
易处理 快速启动、优雅终止 启动 < 5s,SIGTERM 时完成当前请求再退出
开发/生产等价 环境尽量一致 Docker 容器化,避免"在我机器上能跑"
日志 日志作为事件流 输出到 stdout,由外部系统(ELK/Loki)收集,应用不管理日志文件
管理进程 后台管理任务作为一次性进程运行 数据迁移、报表生成等通过独立 Job 执行

注解:12-Factor 诞生于 2012 年 Heroku 时代,核心思想至今有效。现代演进为 15-Factor(补充 API 优先、遥测、认证授权),但 12 条仍是基础。


3. 核心设计原则

原始材料提炼为四字诀:

原则 含义 实践
缓存 复用数据,减少重复计算 CDN、Redis、本地缓存、浏览器缓存
异步 避免阻塞,提升吞吐 消息队列、事件驱动、回调网关
前置 提前准备,缩短响应路径 CDN 预热、边缘计算、数据预加载
拆分 减少复杂度,隔离故障 微服务、DDD 限界上下文、读写分离

4. 系统分层设计

为什么要分层?

当组织节点较多时调用关系和逻辑愈发复杂,好的分层设计可以带来以下好处:

  1. 复用代码,
  2. 解耦合
  3. 屏蔽细节

分层带来的问题:

  1. 请求处理时间可能会增加
  2. 运维复杂性增加

4.1 物理分层(请求流向)

1
用户 → 终端 → 边缘设备(CDN) → 网关 → 应用层 → 数据层 → 基础设施层

4.2 逻辑分层

层级 职责 示例
视图层 用户可见的界面 Web 页面、App UI
网关层 路由、鉴权、限流 Spring Cloud Gateway、Kong、Envoy
前端业务层 校验、数据准备 参数校验、DTO 组装
核心业务层 主业务逻辑 订单创建、支付处理
基础业务层 通用后台功能 用户中心、支付中心、文件服务
基础数据层 数据访问抽象 ORM、数据库中间件、缓存中间件

注解:分层的本质是数据的移动——同一数据在不同层以最优形式展现。代价是请求链路变长、运维复杂度增加。分层不是越多越好,通常 3~4 层足够。

4.3 小前台、大中台

  • 小前台:前端系统尽量小,要求快速迭代和灵活响应业务
  • 大中台:将身份认证、交易、支付、消息等通用能力服务化,供多个前台复用

注解:中台不是技术中台一个概念,还包括业务中台、数据中台、算法中台。中台建设最大的坑是"为了中台而中台"——先有小前台的真实复用需求,再沉淀中台能力,而非先建中台再找场景。

4.4 前后端分离

分离前 分离后
后端渲染 HTML 后端提供 API(JSON/XML),前端独立渲染
前端小改动需后端配合发布 前后端独立部署、独立迭代

代价:SEO 不友好(SPA 需 SSR 解决)、沟通成本增加、团队技能要求分化。

4.5 其它分层

数据服务层: 对不同业务单元的数据提供统一的访问形式

  • 屏蔽多种业务的数据库和缓存等逻辑
  • 提供统一的 API 接口,上层业务无需关注分库分表等细节

5. 服务化与微服务

5.1 服务化抽象方向

抽象对象 服务化后 收益
数据库访问 数据访问服务(DAS) 屏蔽分库分表、缓存同步逻辑
缓存 缓存服务 统一缓存策略,替换组件(如 Memcached → Redis)不影响上层
用户数据 用户中心 统一用户画像、认证授权

5.2 服务化核心能力

  • 注册发现:服务自注册到注册中心(Nacos/Consul/etcd),调用方动态发现
  • 容错路由:熔断、限流、降级、重试
  • 本地短路:部分服务优先本地调用(同机部署)以减少网络开销
  • 调用方式:同步、异步、并行调用按需选择
  • 故障隔离:核心/非核心服务分开部署,单服务故障不扩散
  • 屏蔽细节:屏蔽底层实现细节,只暴露必要的业务 API

5.3 高可靠性设计

  1. 无状态设计:状态外置(Redis/DB),实例可任意替换
  2. 注册中心集群:即使注册中心宕机,已缓存的服务列表仍可继续运行
  3. API 网关屏蔽故障节点:健康检查自动剔除异常实例
  4. 跨机房路由:异地多活,就近访问

6. 依赖与耦合管理

6.1 反向依赖问题

问题:业务 A 变动,需要 B/C/D/F 配合修改。

场景 问题 解法
下游 IP 变更 上游硬编码 IP,需改配置重启 使用内网域名 + DNS,应用层具备重连机制
下游扩容 上游需同步调整连接池 引入注册中心或负载均衡器,上游无感知
公共库耦合 非共性功能沉淀在公共库 非共性上移;公共库改造为服务层,保持接口兼容

6.2 服务发现演进

1
硬编码IP → 配置文件 → 域名+hosts → 域名+DNS → 注册中心(etcd/Consul/Nacos) → K8s Service DNS
方案 优点 缺点
域名 + DNS IP 变动无需改应用 DNS 缓存更新慢(TTL),长连接不自动切换
注册中心 实时感知服务变化 引入新组件,需考虑自身高可用
K8s Service DNS 云原生原生支持 绑定 K8s 生态
网关负载均衡 集中管理路由 额外引入组件,需考虑自身高可用

注解:DNS 缓存是服务发现中最容易被忽视的问题。Linux 默认 nscd 缓存 5 分钟,JVM 缓存更久。生产环境建议 DNS TTL 设 10~30 秒,或应用层主动刷新。


7. 高可用设计

7.1 单点类型与消除

单点类型 示例 消除方案
入口型 Nginx、负载均衡器 多节点 + Keepalived/VRRP 虚拟 IP
存储型 数据库、SFTP 主从复制、多副本、分布式存储
逻辑型 定时任务调度器 分布式锁(Redis/ZooKeeper)选举主节点

注解:主备方案资源利用率仅 50%,现代架构倾向 多活(Active-Active)——所有节点同时提供服务,故障时流量自动切换,利用率接近 100%。

7.2 高可用机制

机制 原理 适用
副本机制 数据多份存储,一主多从 数据库、消息队列
Leader 选举 主节点故障时自动选举新主 Redis Sentinel、Kafka Controller、etcd
纠删码(Erasure Coding) 将数据分片编码存储,部分丢失可重建 对象存储(HDFS、Ceph、MinIO),节省存储成本

注解:纠删码 vs 副本的权衡——3 副本存储开销 200%,纠删码(如 4+2)开销 50%,但纠删码计算开销大、恢复慢。热数据用副本,冷数据用纠删码。

7.3 断路器(Circuit Breaker)

当外部接口大面积错误时:

  1. 限流降级:减少请求量,只保留核心请求
  2. 熔断断开:直接拒绝请求,1~3 分钟后探测恢复
  3. 快速失败:设置超时,避免长时间阻塞

注解:断路器三态——关闭(正常)→ 打开(熔断)→ 半开(探测)。半开状态放少量请求试探,成功则关闭,失败继续保持打开。Hystrix 已停止开发,现代用 Resilience4j(Java)或 Sentinel(阿里,功能更丰富)。


8. 容量与性能设计

8.1 容量评估四步法

步骤 方法 注意
1. 总访问量 业务方预估上线后总用户量 考虑交易特性(如电商大促)
2. 平均 QPS 总量 ÷ 总时间 按白天 12 小时 ≈ 4 万秒计算
3. 高峰 QPS 根据历史曲线或业务特征预估 秒杀场景峰值可能是均值 10~100 倍
4. 单机极限 压测得出单机最大 QPS 分层较多时先找到瓶颈层

最终资源 = 高峰 QPS ÷ 单机极限 QPS × 冗余系数(通常 1.5~2)

8.2 架构分离范式

分离方式 目的 实践
动静分离 静态资源走 CDN,动态请求走源站 页面/JS/CSS/图片/视频 上 CDN
读写分离 线性提升读性能 主库写、从库读,配合延迟监控
前后台分离 用户侧与运营侧解耦 前台保低延迟,后台容忍高延迟

注解:动态页面静态化(如新闻首页、商城首页提前生成 HTML)是动静分离的进阶——数据量不大、更新频率低的页面,定时任务生成静态页,用户直接访问 CDN 上的 HTML,源站压力趋近于零。


9. 扩展性设计

9.1 何时需要扩展

  • 业务量增 10~100 倍,数据量增数十 TB
  • 延迟要求更低,响应速度要求更快
  • 云化/容器化、新增数据中心
  • 引入新组件(大数据、AI)、接入公共服务(SSO)
  • 安全要求提升(双活多活、风控)

9.2 扩展性设计要点

  1. 不要过度设计:先满足当前 1~2 年需求,预留扩展接口
  2. 功能开关(Feature Toggle):新功能通过开关控制,随时回退
  3. 无状态化:状态外置,扩容只需加实例
  4. 水平扩展优先:加机器 > 升配置
  5. 接口兼容:向后兼容,支持灰度升级
  6. 故障隔离:单组件故障不扩散,可独立降级
  7. 成本控制:避免资源浪费,成本控制在可接受范围内

10. 现代架构设计要点(补充)

原始材料缺少以下现代架构核心内容,补充如下:

10.1 云原生(Cloud Native)

要素 含义 技术
容器化 应用打包为容器镜像,环境一致 Docker、containerd
编排 自动化部署、扩缩容、自愈 Kubernetes
微服务 服务独立部署、独立扩展 Spring Cloud、Dubbo、gRPC
服务网格 基础设施层处理服务间通信 Istio、Linkerd
声明式 API 描述期望状态,系统自动达成 K8s YAML、Terraform

注解:云原生的核心不是"用 K8s",而是不可变基础设施——服务器只读,任何变更通过重新部署实现,杜绝" snowflake server “(手工配置、无法复现的服务器)。

10.2 可观测性(Observability)

三大支柱 + 一个基础:

支柱 内容 工具
Metrics(指标) 聚合数值,看趋势 Prometheus + Grafana
Logging(日志) 离散事件,查细节 ELK / Loki / Fluentd
Tracing(追踪) 请求链路,定位慢点 Jaeger / SkyWalking / Zipkin
Profiling(剖析) 代码级性能分析 Pyroscope / Parca / Arthas

注解:可观测性 ≠ 监控。监控是"我知道问题在哪,设个告警”;可观测性是"我不知道问题在哪,通过数据探索发现"。现代架构要求OpenTelemetry 统一标准,避免各系统数据孤岛。

10.3 安全设计(Security by Design)

原则 实践
零信任(Zero Trust) 默认不信任任何请求,内外网一视同仁,全部认证授权
最小权限 服务只拥有完成工作所需的最小权限
安全左移 安全扫描前置到 CI 阶段(SAST/DAST/依赖扫描)
Secrets 管理 密码/密钥不硬编码,用 Vault / K8s Secret / 云 KMS
mTLS 服务间通信双向 TLS 加密(Istio/Linkerd 自动实现)

10.4 数据架构设计

模式 适用场景
CQRS 读写模型分离,读模型独立优化(ES/Redis)
Event Sourcing 审计要求高、需回放历史的场景
Saga 长事务分布式场景,通过补偿回滚
Outbox 保证数据库写入和消息发送原子性

10.5 SRE 与可靠性工程

概念 含义
SLI 服务质量指标(如延迟 P99 < 200ms)
SLO 服务质量目标(如可用性 99.99%)
SLA 服务等级协议(违约赔偿条款)
Error Budget 允许的错误配额,用完则暂停发布
Chaos Engineering 故意注入故障,验证系统恢复能力

10.6 FinOps(云成本优化)

  • 资源标签化,按团队/项目追踪成本
  • 自动伸缩(HPA/VPA/Cluster Autoscaler)避免过度预留
  • Spot/Preemptible 实例用于非关键负载
  • 存储分层(热数据 SSD、温数据 HDD、冷数据对象存储)

11. 架构设计 Checklist

业务功能

  • 需求理解 → 领域建模(DDD) → 数据结构设计
  • 选择合适的技术栈(语言、框架、数据库)

非业务功能

  • 安全性:防攻击、密码安全、传输加密、访问控制
  • 稳定性:防崩溃、故障隔离、风险承受能力评估
  • 高性能:响应时间、吞吐量、资源利用率
  • 灵活性:敏捷性(快速引入/淘汰组件)、弹性(平滑扩缩容)
  • 可维护性:自动化部署、故障自愈、减少人工介入
  • 成本:物理成本、建设成本、维护成本、人员成本
  • 易用性:运营人员能否通过系统产出决策
  • 生命周期:满足上线时间、运行周期、平稳下线
  • 外部依赖:外部系统支撑能力弱时,是否有冗余/容错设计

架构验证

  • 是否遵循 12-Factor / 云原生原则
  • 是否消除单点故障
  • 容量评估是否覆盖峰值(含秒杀场景)
  • 是否具备熔断、限流、降级能力
  • 是否具备可观测性(Metrics/Logging/Tracing)
  • 是否设计功能开关,支持灰度发布
  • 安全扫描是否集成到 CI 流水线
  • 是否具备混沌工程演练能力

文档版本:v2.0
整合说明:基于 12 份原始设计原则材料整合,修正了"频闭"等错别字、编号重复等问题,补充了 CAP/BASE/PACELC、云原生、可观测性、零信任安全、SRE、FinOps、CQRS/Event Sourcing/Saga 等现代架构设计要点。

Licensed under CC BY-NC-SA 4.0
转载或引用本文时请遵守许可协议,知会作者并注明出处
不得用于商业用途!
最后更新于 2026-03-15 00:00 UTC