web系统后端通用架构规范-v1.0

Web 系统后端通用架构规范 v1.0

文档信息

项目内容
文档名称Web 系统后端通用架构规范
文档版本v1.0
作者花海
创建日期2026-08-06
更新日期2026-08-06
适用范围单体架构、模块化单体、微服务架构与分布式系统;多租户(SaaS)领域见关联文档《多租户与数据隔离规范》

文档描述:本规范定义 Web 系统后端架构层的全量工程契约,涵盖分层架构、错误码、常量管理、认证授权、远程调用韧性、缓存、消息队列、数据持久化、测试门禁、版本控制、资源安全及通用编码约束。本规范同时适用于单体架构、模块化单体、微服务架构与分布式系统,不绑定任何实现方与编程语言。所有后端系统模块必须遵守本规范。

目录


1 · 总览与适用范围

1.1 规范层级

章节主题优先级核心关注点
2分层架构与模块组织强制按业务功能组织(Package by Feature)
3接口与扩展机制规范强制接口设计原则、SPI 扩展点、接口兼容性
4错误码规范强制错误码注册表、跨模块透传、边界收敛
5常量分类统一管理强制常量分层、分类前缀、业务状态集中定义
6认证与授权规范强制OAuth2.0、统一入口鉴权、RBAC 最小化
7远程调用与韧性设计强制超时、重试、熔断、降级(外部系统/服务间)
8缓存全生命周期规范强制更新策略、穿透/雪崩防护
9消息队列消费规范强制ACK 策略、幂等、批量、顺序
10数据访问与查询规范强制索引、深分页、慢 SQL 门禁
11测试与质量门禁强制覆盖率阈值、测试环境隔离、契约测试
12API 设计规范推荐资源命名、HTTP 动词、幂等键、版本控制
13数据变更管理推荐脚本命名(基线/版本)、DDL/DML 分类、数据归档
14资源池化配置推荐连接池公式、线程池命名
15依赖安全与配置安全推荐OWASP、配置中心加密
16通用编码约束强制时区、业务状态、空值
17日志规范强制日志级别、脱敏、TraceId 链路追踪
18指标与告警规范强制Metrics、SLO、告警分级与响应时效
19部署与发布强制环境划分、配置隔离、发布策略、健康检查
20镜像与 CI/CD推荐镜像构建、扫描、流水线门禁、环境递进
21事务规范强制事务边界、分布式事务、本地事务表
22文件与对象存储规范强制上传限制、签名 URL、防盗链、分片上传
23定时任务与调度规范强制防重复执行、锁租约、超时重试、执行记录
24数据库备份与恢复强制RTO/RPO、备份节奏、校验、恢复演练
25应用层安全规范强制注入防护、XSS、越权(水平/垂直)
26架构审查红线(汇总)强制Checklist
附录 A参考实现(配置示例、公式与取舍讨论)参考非强制条款,落地时参考;与正文冲突以正文为准

1.2 术语约定

  • 模块:最小的业务组织单元。单体架构中为进程内模块;微服务架构中一个模块即一个服务。
  • 调用:模块间的协作方式。单体架构中为进程内调用;微服务架构中为远程调用。
  • 统一入口:对外的请求边界。单体架构中为入口中间件/过滤器;微服务架构中为 API 网关。
  • 请求上下文:一次请求链路内共享的用户与链路信息。

语言中立性说明:本规范不绑定任何实现方与编程语言,但示例以 Java 生态为主(如 ThreadLocalPreparedStatementOptionalJSP/ThymeleafHikariCP)。其他语言按等价概念映射理解,例如:ThreadLocal → Go 的 context.Context、Python 的 threading.localPreparedStatement → 各语言的参数化查询 API;Optional → 各语言的可空/可选类型约定。示例仅为说明契约语义,非强制技术选型

1.3 单体 vs 微服务适配表

同一架构原则在不同部署形态下的落地方式不同,本规范条款均已按通用原则表述,下表给出适配指引:

条款单体 / 模块化单体微服务 / 分布式
§1.4 无状态单实例可本地缓存(见 §8.4);多实例必须外置;Session 必须集中式存储必须外置(分布式缓存/数据库/配置中心);Session 必须集中式存储
§1.5 前后端分离默认优先;后端只提供 API,认证优先 Token/OAuth2.0默认优先;后端只提供 API,认证优先 Token/OAuth2.0
§2 分层组织同进程模块化,按业务域拆分包业务域即服务,独立部署
§3 接口与扩展模块间面向接口协作,扩展点内置面向接口 + SPI 扩展点 + 默认实现
§4 错误码模块间可共享错误码注册表;边界收敛由入口中间件完成禁止跨服务引用错误码定义,只传 code;边界收敛由网关完成
§5 常量全局常量公共包共享;业务域常量仍禁止跨模块引用全局常量下沉公共包;业务域常量禁止跨服务 import
§6 认证授权入口中间件统一校验,进程内传递请求上下文;仅传统后端渲染场景可用 Session-Cookie网关统一校验,透传上下文头(X-User-Id 等);通常用 Token
§7 韧性设计进程内调用无需超时/熔断;调用外部系统仍必须遵守本规范服务间远程调用 + 外部系统调用均须遵守
§8 缓存单实例可用本地缓存;多实例部署仍按本规范分布式缓存为主,本地缓存 TTL ≤ 分布式 TTL 的 1/3
§9 消息队列适用(解耦异步任务)适用(服务间事件驱动)
§10 数据访问多模块共享数据库需约定模块间数据访问边界服务独立库,禁止跨服务直连数据库
§12 API 版本适用适用
§13 数据变更单一变更管线每服务独立变更管线
§14 资源池化适用适用
§15 安全适用适用
§16 编码约束适用适用
§17 日志规范单实例可本地日志;多实例需集中采集必须集中采集 + TraceId 跨服务透传
§18 指标与告警单实例本地指标采集 + 基础告警集中指标采集 + 指标大盘 + SLO 与告警分级
§19 部署发布全量发布为主;环境隔离仍需遵守独立部署 + 蓝绿/灰度 + 健康检查
§20 镜像与 CI/CD流水线全量构建 + 镜像管理流水线构建 + 镜像扫描 + 环境递进部署
§21 事务规范进程内本地事务分布式事务(Saga/TCC/本地事务表)
§22 文件存储本地磁盘 + 服务器直出;需自行约束大小与清理对象存储私有读写 + 签名 URL + 防盗链;大文件分片上传
§23 定时任务单实例本地调度;多实例需自行防重复调度中心/选主 + 分布式锁租约;防重复、超时、重试、执行记录
§24 备份恢复本地全量备份,无校验无演练全量 + 增量 + 日志归档按 RPO;异地保存、校验、定期恢复演练
§25 应用层安全适用适用
§26 红线汇总适用适用

1.4 全局无状态设计原则

本规范定义 Web 系统架构的最高层原则:不论单体还是微服务,模块/服务默认必须无状态。仅当存在性能极致敏感场景(如本地缓存热点数据、计算密集型中间结果)时,才允许保留状态,且必须显式声明并评估副作用。

1.4.1 无状态定义

模块/服务的任何请求处理不依赖本实例的内存状态,所有可变状态必须外置:

状态类型外置方式说明
用户会话集中式存储(如 Redis、数据库)禁止存本实例内存
业务数据数据库 / 分布式缓存禁止本实例内存缓存(除允许场景)
临时中间结果分布式缓存 / 消息队列禁止存本实例内存
配置配置中心禁止本地文件硬编码

1.4.2 允许有状态的场景

仅以下场景允许保留状态,且必须满足约束:

场景允许状态约束
性能极致敏感的热点数据本地缓存TTL ≤ 分布式缓存 TTL 的 1/3,且写操作必须走分布式缓存(见 §8.4)
计算密集型中间结果本实例内存(如报表聚合)结果必须可重建,进程重启不丢失业务正确性
单实例部署的临时状态本实例内存仅限单实例,多实例部署时必须外置

禁止以"实现简单"为由保留状态。任何有状态设计必须经过架构评审,并在代码注释中显式标注 @Stateful 及原因。

1.4.3 无状态的收益

  • 水平扩展:任意增减实例,无需考虑状态迁移。
  • 故障恢复:实例崩溃后,新实例立即接管,无状态重建成本。
  • 负载均衡:请求可路由到任意实例,无会话粘滞需求。
  • 部署简单:蓝绿/灰度发布无需考虑状态同步。

1.4.4 架构审查红线

  • ❌ 默认将有状态设计作为首选(如本地内存存会话)
  • ❌ 以"实现简单"为由保留状态,未评估副作用
  • ❌ 有状态设计未显式标注 @Stateful 及原因
  • ❌ 多实例部署仍用本实例内存存状态
  • ❌ 前后端分离项目仍用后端渲染(如 JSP/Thymeleaf 直出页面)
  • ❌ 前后端分离项目用 Session-Cookie 做认证(跨域/多端受限)
  • ❌ 后端接口返回 HTML 片段而非 JSON 数据
  • ✅ 默认无状态,状态外置到数据库/分布式缓存/配置中心
  • ✅ 仅性能极致敏感场景允许有状态,且必须显式评审

1.5 前后端分离优先原则

本规范定义 Web 系统架构的第二层原则:项目架构优先考虑前后端分离。前后端分离与全局无状态原则(§1.4)相辅相成,是现代 Web 系统的默认架构模式。

1.5.1 前后端分离定义

维度说明
职责划分前端负责页面渲染与用户交互,后端只提供 API 接口
通信方式前后端通过 HTTP API 通信,禁止后端直接渲染页面(如 JSP/Thymeleaf)
部署方式前端与后端独立部署,可独立扩展与发布

1.5.2 前后端分离 vs 传统后端渲染

两种架构模式的适用场景、认证模式与优先级对比见 附录 A.1(参考实现)。本规范默认采用前后端分离(见 §1.5.1 定义与 §1.5.4 认证关系)。

1.5.3 前后端分离的收益

  • 多端复用:一套 API 支持 Web、App、小程序等多端。
  • 独立扩展:前后端独立部署、独立扩缩容。
  • 开发并行:前后端并行开发,接口契约先行(见 §11.2 契约测试)。
  • 技术栈灵活:前端可独立演进技术栈,不受后端框架限制。

1.5.4 与认证模式的关系

前后端分离架构下,认证模式优先选择 Token / OAuth2.0

  • Token 无状态、自包含,适合 API 服务与多端场景。
  • Session-Cookie 依赖 Cookie 与集中式 Session 存储,在跨域、多端场景下受限。

仅当满足以下全部条件时,才允许选择 Session-Cookie

  • 单体架构 + 后端渲染(非前后端分离)。
  • 仅 Web 浏览器端,无 App/小程序等多端需求。
  • 无跨域调用需求。

1.5.5 架构审查红线

  • ❌ 前后端分离项目仍用后端渲染(如 JSP/Thymeleaf 直出页面)
  • ❌ 前后端分离项目用 Session-Cookie 做认证(跨域/多端受限)
  • ❌ 后端接口返回 HTML 片段而非 JSON 数据
  • ✅ 默认前后端分离,后端只提供 API
  • ✅ 前后端分离项目认证优先 Token / OAuth2.0

2 · 分层架构与模块组织

2.1 按业务功能组织(非分层平铺)

系统按业务功能组织,而非按技术分层平铺。同一业务域的相关代码聚合在一起,降低认知成本与变更影响面。单体架构下为同进程模块,微服务架构下模块即服务,包结构与职责划分保持一致。

<根命名空间>.<业务模块>
├── config           // 配置装配
├── api/接入层        // 接口入口:仅做参数校验与转发
├── application/应用层 // 业务逻辑编排、事务边界
│   └── impl
├── domain/领域模型    // 贫血模型下的业务数据包(非 DDD 战术设计中的聚合根/实体概念)
│   ├── entity        // 数据实体(与数据库表对应)
│   ├── vo            // 视图对象
│   ├── dto           // 传输对象
│   ├── repository/dao // 数据访问接口(非 DDD 仓储模式)
│   └── constants     // 业务域常量
├── infrastructure/基础设施 // 外部系统调用、消息发送、缓存配置
├── utils            // 工具类(无状态、线程安全)
└── exception        // 自定义异常/错误码定义

非 DDD 声明:本规范采用贫血模型 + 分层架构(非 DDD 战术设计)。domain 目录仅为业务数据包(实体/VO/DTO/数据访问接口),不涉及 DDD 中的聚合根(Aggregate Root)、实体(Entity)、值对象(Value Object)等领域概念;repository 指数据访问接口,非 DDD 仓储模式。

2.2 分层约束

层级职责禁止
接入层参数校验、调用应用层、返回结果写业务逻辑、直接操作数据访问层
应用层业务编排、事务边界、抛出异常跨模块依赖对方异常定义、裸拼接查询条件
数据访问层数据读写写业务判断、返回 null 不处理
基础设施层外部系统调用封装、降级兜底抛业务异常、透传用户凭证

2.3 模块间边界

  • 模块之间只能通过公开接口协作,禁止绕过模块接口直接访问其内部数据(如直连其他模块的数据表)。
  • 单体架构下,跨模块调用仍须遵守公开接口约束,防止模块耦合腐化。
  • 微服务架构下,模块(服务)间只能通过远程调用协作,禁止共享数据库。

3 · 接口与扩展机制规范

本规范定义内部接口设计原则、扩展点(SPI)机制及接口兼容性约束。模块间协作与功能拓展必须通过接口完成,禁止实现级耦合与硬编码分支扩展。

3.1 接口设计原则

约束项❌ 禁止✅ 推荐
面向接口编程模块依赖对方具体实现类面向接口编程(依赖倒置),模块间只依赖接口,禁止依赖实现
接口隔离大而全的上帝接口接口隔离(ISP),按职责拆分小接口,避免无关依赖
接口粒度接口过粗或过细失衡接口粒度与业务用例对齐,方法单一职责

3.2 接口分层

  • 接入层接口:对外 API(见 §12 API 设计规范),仅做参数校验与转发。
  • 应用层接口:业务服务接口,模块内部对外的协作契约。
  • 数据访问接口:仓储/DAO 接口,隔离数据访问实现。
  • 扩展点接口:可插拔功能拓展的契约(见 §3.3)。

3.3 扩展点(SPI)机制

功能拓展必须通过定义扩展接口实现,禁止硬编码分支扩展。

