微服务架构下,系统被拆分成多个独立服务,每个服务负责特定功能。但一旦某个服务出问题,比如订单服务突然无法响应,用户下单就会卡住,这时候异常处理机制就显得特别关键。
异常来源多种多样
网络抖动、数据库连接超时、第三方接口返回错误,甚至服务自身代码逻辑缺陷,都可能引发异常。比如支付服务调用银行接口时,网络延迟导致请求超时,如果不做处理,整个流程就会中断。
统一异常响应格式
各个服务返回的错误信息应该保持一致,前端或调用方才能方便解析。可以定义一个通用结构:
{
"code": 5001,
"message": "支付服务暂时不可用",
"timestamp": "2024-04-05T10:23:10Z",
"service": "payment-service"
}
使用熔断防止雪崩
当订单服务频繁调用库存服务失败,继续重试只会拖垮自己。引入熔断器(如 Hystrix 或 Resilience4j),在失败率达到阈值后自动切断请求,让系统有机会恢复。就像家里电路跳闸,避免火灾一样。
配置简单示例
.circuitBreakerConfig(CircuitBreakerConfig.ofDefaults())
.timeoutConfig(TimeoutConfig.of(Duration.ofSeconds(3)))
.retryConfig(RetryConfig.ofDefaults())
日志记录要具体
异常发生时,只记录“调用失败”没意义。必须带上服务名、请求ID、时间戳和堆栈信息。结合 ELK 或 Loki 这类工具,排查问题时能快速定位到哪台机器、哪个实例出了问题。
异步任务别忘了兜底
有些操作走消息队列异步处理,比如发邮件。如果消费者处理时报错又没捕获,消息可能直接丢弃。应该设置死信队列,把失败的消息存起来,后续人工干预或重试。
模拟故障做演练
定期通过 Chaos Monkey 这类工具随机关闭某个服务实例,看看整体系统能否扛住。就像消防演习,真着火时不慌。某次测试中故意停掉用户服务,结果发现订单服务立刻大面积报错,这才暴露出缓存降级策略没做好。
接口层做好校验
前端传了个非法参数,比如负数金额,后端不能直接抛异常。应在 API 网关或控制器层面拦截,返回明确提示。否则调用方看到的是 500 错误,以为是服务器问题,其实只是数据不对。