Spring Cloud Alibaba 生产实践:从面试题到线上事故的血泪总结
上周五晚上十点,我瘫在工位上盯着 Grafana 面板,心里默默问候产品经理全家——又一个“临时加个功能,明天上线”的需求。这已经是入职新公司的第二个月了,说好的“技术驱动、注重架构”呢?怎么感觉还是“能跑就行”?好在我有我的老伙计 GitHub Copilot(付费版用了快两年了,真香),不然这种 deadline 压顶的日子,怕是得秃成地中海。
说到架构,最近团队决定把老掉牙的单体 Spring Boot 应用拆成微服务,还指名要用 Spring Cloud Alibaba(SCA)。领导拍板时一脸自信:“Nacos 做注册中心,Sentinel 熔断限流,Seata 分布式事务,一套全家桶,稳!”
我内心 OS:你怕是没经历过生产环境凌晨三点被 PagerDuty 叫醒的痛。
不过也好,正好趁这个机会把之前跳槽面试时被问烂的 “Spring Cloud Alibaba 和 Spring Cloud Netflix 有什么区别?” 这类 面试题挑战 给落地实操一遍。纸上谈兵谁都会,线上炸了才是真考验。
起手式:别被“全家桶”骗了
刚接触 SCA 的人容易有个误区:以为装个 starter 就万事大吉。现实是,配置不对,服务注册不上;熔断不配,雪崩分分钟教你做人。
我们项目是个典型的前后端分离架构:前端 Vue 写死在 Nginx,后端是几个 Spring Boot 微服务(用户中心、订单、支付、商品)。前端同学最烦的就是后端改个接口不通知,结果页面白屏。所以我们在设计 API 时特别强调 契约先行 —— 先写 OpenAPI Spec,再开发,避免“前端联调=猜字段”。
但微服务一拆,问题来了:前端要调多个服务,总不能每个域名都暴露出去吧?于是网关成了刚需。Spring Cloud Gateway + Nacos 动态路由,安排!
关键配置:Nacos 注册中心
# bootstrap.yml
spring:
application:
name: user-service
cloud:
nacos:
discovery:
server-addr: ${NACOS_HOST:localhost}:${NACOS_PORT:8848}
namespace: prod # 别用 public!生产务必隔离 namespace
group: DEFAULT_GROUP
config:
server-addr: ${NACOS_HOST:localhost}:${NACOS_PORT:8848}
file-extension: yaml
namespace: prod
💡 血泪教训:一开始我们没设
namespace,测试和生产共用一个 Nacos,结果测试环境的服务注册到生产,前端调着调着突然返回{"code":500, "msg":"test data"}……运维差点把我叉出去。
Sentinel:不是配了就安全,得会“预热”
微服务最怕什么?级联失败。一个服务慢,拖垮整个链路。这时候 Sentinel 就派上用场了。
但很多人只配了 @SentinelResource,以为万事大吉。错!流量控制策略必须结合业务场景。
比如我们的下单接口,高峰期 QPS 3000+。如果直接设置 QPS = 1000,那超出的部分全拒,用户体验爆炸。所以我们用了 Warm Up(预热)模式:
// 在初始化时加载规则
@PostConstruct
public void initFlowRules() {
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setResource("createOrder");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setCount(1000); // 最终阈值
rule.setWarmUpPeriodSec(60); // 60秒内从 1/3 阈值逐渐上升
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
这样系统启动或流量突增时,不会因为冷启动直接拒绝大量请求,而是平滑过渡。
🤯 真实事故:去年双11压测,我们没开 Warm Up,结果一放量,Sentinel 直接把 70% 请求 block 掉,监控告警响成交响乐。当时真的想砸 Mac(还好忍住了,毕竟 M2 Pro 太贵)。
Seata:分布式事务不是银弹
说到 Seata,很多人一听“AT 模式自动回滚”,眼睛一亮。但生产环境哪有那么简单?
我们订单服务调用库存服务,必须保证 下单成功则扣库存,失败则回滚。Seata AT 模式确实方便,但有两个坑:
- 全局锁性能瓶颈:高并发下,
undo_log表争抢严重。 - 数据库必须支持 undo log:我们用的是 MySQL 8.0 + InnoDB,没问题;但如果你用 MongoDB 或 PG,就得换 TCC 模式。
我们的解决方案是:核心链路用 Seata AT,非核心异步补偿。
比如发优惠券这种操作,即使失败也不影响主流程,就扔到 MQ 里,失败重试三次,还不行就人工介入。既保证了主链路性能,又不失可靠性。
// 订单服务
@GlobalTransactional
public void createOrder(OrderDTO dto) {
orderMapper.insert(dto);
stockClient.decreaseStock(dto.getProductId(), dto.getCount()); // 远程调用
couponClient.issueCouponAsync(dto.getUserId()); // 异步,不参与全局事务
}
🧠 架构思考:不是所有操作都要强一致。CAP 理论告诉我们,AP 或 CP 得根据业务选。电商下单要 CP,但发通知可以 AP。
前端联调:别让微服务变成“微烦恼”
微服务对后端友好,但对前端简直是灾难。以前一个 /api/order,现在变成 /user/info、/product/detail、/order/create……前端同学每天在 Postman 里切来切去,人都麻了。
我们的解法是:网关聚合 + Mock 机制。
- 所有后端服务走 Spring Cloud Gateway,前端只对接
gateway.example.com - 网关根据路径路由到不同服务:
spring: cloud: gateway: routes: - id: user-service uri: lb://user-service predicates: - Path=/api/user/** - id: order-service uri: lb://order-service predicates: - Path=/api/order/** - 开发阶段,前端可通过 Nacos 配置开关,启用 Mock 数据(用 WireMock 实现),不用等后端接口 ready
这样一来,前端再也不用求着后端“先给我个假数据”,自己就能跑通流程。产品经理看了都说“效率提升了”(虽然他根本不知道改了啥)。
生产运维:日志、监控、告警一个不能少
代码写完只是开始,上线才是噩梦的起点。
我们在 SCA 基础上,集成了:
| 组件 | 作用 | 坑点 |
|---|---|---|
| SkyWalking | 链路追踪 | Agent 版本必须和 Spring Boot 匹配,否则启动失败 |
| Prometheus + Grafana | 指标监控 | Sentinel 指标需手动暴露 /actuator/sentinel |
| ELK | 日志收集 | Nacos 日志默认输出到 logs/,得挂载 volume |
特别提一句:Nacos 的持久化必须做!
默认 Nacos 是内存存储,重启就丢服务列表。生产必须连 MySQL:
-- 执行 nacos/conf/nacos-mysql.sql 初始化表
# application.properties
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://mysql:3306/nacos?charset=utf8mb4
db.user.0=nacos
db.password.0=xxx
😅 社死现场:有一次运维升级 Nacos 忘了配 DB,重启后所有服务“失联”,前端页面全部 502。我一边回滚,一边在 Slack 里打字:“兄弟们,今天午饭我请……”
总结:SCA 不是万能药,但用好了真香
经过两个月折腾,我们的微服务架构终于稳定跑在生产环境。QPS 提升了 3 倍,故障恢复时间从小时级降到分钟级。更重要的是,面试官再问我 SCA 实战经验,我能掏出一堆线上案例,而不是背八股文。
几点心得送给大家:
- 别迷信“全家桶”:SCA 提供的是工具,不是解决方案。你怎么用,决定了系统稳不稳。
- 配置即代码:Nacos 配置要纳入 Git 管理,每次变更可追溯。
- 压测必须做:Sentinel 规则、Seata 性能,不压测等于裸奔。
- 前端体验很重要:微服务不该增加前端负担,网关和 Mock 是润滑剂。
最后,感谢 GitHub Copilot。没有它,我可能还在手敲那些重复的 @FeignClient 和 @SentinelResource。虽然它偶尔会生成一些离谱代码(比如把 userId 写成 useId),但整体效率提升至少 30%。作为用了快两年的付费用户,我觉得这钱花得值。
哦对了,下周又要和产品经理 battle 新需求了。他说“能不能在下单时顺便预测用户明天早餐吃啥”……我准备直接甩给他一篇《机器学习与 Spring Cloud Alibaba 的边界》。
祝大家代码无 bug,线上不报警,前端不催接口,产品不改需求!

评论 0