约束项❌ 禁止✅ 推荐
扩展方式业务代码 if-else 硬编码分支扩展定义扩展接口(SPI),扩展实现类承载差异化逻辑
注册方式扩展散落、无统一入口统一扩展注册机制(注册表/配置声明),显式注册
默认实现扩展点无默认实现,核心逻辑依赖扩展扩展点必须提供默认实现,核心功能不因扩展缺失而失效
优先级同类型扩展冲突无排序支持优先级排序,按优先级生效,可覆盖默认实现
扩展隔离扩展直接修改核心模块代码扩展只能实现扩展接口,禁止修改核心模块代码
无状态扩展实例携带状态扩展实现默认无状态;若需状态,必须在扩展内部显式管理(如通过参数传递),禁止依赖实例级共享可变状态(见 §1.4)

3.4 接口兼容性

  • 对外接口:按 §12.5 兼容性约束,破坏性变更必须发新版本。
  • 内部接口:变更须评估调用方影响,禁止静默破坏调用方。
  • 扩展接口:发布即契约;新增方法兼容,删除/修改签名属破坏性变更,需走版本评审。

3.5 架构审查红线

  • ❌ 模块依赖对方具体实现类(而非接口)
  • ❌ 业务功能拓展用 if-else 硬编码分支
  • ❌ 扩展点无默认实现,核心逻辑依赖扩展
  • ❌ 扩展直接修改核心模块代码
  • ❌ 扩展实例有状态
  • ✅ 模块间面向接口编程
  • ✅ 功能拓展走扩展接口 + 统一注册机制
  • ✅ 扩展点有默认实现、可排序、无状态

4 · 错误码规范

本规范定义 Web 系统统一的错误码体系:格式、分类、传递契约、边界收敛策略,以及业务模块自定义错误码的指引。所有模块必须遵守本规范。

4.1 错误码格式

格式:E<大类>-<子类/域>-<3位编号>,共三段,如 E4-ORDER-001

E4 - ORDER - 001
│    │      └── 3 位编号(段内递增,如 001/002...)
│    └── 子类(E1/E2/E3/E5)或 域(E4 业务域,由业务模块自定义)
└── 大类码(E1~E5)
  • 成功码S0000,不参与 E 前缀分类。
  • 未识别前缀E5(系统未知)兜底——安全失败原则,避免误判为可重试或客户端错误。

4.2 错误码分类表

前缀大类第二段语义默认 HTTP对外收敛后 HTTP日志级别可重试
E1参数类子类:PARAM/VALID/TYPE/FILE/RATE/HTTP缺参、类型错误、校验失败、文件内容非法、限流、方法不允许400200INFO
E2权限类子类:AUTH/TOKEN/PERM未认证、token 过期、无权限401200INFO
E3基础设施类子类:DB/CACHE/HTTP/THIRD/PAY/FILE/LOCK/SMS数据库、缓存、第三方调用、文件存储、锁获取失败500200ERROR
E4业务域类:ORDER/USER/GOODS...(业务模块自定义,COMMON 为通用业务域)业务规则冲突、状态非法、资源不存在422200WARN
E5系统未知类子类:SYS/UNKNOWN未知异常、代码缺陷、兜底500200ERROR
S成功-操作成功200200--

分层说明:"默认 HTTP"为模块间调用、内部服务间调用使用的真实 HTTP 状态码;"对外收敛后 HTTP"为面向外部客户端的统一入口响应收敛后的状态码(默认 200,见 §4.6)。两层状态码职责不同,不可混用。

4.2.1 子类 vs 域

  • 子类:E1/E2/E3/E5 的第二段,是该大类下的细分(如 E3 下的 DB/CACHE/HTTP)。
  • :E4 的第二段,是业务域(对应业务模块),由各业务模块自定义,避免与 COMMON 冲突。

4.2.2 通用错误码参考表

code场景默认 HTTP(模块间/内部调用)
S0000操作成功200
E5-SYS-000系统未知异常(对外兜底码)500
E5-SYS-001通用服务器错误500
E5-SYS-002服务不可用503
E1-PARAM-000参数错误400
E1-PARAM-001查询参数不能为空400
E2-AUTH-000未认证401
E2-AUTH-001凭证已过期401
E2-PERM-000无权限403
E4-COMMON-000资源不存在404
E4-COMMON-001资源冲突409
E1-HTTP-000方法不允许405
E1-RATE-000请求过于频繁429
E3-LOCK-000锁获取失败423

说明:本表 HTTP 为模块间/内部调用的默认状态码;对外统一入口响应按 §4.6 收敛为 200。

内部专用码405(方法不允许)、423(WebDAV 扩展 Locked,锁获取失败)等状态码仅用于模块间/内部调用的语义表达,对外统一收敛为 200。423 属 WebDAV 扩展而非通用 HTTP 标准,内部使用前须确认下游能正确解析;如无法解析,可用 409(冲突)或 500 替代。

4.3 错误码解析机制

  • 提供统一的错误码解析入口(错误码注册表 / 前缀解析器):任意模块收到错误码字符串即可推导大类,无需依赖对方模块的错误码定义。
  • 解析能力至少包含:大类描述、默认 HTTP 状态、是否为客户端错误(客户端错误记 INFO,服务端错误记 ERROR)、是否可重试(仅 E3 基础设施类可重试)。
  • 禁止在业务代码中自行对前缀做字符串判断(如 code.startsWith("E1")),必须统一走解析入口。

4.4 错误码定义契约

  • 错误码必须使用枚举定义(显式声明 code + message),禁止散落裸字符串/数字;HTTP 状态由解析入口按前缀推导,需要精确状态时显式覆盖。
  • 业务规则/资源类错误用 E4-<业务域>-<编号>;参数/权限类复用通用 E1/E2 子类。
  • 错误码一经发布即视为对外契约,禁止修改已发布 code 的语义

4.5 错误码传递契约(跨模块 / 跨服务)

4.5.1 传递契约

  • 模块间只传递统一响应结构(code 字符串 + message + data),错误码原样透传
  • 单体架构:模块间可直接共享错误码注册表,但仍禁止模块 A 直接依赖模块 B 的错误码定义类(模块 B 的域错误码由模块 B 自行声明)。
  • 微服务架构:禁止跨服务引用对方的错误码定义类,只传 code 字符串。
  • 解析对方错误码统一走错误码解析入口,禁止自行写前缀判断。
  • 未知错误码按 E5 兜底。

4.5.2 透传链路

上游抛出 E4-ORDER-001(订单不存在)
  → 全局异常处理按默认 422 响应
  → HTTP 422 + {"code":"E4-ORDER-001","message":"订单不存在","data":null}
  → 下游解析统一响应结构
  → 响应非成功 → 采用上游 HTTP 状态(否则按前缀推导)
  → 构造等价业务异常并抛出
  → 下游全局异常处理响应 HTTP 422 + {"code":"E4-ORDER-001",...}

4.5.3 调用方处理策略

上游响应下游处理
2xx + 业务成功正常返回 data
2xx + 业务失败错误码原样透传,httpStatus 按前缀推导
4xx/5xx + 标准响应结构错误码原样透传,httpStatus 采用上游 HTTP 状态码
4xx/5xx + 非标准结构抛通用调用异常,触发熔断降级

4.5.4 异步链路错误码传递

消息队列/事件等异步链路的错误码传递,与同步调用保持一致:

  • 消息体中必须包含 code 字段(如 E4-ORDER-001),消费者按错误码解析入口推导语义。
  • 消费者处理失败时,错误码随消息进入重试/死信队列,便于链路追踪与重放。
  • 异步链路中禁止抛裸异常,必须转换为错误码后传递。

4.6 边界收敛策略

4.6.1 收敛规则

本节仅针对面向外部客户端的统一入口响应(出网响应)。模块间调用、内部服务间调用仍按 §4.2 错误码分类表使用真实 HTTP 状态码(E1→400、E2→401、E3→500、E4→422),不执行收敛;仅当响应经统一入口发给外部调用方时,才按本节收敛为 responseStatus(默认 200)。

统一入口(API 网关 / 入口中间件)对出网响应(发给外部调用方)做映射:

大类策略外部调用方看到
E1/E2/E4透传原 code + 原 message(调用方需提示用户)
E3/E5收敛隐藏E5-SYS-000 + "系统繁忙,请稍后重试"(隐藏内部细节)
S透传S0000

响应状态码统一收敛为 responseStatus(默认 200),业务结果由 body.code 表达——外部调用方不感知系统内部真实异常状态码。

例外场景:文件下载、文件流、长连接(SSE/WebSocket)、限流响应(429 + Retry-After,客户端需感知重试时机) 等非 JSON 响应场景,允许使用真实 HTTP 状态码表达结果(如下载失败返回 404/500),不受统一收敛约束。幂等冲突(§12.6)等业务正常路径仍收敛为 200。

4.6.2 配置项

统一入口错误码收敛的配置字段与参考示例见 附录 A.2(参考实现)。

4.7 统一响应结构

  • 成功:code=S0000,携带可选数据。
  • 失败:code=错误码 + message + data=null
  • 接入层直接返回业务数据,由统一包装机制自动包成响应结构;业务失败通过异常机制统一拦截处理。

4.8 架构审查红线

  • ❌ 跨模块/跨服务引用对方模块的错误码定义类
  • ❌ 自行对错误码前缀做字符串判断
  • ❌ 模块间传递非统一响应结构
  • ✅ 模块间只传递 code 字符串,统一走解析入口
  • ✅ 错误码发布后不可变更语义,新增只能追加

5 · 常量分类统一管理

本规范定义常量的分层存放、分类标识、命名契约及使用约束。所有魔法值(除数学 0/1 外)必须具名化,禁止裸字符串/数字出现在业务代码中。

5.1 分层体系

常量按作用域分三层,与错误码的"全局 → 业务域 → 模块内"层级对齐:

层级作用域存放位置变更控制
全局常量跨模块共享公共常量包需架构评审,发布后保持向后兼容
业务域常量模块内跨子模块业务域常量包模块 Owner 审批,code 一旦发布不可变更
模块内常量模块私有模块常量包模块负责人自主,但禁止跨模块引用

5.2 分类维度(与错误码大类对齐)

分类前缀说明对应错误码典型场景
参数类PARAM_校验阈值、默认值、正则、分页E1最大分页、手机号正则
权限类AUTH_角色码、权限点、凭证时效配置E2凭证过期时间、密钥标识
基础设施类INFRA_缓存 Key、消息 Topic、超时、重试E3缓存前缀、调用读超时
业务域类BIZ_业务状态值、业务规则阈值、计算系数E4订单状态、库存扣减上限
系统类SYS_框架配置、系统默认值、环境标识E5环境标识、线程池命名前缀

说明SYS_ 类常量对应的异常若无法归类(不属于 E1~E4 任何已知大类),统一收敛至 E5 系统未知类兜底(见 §4.1)。

5.3 命名规范

5.3.1 格式

<分类前缀>_<业务域简写>_<具体含义>[_<属性>]
约束
分类前缀必须为PARAM_ / AUTH_ / INFRA_ / BIZ_ / SYS_ 之一
业务域简写与错误码 E4 域一致,如ORDER / USER / GOODS;全局常量用 COMMON
具体含义动名词组合,如MAX_PAGE_SIZESTATUS_PENDING
属性可选,如_MILLIS_PREFIX_PATTERN

5.3.2 正反示例

场景❌ 禁止✅ 推荐
分页大小MAX = 500PARAM_COMMON_MAX_PAGE_SIZE = 500
缓存前缀CACHE = "order"INFRA_CACHE_ORDER_PREFIX = "web:order:v1:"
订单状态STATUS = 0见下方业务状态规范
凭证过期EXPIRE = 30AUTH_TOKEN_EXPIRE_MINUTES = 30

5.4 业务状态定义规范

术语说明:本规范统一术语——API 响应的错误码沿用"错误码"(Error Code,见 §4);业务实体生命周期状态(如订单状态 PENDING/PAID)统称为**"业务状态"**(Business Status),不再使用"状态码"一词指代。

业务状态必须集中定义,禁止用散落的裸 int/String 常量定义业务状态。

5.4.1 契约

  • 业务状态必须使用枚举定义,显式声明 code + 描述code 一旦发布不可变更,新增状态只能追加。
  • 业务状态存入数据库必须做映射:入库时映射为 code 值存储,读取时按 code 反查枚举;严禁直接存枚举本身(枚举名或序列化对象)。
  • 必须提供按 code 反查业务状态的能力;查询到未知 code 时抛出明确的业务异常(而非静默返回默认值)。
  • 同一业务状态集合只允许存在一份定义,禁止多处重复声明。

5.4.2 正反示例

✅ 推荐:集中定义,code 显式声明,带描述,支持反查与未知值校验
BizOrderStatus: PENDING("0","待支付") / PAID("1","已支付") / SHIPPED("2","已发货") ...

❌ 禁止:裸 int 状态散落各模块,无描述,无法反查
OrderConstants.STATUS_PENDING = 0
✅ 入库映射:DB 存 code 值(如 "0"),读取时反查枚举
   DB: "0"  →  BizOrderStatus.of("0") → PENDING

❌ 禁止:直接存枚举本身(枚举名 PENDING 或序列化对象)

5.5 字符串拼接规范

含动态段的字符串(如缓存 Key web:user:v1:detail:{userId}、MQ Topic、日志标签)必须走常量模板 + 统一拼接,禁止业务代码散落手写拼接:

约束项❌ 禁止✅ 推荐
拼接位置业务代码中散落"web:order:" + orderId拼接收敛到统一生成方法(如KeyBuilder),业务代码只调用方法名
模板定义把含动态段的完整 Key 写成常量常量只定义带占位符的静态模板(如web:order:v1:detail:{id}),动态段运行时注入
分隔符混用:_- 无统一约定默认统一用: 分隔段,段内用 _;不同场景类别可约定不同分隔符,但同一类别内必须一致
动态段校验动态段为空/含非法字符直接拼接拼接前校验动态段(非空、合法字符),校验失败抛业务异常
参数顺序连续+ 拼接,参数顺序错乱难排查用占位符模板显式声明参数位置,按序注入
可读性拼接结果无业务语义、无法全局搜索模板常量具名化(如INFRA_CACHE_ORDER_DETAIL),全链路可搜索与复用

