业务系统性能改造手册 · 验收交付

交付可迁移的性能治理包

2026-08-053 min read验收交付
摘要

把代码、配置、实验输入、原始结果、决策与回退条件组织成可校验的资产清单,并用只读评估区分可迁移原则、待重填模板和订单案例事实。

交付可迁移的性能治理包

性能改造结束后,团队经常留下一份汇报:接口快了多少、数据库压力降了多少、峰值扛到了多少。过几个月再问“对应哪次构建、哪份数据、哪些开关,怎样回退”,答案开始散落在聊天记录、监控截图和某个人的电脑里。

这样的结果很难审计,也不能安全迁移。数字脱离实验现场后只剩结论,配置脱离适用边界后则可能变成下一次事故的输入。

小编更愿意把性能治理的交付物看成一组相互引用的工程资产:代码和配置说明改了什么,实验材料说明怎样验证,决策记录说明为什么保留,回退索引说明出问题后怎样退出。可迁移的是这套证据与决策方式,不是订单案例里的参数和容量数字。

先把真实性说清楚:当前系列正文提供了代码片段、配置形状、实验协议和报告模板,但磁盘上没有一套已经运行的完整 Spring Boot 案例工程,也没有真实压测原始数据。因此本文给出交付目录、Manifest 和完成门禁;未产生的资产必须标记为 missingplanned,不能因为模板存在就写成已验收。

一、先规定包里应该有什么

治理包不应按文章编号简单归档。使用者需要从“一个结论”走回它的输入、实现、验证和退出路径。可以采用下面的目录契约;路径是建议结构,不代表这些文件当前已经存在:

text
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.yaml

README.md 只负责导航:包的适用系统、负责人、当前发布版本、已完成和缺失的资产、验证入口以及敏感信息处理规则。它不复制各实验结论。大体积原始数据可以放在受控对象存储,但目录中要保存不可歧义的引用、保留期和校验值。

1.1 每种资产回答一个问题

资产回答的问题最低追溯字段
代码与数据库变更实际改了什么提交、镜像摘要、迁移版本、生成方式
生效配置运行时究竟用了什么脱敏快照、来源、作用域、单位、配置摘要
数据与负载给系统输入了什么快照/生成脚本、分布、场景、脚本版本
监控查询与原始结果观察依据在哪里查询文本、数据源、时间窗、原始文件、校验值
决策与失败证据为什么保留或拒绝方案假设、候选、结果、限制、负责人、日期
回退与核对工具出问题后怎样安全退出前置条件、步骤、兼容性、停止条件、验收查询

一张截图可以帮助阅读,却不能替代查询定义和原始数据引用;仓库里的默认配置也不能替代运行时生效快照。哈希能够发现文件后来是否变化,不能证明文件来源可信,所以 Manifest 还要记录生成者、生成命令或系统、采集时间和访问位置。

二、用 Manifest 把资产和证据连起来

可迁移交付包要用 Manifest 把代码配置实验证据与决策串成可追溯链 Manifest 是治理包的入口,不是附件清单。每个资产都需要稳定 ID、类型、版本、来源、状态、校验值和依赖关系。状态至少区分:只有模板、已产生但未验证、已验证、缺失和不适用。

yaml
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 一个改造需要完整证据链

以“缓存热点订单”为例,资产关系应当能够串起来:

text
1决策记录 2 ├─> 业务时效契约 3 ├─> 代码提交 + 生效配置 4 ├─> 数据快照 + 负载场景 5 ├─> 单项与组合实验运行 6 │ ├─> 原始请求结果 7 │ ├─> 数据库与缓存指标查询 8 │ └─> 数据偏差检查 9 └─> 保留结论 + 回退入口

任何一段缺失,结论就应降级。只有汇总报告而没有运行编号和原始结果,无法复算;只有代码而没有运行时配置,无法证明路径生效;只有性能收益而没有数据偏差检查,无法证明业务结果仍然成立。

三、决策记录要保留被拒方案和失败实验

交付包若只保存最终方案,后来的人很容易重新尝试已经被否定的路径。每项改造可以用一份短决策记录保存当时的上下文:

yaml
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 和去重记录却不能丢;批量写入已经提交的分块也不会随代码回退自动撤销。

回退索引不复制操作手册全文,只给值班人员一个确定入口:

yaml
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、批次大小、线程数、连接数、重试次数、超时和限流速率,都绑定原来的业务承诺、数据分布、依赖容量和实例拓扑。

迁移清单先做分类:

yaml
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、脱敏流量摘要和现有监控定义,形成事实与缺口:

yaml
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。文章完成、审阅通过或目录生成,都不能替代这道门禁。

这套治理最终留下的是一条不会因人员变化而断掉的证据链。后来的人可以从一个结论找到原始运行,从一项配置找到容量依据,从一个开关找到数据兼容与回退步骤;迁移到新系统时,又知道哪些原则可以复用、哪些模板必须重填、哪些数字绝不能照搬。做到这里,一次性能改造才从项目记忆变成了可审计的工程资产。