业务系统性能改造手册 · 验收交付
交付可迁移的性能治理包
把代码、配置、实验输入、原始结果、决策与回退条件组织成可校验的资产清单,并用只读评估区分可迁移原则、待重填模板和订单案例事实。
交付可迁移的性能治理包
性能改造结束后,团队经常留下一份汇报:接口快了多少、数据库压力降了多少、峰值扛到了多少。过几个月再问“对应哪次构建、哪份数据、哪些开关,怎样回退”,答案开始散落在聊天记录、监控截图和某个人的电脑里。
这样的结果很难审计,也不能安全迁移。数字脱离实验现场后只剩结论,配置脱离适用边界后则可能变成下一次事故的输入。
小编更愿意把性能治理的交付物看成一组相互引用的工程资产:代码和配置说明改了什么,实验材料说明怎样验证,决策记录说明为什么保留,回退索引说明出问题后怎样退出。可迁移的是这套证据与决策方式,不是订单案例里的参数和容量数字。
先把真实性说清楚:当前系列正文提供了代码片段、配置形状、实验协议和报告模板,但磁盘上没有一套已经运行的完整 Spring Boot 案例工程,也没有真实压测原始数据。因此本文给出交付目录、Manifest 和完成门禁;未产生的资产必须标记为 missing 或 planned,不能因为模板存在就写成已验收。
一、先规定包里应该有什么
治理包不应按文章编号简单归档。使用者需要从“一个结论”走回它的输入、实现、验证和退出路径。可以采用下面的目录契约;路径是建议结构,不代表这些文件当前已经存在:
1performance-governance-package/
2├── manifest.yaml
3├── README.md
4├── environment/
5│ ├── baseline-protocol.yaml
6│ ├── versions.yaml
7│ └── sanitized-config/
8├── data/
9│ ├── preparation/
10│ ├── snapshot-manifest.yaml
11│ └── validation/
12├── workload/
13│ ├── scripts/
14│ ├── datasets/
15│ └── scenarios.yaml
16├── changes/
17│ └── <change-id>/
18│ ├── decision.md
19│ ├── code-reference.yaml
20│ ├── config.yaml
21│ ├── compatibility.yaml
22│ └── acceptance.yaml
23├── experiments/
24│ └── <experiment-id>/
25│ ├── run-manifest.yaml
26│ ├── raw/
27│ ├── queries/
28│ ├── summary.yaml
29│ └── checksums.txt
30├── operations/
31│ ├── rollback-index.yaml
32│ ├── failure-runbooks/
33│ └── reconciliation/
34└── migration/
35 ├── classification.yaml
36 ├── read-only-assessment.yaml
37 └── fit-gap-report.yamlREADME.md 只负责导航:包的适用系统、负责人、当前发布版本、已完成和缺失的资产、验证入口以及敏感信息处理规则。它不复制各实验结论。大体积原始数据可以放在受控对象存储,但目录中要保存不可歧义的引用、保留期和校验值。
1.1 每种资产回答一个问题
| 资产 | 回答的问题 | 最低追溯字段 |
|---|---|---|
| 代码与数据库变更 | 实际改了什么 | 提交、镜像摘要、迁移版本、生成方式 |
| 生效配置 | 运行时究竟用了什么 | 脱敏快照、来源、作用域、单位、配置摘要 |
| 数据与负载 | 给系统输入了什么 | 快照/生成脚本、分布、场景、脚本版本 |
| 监控查询与原始结果 | 观察依据在哪里 | 查询文本、数据源、时间窗、原始文件、校验值 |
| 决策与失败证据 | 为什么保留或拒绝方案 | 假设、候选、结果、限制、负责人、日期 |
| 回退与核对工具 | 出问题后怎样安全退出 | 前置条件、步骤、兼容性、停止条件、验收查询 |
一张截图可以帮助阅读,却不能替代查询定义和原始数据引用;仓库里的默认配置也不能替代运行时生效快照。哈希能够发现文件后来是否变化,不能证明文件来源可信,所以 Manifest 还要记录生成者、生成命令或系统、采集时间和访问位置。
二、用 Manifest 把资产和证据连起来
Manifest 是治理包的入口,不是附件清单。每个资产都需要稳定 ID、类型、版本、来源、状态、校验值和依赖关系。状态至少区分:只有模板、已产生但未验证、已验证、缺失和不适用。
1package:
2 schemaVersion: 1
3 packageId: ${PACKAGE_ID}
4 system: ${SYSTEM_AND_SCOPE}
5 release: ${PACKAGE_RELEASE}
6 createdAt: ${TIMESTAMP}
7 owner: ${OWNER}
8 status: ${DRAFT_INCOMPLETE_OR_VERIFIED}
9 sourceSeries:
10 topic: business-system-performance-handbook
11 topicFileChecksum: ${CHECKSUM}
12
13assets:
14 - id: ${ASSET_ID}
15 type: ${CODE_CONFIG_DATA_SCRIPT_QUERY_RAW_RESULT_REPORT_RUNBOOK_OR_DECISION}
16 status: ${TEMPLATE_PLANNED_PRODUCED_VERIFIED_MISSING_OR_NOT_APPLICABLE}
17 location: ${REPOSITORY_PATH_OR_CONTROLLED_STORAGE_URI}
18 source:
19 repository: ${REPOSITORY}
20 commitOrImageDigest: ${COMMIT_DIGEST_OR_NOT_APPLICABLE}
21 generatedBy: ${COMMAND_PIPELINE_OR_PERSON}
22 generatedAt: ${TIMESTAMP}
23 integrity:
24 algorithm: sha256
25 checksum: ${CHECKSUM_OR_MISSING}
26 compatibility:
27 javaSpringAndLibraries: ${VERSIONS_OR_REFERENCE}
28 databaseCacheMq: ${VERSIONS_OR_REFERENCE}
29 schemaAndApi: ${VERSIONS_OR_REFERENCE}
30 dependsOn: ["${ASSET_IDS}"]
31 validates: ["${CHANGE_OR_REQUIREMENT_IDS}"]
32 sensitivity: ${PUBLIC_INTERNAL_CONFIDENTIAL_OR_SECRET_REFERENCE_ONLY}
33 retention: ${POLICY_OR_NOT_APPLICABLE}
34 limitations:
35 - ${KNOWN_LIMITATION}
36
37releaseGate:
38 requiredAssetIds: ["${ASSET_IDS}"]
39 missingOrUnverified: ["${ASSET_IDS}"]
40 approvedBy: ${IDENTITY_OR_PENDING}
41 approvedAt: ${TIMESTAMP_OR_PENDING}Manifest 自己也要进入版本控制并计算摘要。引用外部结果时,URI、对象版本或不可变标识和校验值缺一不可;latest/report.json 这类会漂移的路径不能成为审计依据。
凭据、生产连接串和未脱敏业务数据不进入包。Manifest 只保存密钥管理系统中的安全引用和所需权限说明,不保存秘密值。订单号、用户标识等样本也要按项目数据规范脱敏,并记录脱敏方法是否改变了热点与分布特征。
2.1 一个改造需要完整证据链
以“缓存热点订单”为例,资产关系应当能够串起来:
1决策记录
2 ├─> 业务时效契约
3 ├─> 代码提交 + 生效配置
4 ├─> 数据快照 + 负载场景
5 ├─> 单项与组合实验运行
6 │ ├─> 原始请求结果
7 │ ├─> 数据库与缓存指标查询
8 │ └─> 数据偏差检查
9 └─> 保留结论 + 回退入口任何一段缺失,结论就应降级。只有汇总报告而没有运行编号和原始结果,无法复算;只有代码而没有运行时配置,无法证明路径生效;只有性能收益而没有数据偏差检查,无法证明业务结果仍然成立。
三、决策记录要保留被拒方案和失败实验
交付包若只保存最终方案,后来的人很容易重新尝试已经被否定的路径。每项改造可以用一份短决策记录保存当时的上下文:
1changeDecision:
2 changeId: ${CHANGE_ID}
3 problemEvidence: ${BOTTLENECK_OR_COST_CHAIN_REFERENCE}
4 scope: ${AFFECTED_ACTIONS_AND_COMPONENTS}
5 selectedOption: ${OPTION}
6 alternatives:
7 - option: ${REJECTED_OPTION}
8 rejectedBecause: ${EVIDENCE_COST_OR_BOUNDARY}
9 reconsiderWhen: ${CONDITION_OR_NEVER_WITH_REASON}
10 implementation:
11 codeAndConfigAssets: ["${ASSET_IDS}"]
12 dataCompatibility: ${REQUIREMENTS}
13 operationalCost: ${MEASURED_OR_QUALITATIVE_EVIDENCE}
14 acceptance:
15 experiments: ["${EXPERIMENT_IDS}"]
16 performanceResult: ${REFERENCE_OR_MISSING}
17 correctnessResult: ${REFERENCE_OR_MISSING}
18 recoveryResult: ${REFERENCE_OR_MISSING}
19 failedOrNoBenefitRuns: ["${RUN_IDS}"]
20 decision: ${KEEP_ADJUST_ROLLBACK_OR_MORE_EVIDENCE}
21 limitations: ["${LIMITATIONS}"]
22 decidedBy: ${IDENTITIES}
23 decidedAt: ${TIMESTAMP}失败实验不应该被覆盖成一份成功摘要。保留无效原因、原始输出和后续修正;无收益方案则保留有效运行和决策理由。这样才能区分“实验执行坏了”与“方案在当前场景确实没有价值”。
四、回退索引要按依赖和数据状态执行
“关闭开关即可回退”通常只对无状态读路径成立。新索引要等旧查询恢复且没有消费者后再删除;异步消费者可以停止,新旧状态、Outbox 和去重记录却不能丢;批量写入已经提交的分块也不会随代码回退自动撤销。
回退索引不复制操作手册全文,只给值班人员一个确定入口:
1rollbackIndex:
2 packageRelease: ${PACKAGE_RELEASE}
3 entries:
4 - changeId: ${CHANGE_ID}
5 currentStateEvidence: ${FLAG_CONFIG_SCHEMA_AND_WORK_REFERENCE}
6 trigger: ${MEASURABLE_CONDITION}
7 authority: ${WHO_CAN_DECIDE_AND_EXECUTE}
8 dependencies:
9 rollbackBefore: ["${CHANGE_IDS}"]
10 rollbackAfter: ["${CHANGE_IDS}"]
11 compatibility:
12 minimumApplicationVersion: ${VERSION}
13 schemaAndDataRequirements: ${REQUIREMENTS}
14 clientContractRequirements: ${REQUIREMENTS}
15 inFlightWork:
16 query: ${QUERY_OR_TOOL}
17 drainCancelReconcilePolicy: ${REFERENCE}
18 stepsReference: ${VERSIONED_RUNBOOK_ASSET_ID}
19 stopConditions: ["${CONDITIONS}"]
20 verification:
21 businessCorrectness: ${QUERY_OR_TEST}
22 performanceAndResources: ${QUERY_OR_DASHBOARD_DEFINITION}
23 recoveryWindow: ${DURATION_FROM_EVIDENCE}
24 forwardRecovery: ${WHEN_ROLLBACK_IS_UNSAFE_OR_IMPOSSIBLE}
25 lastRehearsed: ${TIMESTAMP_OR_NEVER}
26 rehearsalEvidence: ${EXPERIMENT_ID_OR_MISSING}回退顺序来自依赖关系,不由文章顺序决定。关闭请求合并前缓存可以继续存在;停止异步中继前要停止新认领并处理租约;恢复旧应用版本前要确认它能读取当前 Schema 和状态值。若数据已经发生不可逆变化,应采用向前修复、补偿或兼容版本过渡,不能执行破坏性“还原”。
回退门禁还要包含正在处理的工作。HTTP 请求、线程池任务、数据库事务、消息租约、延迟重试和 RECONCILING 操作分别怎样排空或核对,必须有查询入口。运行手册从未演练过时,Manifest 应标记 lastRehearsed: never,而不是默认它可用。
五、迁移前先把内容分成三类
治理包到了另一个系统,最危险的动作是复制参数。订单服务测出的缓存 TTL、批次大小、线程数、连接数、重试次数、超时和限流速率,都绑定原来的业务承诺、数据分布、依赖容量和实例拓扑。
迁移清单先做分类:
1migrationClassification:
2 reusablePrinciples:
3 - define_comparable_experiment_before_change
4 - connect_business_outcome_stage_wait_and_resource_saturation
5 - bound_queues_retries_timeouts_and_concurrency
6 - preserve_correctness_failure_and_rollback_evidence
7 refillTemplates:
8 - baseline_protocol
9 - load_model
10 - bottleneck_evidence
11 - change_acceptance
12 - regression_matrix
13 - rollback_index
14 caseFactsNeverCopied:
15 - endpoint_and_business_state_contracts
16 - dataset_scale_distribution_and_hot_keys
17 - cache_ttl_and_staleness_window
18 - sql_index_and_batch_size
19 - thread_connection_and_downstream_concurrency
20 - timeout_retry_rate_limit_and_recovery_parameters
21 - measured_throughput_latency_error_and_resource_results可复用原则描述判断方式,不带订单参数。模板可以复制结构,但所有 ${...} 字段重新填写,并生成新的实验 ID、资产 ID 和校验值。案例事实只作为原系统证据,进入新系统后必须重新测量;即使技术栈和机器规格相同,也不能直接继承。
5.1 用只读评估决定是否值得迁移
新场景的第一轮工作不改代码、不建索引、不改配置。只在已授权范围内读取仓库、部署描述、Schema、脱敏流量摘要和现有监控定义,形成事实与缺口:
1readOnlyMigrationAssessment:
2 targetSystem: ${SYSTEM_AND_SCOPE}
3 authorization: ${APPROVED_READ_ONLY_SOURCES}
4 sourcePackage: ${PACKAGE_ID_AND_RELEASE}
5 collectedFacts:
6 businessActionsAndPromises: ${REFERENCE_OR_UNKNOWN}
7 architectureAndDependencies: ${REFERENCE_OR_UNKNOWN}
8 versionsAndResources: ${REFERENCE_OR_UNKNOWN}
9 dataScaleAndDistribution: ${REFERENCE_OR_UNKNOWN}
10 requestMixAndArrivalShape: ${REFERENCE_OR_UNKNOWN}
11 existingMetricsAndTraces: ${REFERENCE_OR_UNKNOWN}
12 failureAndRollbackMechanisms: ${REFERENCE_OR_UNKNOWN}
13 fitGap:
14 reusablePrinciples: ["${ITEMS_WITH_REASON}"]
15 templatesToRefill: ["${ITEMS_AND_OWNERS}"]
16 incompatibleAssumptions: ["${ITEMS_WITH_EVIDENCE}"]
17 missingEvidence: ["${ITEMS}"]
18 proposedFirstExperiment:
19 hypothesis: ${ONE_NARROW_HYPOTHESIS}
20 requiredWriteAuthorization: ${CHANGES_NOT_YET_AUTHORIZED}
21 safetyAndRollbackPrerequisites: ${REQUIREMENTS}
22 decisionGate: ${WHO_APPROVES_NEXT_STEP}
23 conclusion: ${NO_ACTION_MORE_READ_ONLY_EVIDENCE_OR_PROPOSE_CONTROLLED_EXPERIMENT}只读评估的产物是 fit-gap,不是一份“建议直接套用”的配置。新系统连业务动作、时效承诺和负载分布都说不清时,合理结论可能是先补观测,而不是选择缓存或扩大线程池。
六、用完成门禁决定它能不能交付
目录齐全不等于治理包可用。正式标记为 verified 前,至少检查:
- Manifest 中所有必需资产都存在,路径、版本与 SHA-256 可以核对。
- 每个性能结论能追到环境、数据、负载、运行编号、原始结果和指标查询。
- 06-01 的单项、累积、交互和最终组合结论保留实际运行范围与限制。
- 正确性、失败和恢复证据与性能数据一起归档,没有只留成功路径。
- 每项保留改造都有生效状态、兼容边界、回退入口和可量化触发条件。
- 秘密值和未脱敏数据没有进入包,外部资产具有权限与保留期说明。
- 至少按风险要求演练关键回退;未演练项明确阻塞或限制发布。
- 在一个新场景完成只读迁移评估,确认没有复制案例参数和容量结果。
当前系列可以交付的是这套文档协议和待填模板。只有真实案例工程、版本化配置、可复现脚本、原始实验数据、监控查询和回退演练按 Manifest 补齐后,才能把某个治理包发布标记为 verified。文章完成、审阅通过或目录生成,都不能替代这道门禁。
这套治理最终留下的是一条不会因人员变化而断掉的证据链。后来的人可以从一个结论找到原始运行,从一项配置找到容量依据,从一个开关找到数据兼容与回退步骤;迁移到新系统时,又知道哪些原则可以复用、哪些模板必须重填、哪些数字绝不能照搬。做到这里,一次性能改造才从项目记忆变成了可审计的工程资产。