说明:分隔符按场景类别约定——缓存 Key、业务字符串默认用 : 分隔段;MQ Topic 等按 MQ 社区惯例可用 -(见 §5.7 消息常量规范)。同一场景类别内必须全局一致,禁止混用。

占位符模板 + 统一生成方法的正反示例见 附录 A.10(参考实现)。

  • 动态段(id、userId)禁止写入常量名或常量值,只作为参数传入生成方法。
  • 含动态段字符串的生成统一收敛到基础设施层(如 KeyBuilder/TopicBuilder),业务层禁止自行拼接。
  • 同一模板常量全局唯一,禁止多处重复定义等价拼接格式。

5.6 缓存 Key 规范

缓存 Key 必须走常量模板 + 统一生成方法,禁止在业务代码中拼接字符串(按 §5.5 字符串拼接规范执行)。

约束项❌ 禁止✅ 推荐
命名空间"user_" + userIdkey = KeyBuilder.build(INFRA_CACHE_USER_DETAIL, userId) // → web:user:v1:detail:1001
版本控制无版本,重构后冲突必须带版本号web:<module>:v1:<biz>,版本段写在模板常量中
TTL业务代码硬编码常量定义 TTL,配置中心可覆盖
大 Key 前缀无业务域隔离必须包含模块名 + 业务域,如web:order:v1:detail:{id}(占位符见 §5.5)

多租户场景:缓存 Key 必须包含租户维度,模板格式为 web:{tenantId}:<module>:v1:<biz>:{id},按 §5.5 字符串拼接规范走统一生成方法(多租户约束见关联文档《多租户与数据隔离规范》第 3 章)。

5.7 消息常量规范

约束项❌ 禁止✅ 推荐
Topic 命名"topic""order-topic"INFRA_MQ_TOPIC_ORDER = "web-order-topic"
Tag 命名"tag1""order"INFRA_MQ_TAG_ORDER_PAY = "ORDER_PAY"(与业务域对齐)
消费组默认 GroupINFRA_MQ_GROUP_ORDER_PAY = "web-order-pay-consumer"
消息体状态魔法值描述状态走业务状态定义getConstantCode()

5.8 正则与校验规则常量

校验规则必须具名化,禁止在注解/校验器中写裸正则。

约束项❌ 禁止✅ 推荐
正则校验注解中直接写裸正则集中到常量定义,引用常量名

5.9 跨模块引用约束

场景约束
全局常量下沉到公共常量包,所有模块依赖
业务域常量禁止跨模块直接引用对方常量;需共享时下沉到公共常量包,或传递字符串
错误码严格按 §4.5.1,模块间只传递 code 字符串,禁止引用对方错误码定义

