2. 银行交易系统演进

要理解可观测性为什么在银行交易系统中变得如此关键,必须先回到系统架构本身的演进路径。集中式时代的交易链路是"看得见、摸得着"的,而微服务化之后,一笔交易可能横跨十几个服务、多个中间件和异构数据源,链路的形态发生了根本性变化。本节从架构变迁出发,梳理典型交易场景,并引出可观测性面临的核心挑战。

一、架构变迁:从单体集中式到微服务化

早期银行核心系统普遍采用集中式架构,典型代表是基于大型机或小型机的主机集中模式。所有交易逻辑、账务处理、数据存储都运行在同一台或同一组高可用主机上,通过事务管理器保证强一致性。这种架构的优势是链路短、事务边界清晰、故障定位相对直接,但扩展性差、迭代周期长、单点风险高。

随着互联网业务爆发,银行开始向分布式架构演进,大致经历三个阶段:

  • 垂直拆分阶段:按业务条线将单体系统拆分为网银、手机银行、支付、账务等独立应用,各应用独立部署,但跨系统调用开始出现。
  • 服务化阶段:引入 SOA 和 ESB,通过服务注册与总线完成系统间通信,链路开始出现中间层。
  • 微服务阶段:按业务能力细粒度拆分,服务独立部署、独立扩缩容,配合容器化与 Service Mesh,链路彻底碎片化。

这一演进带来的直接结果是:一笔交易从"一次调用"变成"一张调用网"。下图展示了集中式与微服务两种架构下,同一笔转账交易在链路形态上的本质差异。

集中式与微服务架构下的交易链路对比 集中式架构 渠道接入(柜面/网银) 统一入口 核心主机(交易+账务+数据) 单一事务边界 · 强一致 链路深度:1~2 跳 集中式数据库 单库 · 单表 · 单事务 微服务架构 网关 用户服务 账户服务 风控服务 账务服务 支付服务 通知服务 MySQL Redis Kafka 链路深度:8~15 跳 · 最终一致

二、典型交易场景与链路特征

银行交易场景种类繁多,但按链路复杂度可以归纳为几类典型模式。理解这些模式,是设计可观测性方案的前提。

交易场景 典型链路 关键中间件 可观测性关注点
账户余额查询 网关 → 账户服务 → 缓存 → 数据库 Redis、MySQL 缓存命中率、P99 延迟、慢查询
行内转账 网关 → 账户 → 账务 → 支付 → 通知 MQ、分布式事务 事务一致性、补偿链路、消息积压
跨行支付 网关 → 支付 → 风控 → 渠道适配 → 外部清算 Kafka、HTTP 外部接口 外部依赖超时、重试、对账差异
批量代发 调度 → 批量服务 → 账务 → 文件服务 定时任务、对象存储 任务分片、失败重跑、进度追踪

可以看到,越靠近核心账务和外部清算,链路越长、依赖越多、一致性要求越高。一笔跨行支付在高峰期可能同时触发风控规则、渠道限流、外部超时重试,任何一个环节的抖动都会沿着调用链向上传导。

三、链路复杂度带来的可观测性挑战

微服务化之后,可观测性面临的挑战不再是"有没有日志",而是"能不能把碎片化的信号拼成一条完整的因果链"。具体表现为四个层面:

  1. 调用链断裂:跨进程、跨线程、跨消息队列的上下文传递容易丢失,TraceID 在异步场景下无法自动透传,导致链路出现断点。
  2. 指标维度爆炸:服务数量、实例数量、接口数量相乘后,指标基数急剧膨胀,传统监控的聚合方式难以定位到具体实例和具体调用。
  3. 日志分散:同一笔交易的日志散落在十几个服务的日志文件中,缺乏统一 TraceID 关联时,排查一次失败交易可能需要登录多台机器逐一检索。
  4. 根因定位困难:一个超时可能是下游数据库慢查询、中间件积压、网络抖动或上游流量突增共同作用的结果,单点指标无法给出因果结论。

常见误区:很多团队认为"接入了 APM 工具就等于具备可观测性"。实际上,如果 TraceID 没有贯穿异步链路、如果日志没有结构化、如果指标没有统一标签体系,APM 只能看到局部片段,反而会让人误以为链路是完整的。

四、从监控到可观测性的能力跃迁

传统监控回答的是"系统是否正常",可观测性回答的是"为什么会出现这个现象"。在银行交易链路中,这意味着需要把 Metrics、Tracing、Logging 三类信号通过统一的 TraceID 和标签体系关联起来。

一个可落地的判断标准是:给定一笔失败交易的流水号,能否在 5 分钟内还原出它经过的每一个服务、每一次调用耗时、每一段日志和当时的资源指标。如果做不到,说明可观测性体系还存在断点。

下面是一段典型的链路上下文透传配置示例,展示了在服务入口处如何从请求头提取 TraceID 并注入到日志 MDC 中,这是打通链路的基础动作:

// 服务入口拦截器:提取并透传 TraceID
public class TraceInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest req,
                             HttpServletResponse resp,
                             Object handler) {
        String traceId = req.getHeader("X-Trace-Id");
        if (traceId == null || traceId.isEmpty()) {
            traceId = UUID.randomUUID().toString().replace("-", "");
        }
        MDC.put("traceId", traceId);
        resp.setHeader("X-Trace-Id", traceId);
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest req,
                                HttpServletResponse resp,
                                Object handler, Exception ex) {
        MDC.remove("traceId");
    }
}

这段代码看似简单,但它决定了后续所有日志、指标和链路数据能否被正确关联。在异步线程池、消息消费、定时任务等场景中,还需要额外做上下文传递,否则 TraceID 会在这些边界处丢失。

实践建议:在架构演进过程中,可观测性建设应与微服务拆分同步推进,而不是等系统上线后再补。每新增一个服务,就应同步确定它的 TraceID 透传方式、日志格式和关键指标,避免技术债累积成排查黑洞。

总结来看,银行交易系统从集中式走向微服务,本质上是把"一个事务"拆成了"一张调用网"。链路复杂度的提升不是可观测性的附加题,而是必答题。只有先看清链路的真实形态,才能在后端章节中进一步讨论如何用工具和规范把它重新"拼"回来。