架构评审、灰度、监控与回滚:方案怎样变成可运营系统
商品查询接口对外返回 id、description、priceCents、version,新版内部接口却使用 productId、label、money、revision。客户端暂时不能统一升级,新模型又需要继续开发。可以保留旧服务、推动客户端同步改造,也可以在入口适配新结构。每种选择都会影响后续开发、一次请求的耗时和出错后的处理方式。
评审需要判断这几个选择怎样满足客户端兼容和后续开发的要求,并找出还缺少的验证。设计确定后,实现、部署和运行观察继续检验这些判断是否成立。
从变更动机写出可以检查的质量要求
驱动、约束和假设怎样区分
“查询商品”是功能;“已有客户端继续使用原接口”“新版字段变化只修改适配器”“候选出错时停止向它分流”描述了系统在变化中应具有的性质。后者往往决定组件怎样拆分、协议如何兼容、哪些操作必须由管理入口控制。
先把题目中的条件写清。以下是一组教学假设,用于比较设计;它们不是某个企业的实际需求或生产事故记录。
| 项目 | 本例的具体写法 | 对选择的影响 |
|---|---|---|
| 变更驱动 | 新商品读模型要独立调整字段组织,避免每次内部修改都要求客户端同步升级 | 需要隔离内部结构与公开协议的变化 |
| 现状 | 旧接口已经提供四个公开字段;新版把金额组织为 money.minor 与 money.currency | 比较时使用同一商品、同一业务含义 |
| 强约束 | 原客户端本阶段不修改;公开价格单位仍为分,币种固定为 CNY,版本值保留 | 不能靠改字段含义来获得兼容 |
| 阶段范围 | 只选择商品读取路径,写入入口和写入归属保持现状 | 不把读流量比例顺便用于写请求 |
| 偏好 | 尽量减少长期维护的组件和跨团队协调 | 在满足强约束的候选中继续权衡 |
| 待证假设 | 网关适配的延迟可接受;旧端能承接回退后的全部读负载 | 需要负载和恢复测试,不能由代码结构推定 |
强约束需要有来源。例如客户端升级受合同约定限制,提出者是产品负责人;部署位置受现有网络要求限制,提出者是基础设施负责人。若条件只是“大家一直这样做”,应先确认它是否真的不能调整。把个人偏好写成强约束,会在比较开始前排除本来可行的方案。
参与者也由影响决定。商品维护者知道金额和版本的含义,客户端维护者知道兼容成本,运行人员知道恢复时的实际容量,安全人员确认访问方式是否可接受。SEI 的质量属性工作坊把这类业务目标和相关方关注转成优先场景,可作为需求讨论的方法入口。SEI:Quality Attribute Workshop
把“性能好、容易恢复”改成质量属性场景
一个可检查的场景包含六个部分:谁产生刺激、发生什么、作用于哪个对象、处于什么环境、系统怎样响应,以及用什么量衡量响应。这种结构能保留“正常运行”和“故障中”的条件差异。SEI:六要素质量属性场景
以商品读适配为例,可以这样填写:
| 要素 | 契约兼容场景 | 故障恢复场景 |
|---|---|---|
| 刺激源 | 已有版本的商品客户端 | 获准执行回退的运行人员 |
| 刺激 | 请求一个存在的商品 | 发现候选返回错误金额,执行回旧操作 |
| 对象 | 网关的公开查询接口及新端适配器 | 读路由配置与旧商品查询服务 |
| 环境 | 新旧路径并存;同一商品数据相同;不进行写迁移 | 候选已接流量;旧端健康且仍能读取当前商品 |
| 响应 | 返回原来的四个字段,金额单位和版本保持一致 | 后续原候选分组请求改由旧端响应,结果恢复正确 |
| 衡量 | 固定商品集合逐字段一致;额外字段、非整数金额、币种不符均拒绝或报差异 | 从执行回退到停止错误响应不超过 30 s;确认恢复后的新请求错价数为零,额外业务写操作为零 |
30 s 是设计题给出的恢复目标,需要在实际发布环境计时验证。后面的功能实验检查重新请求的结果,没有把这个目标当作已测得的恢复时长。
性能场景还要补负载范围。比如设计题可以要求:“在给定商品分布、并发量和连接复用方式下,网关收到请求后,99% 的合格商品查询在 200 ms 内返回正确结果。”其中 200 ms 是待协商目标;随后要说明并发量、采样窗口、失败请求如何计入。没有这些条件,两个测试报告中的“p99”可能统计了完全不同的请求。
安全场景同样可以具体填写:“一个只有 A 租户权限的客户端,在正常运行期间请求 B 租户商品,服务拒绝访问且不返回商品字段。”测试需要真实身份和数据归属,商品 ID 难猜或接口返回 404 都不能代替授权实现。租户、身份与地区规则的具体落点见多租户、国际化与安全边界。
场景不必全部同时成为最高优先级。先识别违反后不能接受的结果,再比较改动频率、性能、恢复速度和运行成本。价格正确性属于本例的强约束;性能问题可以尝试通过容量配置改善,调整带来的费用仍要回到方案比较中。
比较候选,并优先验证会改变决定的假设
维持现状也需要写出收益与代价
候选应足够具体,能够说明改哪些组件、谁继续维护、客户端和数据是否变化。以读模型改造为题,可以得到三个选择:
| 候选 | 怎样实现 | 能保留什么 | 必须承担什么 |
|---|---|---|---|
| A:继续旧服务 | 暂不接入新版读接口,在原模块中完成需求 | 原调用路径、部署方式和运行经验 | 新读模型独立演进的目标推迟,内部结构仍受旧接口约束 |
| B:客户端直接改用新版 | 客户端理解 productId 和 money,协调切换协议 | 少一层服务端转换 | 需要管理客户端版本共存和升级顺序,违反本阶段“不修改客户端”的约束 |
| C:网关适配新版读取 | 网关维持原接口,转换新端字段;按稳定分组选择新旧读路径 | 原客户端契约;可以分组观察候选 | 多一次转换与下游调用,适配器需要测试、运行和后续维护 |
A 有清楚的采用条件:独立演进没有当前收益,或者 C 的运行代价仍无法接受。B 在当前约束下被排除;如果客户端可以分阶段升级,它可以重新进入比较。C 解决的是公开协议与内部读模型的耦合,没有因此获得写入迁移、跨机容灾或更低成本。
也应考虑局部调整:能否只在旧服务内部增加一个适配模块,先不新增远程调用?如果新模型还不需要独立部署,这通常值得先验证。本例把独立读服务作为给定演进方向,才继续比较网关适配。模块拆分与远程拆分的成本差别见模块化单体。
权衡分析关注哪个参数会改变结论
“方案 C 综合得分最高”很难解释一个新发现为何足以推翻决定。更有用的写法是指出敏感参数:如果商品查询主要耗时来自跨区调用,网关部署位置可能比 JSON 转换速度重要;如果字段调整每次都伴随业务含义变化,适配器就需要业务规则,维护代价也会增加。
一个措施还可能同时影响几项要求。保留旧端有助于回退,却延长双路径运行成本;增加缓存可能降低读取延迟,却引入数据新鲜度要求。SEI 的 ATAM 通过场景分析识别风险、敏感点与质量属性间的取舍,适合进一步组织这类讨论。SEI:Architecture Tradeoff Analysis Method
未知成本可以记录为区间,列明估算前提,或标注“尚未测量”。已知的正确性失败则应单独保留,不能靠其他项目的加权得分抵消。负载、排队、数据库提交与成本的同条件比较,见高并发、一致性与成本。
架构图先选要回答的问题
向相关方解释用户、外部系统与目标商品系统的关系,可以用系统上下文图;展开目标系统,查看内部网关、商品服务和数据库之间的主要运行关系,可以用容器图;检查某次查询的转换和失败返回,用动态图;讨论多个实例是否共用宿主机和数据库,则需要部署图。只有要定位适配器内部职责时,才继续展开组件或代码。C4 按不同缩放层次组织图,并提供动态、部署等补充视图,无需为了凑齐层次把每一张都画出来。C4:Diagrams
下面实验的请求关系很简单:
同一组商品 p1 / p2 / p3
│
▼
采样器 ── X-Lab-Cohort ──► gateway /products/{id}
├─ legacy ─► 公开四字段
└─ next /v2/products/{id}
└─ 字段与金额转换 ─► 公开四字段
每次请求保存分组、传输结果、HTTP 状态、字段比较和耗时
legacy 与 next 各读一个数据库,两个数据库位于同一 PostgreSQL 实例这张图表达调用选择,没有表达物理故障隔离。一个数据库实例故障会同时影响两组,部署环境也可能共同成为瓶颈。若据此讨论生产隔离,必须补部署条件和对应测试。
实验先回答最有价值的未知项
对 C 来说,第一项问题是转换是否保留商品语义。只测“接口能通”成本很低,但错误金额仍然可以得到 200。更有效的对照是保持商品数据、请求类型和采样方法相同,只改变候选返回行为,再观察检查器能否区分成功、错价和服务错误。
每个实验至少要有一个可能改变行动的结果。契约错误会停止该候选;性能目标未达成会回到容量或部署设计;没有足够候选样本,则增加观察而不继续放量。已经知道不会改变任何决定的测试,通常可以延后。
灰度、影子、蓝绿、滚动更新和特性开关各自控制不同对象:
| 方式 | 实际改变的对象 | 在读模型改造中的用途 |
|---|---|---|
| 灰度 | 一部分请求或用户实际使用哪个版本 | 让候选处理有限请求,与旧端同期比较 |
| 影子请求 | 复制请求给候选,主路径结果仍交给客户端 | 在不使用候选响应的条件下收集差异;需要另设比较器 |
| 蓝绿 | 两套已部署环境之间的流量归属 | 新环境准备好后切流,也可结合灰度逐步切换 |
| 滚动更新 | 逐批替换运行实例 | 在新旧版本共存期间保持接口与数据兼容 |
| 特性开关 | 已部署代码中的某条功能分支 | 将功能启用与程序部署分开管理 |
Google SRE 的灰度方法强调有限候选、对照组与有代表性的观察;分组比例需要与实际流量、功能分布和观察时间一起确定。Google SRE:Canarying Releases
蓝绿的两套环境与流量切换见 AWS 蓝绿部署方法;Kubernetes 的滚动更新通过逐步缩减旧副本、增加新副本完成实例替换,具体控制项见 Deployment 文档。它们可以组合使用,无需排成同一条必经流程。
影子请求仍会在接收端执行。以 Istio 为例,镜像请求的响应被丢弃,系统不会因此自动比较业务字段。Istio:Mirroring 如果候选会扣库存、发送短信或发布事件,复制流量就会复制副作用;必须先安排隔离目标或确认纯读。下面只使用禁写的商品夹具,不镜像写操作。
用真实 HTTP 对照检查候选,并验证恢复
准备独立的只读环境
下载服务迁移与灰度实验工程,解压到一个新的可写目录,进入其中含 pom.xml 的 evolution-migration-lab 目录。这里选择 canary 初始化,不需要先执行写权迁移。
命令使用 Linux Bash、Docker Engine、Compose v2、openssl 和 curl。宿主使用有 Docker 权限的普通用户;构建与应用容器使用宿主 UID/GID,数据库由官方镜像入口以 postgres 身份运行。Docker daemon 的管理权限与容器内用户分别处理。
编译目标是 Java 17,构建工具为 Maven 3.9.12。运行默认使用 Temurin 17.0.20+8,PostgreSQL 18.6;也可在初始化前执行 export LAB_JAVA_IMAGE=eclipse-temurin:25.0.4_7-jdk,运行同一份 Java 17 字节码。构建镜像的 JDK 补丁与应用运行镜像分别管理,不从 Maven 标签推断实际 Java 补丁。
set -euo pipefail
mkdir -p .m2
docker run --rm --user "$(id -u):$(id -g)" --entrypoint mvn \
-e MAVEN_CONFIG=/m2 -v "$PWD:/work" -v "$PWD/.m2:/m2" -w /work \
maven:3.9.12-eclipse-temurin-17 \
-B -Dmaven.repo.local=/m2 clean verify构建应执行七个测试并以 BUILD SUCCESS 结束,target 与 .m2 由当前用户写入。依赖下载失败先检查网络或企业 Maven 配置;目录不可写先核对宿主所有者和挂载权限,不通过给目录开放全员写权限解决。
启动前确认回环端口 18832、18881、18882、18880 没有被其他实验使用。若已运行迁移实验,先在它自己的目录执行 bash stop.sh。本实验为 PostgreSQL 配置 512 MiB,三个 HTTP 服务各 192 MiB,管理命令还会短暂启动工具容器。
export LAB_PROJECT=evo25review
bash setup.sh canary
bash up.sh
curl -q --noproxy '*' --fail-with-body --silent --show-error \
--max-time 10 -D work/first.headers \
http://127.0.0.1:18880/products/p1
bash run.sh inspectup.sh 轮询三个服务的健康接口,成功后输出 READY。首次商品查询应为 priceCents=1000、version=1,响应头 X-Lab-Backend 为 legacy。inspect 应显示两个库各有三个相同商品、零条操作记录、写控制均为 false。
work/runtime.env 包含随机生成的数据库凭据,应保留在私有目录。初始化拒绝覆盖已有配置和数据库;已有环境运行失败时先检查当前状态,不重新初始化。
健康等待失败或请求没有得到预期结果,使用同一项目名查看服务:
docker compose --env-file work/runtime.env -p "$LAB_PROJECT" ps
docker compose --env-file work/runtime.env -p "$LAB_PROJECT" \
logs --tail 60 legacy next gateway数据库未就绪先查看 database 服务日志;应用类找不到则回到构建结果;端口冲突先确认占用者,再使用工程支持的 PG_PORT、OLD_PORT、NEXT_PORT、GATEWAY_PORT 环境变量统一调整。之后的 curl 地址也要跟随网关端口变化。
固定分组,保留每次尝试
X-Lab-Cohort 是实验用分组键。网关对它的 UTF-8 字节计算 SHA-256,取前四字节组成的无符号整数再模 100;桶值小于候选百分比时读取 next。同一个键在相同配置下稳定进入同一组。
bash run.sh route-read 20
bash run.sh sample small 4 1
bash run.sh sample good 40 1sample 的后两个参数是分组键数量和轮数。每个键都请求 p1、p2、p3,控制组与候选组在同一轮中交错出现。四个固定键共发出 12 次请求,这些键恰好全部分到 legacy,所以第一次得到 OBSERVE_SMALL_SAMPLE。
第二次有 40 个键、120 次请求,其中 legacy 为 87 次,next 为 33 次。候选占比是 33/120,不是恰好 20%;20 是分桶阈值,有限且固定的键集合可以偏离这个比例。初始无故障时两组字段比较全部相同,结果为 CONTINUE_OBSERVING,不会自动增加比例。
每轮样本保存到 work/small.csv、work/good.csv,字段为:
scenario,sequence,cohortKey,bucket,selectedVersion,productId,
transportResult,httpStatus,semanticResult,elapsedNanosselectedVersion 记录按分组规则应选的版本;语义比较还检查实际响应中的 X-Lab-Backend,以发现路由与预期不符。非 2xx 响应不参与商品字段比较。耗时从这一次 HTTP 尝试开始计量;输出的 p95 包含该组所有尝试,包括失败和超时,不能与“仅成功请求的 p95”混用。
CSV 使用新建模式,重复名字会报错而不覆盖旧样本。可以换一个采样名称保留下一轮,或在另一个新环境重新走完整步骤。工程还提供 verify-canary.sh 自动演示;同一环境选择自动脚本或以下逐步路径之一。
200 错价与 500 使用不同分母
给候选注入一个确定的业务错误:价格增加一分,HTTP 状态仍为 200。
bash run.sh fault wrong-price
bash run.sh sample semantic 40 1
bash run.sh analyze semantic分析器重新读取 work/semantic.csv。关键统计应为:
legacy: attempts=87 http2xx=87 semanticMatch=87/87 semanticBad=0
next: attempts=33 http2xx=33 semanticMatch=0/33 semanticBad=33
decision=ROLLBACK_SEMANTIC这里的 HTTP 成功率没有下降;候选 33 次响应里的金额却全部不符。商品 ID、说明、价格和版本由固定夹具逐字段比较;适配器还检查新版金额结构及 CNY 币种。服务产生的错误金额经过网关转换,最终被采样器记录为字段差异。
分析命令只给建议,没有自动切换路由。执行回旧后,再对刚才进入候选的 11 个键发出新请求:
bash run.sh route-read 0
bash run.sh probe canary-return应输出 backend=legacy、correct=true、operations=0,检查的原候选键数量为 11。恢复验证查看实际响应来源和商品结果,而不是只读取路由配置。
再让 next 真正返回 HTTP 500,重新开放相同的候选分组:
bash run.sh fault http-500
bash run.sh route-read 20
bash run.sh sample errors 40 1
bash run.sh route-read 0
bash run.sh probe canary-return本轮 next 的 33 次传输都收到 HTTP 响应,http2xx=0,语义结果为 0/0,决策为 ROLLBACK_CANDIDATE_ERRORS。语义分母为零表示没有可比较的成功商品响应;将它填成“正确率 100%”或“金额为零”都会误导判断。
演示分析器优先处理候选语义错误,发现后建议回退。没有这类错误时,再检查控制组;控制组失败则暂停。控制组正常、候选至少有 20 次尝试且 HTTP/传输失败比例达到 10% 时,建议回退。候选样本不足则继续观察,少量样本已出现失败时暂停。20 次和 10% 是演示策略,实际生产阈值需要根据业务损害、流量和观察窗口确定。这里的 120 次请求还共享 40 个键与三个商品,不能当成 120 个独立用户的统计结论。
修复后重新进入候选
移除故障,保持相同的分组算法和商品数据:
bash run.sh fault good
bash run.sh route-read 20
bash run.sh probe canary-fixed
bash run.sh sample repaired 40 1
bash run.sh inspect
bash stop.sh原候选的 11 个键应重新由 next 返回正确商品,repaired 为 legacy 87 次、next 33 次全部匹配。两个数据库仍各有三个商品、零条操作、禁写。stop.sh 关闭本项目所有服务与网络,保留数据库卷和 work 文件,便于追溯结果。
这组实验支持“给定商品夹具的转换正确、两类错误能被识别、路由回旧及修复回新都能恢复正确读取”。它没有测出生产容量,也没有实现客户端鉴权、跨机故障转移或持续变化数据的同步。读灰度保持写入归属不变;真正转移写权、复制幂等结果和处理提交后断连,见微服务拆分与服务迁移。
把取舍写成一份完整的架构决策记录
ADR 保存决定及其成立条件
架构决策记录(Architecture Decision Record,ADR)适合保存影响结构、关键质量属性或后续修改成本的决定。详细接口和运维步骤可以另外维护,ADR 要让后来者单独读懂:当时的问题是什么,有哪些可行选择,为何采用这一项,接受了哪些代价。Microsoft:Architecture Decision Record
记录中的“决定”要使用明确动词,例如“公开接口继续使用四字段格式,新端响应由网关转换”。“考虑采用适配器”“持续关注稳定性”还没有确定执行方向。
常用状态有 Proposed、Accepted、Rejected、Superseded。提议阶段可以随讨论修改;决定接受后保留当时理由,后来的替代方案写新记录并关联旧记录,旧状态改为已替代。这样能看到需求变化怎样导致新选择,而不会把历史修改得像一开始就知道全部结果。AWS:ADR process
已填写示例:商品查询保留公开契约,网关适配新版读模型
以下 ADR 使用前面的教学假设和实验工程。岗位分工是设计题中的安排,运行结果来自实际实验;没有对应的生产事故或已完成的生产发布。
记录:ADR-PRODUCT-READ-01
状态:Accepted,接受读适配设计。
发布资格:限隔离环境验证;生产接流量条件尚未满足。
问题与驱动。 新版商品读模型需要调整字段组织,已有客户端本阶段不能升级。公开查询保持 id、description、priceCents、version,价格单位为分,内部货币值限定为 CNY。阶段目标是让内部读取结构可以独立演进,暂不改变写入入口。
候选及取舍。 A 保留旧服务,运行改动最小,但推迟独立读模型目标;它继续作为本阶段生产路径。B 要求客户端直接接新版,违反当前升级约束。C 由网关转换新版响应,并按稳定分组选择读路径,满足设计目标,但增加适配器维护、下游调用和双路径运行成本。选择 C 作为实现方向;如果独立部署需求取消,则重新比较在旧服务内部增加适配模块的方案。
决定。 公开协议保持四字段格式。网关只转换已识别的新版结构,检查金额类型、币种与版本;候选错误由观测结果触发停止分流。客户端重试使用同一分组键,读流量控制不改变写入归属。旧端保留到生产观察和回退条件满足后,再独立决定退出。
已经得到的结果。 在相同的三个静态商品上,40 个固定键产生 legacy 87 次、next 33 次请求,正常场景全部匹配。候选错价时 33 次 HTTP 200 全部被判定为字段差异;候选 500 时没有可比较的商品响应,按失败比例判定。原候选键回旧后得到正确旧端结果;解除故障后重新进入 next,结果再次正确。采样过程中两库没有写操作。
尚未验证的条件。 此实验使用同一 PostgreSQL 实例中的双数据库,不覆盖数据库故障隔离。静态夹具不验证生产商品持续更新时的新鲜度。固定键不是实际租户或客户端分布,p95 没有生产容量含义。客户端鉴权、真实超时链、网关和管理入口的故障转移、旧端全量回退容量及 30 s 恢复目标仍待验证。
接受的代价与限制。 接受新增适配器以及过渡期双路径维护;运行成本尚无实测金额,不声称 C 更便宜。当前管理工具依赖单管理数据库会话和本机配置,不能作为生产高可用控制面。生产读取继续使用 A;C 的 Accepted 状态不授权接管写入或直接放量。
执行安排。 适配器维护者负责新旧字段映射及契约测试;商品维护者提供具有代表性的数据并确认新鲜度要求;运行负责人验证旧端全量回退容量、路由权限与健康观察;安全负责人完成真实客户端身份的正反测试。发布负责人在这些结果齐备后确定生产候选范围、观察窗口和停止阈值。任一项尚未完成时,保留隔离环境实验状态。
重新评审的触发条件。 公开协议需要改变货币含义;客户端可以独立升级;读模型开始异步同步;计划迁移写权;旧端无法承担回退负载;或双路径长期成本超出批准范围。触发后提出新 ADR,并关联本记录及受影响的接口、测试和发布方案。
退出安排。 生产候选完成约定观察、旧端回退能力仍可用且依赖方确认不再需要旧读取路径后,再评审旧读路由退出。旧服务仍承担写入,因此保留其进程、写入凭据和业务数据;整项服务退役必须另做写权交接决定。后续撤销专属读取凭据或资源前,确认没有写入与共享依赖。移除旧读路径会改变恢复方式,退出决定需记录新的恢复方案。
以后若撤销 C,可以沿记录中的客户端约束与重新评审条件,查回改变决定的原因。
把决定接到发布、监控和后续维护
设计状态与一次发布的允许动作分开保存
ADR 的变化通常比构建和发布慢。同一份已接受的设计可能有多个候选版本,其中一个版本契约测试失败,另一个完成验证。发布记录应关联具体制品、配置、测试结果与适用环境,避免从“设计已接受”推导出“这个版本可以部署”。
一次发布可以把允许动作写成下面的关系:
| 当前条件 | 允许动作 | 下一项需要确认的结果 |
|---|---|---|
| 候选尚未通过契约或权限测试 | 保留隔离测试,修复实现 | 原失败输入通过,未改变其他商品或身份的结果 |
| 具备接流量条件,但候选样本少 | 保持当前有限范围,继续观察 | 实际请求类型和分组有覆盖,观测数据完整 |
| 候选出现错误金额 | 停止继续接流量,按确认可用的旧路由恢复 | 原候选键的新请求来源和金额恢复正确 |
| 控制组也异常,或观测链丢数据 | 暂停扩大,检查共享依赖与采集 | 先恢复能判断的对照条件,再决定候选去留 |
| 候选达到约定窗口和目标 | 按发布计划决定扩大、保持或结束 | 下一范围的容量、业务覆盖和恢复能力仍成立 |
自动化可以执行这些动作,但必须有真实输入和清晰的权限。前面的分析器读取 CSV 后给建议,路由由单独命令修改;把它接入发布系统时,还需处理指标获取失败、命令重复、旧执行者失联和并发操作。该实验没有实现这套生产编排。
监控先定义结果,再安排采集方式
一个“商品查询成功”的定义可以包含 HTTP 成功、结构可解析、金额单位正确以及数据新鲜度满足要求。SLI 衡量实际服务结果,SLO 给出目标与统计窗口;选择从网关日志、客户端或外部探针采集,会改变能覆盖的失败范围。Google SRE:Implementing SLOs
发布观察需要按候选和控制分组查看请求数、失败数及商品差异,同时保留接口类型、配置版本等定位信息。用户键可以留在受控样本中用于追查,不应直接成为无限增长的指标标签。
原始样本还可以回答聚合值回答不了的问题:这次 500 是连接失败还是收到下游错误响应;金额错误是否只影响某种货币;延迟变化是否来自少数冷启动请求。采集端断开时,要显示“缺失”及缺失范围,而非用零错误补齐。
持续运行的告警和一次发布的判断也有不同时间尺度。发布窗口需要能看到刚进入候选的请求;长期 SLO 则关注用户在约定周期内得到的服务。只看跨越发布前后的整段均值,容易把少量候选错误混进大量旧端成功请求。
回退先确认旧路径还能处理现在的数据
在纯读静态夹具中,route-read 0 就能让后续查询返回旧端。生产回退要额外确认旧程序是否仍读得懂当前数据、旧服务容量是否足够,以及候选是否已经产生了外部副作用。
如果只是适配器将一分错误地加到查询响应上,停止该路径可以阻止新错误响应;已经展示给用户的错误价格仍需要评估影响。如果候选已经按错误价格创建订单,切路由只停止新的使用,已创建的订单必须核对处理。涉及数据库写入接管时,还要先恢复旧端所需的数据和幂等响应,不能根据旧镜像仍在就直接切写。
回退与向前修复取决于当时状态。旧端还能安全处理当前请求,回退通常能较快限制影响;旧端已经不兼容新数据时,可能需要停下危险写入并向前修复。方案阶段应列出这些条件,而不是承诺所有故障都能“一键回滚”。具体写权交接步骤继续使用服务迁移实验,不要让灰度脚本越过它的检查。
重新打开决定,并结束临时双路径
运行数据可能证明最初假设需要调整。例如转换本身只占很少耗时,主要等待来自数据库;继续优化字段映射的收益就有限。另一种情况是客户端终于可以升级,长期保留适配器的理由随之改变。复查应围绕发生变化的条件和新的候选,保留原先决定的历史。
临时结构也需要退出工作。旧调用是否真正停止、消费者是否仍依赖旧数据、专属凭据能否撤销,都要通过各自的使用情况确认。移除过程中若发现仍有依赖,先记录依赖及迁移安排,而不是只延长一个无人负责的截止时间。
新路径稳定运行后可以退出旧资源;现状仍满足需求时,也可以暂停演进。若实验否定了原假设,就重新选择方案。无论采用哪条路径,都要留下当前决定、仍在运行的组件及其恢复方式,供后续维护使用。
权威资料与规范地址
质量要求、权衡与架构表达
- SEI Quality Attribute Workshop:https://www.sei.cmu.edu/library/quality-attribute-workshop-collection/
- SEI 六要素质量属性场景原始报告:https://www.sei.cmu.edu/documents/2056/2004_004_001_14348.pdf
- SEI Architecture Tradeoff Analysis Method:https://www.sei.cmu.edu/library/architecture-tradeoff-analysis-method-collection/
- C4 图类型与层次:https://c4model.com/diagrams
决策记录
- Microsoft Architecture Decision Record:https://learn.microsoft.com/en-us/azure/well-architected/architect-role/architecture-decision-record
- AWS ADR 状态与处理过程:https://docs.aws.amazon.com/prescriptive-guidance/latest/architectural-decision-records/adr-process.html
发布方式与服务观察
- Google SRE 灰度发布:https://sre.google/workbook/canarying-releases/
- AWS 蓝绿部署方法:https://docs.aws.amazon.com/whitepapers/latest/blue-green-deployments/introduction.html
- Kubernetes Deployment 与滚动更新:https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
- Istio 流量镜像:https://istio.io/latest/docs/tasks/traffic-management/mirroring/
- Google SRE SLI 与 SLO 实施:https://sre.google/workbook/implementing-slos/