5.10 架构审查红线

  • ❌ 业务代码中出现裸字符串/数字(除数学运算 0/1 及循环索引 i
  • ❌ 一个常量定义中混杂 PARAM_BIZ_INFRA_ 等不同分类
  • ❌ 跨模块引用对方 XxxConstants
  • ❌ 缓存 Key、消息 Topic 在业务代码中硬编码拼接
  • ❌ 含动态段字符串散落手写拼接,未走统一模板与生成方法
  • ❌ 业务状态用裸常量而非集中定义
  • ✅ 所有缓存 Key 必须包含版本号,如 v1
  • ✅ 业务状态一旦发布视为契约,变更需走兼容性评审

6 · 认证与授权规范

本规范定义用户凭证的传输、统一入口鉴权、上下文传递、权限模型及安全约束。支持 OAuth2.0 与 Session-Cookie 两种模式,两种模式均须遵守全局无状态设计原则(见 §1.4)与前后端分离优先原则(见 §1.5)。所有涉及用户认证的系统必须遵守。

6.1 认证模式选择

模式适用场景说明
OAuth2.0 / Token前后端分离、多端(Web/App/小程序)、第三方接入无状态凭证(自包含),前后端分离场景默认优先
Session-Cookie传统后端渲染、单体管理后台、仅 Web 浏览器端有状态凭证(依赖服务端会话),但会话状态必须外置到集中式存储(如 Redis),本实例内存禁止存 Session

选择优先级

  • 前后端分离项目优先选择 Token / OAuth2.0(见 §1.5.4),Session-Cookie 仅在单体 + 后端渲染 + 仅 Web 端的特定场景下使用。
  • 传统后端渲染项目:可选择 Session-Cookie,但需满足 §1.5.4 的全部条件。

与无状态原则的关系

  • "有状态"是指凭证依赖服务端会话状态,而非"本实例内存有状态"。
  • Session-Cookie 模式下,会话数据必须存储到集中式存储(如 Redis、数据库),本实例内存禁止存 Session,确保多实例部署时请求可路由到任意实例。
  • 两种模式可并存(如对外 API 用 Token,内部管理后台用 Session),但同一系统内禁止混用两种凭证格式做同一链路的认证。

6.2 OAuth2.0 凭证格式与传输契约

约束项❌ 禁止✅ 推荐
传输位置Cookie 存凭证(易受 CSRF)HeaderAuthorization: Bearer <token>
凭证内容载荷含敏感字段(密码、手机号)只含userId + scope + exp,敏感信息走独立接口
刷新机制前端主动判断exp 刷新统一入口拦截,返回"凭证即将过期"信号触发前端静默刷新
多设备登录无限制或全局互踢client_id(设备类型)+ deviceId(设备标识)隔离,同一设备类型 + 同一设备标识最多 1 个有效凭证

说明

  • "设备类型"指 OAuth2.0 的 client_id(如 webiosandroid);"设备标识"为 deviceId(如浏览器指纹、设备 UUID),由客户端首次登录时生成并携带。
  • 同一浏览器多标签页属于同一设备标识,必须复用同一凭证(禁止重复申请新凭证);刷新/切页仅用 refresh token 静默续期,不触发互踢。
  • 不同设备(同类型不同 deviceId)才允许各持一个凭证;登录流程须携带 deviceId,服务端据此区分"多标签页"与"真多设备"。
约束项❌ 禁止✅ 推荐
Cookie 属性HttpOnlySecureSameSite必须设置HttpOnlySecureSameSite=Lax(或 Strict
CSRF 防护仅依赖 Session 无 CSRF Token必须配合 CSRF Token(表单头或自定义 Header)
Session 存储进程内存存 Session(重启丢失)集中式 Session 存储(如 Redis),支持多实例共享
Session 时效永不过期滑动过期 + 绝对过期双限制(如 30min 滑动 + 8h 绝对)

6.4 统一入口鉴权策略

认证校验在统一入口完成(单体为入口中间件/过滤器,微服务为 API 网关),业务模块不直接对接认证中心

外部调用方 → 统一入口 → [凭证校验] → 注入 X-User-Id / X-Scope → 业务模块
  • 校验失败:统一入口直接返回未认证/凭证过期错误(401),不进入业务模块
  • 校验成功:统一入口剥离 Authorization Header,注入 X-User-IdX-ScopeX-Client-Id
  • 业务模块禁止Authorization Header 自行解析凭证,统一从请求上下文取 X-User-Id
  • 单体系统:入口中间件校验后,将用户身份写入请求上下文(如 ThreadLocal/请求属性),模块内直接读取,不强制注入 X-User-Id 头;多实例部署时才需透传上下文头。

6.5 上下文传递

请求上下文(用户身份、链路信息)必须在调用链中传递:

场景处理方式
单体 / 模块化单体进程内请求上下文传递(进入模块边界时从上下文取值)
微服务用户请求链路请求上下文取X-User-Id → 调用拦截器 → 注入 X-User-Id
服务内部调用(无用户)使用客户端凭证模式获取服务凭证,注入X-Service-Id
禁止裸传Authorization: Bearer <user-token> 到下游(凭证膨胀、权限放大)

6.6 权限模型(RBAC 最小化)

层级说明对应常量前缀
Scope凭证中的权限范围,如readwriteadminAUTH_SCOPE_*
资源权限声明式控制(注解/策略),如hasAuthority('ORDER_WRITE')AUTH_PERM_*
  • 权限点字符串必须走常量:AUTH_PERM_ORDER_WRITE = "ORDER_WRITE",禁止裸字符串。
  • 权限校验失败统一返回 E2-PERM-000(403)。

6.7 凭证存储与安全

约束项❌ 禁止✅ 推荐
前端存储localStorage 存凭证(XSS 风险)按子模式选择:BFF 模式用httpOnly Cookie;纯 SPA + Token 模式用内存(或 Web Worker)存 access + httpOnly Cookie 存 refresh
凭证黑名单登出时删前端凭证即认为失效统一入口维护服务端黑名单,TTL 按凭证剩余有效期
密钥管理签名密钥硬编码在代码里走配置中心加密存储,支持密钥轮换(kid 标识当前密钥版本)

6.7.1 前后端分离凭证存储子模式

前后端分离场景下,凭证存储按两种子模式选择:

模式一:BFF 模式(后端代理)

  • 统一用 httpOnly Cookie 存 session/token,前端无感知,免疫 XSS 窃取凭证。
  • 由 BFF 层(后端)处理 OAuth2.0 交互与凭证刷新,前端不接触凭证。
  • 适用于同源部署、对安全要求高的场景。

模式二:纯 SPA + Token 模式(前后端直连)

  • access token 存内存(或 Web Worker),refresh token 存 httpOnly Cookie。
  • 页面刷新后内存中的 access token 丢失,需用 refresh token 静默换取新 access token。
  • 必须配合 PKCE(防授权码拦截)+ 短时效 access token(降低 XSS 影响面)。
  • 多标签页登录态同步:同源标签页通过 BroadcastChannel / LocalStorage 事件同步 access token;跨域场景由统一入口会话维持,避免刷新/切页丢失登录态。
场景BFF 模式纯 SPA + Token 模式
凭证存放全部在 httpOnly Cookieaccess 在内存/Web Worker,refresh 在 httpOnly Cookie
OAuth2.0 交互BFF 层处理前端 + 后端配合(需 PKCE)
刷新机制BFF 静默刷新前端持 refresh token 静默换取
多标签页Cookie 天然共享需 BroadcastChannel 同步
适用场景同源部署、安全要求高跨域 CDN 静态托管、多端直连

6.8 错误码衔接(复用 E2 大类)

code场景HTTP
E2-AUTH-000未认证/凭证缺失401
E2-AUTH-001凭证过期401
E2-AUTH-002凭证非法/签名错误401
E2-AUTH-003凭证即将过期(触发刷新)401
E2-AUTH-004单点登录被踢401
E2-PERM-000无权限403

6.9 常量衔接(复用 AUTH_ 前缀)

AUTH_ 前缀常量的参考值见 附录 A.3(参考实现)。

6.10 架构审查红线

  • ❌ 业务模块直接解析 Authorization Header
  • ❌ 裸传用户凭证到下游模块/服务
  • ❌ 权限点用裸字符串
  • ❌ 签名密钥硬编码
  • ❌ 凭证黑名单仅删前端不维护服务端
  • ✅ 统一入口鉴权,业务模块只认 X-User-Id
  • ✅ 调用链区分用户链路(X-User-Id)与服务链路(X-Service-Id

7 · 远程调用与韧性设计

本规范定义远程调用(外部系统、第三方 API、服务间调用)的超时、重试、熔断、降级策略。系统 80% 的故障来自调用链,必须显式约束。

适用范围说明:

  • 单体架构:进程内模块调用无需超时/熔断/重试;但调用外部系统(第三方 API、其他系统、消息中间件等)仍必须遵守本节全部约束。
  • 微服务架构:服务间远程调用与外部系统调用均须遵守本节约束。

7.1 超时配置

约束项❌ 禁止✅ 推荐
全局超时全局统一5s,不区分读/写连接超时1s,读超时按接口 SLA 分级(P0: 3s,P1: 10s
配置方式全局配置覆盖所有下游按下游系统/接口隔离配置,禁止全局覆盖

7.2 重试策略

约束项❌ 禁止✅ 推荐
重试范围默认重试 3 次,不加退避仅幂等接口允许重试,退避策略exponential backoff,最大重试 2 次
重试标识无标识,盲目重试非幂等接口必须显式标记不可重试,幂等接口默认允许
  • 幂等接口允许重试:如库存扣减、状态确认类操作。
  • 非幂等接口禁止重试:如创建订单、转账类操作。

7.3 限流策略

限流与熔断互补:熔断是"对方出问题我保护自己",限流是"请求太多我主动拒绝"。高并发场景下,统一入口与服务层必须同时配置限流。

约束项❌ 禁止✅ 推荐
限流层级只在统一入口限流,服务层无保护统一入口限流 + 服务层限流 + 核心接口独立限流,三层防护
限流算法固定窗口计数(临界突发流量击穿)令牌桶(平滑限流)或漏桶(强制匀速),核心接口用并发数限制
限流粒度全局限流,无法区分接口/用户按接口 + 用户/租户/客户端 IP 多维限流
限流响应直接返回 500返回E1-RATE-000(429)+ Retry-After 头,提示重试时间

三层限流的配置参考示例见 附录 A.4(参考实现)。

7.4 熔断降级

约束项❌ 禁止✅ 推荐
熔断参数全靠框架默认参数按错误率(50%)+ 慢调用比例(80% 响应超 1s)双维度熔断
降级策略无降级,直接抛异常提供降级策略,返回空集合或缓存数据

熔断参数配置参考示例见 附录 A.5(参考实现)。

7.5 架构审查红线

  • ❌ 全局超时配置覆盖所有下游系统
  • ❌ 非幂等接口允许重试
  • ❌ 无降级策略,熔断后裸抛异常
  • ✅ 按下游系统隔离超时配置
  • ✅ 熔断触发后必须有降级策略

8 · 缓存全生命周期规范

本规范定义缓存的更新策略、一致性防护、Key 命名及 TTL 管理。缓存的更新策略和一致性是生产事故高发区。

8.1 更新模式

场景❌ 禁止✅ 推荐
写场景先删缓存再写 DBCache Aside:先写 DB,再删缓存
读场景强制强一致允许短暂不一致,DB 为准
并发写无锁保护配合分布式锁(多实例部署时)或乐观锁,避免脏写

8.2 穿透防护

场景❌ 禁止✅ 推荐
缓存穿透只用null 值缓存布隆过滤器 + 空值缓存(TTL2min)双层防护
  • 缓存未命中且数据不存在时,写入空值缓存(TTL ≤ 2 分钟),防止恶意高频请求打穿到 DB。

8.3 雪崩防护

场景❌ 禁止✅ 推荐
热点 Key热点 key 永不过期热点 key 设置随机抖动 TTL(基础值 + 0~30s 随机偏移)
批量失效大量 key 同时过期基础 TTL 分散,避免整点失效

8.4 本地缓存约束

场景❌ 禁止✅ 推荐
混用策略本地缓存与分布式缓存混用无过期同步本地缓存 TTL 必须 ≤ 分布式缓存 TTL 的1/3,且禁用本地缓存做写操作
一致性本地缓存写后不同步写操作只走分布式缓存,本地缓存仅读
单实例部署本地缓存可独立使用但需评估进程重启导致的缓存重建压力

单实例场景说明:单实例部署且无分布式缓存时,本地缓存 TTL 按业务可接受的数据延迟自行设定,不受 1/3 约束限制;一旦扩展为多实例,必须引入分布式缓存,并遵守"本地缓存 TTL ≤ 分布式缓存 TTL 的 1/3"约束(见 §1.4.2)。

8.5 缓存热更新与重建

缓存预热与热点 Key 变更时的重建策略,避免冷启动与缓存击穿。

约束项❌ 禁止✅ 推荐
系统启动无预热,上线即面对全量穿透核心热点数据(如字典、配置、Top 商品)启动时预热
热点 Key 变更直接删除热点 Key,瞬间击穿 DB热点 Key 变更时先重建再替换,或加互斥锁仅允许一个线程重建
批量失效重建全量 Key 同时失效,DB 被打满批量失效时按批次重建,控制重建并发度,DB 侧限流保护
缓存击穿缓存过期瞬间大量请求回源热点 Key 用互斥锁/逻辑过期(返回旧值 + 异步更新)防止击穿

缓存重建配置参考与热点 Key 重建的具体手段(双 Key 版本号切换、逻辑过期 + 异步重建)见 附录 A.6(参考实现)。

8.6 架构审查红线

  • ❌ 先删缓存再写 DB
  • ❌ 缓存穿透无防护
  • ❌ 热点 Key 固定 TTL 导致雪崩
  • ❌ 本地缓存参与写操作
  • ✅ Cache Aside 模式:先写 DB,再删缓存
  • ✅ 空值缓存 TTL ≤ 2min
  • ✅ 热点 Key 加随机抖动

9 · 消息队列消费规范

本规范定义消息消费者的异常处理、幂等设计、批量消费及顺序消息约束。

9.1 消费异常处理

约束项❌ 禁止✅ 推荐
异常吞没try-catch 后静默吞掉异常异常必须抛出或转入死信队列(DLQ),禁止自动 ACK 后业务失败
ACK 策略自动 ACK手动 ACK,业务成功后 ACK,异常时 NACK 进 DLQ

9.2 幂等设计

约束项❌ 禁止✅ 推荐
幂等约定依赖"业务天然幂等"口头约定所有消费者必须实现幂等键(bizId + msgId),幂等表/键保留 7
  • 消费前先尝试写入幂等键:首次写入成功则执行业务;写入失败(已存在)视为重复消费,直接跳过。

9.3 批量消费

约束项❌ 禁止✅ 推荐
批量大小为提性能无限加大批量批量大小上限500 条/次,总耗时超 30s 强制拆分

9.4 顺序消息

约束项❌ 禁止✅ 推荐
全局顺序全局顺序导致单分片热点仅在必要场景(如订单状态机)用分区键顺序,禁止全局顺序
  • 发送时按业务主键(如 orderId)哈希选择分区,保证同一业务键的消息顺序消费。

9.5 架构审查红线

  • ❌ 自动 ACK + 异常静默吞没
  • ❌ 无幂等键保护
  • ❌ 批量消费无上限
  • ❌ 全局顺序消息
  • ✅ 手动 ACK,异常进 DLQ
  • ✅ 幂等键 bizId + msgId,保留 7 天
  • ✅ 顺序消息仅限分区键级别

10 · 数据访问与查询规范

本规范聚焦查询性能门禁,与持久化层规范互补。

10.1 索引命名

约束项❌ 禁止✅ 推荐
索引命名idx_a_b 语义不明idx_<表名简写>_<字段>,如 idx_ord_user_id

10.2 深分页

约束项❌ 禁止✅ 推荐
深分页LIMIT 1000000, 20游标分页WHERE id > ? LIMIT 20)或搜索引擎承接

10.3 慢 SQL 阈值

约束项❌ 禁止✅ 推荐
慢 SQL 发现线上出问题再查开发/测试环境集成 SQL 审计工具,单表查询超200ms 即阻断 CI

10.4 批量插入

约束项❌ 禁止✅ 推荐
批量插入循环逐条INSERT必须多值批量INSERT ... VALUES (...), (...),单批次 ≤ 1000

10.5 读写分离与连接复用

约束项❌ 禁止✅ 推荐
读写路由所有查询走主库,从库闲置读流量按规则路由到从库(报表、列表、非核心读),写操作与强一致读走主库
读写一致性从库延迟导致读旧数据未处理关键读(如下单后立即查)强制走主库,或用主库读标记控制一致性
连接复用每个请求新建连接统一走连接池复用,禁止裸创建数据库连接

10.6 事务边界与长事务禁止

约束项❌ 禁止✅ 推荐
事务边界事务内嵌套远程调用/文件 IO事务只包含数据库操作,远程调用与文件 IO 必须放在事务外
长事务事务持续时间无限制(如 > 10s)事务持续时间默认 ≤ 5s(默认阈值);复杂报表类操作可放宽,但须标注@LongTransaction 并走审批流程,且记录审计日志;非放宽场景长事务必须拆分或改为异步处理
事务嵌套多层事务嵌套导致锁竞争加剧单层事务为主,嵌套事务必须评估锁粒度

说明@LongTransaction代码注释标记(如 // @LongTransaction: 审批单号-XXX)或语言特定注解,目的是显式标识长事务以便审计与审批追溯;标注必须关联审批记录,未审批的放宽长事务视为违规(见 §26.12)。

10.7 架构审查红线

  • ❌ 索引命名无业务语义
  • LIMIT offset, size 深分页
  • ❌ 单条循环插入
  • ❌ 无索引的 WHERE 条件查询上线
  • ❌ 微服务架构下跨服务直连对方数据库
  • ✅ 游标分页或搜索引擎承接大数据量查询
  • ✅ SQL 审计集成,慢 SQL 阻断 CI
  • ✅ 批量插入单批次 ≤ 1000

11 · 测试与质量门禁

本规范定义单元测试、集成测试、契约测试的覆盖率阈值及自动化执行约束。

11.1 单元测试

约束项❌ 禁止✅ 推荐
测试范围只测接入层核心业务逻辑层覆盖率≥ 70%,分支覆盖 ≥ 60%
测试数据直接连开发环境 DB用容器化测试环境(如 Testcontainers)启动数据库/中间件,测试完自动销毁

11.2 契约测试

约束项❌ 禁止✅ 推荐
API 兼容性口头约定接口字段消费者驱动契约(CDC),API 变更时自动校验兼容性
  • 契约测试适用于所有对外 API(单体系统的外部接口、微服务系统的服务间接口)。
  • 微服务架构下,服务间接口同样必须以契约测试约束,防止隐式破坏。

11.3 性能测试门禁

约束项❌ 禁止✅ 推荐
压测范围只压测核心接口,忽视全链路核心链路(登录、下单、支付、查询)必须压测,覆盖读 + 写
性能指标只看平均延迟必须看 P95/P99 延迟,P95 ≤ 200ms,P99 ≤ 500ms
吞吐量无吞吐量基线核心接口吞吐量基线 ≥ 设计容量的 80%,回归压测不低于基线
压测环境开发环境压测,数据量与生产不符压测环境数据量必须 ≥ 生产数据量的 30%,索引与配置与生产一致

11.4 CI 门禁阈值

指标阈值阻断构建
行覆盖率≥ 70%
分支覆盖率≥ 60%
单表查询耗时≤ 200ms
依赖漏洞(高危)= 0
核心接口 P95 延迟≤ 200ms
核心接口 P99 延迟≤ 500ms
核心接口吞吐量回归不低于基线 80%

11.5 架构审查红线

  • ❌ 无单元测试的业务逻辑层代码合并
  • ❌ 集成测试直连开发环境 DB
  • ❌ API 变更无契约测试
  • ✅ 容器化测试环境隔离
  • ✅ CI 覆盖率不达标阻断构建

12 · API 设计规范

本规范定义 API 资源命名、HTTP 动词语义、请求/响应结构、版本命名、废弃策略及兼容性约束。

12.1 资源命名

约束项❌ 禁止✅ 推荐
资源命名动词式(/getOrder/createUser名词复数(/orders/users),子资源用嵌套(/orders/{id}/items
命名风格大小写混用(/OrderList全小写 + 连字符(/order-items),或下划线(/order_items),全局统一
资源层级过深嵌套(/a/b/c/d/e最多 3 层嵌套,过深改用查询参数

12.2 HTTP 动词语义

动词语义幂等性典型场景
GET查询幂等单查、列表、分页
POST创建/触发动作非幂等创建资源、触发业务动作(如支付)
PUT全量更新幂等整体替换资源
PATCH部分更新非幂等局部更新资源
DELETE删除幂等删除资源
  • 非幂等操作必须用 POST(或显式标注不可重试),禁止用 GET 做写操作。
  • 备注:PATCH 幂等性取决于实现,此处标记为非幂等是出于保守策略;实际设计时若保证请求体语义幂等(如纯字段级覆盖、无条件依赖),可实现幂等 PATCH。
  • 查询参数只做过滤/排序/分页,禁止用查询参数做业务动作。

12.3 请求/响应结构

约束项❌ 禁止✅ 推荐
分页参数各自定义(pageNum/pageSizeoffset/limit 混用)全局统一(推荐pageNo/pageSizeoffset/limit,全局选一种)
排序参数裸字符串拼接(orderBy=name+desc结构化参数(sort=name&order=desc),或 sort=-name(负号表降序),全局统一
响应结构各接口返回结构不一致统一响应结构(code/message/data),分页数据统一 data.list + data.total
文档无文档或文档与代码不一致文档自动化生成(如 OpenAPI/Swagger),代码与文档同步更新

12.4 版本策略

约束项❌ 禁止✅ 推荐
版本位置URL 路径版本与 Header 版本混用选定一种(推荐 URL Path),全局统一
废弃 API直接删除废弃 API 保留2 个主版本周期,标记 @Deprecated

URL 路径版本示例见 附录 A.11(参考实现)。

12.5 兼容性约束

  • 新增字段:兼容,允许
  • 删除字段:不兼容,需发新版本
  • 修改字段类型:不兼容,需发新版本
  • 枚举值新增:兼容,追加即可
  • 枚举值删除/修改 code:不兼容,视为契约变更

12.6 幂等键设计规范

写接口(POST/PATCH)必须支持幂等键(Idempotency-Key),支付、下单、扣款等资金与库存类接口必须使用:

约束项❌ 禁止✅ 推荐
幂等键来源客户端不传键或传可预测值客户端为每次写操作生成 UUID,通过Idempotency-Key Header 传递
服务端处理无幂等校验,重复提交导致重复下单/扣款以幂等键为唯一约束,重复请求返回首次处理结果(幂等键 + 结果缓存)
键存储幂等键仅存内存(重启即丢失)幂等键、请求摘要与处理结果存 Redis/DB,TTL 覆盖重试窗口(如 24h)
作用域幂等键全局唯一(不同用户间冲突)幂等键按用户维度隔离(userId + Idempotency-Key 联合唯一)
与消息幂等对外幂等键与消息幂等键割裂对外幂等键可复用于下游消息幂等键(见 §9.2),链路统一
  • 幂等冲突响应:重复请求返回首次处理结果(对外统一 HTTP 200 + 业务 code,如 S0000 + 原结果标识),禁止返回 409 或再次执行业务逻辑——与 §4.6 对外统一入口收敛策略保持一致。
  • 幂等键必须由服务端幂等表/分布式锁保障原子性,禁止依赖客户端自觉。

12.7 架构审查红线

  • ❌ URL 版本与 Header 版本混用
  • ❌ 直接删除已发布 API
  • ❌ 修改已发布枚举的 code 值
  • ❌ 支付/下单等资金类接口无幂等键保护
  • ✅ 废弃 API 保留 2 个主版本周期
  • ✅ 破坏性变更必须发新版本

13 · 数据变更管理

本规范定义数据库脚本管理、命名规则及禁止操作,涵盖 DDL(结构)与 DML(数据)两类脚本。

13.1 变更工具

约束项❌ 禁止✅ 推荐
DDL 执行手动执行 DDL强制使用数据库变更管理工具(如 Flyway、Liquibase、Alembic、goose),脚本纳入版本控制
  • 单体架构:全库统一变更管线。
  • 微服务架构:每服务独立库、独立变更管线。

13.2 脚本命名

13.2.1 基线脚本(Baseline,用于全新环境初始化)

基线脚本按 序号-模块-init-ddl/dml.sql 命名,存放某一基线版本(如 v1.0.0)的完整库结构,用于全新环境快速初始化:

约束项❌ 禁止✅ 推荐
命名格式init.sqlschema_v2.sql 语义不明序号-模块-init-ddl/dml.sql,如 001-llm-init-ddl.sql
序号序号重复或乱序3 位序号递增(001、002...),全局唯一
模块无模块标识模块简写(如llmorder),便于定位归属
基线定位基线 = "永远最新"(需反复修改)基线 =某一版本快照(如 v1.0.0),用于全新环境初始化
基线不可变修改已发布的基线脚本禁止修改已发布基线脚本;更新基线走"重新打基线"
重新打基线无固定节奏定期(如每 major 版本)以 versions/ 全量增量脚本重新生成 init/ 基线

13.2.2 DDL / DML 分类

数据库脚本按 DDL(结构)与 DML(数据) 分类存放,禁止混放:

约束项❌ 禁止✅ 推荐
分类方式DDL 与 DML 混放同一目录/文件独立目录(ddl/dml/)或独立文件后缀(-ddl.sql-dml.sql)区分

13.2.3 版本脚本管理(增量,另建目录)

日常 DDL 变更只追加版本脚本(增量),与基线脚本分离,另建独立目录存放,命名规范为 V{版本号}-模块-init-ddl/dml.sql

约束项❌ 禁止✅ 推荐
目录分离版本脚本与基线脚本混放另建独立目录(如versions/migration/)管理增量脚本
版本命名无版本号、无模块、无类型V{版本号}-模块-init-ddl/dml.sql,如 V1.0.0-llm-init-ddl.sql
脚本用途增量脚本用于全新环境初始化增量脚本用于升级/回滚(执行后不可变);全新初始化走基线脚本
日常变更回头修改基线/已发布脚本日常 DDL 变更只追加版本脚本,禁止修改已发布的基线与版本脚本
重新打基线每 major 版本以增量脚本全量生成新基线,替换 init/

与变更管理工具的兼容性:基线 + 增量模式与 Flyway/Liquibase 等工具的"脚本不可变"原则兼容——增量脚本执行后不可修改,与工具校验(checksum)机制一致;基线脚本对应工具的 baseline 机制,仅用于全新环境初始化,日常变更一律走增量脚本。

工具原生命名:若使用 Flyway/Liquibase 等工具,脚本命名以工具原生规范为准(如 Flyway 的 V1.0.0__描述.sql、Liquibase 的 changelog),但必须保留 版本号-模块-类型 的语义信息(可通过 description/changelog 注释体现),确保可追溯。

基线脚本、DDL/DML 分类、基线 + 增量目录的示例见 附录 A.12(参考实现)。

13.3 禁止操作

❌ 禁止原因
DELETEWHERE数据误删
DROP TABLE 无备份数据丢失
ALTER TABLE 大表无在线变更锁表导致服务不可用
修改已有列的数据类型(缩小)数据截断

13.4 业务数据生命周期与归档

业务数据(订单、流水、操作记录等)必须有明确的生命周期管理,防止库表无限膨胀:

数据层级定义处理方式
热数据高频访问的在线业务数据主库在线存储,索引完整
温数据访问频率低但仍需在线查询归档到归档表/分库分表/列存,按需精简索引
冷数据仅审计/合规需要,几乎无在线访问转冷存储(对象存储/数仓),应用侧不直接在线访问
约束项❌ 禁止✅ 推荐
保留期限业务数据无限期保留在业务表按业务与合规要求定义保留期限(如订单明细在线保留 3 年后转冷存储)
归档方式直接DELETE 永久删除先软删除/归档到归档表,确认无引用后按策略清理;删除需走审批与备份
清理任务归档清理与业务线程混跑归档/清理走独立定时作业,低峰期执行,分批处理避免长事务与锁表
合规留存一律删除、无留存涉资金、审计、合规的数据按法定年限留存(如流水保留 ≥ 5 年),留存数据仅冷存储
与事务表一致业务归档与本地事务表清理混淆本地事务表(见 §21.3)按消息保留期清理;业务数据归档按生命周期策略,两者分离

13.5 架构审查红线

  • ❌ 手动执行 DDL
  • ❌ 基线脚本命名不规范(无序号/模块/类型标识,如 init.sqlschema.sql
  • ❌ DDL 与 DML 混放不分类
  • ❌ 基线脚本与版本脚本混放同一目录
  • ❌ 修改已发布的基线脚本(日常 DDL 变更应追加增量脚本)
  • DELETE/UPDATEWHERE
  • ❌ 业务数据无保留期限,无限期堆积
  • ✅ 基线脚本按 序号-模块-init-ddl/dml.sql 命名,为某一版本快照,可直接用于全新环境初始化
  • ✅ 版本脚本另建目录,按 V{版本号}-模块-init-ddl/dml.sql 管理,走变更管理工具
  • ✅ 大表变更用在线变更工具(如 pt-online-schema-changegh-ost

14 · 资源池化配置

本规范定义线程池、连接池的配置公式与命名约束。

14.1 连接池

约束项❌ 禁止✅ 推荐
连接池大小凭感觉设置100maxPoolSize = (核心数 * 2) + 有效磁盘数,最小 10,最大 50
超时配置默认30sconnectionTimeout = 3000idleTimeout = 600000maxLifetime = 1800000

连接池公式的"有效磁盘数"说明与配置参考示例见 附录 A.7(参考实现)。

14.2 线程池

约束项❌ 禁止✅ 推荐
线程池命名默认pool-1-thread-1必须自定义命名(biz-pool-%dasync-pool-%d),便于日志追踪
线程池创建每次新建线程池统一走共享线程池实例(由容器/框架统一管理),配置中心可覆盖
线程池大小凭感觉设置IO 密集型:核心数 * 2;CPU 密集型:核心数 + 1;混合型按比例拆分
队列容量无界队列(内存溢出)或0(频繁拒绝)有界队列,容量 = 预估峰值并发 × 2,且必须配拒绝策略
  • 拒绝策略建议:任务积压超限时采用"调用方执行"策略,避免静默丢弃。
  • 队列容量与线程数需联动:容量越大,允许的积压越多,但响应延迟越高;容量越小,拒绝越快,但可能误拒正常流量。

14.3 架构审查红线

  • ❌ 连接池大小凭感觉设置
  • ❌ 线程池无自定义命名
  • ❌ 业务代码中裸创建线程
  • ✅ 连接池按公式配置
  • ✅ 线程池命名前缀统一,日志可追踪

15 · 依赖安全与配置安全

本规范定义依赖漏洞扫描、敏感配置管理及加密存储约束。

15.1 依赖安全

约束项❌ 禁止✅ 推荐
依赖引入不查漏洞直接引入CI 集成 OWASP Dependency-Check,高危漏洞阻断构建

15.2 配置安全

约束项❌ 禁止✅ 推荐
密码存储明文写在配置文件中敏感配置走配置中心 + 加密存储,本地开发用环境变量注入
密钥管理硬编码在代码中走配置中心加密存储,支持密钥轮换

敏感配置的正反示例与无配置中心的降级方案(环境变量 + 本地加密文件)见 附录 A.8(参考实现)。

15.3 架构审查红线

  • ❌ 引入依赖不查漏洞
  • ❌ 密码明文写在配置文件中
  • ❌ 密钥硬编码
  • ✅ CI 集成 OWASP,高危阻断
  • ✅ 敏感配置走配置中心加密

16 · 通用编码约束

16.1 时区规范

约束项❌ 禁止✅ 推荐
时间存储DB 存本地时间全链路 UTC 存储,DTO 层按用户时区转换
序列化时间类型裸序列化统一时间戳/带时区时间类型,序列化格式yyyy-MM-dd'T'HH:mm:ss'Z'

UTC 存储与报表统计的取舍方案(查询转换 / 预聚合 / business_date 冗余列)见 附录 A.9(参考实现)。

16.2 业务状态序列化规范

约束项❌ 禁止✅ 推荐
序列化业务状态直接序列化枚举名必须显式定义code,序列化 code,且 code 一旦发布不可变更
反序列化依赖枚举名走自定义反序列化器,按code 映射
数据库存储直接存枚举本身(枚举名/序列化对象)入库映射为code 值存储,读取时按 code 反查枚举

16.3 空值处理

约束项❌ 禁止✅ 推荐
返回 null裸返回null统一用Optional 或空集合;DTO 中基本类型必须用包装类
集合返回return nullreturn Collections.emptyList()

16.4 并发安全契约

并发场景(线程池、缓存、异步任务、多实例共享资源)必须遵守统一并发契约:

约束项❌ 禁止✅ 推荐
共享可变状态共享可变状态无防护,多个线程裸读写优先不可变对象;其次线程封闭(ThreadLocal/栈局部);必须共享时显式加锁并声明锁对象
锁粒度全局锁/大对象锁导致无谓串行化锁粒度与临界区对齐:读多写少用读写锁;单条数据操作用细粒度锁(如分段锁/分布式锁按业务键)
锁超时锁无超时,持锁线程挂起导致死锁所有锁必须带超时(如 3s 获取超时、5s 持有上限),超时抛业务异常,禁止无限期等待
锁顺序多把锁加锁顺序不一致(死锁)多把锁按固定顺序(如按对象 id 排序)获取;无法排序时用单锁或 tryLock 超时回退
ThreadLocal请求线程池复用,ThreadLocal 不清理请求结束时必须清理ThreadLocal(如 finally 中 remove()),防止线程复用导致数据串扰与内存泄漏
异步上下文异步任务丢失 TraceId/用户上下文异步链路必须显式传递上下文(见 §17.4 链路追踪):提交任务时快照 TraceId/用户身份,异步线程恢复,禁止依赖继承性传递

16.5 架构审查红线

  • ❌ DB 存本地时间
  • ❌ 业务状态序列化枚举名
  • ❌ 返回裸 null
  • ❌ DTO 中使用基本类型 int/long
  • ❌ 共享可变状态无防护(裸读写)
  • ❌ 锁无超时,存在死锁风险
  • ThreadLocal 请求结束不清理
  • ❌ 异步任务丢失 TraceId/用户上下文
  • ✅ 全链路 UTC
  • ✅ 业务状态序列化 code,code 不可变更
  • ✅ 空集合替代 null,DTO 用包装类
  • ✅ 优先不可变对象,共享可变状态显式加锁

17 · 日志规范

本规范定义日志级别、内容格式、敏感信息脱敏、链路追踪及采集约束。日志是生产事故定位的第一依据,缺失或滥用的代价远大于性能损耗。

17.1 日志级别

级别使用场景生产开启
ERROR系统异常、业务失败、基础设施错误
WARN业务异常、预期内异常(如参数校验失败)
INFO关键业务节点、请求入口/出口、核心状态变更
DEBUG调试信息、详细参数否(生产环境关闭)
  • 生产环境禁止开启 DEBUG 日志,防止日志爆炸与性能损耗。
  • 关键业务节点(下单、支付、库存扣减)必须打 INFO 日志,便于审计与回溯。

17.2 日志内容格式

日志必须包含以下要素,便于检索与关联:

[时间] [级别] [TraceId] [模块] [类名.方法] [用户ID] 消息内容 [关键参数]
  • TraceId:一次请求链路唯一标识,跨模块/跨服务传递,禁止缺失。
  • 用户ID:涉及用户操作的日志必须携带用户标识;无用户上下文场景(如系统任务、未登录接口)可省略用户 ID,但须以 systemanonymous 占位,确保日志格式统一、字段不缺失。
  • 关键参数:业务主键(如 orderId、userId)必须输出,禁止只打"操作成功"。

17.3 敏感信息脱敏

约束项❌ 禁止✅ 推荐
密码/密钥明文打印密码、密钥、Token完全禁止打印,或打印为******
身份证号/手机号完整打印中间位打码(如138****1234
银行卡号完整打印只保留后 4 位
详细堆栈生产环境打印完整堆栈到业务日志堆栈单独输出到错误日志文件,业务日志只打摘要

17.4 链路追踪

约束项❌ 禁止✅ 推荐
TraceId 生成无 TraceId,无法串联链路统一入口生成 TraceId,全链路传递
TraceId 传递只在本模块传递跨模块/跨服务/跨消息队列传递,异步链路同样携带
TraceId 关联错误日志与正常日志割裂同一 TraceId 的所有日志(正常 + 错误)可关联查询

17.5 日志采集与存储

约束项❌ 禁止✅ 推荐
单实例部署本地文件即可本地文件 + 日志轮转(按天/按大小),保留 ≥ 30 天
多实例/微服务各实例本地文件,无法统一查询集中式日志采集(如 ELK、Loki),统一查询与告警
日志保留保留 < 7 天生产日志保留 ≥ 30 天,错误日志保留 ≥ 90 天

17.6 架构审查红线

  • ❌ 生产环境开启 DEBUG 日志
  • ❌ 日志中明文打印密码/密钥/Token
  • ❌ 关键业务节点无 INFO 日志
  • ❌ 错误日志无 TraceId,无法定位链路
  • ❌ 多实例部署无集中式日志采集
  • ✅ 日志必须带 TraceId,全链路可关联
  • ✅ 敏感信息必须脱敏

18 · 指标与告警规范

本规范定义 Metrics 指标、SLO 与告警分级约束,与 §17 日志、链路追踪(TraceId)共同构成可观测性三支柱(日志 Logging、指标 Metrics、追踪 Tracing)。没有指标与告警的系统,故障只能在用户投诉后被动发现。

18.1 指标采集(Metrics)

约束项❌ 禁止✅ 推荐
指标范围只采集基础设施指标(CPU/内存)核心业务接口必须采集 RED 指标:Rate(QPS)、Errors(错误率)、Duration(时延)
时延统计只打平均值必须记录分位数 P50/P95/P99,平均值会掩盖长尾问题
指标命名无统一命名、标签带实例 IP统一命名规范({模块}.{接口}.{指标}),标签禁止携带高基数动态值(如用户 ID)
采集方式业务代码手写打点散落各处统一接入指标 SDK/框架,核心接口自动埋点

18.2 SLO 与错误预算

  • 核心接口必须定义 SLO(服务等级目标)并量化,如:P99 ≤ 200ms、错误率 ≤ 0.1%
  • 以滚动窗口(如 30 天)计算错误预算(Error Budget = 1 - SLO),预算耗尽须触发发布冻结或加急优化。
  • SLO 必须可量化、可验证,禁止"尽快""越早越好"等模糊表述。

18.3 告警分级与响应时效

级别定义响应时效(工作日/非工作日一致)示例
P0核心服务不可用、资损、数据损坏立即响应,15 分钟内介入下单接口错误率 > 5%、主库不可用
P1核心功能降级、部分用户受影响30 分钟内介入P99 超阈值、缓存大面积失效
P2非核心功能异常,有降级路径4 小时内处理报表任务失败、次要接口抖动
P3低优先级问题下一个工作日处理磁盘水位预警、指标毛刺

18.4 告警规则设计

  • 告警必须"少而准":禁止无阈值告警(如 CPU 使用率 > 0%)与抖动告警(如单次 P99 毛刺)。
  • 告警必须携带服务/实例/TraceId 维度定位信息,可一键跳转排查。
  • 告警收敛:同一根因的告警合并,抑制派生告警(如"接口错误率高"抑制其下游"数据库慢"告警)。
  • 告警必须有明确恢复条件,防止告警风暴与告警疲劳。

18.5 架构审查红线

  • ❌ 核心接口无 P95/P99 指标
  • ❌ 关键指标无 SLO,无错误预算机制
  • ❌ 核心服务无 P0 告警或告警无人响应
  • ❌ 告警无阈值、抖动告警,导致告警风暴
  • ✅ RED 指标 + P50/P95/P99 分位数覆盖核心接口
  • ✅ 告警分级 + 响应时效 + 收敛抑制

19 · 部署与发布

本规范定义环境划分、配置隔离、发布策略、健康检查及回滚约束。环境管理是架构工程的基础,缺失易导致配置泄露与发布事故。

19.1 环境划分

环境用途数据配置
dev开发自测开发数据,可随时重置开发配置
test测试验证测试数据,定期同步生产结构测试配置
stage预发布与生产同构的数据(脱敏)与生产同构的配置(副本)
prod生产真实数据生产配置(加密存储)
  • 环境之间禁止直连(如 test 直连 prod 数据库),配置必须完全隔离。
  • stage 环境必须存在,用于发布前验证,禁止跳过 stage 直接发 prod。

19.2 配置隔离

约束项❌ 禁止✅ 推荐
配置文件所有环境配置混在一个文件中按环境拆分配置文件(如application-dev.yml),配置中心按环境隔离
敏感配置明文写在配置文件中敏感配置走配置中心加密存储,本地开发用环境变量注入
环境标识无环境标识,配置混用启动时必须显式指定环境(如--spring.profiles.active=prod),禁止默认环境

19.3 发布策略

约束项❌ 禁止✅ 推荐
单体/简单系统直接全量发布,无回滚预案全量发布 + 回滚预案,发布前备份当前版本
微服务/核心系统无灰度,直接全量蓝绿发布或灰度发布,先小流量验证,再全量
发布窗口业务高峰期发布低峰期发布(如凌晨),核心系统禁止白天发布

19.4 健康检查

约束项❌ 禁止✅ 推荐
健康检查无健康检查,发布即切流必须暴露健康检查接口(如/health),发布时先检查再切流
检查内容只检查进程存活检查关键依赖(数据库、缓存、消息队列)连通性
就绪检查启动未完成即接流量就绪检查(readiness)与存活检查(liveness)分离,未就绪不切流

19.5 回滚约束

约束项❌ 禁止✅ 推荐
回滚预案发布失败无回滚手段发布前必须准备回滚预案,版本号与制品可快速回滚
数据库变更发布与 DDL 变更无顺序约定DDL 必须向后兼容;应用发布与 DDL 执行顺序按变更类型确定(加字段/索引/表:先执行向后兼容的 DDL——可空字段或带默认值,再发布应用;删字段/表/约束:先发布应用——确保新代码不再依赖,再执行 DDL),确保任意时刻回滚到旧版本应用,数据库结构仍能兼容

19.6 优雅停机与流量摘除

发布(蓝绿/灰度/滚动)时,旧实例摘除流量后必须优雅停机,禁止直接强杀进程掐断存量请求:

约束项❌ 禁止✅ 推荐
流量摘除直接停止实例,存量请求被掐断先从负载均衡摘除实例(下线探针/就绪状态置为不健康),停止接收新流量,再处理存量
存量请求无等待窗口,立即强杀等待存量请求处理完成,设置等待窗口(如 30s),超时后再强杀
连接排空进程退出时连接未释放关闭监听端口 → 排空数据库/消息/HTTP 连接池 → 完成优雅停机回调 → 退出
平滑发布蓝绿/灰度切换瞬间中断新实例就绪检查通过后再摘除旧实例流量,滚动发布每次只摘一个批次

19.7 架构审查红线

  • ❌ 环境配置混用(如 test 配置连 prod 数据库)
  • ❌ 无 stage 环境,直接发 prod
  • ❌ 发布无健康检查,启动即切流
  • ❌ 发布无回滚预案
  • ❌ 发布时直接强杀旧实例,无优雅停机
  • ❌ 敏感配置明文存储
  • ✅ 环境隔离 + 健康检查 + 回滚预案三要素必须满足
  • ✅ 摘除流量 → 等待窗口 → 连接排空 → 优雅退出

20 · 镜像与 CI/CD

本规范定义容器镜像构建、镜像仓库安全、CI/CD 流水线及构建产物管理约束。镜像与 CI/CD 是质量门禁到生产部署的桥梁,所有涉及容器化部署的系统必须遵守。

20.1 镜像构建规范

约束项❌ 禁止✅ 推荐
基础镜像使用latest 或漂移版本固定明确版本,优先官方镜像,禁止latest
镜像分层每条指令一层,镜像臃肿合并 RUN 指令,减少层数与体积
构建上下文包含.gitnode_modules 等无用文件构建上下文最小化,.dockerignore 排除无关文件
构建方式单阶段构建,体积大多阶段构建(编译环境 → 运行环境),仅保留运行产物
镜像标签latest,无法定位版本测试版:分支名-时间戳-构建号;正式版:语义化版本;latest 仅限最新正式版
不可变性发布后修改已发布镜像镜像不可变,发布后禁止修改,变更走新版本

20.1.1 镜像标签命名规范

镜像类型标签格式示例说明
测试版分支名-时间戳-构建号dev-202608061030-123每次构建唯一,可追溯代码分支与构建序号
正式版语义化版本v1.2.3遵循语义化版本规范(主版本.次版本.修订),用于生产发布
通用latestlatest仅允许打在最新的正式版镜像上,禁止用于测试版
约束项❌ 禁止✅ 推荐
分支名大写、含/小写,/-(如 feature/orderfeature-order
时间戳无时间戳,无法定位构建时间YYYYMMDDHHMM 格式
构建号无构建号,无法定位构建顺序流水线构建序号递增(如123
latest 使用测试版打latest;非最新正式版打 latest仅最新正式版打latest
标签分离正式版复用测试版标签正式版与测试版标签严格分离

20.2 镜像仓库与安全

约束项❌ 禁止✅ 推荐
仓库来源生产环境直拉公共镜像仓库统一私有镜像仓库,公共镜像先拉取到私有仓再使用
漏洞扫描未扫描直接上线CI 集成镜像扫描(如 Trivy、Clair),高危漏洞阻断上线
镜像完整性无签名校验镜像签名校验(如 cosign),防止篡改
拉取策略生产按标签拉取,易被覆盖生产固定digest 拉取,保证不可变

20.3 CI/CD 流水线规范

约束项❌ 禁止✅ 推荐
流水线阶段无固定阶段,随意执行固定阶段:代码检查 → 单元测试 → 构建 → 镜像扫描 → 部署
环境递进跳级部署(跳过 stage 直接 prod)按 dev → test → stage → prod 递进,禁止跳级
失败门禁门禁不达标仍放行覆盖率/慢 SQL/依赖漏洞不达标阻断流水线
流水线幂等重跑产生副作用(重复建表、重复发消息)流水线可重复执行,无副作用,失败可安全重跑

20.4 构建与发布策略

约束项❌ 禁止✅ 推荐
产物管理每次构建产物随机,无法追溯构建产物不可变,统一制品仓库版本化管理,可追溯
部署复用每环境重新构建同一构建产物贯穿环境递进,各环境只做配置差异
发布方式直接全量替换结合 §19 部署与发布的蓝绿/灰度策略

20.5 架构审查红线

  • ❌ 基础镜像使用 latest
  • ❌ 测试版镜像打 latest 标签
  • ❌ 非最新正式版打 latest 标签
  • ❌ 测试版镜像标签无分支/时间戳/构建号(无法追溯)
  • ❌ 生产环境直拉公共镜像仓库
  • ❌ 镜像高危漏洞未扫描通过即上线
  • ❌ CI 跳级部署(如跳过 stage 直接 prod)
  • ❌ 构建产物不版本化、无法追溯
  • ❌ 流水线重跑产生副作用
  • ✅ 镜像固定版本 + digest 拉取,扫描通过才上线
  • ✅ 流水线环境递进 + 门禁阻断 + 幂等可重跑

21 · 事务规范

本规范定义事务边界、分布式事务策略、本地事务表模式及一致性约束。事务是数据一致性的核心,缺失易导致脏数据与资金损失。

21.1 事务边界

约束项❌ 禁止✅ 推荐
事务范围事务内嵌套远程调用/文件 IO/消息发送事务只包含数据库操作,远程调用与文件 IO 必须放在事务外
事务声明隐式事务,无明确边界显式声明事务边界(注解/代码块),禁止隐式提交
事务隔离默认隔离级别不评估默认用READ COMMITTED;涉及资金/库存用 REPEATABLE READ 或显式加锁

21.2 分布式事务策略

跨服务/跨模块的分布式事务,按业务一致性要求选择策略:

策略适用场景一致性说明
本地事务单模块内操作强一致单库事务即可
本地事务表本地事务 + 消息发送最终一致本地事务写业务表 + 消息表,异步投递消息
Saga长流程业务(如订单 → 库存 → 支付)最终一致每步本地事务 + 补偿动作,失败时按序回滚
TCC资金/库存等强一致要求强一致(预留)Try(预留)→ Confirm(确认)/ Cancel(取消),需业务侵入
2PC/XA跨库强一致(性能差)强一致仅限同机房、低并发场景,禁止跨服务使用
  • 优先选择:本地事务表(简单、可靠、性能好),其次 Saga,TCC 仅在资金/库存等核心场景使用。
  • 禁止:跨服务使用 2PC/XA,性能差且易死锁。

21.3 本地事务表模式(推荐)

本地事务 + 消息发送的一致性保障,推荐用于异步解耦场景:

本地事务:
  1. 写业务表(如订单表)
  2. 写消息表(如 order_msg,状态 = 待发送)
  提交事务(业务表与消息表同库,保证原子性)

异步任务:
  3. 定时扫描消息表,投递消息到 MQ
  4. 投递成功后更新消息表状态 = 已发送
  5. 投递失败重试,超限后告警
  • 消息表必须包含:消息 ID、业务键、消息体、状态、重试次数、created_at(创建时间)、cleaned_at(清理时间)。
  • 投递失败必须重试,重试超限(如 5 次)后告警并人工介入。

清理策略

  • 已投递成功的消息记录必须定期清理(如保留 7 天后删除或归档),防止消息表长期累积膨胀。
  • 清理任务必须走独立定时作业(独立线程池/调度),避免与业务线程竞争资源。
  • 清理以 created_at 为保留判断依据,清理完成后回写 cleaned_at,便于审计与排查。

21.4 架构审查红线

  • ❌ 事务内嵌套远程调用/文件 IO
  • ❌ 跨服务使用 2PC/XA
  • ❌ 本地事务 + 消息发送无本地事务表保障
  • ❌ 分布式事务无补偿/回滚策略
  • ✅ 事务边界只包含数据库操作
  • ✅ 异步解耦优先用本地事务表模式

22 · 文件与对象存储规范

本规范定义文件上传、存储、访问控制与生命周期管理约束(对应错误码 E3-FILE)。头像、附件、导出文件等是 Web 系统的常见需求,缺少约束会导致磁盘膨胀、越权下载与恶意上传。

22.1 存储选型与分类

文件类型推荐存储访问方式
头像/图片/富文本附件对象存储(如 MinIO、云 OSS)私有读写 + 签名 URL
导出/报表文件对象存储或本地临时目录(短生命周期)签名 URL,TTL 到期清理
日志/备份类大文件对象存储冷存储/归档非在线访问
  • 禁止把业务文件直接存数据库大字段(BLOB),大字段导致数据库膨胀与性能劣化。

22.2 上传约束

约束项❌ 禁止✅ 推荐
大小限制无限制或仅前端限制后端强制限制上传大小(如图片 ≤ 5MB、附件 ≤ 50MB),超限返回E1-FILE-xxx
类型校验仅信任文件名后缀校验文件内容签名(魔数)+ 后缀白名单,禁止可执行文件(.exe/.sh/.jsp
临时文件上传失败/过期后残留临时文件临时目录必须定期清理(TTL,如 24h),独立定时作业扫描删除

22.3 访问控制

约束项❌ 禁止✅ 推荐
私有文件URL 公开可访问(猜 URL 即下载)对象存储私有读写;对外访问走签名 URL(带过期时间与权限,如有效期 ≤ 10min)
防盗链任意来源可热链引用签名 URL 参数校验 + Host 白名单为主要防护;Referer 可被伪造/为空,仅作辅助手段,不可作为安全依赖;必要时加 CDN 防盗链
越权下载任意登录用户可下载他人文件文件归属校验:下载接口必须校验文件属主与访问者权限(水平越权,见 §25.3)

22.4 分片上传与断点续传

  • 大文件(> 50MB)必须支持分片上传:初始化上传任务 → 逐片上传 → 合并校验(MD5/大小)。
  • 分片需支持断点续传与失败重试(重试幂等,见 §12.6 幂等键)。
  • 合并前校验分片完整性,合并后清理分片与临时任务记录。

22.5 架构审查红线

  • ❌ 文件存数据库大字段(BLOB
  • ❌ 上传无大小/类型后端校验
  • ❌ 私有文件公开 URL 可下载(无签名)
  • ❌ 下载接口不校验文件属主(越权下载)
  • ❌ 临时文件不清理
  • ✅ 对象存储私有读写 + 签名 URL + 防盗链
  • ✅ 大文件分片上传 + 断点续传

23 · 定时任务与分布式调度规范

本规范定义定时任务的分布式调度约束(防重复执行、超时、重试、执行记录)。文档多处依赖定时任务(本地事务表清理 §21.3、缓存预热 §8.5、报表预聚合 §16.1),调度本身必须有规范,否则多实例部署时任务重复执行。

23.1 任务定义

  • 每个任务必须有全局唯一标识、模块归属、执行间隔与描述,禁止匿名任务。
  • 任务执行必须可观测:开始/结束/失败/耗时写入执行记录(与 §17 日志、§18 指标联动)。

23.2 分布式防重复执行

约束项❌ 禁止✅ 推荐
多实例执行每实例独立执行,任务重复运行分布式环境必须保证单实例执行:选主(如 Quartz 集群/xxl-job 调度中心)或分布式锁(如 Redis 锁 + 租约)
锁时效分布式锁无过期时间,持锁者宕机锁必须带过期时间(租约),过期自动释放,防止持锁实例宕机导致任务永久阻塞
重叠执行上一轮未结束下一轮已开始禁止任务重叠:任务开始/结束标记或锁的tryLock,超时未拿到锁则跳过本轮

23.3 超时与失败重试

  • 任务必须配置超时时间,超时中断并告警(P2,见 §18.3),防止任务卡死占用线程。
  • 失败重试策略按任务类型定义:允许重试的任务设置次数上限(如 3 次)与退避间隔;禁止无限重试
  • 重试必须幂等(见 §12.6 幂等键、§9.2 消息幂等),重试不产生重复副作用。

23.4 执行记录留存

  • 每次执行记录:任务 ID、触发时间、耗时、结果(成功/失败/跳过)、失败原因。
  • 执行记录保留期限按审计要求(如 ≥ 90 天),定期归档(见 §13.4 数据生命周期)。
  • 连续失败任务必须告警并自动降频或暂停,禁止静默失败。

23.5 架构审查红线

  • ❌ 多实例部署任务重复执行(无选主/无锁)
  • ❌ 分布式锁无过期时间
  • ❌ 任务无超时、无失败重试上限
  • ❌ 无执行记录,失败静默
  • ✅ 单实例执行保障(选主/分布式锁)+ 锁租约
  • ✅ 超时中断 + 幂等重试 + 执行记录留存

24 · 数据库备份与恢复(RTO/RPO)

本规范定义数据库备份节奏、校验与恢复演练约束。事务一致性(§21)与缓存(§8)保证的是运行期正确性,备份恢复是灾难场景的最后防线,缺失即"裸奔"。

24.1 RTO / RPO 目标

  • RTO(恢复时间目标):故障后系统恢复可用所需时间,按业务等级定义(如核心库 ≤ 30min,普通库 ≤ 4h)。
  • RPO(恢复点目标):可接受的数据丢失量(如核心库 ≤ 5min,即丢失不超过 5 分钟数据)。
  • 所有数据库必须声明 RTO/RPO 目标并纳入备份方案设计,禁止无目标"每日备份"。

24.2 备份节奏

备份类型频率说明
全量备份每日(低峰)核心库每日全量,普通库可按业务频率(如每周全量 + 每日增量)
增量备份频繁按 RPO 要求配置(如每小时/每 5 分钟),缩小恢复点
日志归档持续事务日志/WAL 持续归档,用于时间点恢复(PITR)
  • 备份文件必须异地/跨可用区保存,防止单机房故障时备份与数据同毁。
  • 备份加密存储(传输与落盘),密钥走配置中心(见 §15.2)。

24.3 备份校验

  • 每次备份必须自动校验完整性(校验和/抽样恢复),校验失败立即告警(P1),禁止"备份从未被验证过"。
  • 备份作业本身必须可观测:开始/结束/大小/耗时记录,失败告警。

24.4 恢复演练

  • 必须定期执行恢复演练(如每季度一次核心库演练),验证 RTO/RPO 目标可达。
  • 演练在生产副本/隔离环境执行,演练结果记录并评审;连续演练不达标必须调整备份方案。
  • 恢复流程文档化(SOP),演练覆盖:全量恢复、增量+日志时间点恢复、备份文件损坏场景。

24.5 架构审查红线

  • ❌ 无 RTO/RPO 目标
  • ❌ 备份不校验完整性,从未验证可恢复
  • ❌ 备份与数据同机房/同可用区
  • ❌ 无恢复演练
  • ❌ 备份明文存储、密钥硬编码
  • ✅ 全量 + 增量 + 日志归档按 RPO 配置
  • ✅ 定期恢复演练验证 RTO/RPO

25 · 应用层安全规范

本规范定义应用层(代码层)的安全约束,与 §15 依赖安全/配置安全互补。SQL 注入、XSS、越权是 Web 系统最常被利用的漏洞,必须在架构与编码层统一防护。

25.1 注入防护

约束项❌ 禁止✅ 推荐
SQL 注入字符串拼接 SQL、${} 直接拼参数强制参数化查询PreparedStatement/ORM 参数绑定),禁止拼接 SQL
动态排序排序字段/表名由用户输入直接拼接排序字段走白名单映射,禁止直接拼接用户输入
其他注入命令注入、模板注入、NoSQL 注入禁止把用户输入拼进系统命令/模板;NoSQL 查询同样参数化

25.2 XSS 防护

  • 输出侧:所有用户输入渲染到页面/日志前必须转义或编码(HTML/JS 上下文),前端框架默认转义不可关闭。
  • 存储侧:富文本内容必须走白名单过滤(标签/属性/协议),禁止"先存储后过滤"或完全信任用户 HTML。
  • 配合安全头:Content-Security-PolicyX-Content-Type-Options: nosniff

25.3 越权防护(水平 / 垂直)

越权类型定义❌ 禁止✅ 推荐
水平越权访问他人同等级数据业务代码中裸判断userId == ?数据归属校验必须走统一鉴权层/数据权限组件,按资源属主(owner_id)统一拦截
垂直越权低权限调用高权限接口仅前端隐藏按钮,后端不校验后端必须按角色/权限点校验(RBAC,见 §6.6),权限校验不可依赖前端
  • 强制要求:数据权限校验必须走统一鉴权层(统一入口/权限组件),禁止在业务代码中裸判断越权(散落判断难以审计、易遗漏)。
  • 越权检测:核心资源接口纳入安全测试(见 §11 测试),契约测试覆盖权限场景。

25.4 其他应用层风险

  • 文件上传安全:见 §22.2(大小/类型/内容校验)。
  • SSRF:禁止用户输入直接作为目标 URL 发起服务端请求,目标地址走白名单/内网地址黑名单。
  • CSRF:写操作禁止仅靠 Cookie 鉴权,配合 CSRF Token 或自定义 Header(见 §6.3)。

25.5 架构审查红线

  • ❌ SQL 字符串拼接、非参数化查询
  • ❌ 用户输入未转义直接渲染(XSS)
  • ❌ 数据权限在业务代码中裸判断(水平/垂直越权)
  • ❌ 用户输入直拼系统命令/目标 URL(命令注入/SSRF)
  • ✅ 参数化查询 + 排序白名单
  • ✅ 统一鉴权层做数据权限校验,业务代码零散权限判断为零

26 · 架构审查红线(汇总)

本章为正文 §1~§25 各章红线的完整汇总速查,逐条标注来源章节;审查时按本章逐条核对,完整条款见各章末尾红线。红线为强制约束,违反即评审不通过。

26.1 架构层

  • ❌ 接入层写业务逻辑、直接操作数据访问层 → §2.2
  • ❌ 跨模块/跨服务引用对方错误码、常量定义 → §2.3 / §4.5 / §5.9
  • ❌ 模块结构按技术分层平铺(controller/service/dao/ 平铺) → §2.1
  • ❌ 微服务架构下跨服务直连对方数据库 → §2.3
  • ❌ 默认将有状态设计作为首选(如本地内存存会话) → §1.4.1
  • ❌ 以"实现简单"为由保留状态,未评估副作用 → §1.4.2
  • ❌ 有状态设计未显式标注 @Stateful 及原因 → §1.4.2
  • ❌ 多实例部署仍用本实例内存存状态 → §1.4.2
  • ❌ 前后端分离项目仍用后端渲染(如 JSP/Thymeleaf 直出页面) → §1.4.4 / §1.5.5
  • ❌ 前后端分离项目用 Session-Cookie 做认证(跨域/多端受限) → §1.4.4 / §1.5.5
  • ❌ 后端接口返回 HTML 片段而非 JSON 数据 → §1.4.4 / §1.5.5
  • ❌ 模块依赖对方具体实现类(而非接口) → §3.1
  • ❌ 业务功能拓展用 if-else 硬编码分支 → §3.3
  • ❌ 扩展点无默认实现 / 扩展修改核心模块代码 → §3.3
  • ❌ 扩展实例有状态 → §3.3

26.2 错误码与常量

  • ❌ 自行对错误码前缀做字符串判断 → §4.3
  • ❌ 业务代码中出现裸字符串/数字(除数学 0/1) → §5.1
  • ❌ 错误码/业务状态不用枚举定义(散落裸字符串/数字) → §4.4 / §5.4.1
  • ❌ 业务状态用散落裸常量而非集中定义 → §5.4
  • ❌ 业务状态序列化枚举名 → §16.2
  • ❌ 业务状态直接存枚举本身(枚举名/序列化对象入库) → §16.2
  • ❌ 模块间传递非统一响应结构 → §4.7
  • ❌ 一个常量定义中混杂不同分类前缀(PARAM_/BIZ_/INFRA_ 混用) → §5.2
  • ❌ 缓存 Key、消息 Topic 在业务代码中硬编码拼接 → §5.6 / §5.7
  • ❌ 含动态段字符串散落手写拼接,未走统一模板与生成方法 → §5.5
  • ✅ 错误码发布后不可变更语义,新增只能追加 → §4.4

26.3 认证授权

  • ❌ 业务模块直接解析 Authorization Header → §6.4
  • ❌ 裸传用户凭证到下游模块/服务 → §6.5
  • ❌ 签名密钥硬编码 → §15.2
  • ❌ 权限点用裸字符串,未走 AUTH_ 常量 → §6.6
  • ❌ 凭证黑名单仅删前端不维护服务端 → §6.7

26.4 远程调用韧性

  • ❌ 全局超时覆盖所有下游系统 → §7.1
  • ❌ 非幂等接口允许重试 → §7.2
  • ❌ 无降级策略 → §7.4

26.5 缓存与数据

  • ❌ 先删缓存再写 DB → §8.1
  • ❌ 缓存穿透无防护 → §8.2
  • ❌ 热点 Key 固定 TTL → §8.3
  • ❌ 本地缓存参与写操作 → §8.4
  • LIMIT offset, size 深分页 → §10.2
  • ❌ 单条循环插入 → §10.4
  • ❌ 索引命名无业务语义 → §10.1
  • ❌ 无索引的 WHERE 条件查询上线 → §10.3

26.6 消息队列

  • ❌ 自动 ACK + 异常静默吞没 → §9.1
  • ❌ 无幂等键保护 → §9.2
  • ❌ 批量消费无上限 → §9.3
  • ❌ 全局顺序消息 → §9.4

26.7 测试与质量

  • ❌ 无单元测试的业务逻辑层代码合并 → §11.1
  • ❌ 集成测试直连开发环境 DB → §11.1
  • ❌ API 变更无契约测试 → §11.2
  • ❌ 慢 SQL 超 200ms 未阻断 → §10.3 / §11.4

26.8 安全与配置

  • ❌ 密码明文写在配置文件中 → §15.2
  • ❌ 引入依赖不查漏洞 → §15.1

26.9 日志规范

  • ❌ 生产环境开启 DEBUG 日志 → §17.1
  • ❌ 日志中明文打印密码/密钥/Token → §17.3
  • ❌ 关键业务节点无 INFO 日志 → §17.1
  • ❌ 错误日志无 TraceId,无法定位链路 → §17.4
  • ❌ 多实例部署无集中式日志采集 → §17.5

26.10 部署与发布

  • ❌ 环境配置混用(如 test 配置连 prod 数据库) → §19.1 / §19.2
  • ❌ 无 stage 环境,直接发 prod → §19.3
  • ❌ 发布无健康检查,启动即切流 → §19.4
  • ❌ 发布无回滚预案 → §19.5
  • ❌ 发布时直接强杀旧实例,无优雅停机 → §19.6
  • ❌ 敏感配置明文存储 → §19.2 / §15.2

26.11 镜像与 CI/CD

  • ❌ 基础镜像使用 latest → §20.1
  • ❌ 测试版镜像打 latest 标签 → §20.1.1
  • ❌ 非最新正式版打 latest 标签 → §20.1.1
  • ❌ 测试版镜像标签无分支/时间戳/构建号(无法追溯) → §20.1.1
  • ❌ 生产环境直拉公共镜像仓库 → §20.2
  • ❌ 镜像高危漏洞未扫描通过即上线 → §20.2
  • ❌ CI 跳级部署(如跳过 stage 直接 prod) → §20.3
  • ❌ 构建产物不版本化、无法追溯 → §20.4
  • ❌ 流水线重跑产生副作用 → §20.3

26.12 事务规范

  • ❌ 事务内嵌套远程调用/文件 IO → §21.1 / §10.6
  • ❌ 跨服务使用 2PC/XA → §21.2
  • ❌ 本地事务 + 消息发送无本地事务表保障 → §21.3
  • ❌ 分布式事务无补偿/回滚策略 → §21.2

26.13 指标与告警

  • ❌ 核心接口无 P95/P99 指标 → §18.1
  • ❌ 关键指标无 SLO 与错误预算机制 → §18.2
  • ❌ 核心服务无 P0 告警 / 告警无人响应 → §18.3
  • ❌ 告警无阈值、抖动告警,导致告警风暴 → §18.4
  • ❌ 指标标签携带用户 ID、订单号等高基数动态值(cardinality 爆炸) → §18.1
  • ✅ RED 指标 + P50/P95/P99 分位数覆盖核心接口 → §18.1

26.14 API 设计

  • ❌ 支付/下单等资金类接口无幂等键保护 → §12.6
  • ❌ URL 版本与 Header 版本混用 → §12.4
  • ❌ 直接删除已发布 API → §12.4
  • ❌ 修改已发布枚举的 code 值 → §12.5
  • ✅ 写接口支持 Idempotency-Key,服务端幂等保障 → §12.6

26.15 并发安全

  • ❌ 共享可变状态无防护(裸读写) → §16.4
  • ❌ 锁无超时,存在死锁风险 → §16.4
  • ThreadLocal 请求结束不清理 → §16.4
  • ❌ 异步任务丢失 TraceId/用户上下文 → §16.4
  • ✅ 优先不可变对象,共享可变状态显式加锁 → §16.4

26.16 文件与对象存储

  • ❌ 文件存数据库大字段(BLOB) → §22.1
  • ❌ 上传无大小/类型后端校验 → §22.2
  • ❌ 私有文件公开 URL 可下载(无签名) → §22.3
  • ❌ 下载接口不校验文件属主(越权下载) → §22.3
  • ❌ 临时文件不清理 → §22.2
  • ✅ 对象存储私有读写 + 签名 URL + 防盗链 → §22.3

26.17 定时任务与调度

  • ❌ 多实例部署任务重复执行(无选主/无锁) → §23.2
  • ❌ 分布式锁无过期时间 → §23.2
  • ❌ 任务无超时、无失败重试上限 → §23.3
  • ❌ 无执行记录,失败静默 → §23.4
  • ✅ 单实例执行保障 + 锁租约 → §23.2

26.18 数据库备份与恢复

  • ❌ 无 RTO/RPO 目标 → §24.1
  • ❌ 备份不校验完整性,从未验证可恢复 → §24.3
  • ❌ 备份与数据同机房/同可用区 → §24.2
  • ❌ 无恢复演练 → §24.4
  • ✅ 全量 + 增量 + 日志归档按 RPO 配置 → §24.2

26.19 应用层安全

  • ❌ SQL 字符串拼接、非参数化查询 → §25.1
  • ❌ 用户输入未转义直接渲染(XSS) → §25.2
  • ❌ 数据权限在业务代码中裸判断(水平/垂直越权) → §25.3
  • ❌ 用户输入直拼系统命令/目标 URL(命令注入/SSRF) → §25.4
  • ✅ 参数化查询 + 统一鉴权层做数据权限校验 → §25.1 / §25.3

26.20 通用编码约束

  • ❌ DB 存本地时间 → §16.1
  • ❌ 返回裸 null → §16.3
  • ❌ DTO 中使用基本类型 int/long → §16.3
  • ✅ 全链路 UTC 存储,DTO 层按用户时区转换 → §16.1
  • ✅ 空集合替代 null,DTO 用包装类 → §16.3

26.21 资源池化

  • ❌ 连接池大小凭感觉设置 → §14.1
  • ❌ 线程池无自定义命名 → §14.2
  • ❌ 业务代码中裸创建线程 → §14.2
  • ✅ 连接池按公式配置,超时显式设定 → §14.1
  • ✅ 线程池命名前缀统一,日志可追踪 → §14.2

26.22 数据变更管理

  • ❌ 手动执行 DDL → §13.1
  • ❌ 基线脚本命名不规范(无序号/模块/类型标识) → §13.2.1
  • ❌ DDL 与 DML 混放不分类 → §13.2.2
  • ❌ 基线脚本与版本脚本混放同一目录 → §13.2.3
  • ❌ 修改已发布的基线/版本脚本(日常变更应追加增量脚本) → §13.2.1 / §13.2.3
  • DELETE/UPDATEWHERE → §13.3
  • ❌ 业务数据无保留期限,无限期堆积 → §13.4
  • ✅ 大表变更用在线变更工具(如 pt-osc / gh-ost) → §13.2

附录 A · 参考实现(配置示例、公式与取舍讨论)

本附录收录正文各章的参考实现内容(配置示例、公式说明、实现示例、取舍讨论),供落地时参考;与正文条款冲突时,以正文为准。正文各章节对应的参考条目索引:

附录条目对应正文内容
A.1 架构模式取舍§1.5.2前后端分离 vs 传统后端渲染对比
A.2 统一入口收敛配置示例§4.6.2统一入口错误码收敛配置
A.3 认证常量配置示例§6.9AUTH_ 前缀常量参考值
A.4 限流配置参考§7.3三层限流配置示例
A.5 熔断配置参考§7.4熔断参数配置示例
A.6 缓存重建配置与实现参考§8.5缓存重建配置 + 双 Key/逻辑过期伪代码
A.7 连接池公式与配置参考§14.1连接池公式说明与配置示例
A.8 配置安全示例与无配置中心降级§15.2敏感配置示例 + 降级方案
A.9 时区与报表统计取舍§16.1UTC 与报表统计取舍方案
A.10 字符串拼接实现示例§5.5占位符模板正反示例
A.11 版本策略示例§12.4URL 路径版本示例
A.12 数据库脚本目录结构示例§13.2init/versions/ 目录示例

A.1 架构模式取舍(对应 §1.5.2)

架构模式适用场景认证模式优先级
前后端分离现代 Web 应用、多端(Web/App/小程序)Token / OAuth2.0(优先)默认优先
传统后端渲染单体管理后台、简单内部系统Session-Cookie仅限特定场景

A.2 统一入口收敛配置示例(对应 §4.6.2)

# 统一入口配置参考值(微服务为网关,单体为入口中间件)
entry:
  error-code:
    enabled: true
    hide-categories: [E3, E5]          # 收敛隐藏的大类
    pass-categories: [E1, E2, E4]      # 透传的大类
    fallback-code: E5-SYS-000          # 收敛后的通用码
    fallback-message: "系统繁忙,请稍后重试"
    response-status: 200               # 统一入口响应状态码

A.3 认证常量配置示例(对应 §6.9)

AUTH_TOKEN_ACCESS_TTL_MINUTES = 15        # 访问凭证有效期
AUTH_TOKEN_REFRESH_TTL_DAYS = 7           # 刷新凭证有效期
AUTH_TOKEN_BLACKLIST_PREFIX = "auth:bl:"  # 黑名单 Key 前缀
AUTH_SCOPE_READ = "read"
AUTH_SCOPE_WRITE = "write"
AUTH_HEADER_USER_ID = "X-User-Id"
AUTH_HEADER_SCOPE = "X-Scope"
AUTH_HEADER_CLIENT_ID = "X-Client-Id"
AUTH_HEADER_SERVICE_ID = "X-Service-Id"

A.4 限流配置参考(对应 §7.3)

# 限流配置参考值(统一入口)
rate-limit:
  enabled: true
  default-qps: 1000           # 全局默认 QPS
  per-interface:
    "/v1/orders":
      qps: 200                # 核心下单接口独立限流
      burst: 50               # 允许突发 50
  per-user:
    qps: 10                   # 单用户 QPS
  reject-code: E1-RATE-000

A.5 熔断配置参考(对应 §7.4)

# 熔断配置参考值(通用字段名,具体实现按所用框架映射)
circuit-breaker:
  failure-rate-threshold: 50              # 错误率阈值(%)
  slow-call-rate-threshold: 80            # 慢调用比例阈值(%)
  slow-call-duration-threshold: 1s        # 慢调用判定阈值
  wait-duration-in-open-state: 30s        # 熔断开启后等待时间
  permitted-calls-in-half-open-state: 5   # 半开状态允许试探调用数

A.6 缓存重建配置与实现参考(对应 §8.5)

# 缓存重建配置参考值
cache-rebuild:
  warmup-on-startup: true        # 启动时预热
  warmup-keys: [dict, config, top-products]
  rebuild-concurrency: 10        # 重建并发度上限
  mutex-lock-timeout: 5s         # 热点 Key 重建互斥锁超时

手段一:双 Key 版本号切换(重建完成后再原子替换)

# 伪代码(步骤"写新版本数据 + 切换版本引用"必须用 Lua 脚本原子执行)
# KEYS[1] = 版本号 Key;KEYS[2] = 数据 Key 前缀;ARGV[1] = 新数据;ARGV[2] = TTL
def rebuild_hot_key_atomic(biz_key, new_data, ttl):
    version_key = f"{biz_key}:ver"
    new_version = redis.eval("""
        local ver = tonumber(redis.call('GET', KEYS[1]) or '0') + 1
        redis.call('SET', KEYS[2] .. ':' .. ver, ARGV[1], 'EX', ARGV[2])  # 写新版本数据
        redis.call('SET', KEYS[1], ver)                                     # 原子切换版本引用
        return ver
    """, 2, version_key, biz_key, new_data, ttl)
    # 清理旧版本 Key(非关键路径,可异步执行)
    redis.delete(f"{biz_key}:{new_version - 1}")

竞态说明:写新版本数据与切换版本引用必须原子执行(Lua 脚本/事务)。否则并发重建时可能出现:线程 A 写入 version=3 的数据,线程 B 写入 version=2 的数据,线程 B 后执行版本切换将版本号设为 2,导致"数据是 version=3 的、版本号却指向 2"的不一致。

手段二:逻辑过期 + 异步重建(读多写少的超热点)

# 读路径:命中缓存但逻辑已过期 → 先返回旧值,再异步重建
def read(key, expire_at):
    data = redis.get(key)
    if expire_at - now > 0:                    # 未逻辑过期,直接返回
        return data
    if redis.setnx(key + ":lock", 1, ttl=5s):  # 仅一个线程触发重建,其余直接返回旧值
        submit_async(lambda: rebuild(key))
    return data                                # 返回旧值,避免瞬间击穿 DB

约束:双 Key 切换须保证新数据已完整写入缓存后再切换引用;异步重建任务须走独立线程池,禁止占用业务线程。

A.7 连接池公式与配置参考(对应 §14.1)

# 连接池配置参考值(8 核机器示例)
maximum-pool-size: 20       # (8 * 2) + 4 = 20
minimum-idle: 10
connection-timeout: 3000
idle-timeout: 600000
max-lifetime: 1800000

"有效磁盘数"说明:该公式源自数据库连接池社区经验公式 (core_count * 2) + effective_spindle_count,"有效磁盘数"指并发 I/O 能力的等效主轴数(effective spindle count),并非简单的物理磁盘数量:

  • 机械硬盘 / HDD RAID 阵列:≈ 参与数据读写的物理数据盘数量(如 RAID10 的 4 块数据盘 = 4)。
  • SSD / NVMe:无寻道延迟,等效主轴数按 1 计(或按厂商 IOPS 指标折算)。
  • 云数据库 / SAN 共享存储:按 1 计或按分配的 IOPS 折算。

该公式仅为估算起点,最终连接池大小须以压测结果为准。

A.8 配置安全示例与无配置中心降级方案(对应 §15.2)

# ❌ 禁止
password: 123456

# ✅ 推荐
password: ${DB_PASSWORD}  # 环境变量或配置中心加密注入

无配置中心的降级方案:本规范多处依赖配置中心,但不强制所有项目部署配置中心。单体小项目可降级为 环境变量 + 本地加密文件 兜底:

  • 应用代码只依赖统一配置抽象接口(按需读取配置中心或本地配置源),后续引入配置中心时无需改动业务代码。
  • 敏感配置优先环境变量注入;需落盘时使用本地加密文件(文件权限最小化),禁止明文配置文件与硬编码
  • 本地兜底配置仅限无多实例扩展诉求的单体场景;一旦多实例部署或需动态变更配置,必须引入配置中心。

A.9 时区与报表统计取舍(对应 §16.1)

存储层统一 UTC 是底线——时区会随夏令时、服务器迁移、跨区域部署变化,存本地时间会导致数据不可比、不可迁移。按本地时间做报表统计的需求,在查询/聚合层解决,不改存储层:

  • 查询转换:报表 SQL 用数据库时区函数转换后再分组,如 created_at AT TIME ZONE 'Asia/Shanghai'
  • 预聚合:高频报表可建按业务时区预聚合的汇总表/物化视图(ETL 时转换),避免大表实时转换。
  • 冗余列:确需频繁按业务日期过滤时,可增加 business_dateDATE 类型,业务时区的日期,不含时分秒)冗余列,主列仍存 UTC。
    • 该列仅用于日期维度过滤与分组,不用于精确时间排序或跨时区计算。
    • 由应用层/ETL 在写入时从 UTC 主列转换生成,禁止由上游直接传入本地时间。
    • 跨天边界场景(如 UTC 23:00 对应次日业务时区)须在转换逻辑中显式处理。

A.10 字符串拼接实现示例(对应 §5.5)

✅ 推荐:占位符模板 + 统一生成方法
INFRA_CACHE_ORDER_DETAIL = "web:order:v1:detail:{id}"
key = KeyBuilder.build(INFRA_CACHE_ORDER_DETAIL, orderId)   # → web:order:v1:detail:1001

❌ 禁止:业务代码散落 + 拼接
String key = "web:order:v1:detail:" + orderId

A.11 版本策略示例(对应 §12.4)

✅ URL Path 版本
/v1/orders  →  旧版本
/v2/orders  →  新版本

A.12 数据库脚本目录结构示例(对应 §13.2)

# 基线脚本命名(§13.2.1)
001-llm-init-ddl.sql   # LLM 模块建表脚本(基线 v1.0.0)
002-order-init-ddl.sql # 订单模块建表脚本(基线 v1.0.0)
001-llm-init-dml.sql   # LLM 模块初始化数据脚本
# DDL / DML 分类(§13.2.2)
db/
├── ddl/   # 表结构类脚本(建表、加列、索引)
│   ├── 001-llm-init-ddl.sql
│   └── 002-order-init-ddl.sql
└── dml/   # 数据类脚本(初始化数据、字典、配置)
    ├── 001-llm-init-dml.sql
    └── 002-order-init-dml.sql
# 基线 + 增量目录(§13.2.3)
db/
├── init/        # 基线脚本(某一版本快照,全新初始化用)
│   ├── ddl/001-llm-init-ddl.sql
│   └── dml/001-llm-init-dml.sql
└── versions/    # 增量脚本(另建目录,走变更管理工具,如 Flyway/Liquibase)
    ├── V1.0.0-llm-init-ddl.sql
    ├── V1.1.0-order-add-index-ddl.sql
    └── V1.2.0-order-add-column-ddl.sql

关联文档

本规范为 Web 后端架构规范族的顶层文档。特定领域或特定场景的规范以独立文档形式存在,作为本规范的下位扩展。下位规范不得与本规范冲突,本规范更新时须同步评估下位规范的兼容性。

规范名称适用范围触发条件状态
《多租户与数据隔离规范》SaaS / 多租户产品系统需支持多租户、租户间数据隔离时已发布
《AI 与大模型扩展规范》集成大模型能力的系统系统需调用第三方模型或自建模型服务时待编写
《灰度发布实施细则》微服务 / 核心系统需要按比例灰度、分批放量发布时待编写
《分布式调度规范》多实例 / 分布式部署系统存在定时任务且需防重复执行时待编写

说明:多租户规范已有独立文档(web系统后端通用架构规范-多租户扩展-v1.0.md);《分布式调度规范》与正文 §23 定时任务与分布式调度规范的强制条款互补,如需要更细的调度平台实施细则,可另立下位文档。

引用约定:

  • 本规范正文中以"见《XX 规范》"标注的条款,为下位规范的强制引用入口
  • 下位规范须在文档开头声明其上位依据,并注明与本规范的冲突处理原则(以上位规范为准)。
  • 下位规范涉及本规范已有概念(错误码、TraceId、环境划分等)时,术语与编号必须保持一致。
JAM
更新于 2026-08-06
上一篇 通用规范
下一篇 没有了
评论交流

文档目录