首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >微服务进阶的3个硬核问题:分布式事务、可观测性与契约治理

微服务进阶的3个硬核问题:分布式事务、可观测性与契约治理

原创
作者头像
用户12658083
修改2026-07-30 11:36:50
修改2026-07-30 11:36:50
1020
举报

微服务进阶的3个硬核问题:分布式事务、可观测性与契约治理

做后端开发到第五年,微服务该用的组件都用过了,但真正让我在线上吃过亏的,翻来覆去就是三个问题:分布式事务怎么收场、出了故障怎么快速定位、接口变更怎么不炸上游。

这篇文章不讲理论,直接给方案和代码。

一、分布式事务:本地消息表 + 定时补偿,放弃强一致性

线上出过一次事故:订单服务调库存服务扣减,库存服务超时回滚,但订单状态已经改成"已支付",两边数据对不上,最后手工修了半小时数据。

教训: 跨服务的强一致性在真实网络环境下是奢望。

我的方案是本地消息表 + 定时对账,核心逻辑就三块:

代码语言:javascript
复制
// 1. 本地事务:订单入库 + 消息落库(同库,保证原子性)
@Transactional
public void createOrder(OrderDTO order) {
    orderMapper.insert(order);
    messageMapper.insert(new PendingMessage(
        "inventory", 
        "deduct", 
        order.getSkuId(), 
        order.getQuantity()
    ));
}

// 2. 定时任务:轮询未发送消息,调用库存服务(带指数退避重试)
@Scheduled(fixedDelay = 5000)
public void dispatchPendingMessages() {
    List<PendingMessage> messages = messageMapper.selectUnsent(100);
    for (PendingMessage msg : messages) {
        try {
            inventoryClient.deduct(msg.getSkuId(), msg.getQty());
            messageMapper.markSent(msg.getId());
        } catch (Exception e) {
            msg.retryCount++;
            msg.nextRetryTime = now + 2 ^ msg.retryCount * 1000;
            messageMapper.update(msg);
        }
    }
}

// 3. 每日对账:拉取订单和库存流水,自动发现不一致并告警
@Scheduled(cron = "0 1 0 * * ?")
public void dailyReconciliation() {
    List<Order> orders = orderMapper.selectYesterday();
    List<InventoryLog> logs = inventoryLogMapper.selectYesterday();
    // 比对两边数据,发现差异自动生成工单
    List<Mismatch> mismatches = compare(orders, logs);
    if (!mismatches.isEmpty()) {
        alertService.send("对账异常", mismatches);
    }
}

这套方案上线后跑了半年,没有再出现过数据不一致的线上事故。代价是增加了5-10分钟的延迟(异步补偿),但业务可以接受。

二、可观测性:结构化日志 + 全链路追踪,3分钟定位故障

以前排查故障的流程:用户报障 → 查Nginx日志找时间戳 → 跳转到应用服务器翻业务日志 → 发现日志不全 → 再查数据库慢查询 → 半小时过去了。

转折点是引入了OpenTelemetry + Jaeger,要求所有服务统一埋点。

日志改造前后对比:

代码语言:javascript
复制
# 改造前:纯文本日志,无法检索
logger.info("Order created, orderId: 12345")

# 改造后:结构化日志,自带trace_id
logger.info(
    "Order created",
    extra={
        "trace_id": trace_id,
        "order_id": "12345",
        "user_id": "67890",
        "cost_ms": 120,
        "service": "order-service"
    }
)

Java服务端的拦截器配置(所有请求自动注入trace_id):

代码语言:javascript
复制
@Component
public class TraceInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, 
                            HttpServletResponse response, 
                            Object handler) {
        // 从上游提取或生成新的traceId
        String traceId = request.getHeader("X-Trace-Id");
        if (StringUtils.isEmpty(traceId)) {
            traceId = UUID.randomUUID().toString();
        }
        // 放入MDC,日志框架自动打印
        MDC.put("trace_id", traceId);
        // 传递给下游服务
        response.setHeader("X-Trace-Id", traceId);
        return true;
    }
}

现在排查流程变成:输入trace_id → Jaeger展示完整调用链 → 点击每个span看结构化日志 → 定位到具体方法和SQL → 全过程不超过3分钟

三、契约治理:Consumer-Driven Contract,防止上游被下游坑

最痛的教训是某次重构,把订单服务的返回值从String orderId改成了Long orderId,结果上游支付服务直接报反序列化错误,回滚了两次才找到原因。

解决方案是引入消费者驱动契约(CDC),使用Spring Cloud Contract:

代码语言:javascript
复制
// 服务提供方定义契约(order-service)
Contract.make {
    description "获取订单详情接口,必须返回订单ID为Long类型"
    request {
        method GET()
        url "/order/10001"
        headers {
            header "Content-Type": "application/json"
        }
    }
    response {
        status 200
        body([
            orderId: 10001L,        // Long类型,明确声明
            amount: 99.50,
            status: "PAID"
        ])
        headers {
            header "Content-Type": "application/json"
        }
    }
}

代码语言:javascript
复制
<!-- Maven插件配置:自动生成契约测试 -->
<plugin>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-contract-maven-plugin</artifactId>
    <version>4.0.0</version>
</plugin>

每次代码提交时,CI流水线会自动执行契约测试。如果接口改动导致契约不兼容,构建直接失败,把问题拦截在开发阶段,而不是等到上线后才发现

现在团队规定:所有对外接口的改动,必须同步更新契约文件,否则PR不予合并。

写在最后

这三个问题解决之后,我最大的感受是:微服务的稳定性不是靠"不出错",而是靠"出错了能快速发现、快速恢复"。

分布式事务方案接受最终一致性,可观测性做到全链路可追踪,接口变更靠契约测试保底——这三件事做扎实了,系统就具备了基本的"抗造能力"。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 微服务进阶的3个硬核问题:分布式事务、可观测性与契约治理
    • 一、分布式事务:本地消息表 + 定时补偿,放弃强一致性
    • 二、可观测性:结构化日志 + 全链路追踪,3分钟定位故障
    • 三、契约治理:Consumer-Driven Contract,防止上游被下游坑
    • 写在最后
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档