Page 173 - 《软件学报》2026年第2期
P. 173

652                                                        软件学报  2026  年第  37  卷第  2  期


                 依赖图, 其中节点代表服务, 边代表调用关系. 这个精炼后的依赖图将作为核心输入, 传递给后续的变更评分模块
                 进行更精细化的根因分析.
                  4.5   变更依赖关系构建
                    由于服务功能的快速迭代, 现代微服务架构中的单个服务可能会在极短时间窗口内                             (如  48 h) 经历多次变更
                 部署. 这种高频变更特性使得故障诊断面临新的挑战: 当系统出现异常时, 运维团队不仅需要定位故障服务, 还需
                 要在众多变更中准确识别导致问题的具体变更版本. 在获得完整的服务依赖图后, 我们可以通过集成变更管理系
                 统  (如  GitOps 工具链或企业内部的变更单系统) 查询服务依赖图上所有服务在最近                    H h  内发生的变更列表. 值得
                 注意的是, 一个服务的多次变更之间往往不是相互孤立的, 而是存在复杂的版本依赖关系链. 例如, 假设服务                                A  的
                 变更  1  在  24 h  前开始部署, 并在  12 h  前完成; 随后, 服务  A  的变更  2  在变更  1  完成后立即开始部署. 这种情况下,
                 变更  2  在版本上直接依赖于变更        1  的基础代码状态. 如果最终发现是变更           1  引入了缺陷, 那么仅回滚到变更        2  之
                 前的版本并不能彻底解决问题, 因为变更             2  是基于已经存在缺陷的变更         1  版本进行的迭代. 此时, 必须回滚到变
                 更  1  之前的原始稳定版本, 系统才能完全恢复正常. 因此, 在分析故障时, 对同一个服务的多个变更, 必须首先通过
                 代码仓库的提交历史、构建流水线的依赖关系或部署系统的版本记录, 精确还原它们之间的版本依赖图谱.
                    为了获得同一个服务的多个版本之间的依赖关系, 需要建立系统化的版本溯源机制. 具体而言, 可以从以下                                 3
                 个维度进行依赖关系提取: (1) 代码仓库维度: 通过分析              Git 提交历史中的分支合并记录和         tag  标记, 确定各版本间
                 的代码继承关系; (2) 构建流水线维度: 检查          CI/CD  系统中各次构建的输入输出依赖, 特别是容器镜像的层级依赖
                 关系; (3) 部署配置维度: 比对     Kubernetes 等编排系统中的    Deployment 版本更迭记录, 识别滚动更新过程中的版本
                 替换顺序. 这   3  个维度的数据可以通过调用各系统的开放             API 进行自动化采集, 并存储为有向无环图            (DAG) 的形
                 式, 其中节点代表特定版本, 边代表版本间的依赖关系. 例如, 当服务                  A  的  v1.2  版本是基于  v1.1  版本的代码构建,
                 而  v1.3  又依赖于  v1.2  时, 就会形成  v1.1→v1.2→v1.3  的依赖链. 这种显式的版本依赖图谱不仅可以帮助快速定位
                 需要回滚的目标版本, 还能在变更前进行影响评估, 预测某个变更可能波及的依赖服务范围. 在实际实现中, 可以
                 开发专门的版本依赖分析器, 定期从各子系统同步元数据, 并建立统一的版本依赖知识图谱, 为故障诊断提供更全
                 面的上下文信息.
                  4.6   根因变更推断
                    在完成服务依赖图的构建和变更依赖关系的分析后, 系统已经具备了完整的拓扑结构和变更上下文信息. 接
                 下来的核心挑战是从众多候选变更            (通常每个故障事件涉及上百个时空相关变更) 中准确定位最可能导致故障的
                 根因变更. 本文在根因变更推断中综合考虑了变更前后 KPI 差异、变更时间与故障时间的相关性和服务依赖强度
                 这  3  个关键维度的因素, 这些因素共同构成了一个多维评估框架.
                  4.6.1    KPI 差异得分计算
                    为了降低部署新软件版本所带来的风险, 灰度变更已经成为软件部署中一种流行的技术手段. 在灰度变更中,
                 工程师们首先只在一部分服务实例上部署软件变更, 而不是立即更新整个服务的所有实例. 这样做的好处在于, 如
                 果已变更的服务实例引发异常, 可以及时回滚. 如果没有出现异常, 就可以逐步将变更推广到属于该服务的所有实
                 例, 直到所有服务实例都完成更新.
                    大多数变更故障通常会在灰度变更过程中显现出来. 其典型表现是已变更服务实例组和未变更服务实例组之
                 间出现明显的性能或可靠性差异. 例如在图              6  中, 服务  A  上线了一个缺陷变更, 当前处于灰度变更过程中. A 1 和
                 A 2 是已变更服务实例, A 3 和   A 4 是未变更服务实例. 图中的曲线表示每个服务实例的请求延迟. 此次服务                      A  的变
                 更引发系统延迟上升, 进而触发告警系统. 通过分析服务                 A  中已变更服务实例组和未变更服务实例组之间的请求
                 延迟可以发现, 已变更的       A 1 和  A 2 的请求延迟剧烈上升, 而未变更的       A 3 和  A 4 的请求延迟保持稳定. 通过对比      A 1
                 和  A 2 与  A 3 和  A 4 可以发现只有已变更的服务实例出现异常, 因而可以推断异常是由              A  的缺陷变更导致的.
                    为了检测出已变更和未变更服务实例组之间是否出现显著的差异, 本文采用了一种分流思想                                [36] 对比测试组
                 (已变更服务实例) 和对照组        (未变更服务实例) 的性能表现. 其核心思路是, 在灰度变更过程中, 如果一个故障是由
   168   169   170   171   172   173   174   175   176   177   178