第 1 章 · 企业级架构原则与分层
场景说明
团队把 demo-mall 从单机 Docker 迁到 K8s 后,功能都能跑,但大促前老板问三个问题:单点挂了怎么办?P99 多少?发布回滚要多久? 答不上来,说明还停在「演示级」,没到「企业级」。
本章建立 企业级架构 的共同语言:分层、边界、非功能需求(NFR)、架构决策记录(ADR)与技术栈映射。
课程结构:第 1~8 章概论 · 第 9~15 章专业深化 · 第 16~18 章三大跟练 · 工件格式见 ch14。
前置:xiaozi-cloud、paas 基础;ops-deploy 中与发布、监控相关的章节可并行阅读。
学完你能
| 能力 | 说明 |
|---|---|
| 区分演示级 vs 企业级 | 可用性、扩展、安全、可观测、演进五维 |
| 画四层架构 | 接入 / 应用 / 领域 / 数据及禁止事项 |
| 填写 NFR 清单 | 性能、一致性、容量、合规等 |
| 写 ADR 骨架 | 决策、备选、后果(ch14 详述) |
1.1 什么是「企业级」
| 维度 | 演示级 | 企业级 | 量化参考 |
|---|---|---|---|
| 可用性 | 单点、可停机 | 目标 SLA | 99.9% ≈ 年停机 8.76h;99.95% ≈ 4.38h |
| 扩展 | 垂直扩容 | 水平扩展、无状态 | 单服务副本 3~10,HPA 按 CPU 70% |
| 安全 | 内网裸奔 | 认证鉴权、审计、最小权限 | 100% API 鉴权;审计留存 ≥ 180 天 |
| 可观测 | 看日志 | 指标 + 日志 + 链路 | MTTR < 30min;告警 5min 内触达 |
| 演进 | 大改重写 | 渐进式、可回滚 | 发布回滚 ≤ 5min;灰度 10% 起 |
行业案例 · 贤紫优选商城:早期单体 Django 可支撑日活 < 5000;大促前按企业级标准拆出 订单 / 商品 / 支付 独立 Deployment,接入 Redis Session、Kafka 异步通知,P99 从 800ms 降至 220ms,大促零扩容手工干预。
1.2 经典分层架构
┌─────────────────────────────────────────────────────────┐
│ 接入层:Ingress / API Gateway / CDN / WAF │
├─────────────────────────────────────────────────────────┤
│ 应用层:BFF / 微服务 API / 领域服务 │
├─────────────────────────────────────────────────────────┤
│ 领域层:聚合根、领域事件、业务规则(代码内包结构) │
├─────────────────────────────────────────────────────────┤
│ 数据层:DB / 缓存 / 消息 / 搜索 / 对象存储 │
└─────────────────────────────────────────────────────────┘
▲ 可观测(Prometheus/Jaeger)、安全横切各层
| 层 | 职责 | 贤紫/PaaS 对应 | 禁止事项 |
|---|---|---|---|
| 接入 | 路由、TLS、限流、鉴权粗粒度 | Traefik、APISIX、Nginx | 在网关写业务逻辑 |
| 应用 | 用例编排、DTO 转换 | 应用部署 Deployment | 跨层直连 DB |
| 领域 | 不变式、状态机 | 代码 domain/ 包 | 依赖框架注解污染领域 |
| 数据 | 持久化、缓存、投递 | MySQL、Redis、Kafka | 应用层拼裸 SQL 跨服务 |
1.2.1 贤紫商城分层落地示例
apps/customer/ # BFF + 页面(接入侧聚合)
apps/order/ # 订单领域服务
apps/catalog/ # 商品目录服务
middleware/ # K8s Namespace:MySQL、Redis、Kafka
依赖方向:customer → order-api → order-db,禁止 customer → order-db 直连。
1.3 非功能需求(NFR)清单
设计任何系统前先填表;L3 认证设计题 必须先写 NFR。
| NFR | 关键问题 | 示例指标 | 验证方式 |
|---|---|---|---|
| 性能 | QPS / 延迟? | 核心下单 P99 < 200ms | k6 压测 + Grafana |
| 可用性 | 允许停多久? | 99.9%,单组件故障不影响下单 | 混沌杀 Pod 演练 |
| 一致性 | 强一致还是最终一致? | 订单+库存强一致;搜索 5s 内一致 | 对账脚本 |
| 安全 | 谁可访问什么? | RBAC + JWT;管理端 MFA | 渗透清单 |
| 合规 | 日志留存多久? | 180 天;PII 脱敏 | 审计抽查 |
| 容量 | 峰值几倍日常? | 大促 10×,30min 内自动扩容 | HPA + 预案 |
| 可维护性 | 新人多久能改一功能? | 模块边界清晰,README + OpenAPI | 代码评审 |
1.3.1 NFR 填写模板(可复制)
# nfr-order-service.yaml — 架构评审附件
service: order-api
owner: platform-team
sla:
availability: "99.95%"
latency_p99_ms: 200
rto_minutes: 30
rpo_minutes: 5
capacity:
baseline_qps: 500
peak_qps: 5000
replicas: { min: 3, max: 15 }
security:
auth: JWT + RBAC
data_classification: PII-L2
compliance:
log_retention_days: 180
1.4 边界与模块化原则
| 原则 | 说明 | 反例 |
|---|---|---|
| 单一职责 | 一个模块一个变化理由 | utils.py 2000 行万能包 |
| 依赖倒置 | 领域不依赖基础设施 | 领域层 import django.db |
| 开闭原则 | 扩展开放、修改关闭 | 每加支付方式改 20 处 if |
| 显式边界 | API / 事件为唯一跨模块出口 | 共享 models.py 全库引用 |
1.4.1 行业案例 · 某零售中台
某省级连锁零售中台将 促销引擎 与 定价引擎 混在同一服务,每次大促双方互相阻塞发布,季度发布失败 3 次。重构后:
- 促销服务只发布
PromotionApplied事件 - 定价服务订阅后计算最终价
- 独立 Deployment,发布频率从 月级 提升到 周级
1.5 架构决策记录(ADR)
重大选型写 ADR,避免「为什么用 Kafka」半年后无人记得。
# ADR-003 订单服务消息中间件选用 RocketMQ
## 状态:已采纳(2025-06-12)
## 背景
- 日订单峰值 12 万;需事务消息保障「建单 + 扣库存」
- 团队已有 RocketMQ 运维经验(PaaS 第 4 章)
## 决策
- 生产:RocketMQ 双 Broker + DLedger(外置或自定义 YAML)
- 非核心通知走 Kafka(日志、埋点)
## 备选方案
| 方案 | 弃用原因 |
|------|----------|
| 纯 Kafka 事务 | 运维与业务事务消息心智成本高 |
| RabbitMQ | 峰值堆积时 shovel 经验不足 |