Spring Cloud Alibaba 生产踩坑全记录:三年老狗的血泪总结
上周五晚上十点半,我正一边啃着冷掉的黄焖鸡,一边盯着灰度环境里那个诡异的服务注册失败日志。产品经理在钉钉群里@我:“这个需求明天上线哈,老板很关注。”
我叹了口气,默默把 nacos-client 的 debug 日志级别调到了 TRACE——这已经是我这周第三次和 Spring Cloud Alibaba(SCA)“亲密接触”了。
大家好,我是某二线互联网公司干了三年多的 Java 算法工程师(别问为什么算法岗天天写业务代码,问就是“AI赋能业务”)。最近在认真考虑跳槽,所以趁项目间隙,把这几年在生产环境中折腾 SCA 的经验整理出来,既是复盘,也算给后来人铺点路。毕竟,有些坑,真的没必要再踩一遍。
为什么我们选了 Spring Cloud Alibaba?
三年前,公司微服务架构还在用 Spring Cloud Netflix 那套全家桶。但随着 Eureka 停更、Hystrix 不再维护,加上团队对国产化中间件的兴趣(以及老板对“信创”的执念),我们决定迁移至 SCA。
技术选型会上,运维同事拍胸脯保证:“Nacos 比 Eureka 轻量,Sentinel 比 Hystrix 好用,Seata 能搞定分布式事务!”
结果上线第一个月,我们就经历了 Nacos 集群脑裂、Sentinel 规则不生效、Seata 锁超时导致订单卡住……那段时间,每天睁眼第一件事就是看 Grafana 面板有没有红色警报。
注册中心:Nacos 别只用单机模式!
很多人本地开发图省事,直接 startup.sh -m standalone 跑单机版 Nacos。千万别带到生产环境!
我们早期就栽在这儿。双11压测期间,Nacos 单节点 CPU 打满,服务心跳全部超时,整个微服务集群“集体失联”。监控面板瞬间变红,运维大哥直接冲到我工位:“你们是不是又没配集群?”
正确姿势:
- 生产必须部署 Nacos 集群(至少3节点),配合 Nginx 做 VIP。
- 客户端配置要加
namespace隔离环境(dev/test/prod)。 - 心跳间隔和超时时间别用默认值!
spring:
cloud:
nacos:
discovery:
server-addr: nacos-vip.company.com:8848
namespace: prod-namespace-id
# 关键!调整心跳频率,避免网络抖动误判
heartbeat-interval: 5
ip-delete-timeout: 30
💡 经验:我们线上设置
heartbeat-interval=5s,ip-delete-timeout=30s,既保证故障快速剔除,又避免因 GC 暂停被误踢。
配置中心:别把敏感信息明文写进去!
有一次安全扫描,发现数据库密码、Redis 密钥全明文躺在 Nacos 配置里。安全部门直接发邮件通报,CTO 在周会上点名批评。我当场就想原地辞职。
解决方案:
- 敏感配置加密:用 Jasypt 或自研 KMS 加解密。
- 权限控制:Nacos 开启 RBAC,限制开发人员只能读不能改生产配置。
- 配置变更审计:所有配置修改必须走工单+审批+灰度发布。
我们后来搞了个内部工具,提交配置时自动加密,应用启动时通过 Vault 动态解密。虽然麻烦了点,但再也不怕被安全团队“关爱”了。
流量治理:Sentinel 规则不是配完就完事
Sentinel 的 Dashboard 很香,但规则默认是内存态的!服务一重启,限流规则就没了。我们曾因此在促销活动时被突发流量打崩。
生产级做法:
- 规则持久化到 Nacos 或 Apollo。
- 使用
@SentinelResource注解时,务必指定blockHandler和fallback。 - 监控指标接入 Prometheus + Grafana。
@SentinelResource(
value = "createOrder",
blockHandler = "handleBlocked",
fallback = "fallbackCreateOrder"
)
public Order createOrder(OrderRequest request) {
// 业务逻辑
}
// 限流/降级处理
public Order handleBlocked(OrderRequest request, BlockException ex) {
log.warn("请求被限流", ex);
return Order.empty(); // 返回兜底数据
}
// 异常 fallback
public Order fallbackCreateOrder(OrderRequest request, Throwable t) {
log.error("创建订单异常", t);
return Order.empty();
}
🤯 吐槽:Sentinel 的
blockHandler方法签名必须和原方法一致,连参数顺序都不能错,否则运行时报NoSuchMethodException,调试到怀疑人生。
分布式事务:Seata 别乱用 AT 模式
我们有个资金账户服务,早期用 Seata AT 模式处理转账。结果某次主库主从延迟,undo_log 回滚时读到旧数据,导致余额不一致。财务小姐姐差点报警。
AT 模式的坑:
- 要求所有参与方都能访问 undo_log 表。
- 主从延迟场景下可能回滚错误。
- 不支持跨 DB 类型(比如 MySQL + Oracle)。
我们的妥协方案:
| 场景 | 方案 |
|---|---|
| 强一致性(如支付) | TCC 模式 + 人工对账 |
| 最终一致性(如积分) | 本地消息表 + 定时补偿 |
| 非关键路径 | 直接放弃事务,靠监控告警+人工介入 |
Seata 现在我们只在内部低风险系统用,核心链路还是靠“消息队列 + 幂等 + 对账”。
网关整合:Spring Cloud Gateway + SCA
我们用 Spring Cloud Gateway 做统一入口,集成 Nacos 服务发现和 Sentinel 限流。但早期配置错了路由权重,导致灰度流量全打到新版本,线上直接 5xx。
关键配置:
spring:
cloud:
gateway:
discovery:
locator:
enabled: true # 开启服务发现
routes:
- id: order-service
uri: lb://order-service # lb 表示负载均衡
predicates:
- Path=/api/order/**
filters:
- StripPrefix=1
# 接入 Sentinel 限流
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
记得在网关加全局异常处理,不然一个服务挂了,前端收到 500 而不是友好的 {code: 50001, msg: "服务暂不可用"}。
性能与监控:别等出事才看指标
SCA 组件本身很轻量,但不当使用会拖垮性能。比如:
- Nacos 频繁监听配置变更,导致大量长连接。
- Sentinel 指标采集太密集,占用过多内存。
- Seata 全局锁竞争激烈,TPS 直接腰斩。
我们现在的监控体系:
| 组件 | 监控项 | 告警阈值 |
|---|---|---|
| Nacos | 服务注册数、心跳失败率 | >5% 失败率 |
| Sentinel | QPS、Block 数、RT | Block 突增 10 倍 |
| Seata | 全局事务数、锁等待时间 | 锁等待 >1s |
| 应用 | JVM GC、线程池队列 | Full GC >1 次/小时 |
所有指标接入公司统一监控平台,配合企业微信机器人,半夜也能把我叫醒。
写在最后:稳定大于一切
说实话,SCA 是个好东西,尤其适合国内技术栈。但微服务不是银弹,组件越多,运维复杂度指数级上升。
现在我们团队有个不成文的规定:新项目除非强需求,否则先单体,再拆微服务。毕竟,老板要的是功能上线,不是架构炫技。
这篇文章写完,我的简历也差不多更新好了。希望下一家公司,能让我少修点“祖传代码”,多写点真正有意思的算法模型。
如果你也在用 SCA,欢迎留言交流踩坑经验。毕竟,程序员的快乐,有时候就来自于一句“我也遇到过!”。
最后送大家一句真理:线上无小事,配置即代码,变更需谨慎。
—— 一个被 Nacos 虐哭过的 Java 工程师

评论 0