Spring Cloud Alibaba 在我们小厂的落地血泪史
去年冬天,我还在为毕设焦头烂额的时候,怎么也没想到自己会卷入一场微服务架构的大改造。作为一个双非院校、靠自学摸爬滚打进入这家百人规模互联网公司的大二实习生,能参与核心系统的重构,说实话,既兴奋又慌得一批。
我们组主要负责公司内部的订单中台,之前是单体架构,代码臃肿得像泡面桶——层层嵌套、逻辑混乱。产品经理动不动就甩一句“这个需求很简单”,结果改完之后线上直接 502,运维大哥半夜打电话骂街。去年双11前两周,系统直接崩了半小时,老板震怒,CTO拍板:必须上微服务!
于是,Spring Cloud Alibaba(SCA)就成了我们的救命稻草。
为什么选 SCA?不是 Dubbo 吗?
说实话,一开始团队里有人力推 Dubbo。但考虑到我们后端主力是 Java,前端用 Vue,中间还有几个 Python 写的数据处理脚本要对接,Dubbo 的 RPC 调用对非 Java 系统不太友好。而 SCA 基于 Spring Cloud 生态,HTTP + JSON 的通信方式天然兼容 Python 客户端(比如用 requests 调个接口就行),资源复用成本低得多。
而且,我们公司用的是阿里云,Nacos、Sentinel、Seata 这些组件都能无缝对接云产品,省了自建注册中心和配置中心的麻烦。对我们这种没专职 SRE 的小团队来说,简直是天降甘霖。
注:别信网上说“SCA 只适合阿里系”,我们这种草台班子都跑稳了,说明它确实够接地气。
第一坑:Nacos 配置中心连不上
刚搭好环境那天,我信心满满地启动服务,结果控制台刷出一行红字:
com.alibaba.nacos.api.exception.NacosException: failed to req API:/nacos/v1/ns/instance after all servers([localhost:8848]) tried
当时我真的想砸电脑。查了半天,发现是 Docker 容器网络问题——本地开发用 Docker Compose 起 Nacos,但服务注册时用了 localhost,而容器内部访问不到宿主机的 localhost。
解决办法很简单,在 application.yml 里显式指定 Nacos 地址:
spring:
cloud:
nacos:
discovery:
server-addr: host.docker.internal:8848 # Mac/Windows 用这个
# Linux 用户可能需要改成宿主机 IP
config:
server-addr: host.docker.internal:8848
file-extension: yaml
不过生产环境我们直接部署在 ECS 上,就没这问题了。这里提醒大家:本地开发和生产环境网络拓扑差异巨大,别偷懒用默认配置!
配置管理:别再把数据库密码写死在代码里了!
以前我们项目里,application-prod.yml 直接明文写着数据库账号密码,还提交到了 Git。某次实习生误删了分支,恢复时不小心把配置文件发到群里,运维当场血压拉满。
现在全部迁移到 Nacos 配置中心,按环境隔离:
| Data ID | Group | 用途 |
|---|---|---|
| order-service-prod.yaml | DEFAULT_GROUP | 生产环境配置 |
| order-service-test.yaml | DEFAULT_GROUP | 测试环境配置 |
| common-db.yaml | SHARED_CONFIG | 共享数据库配置 |
关键配置示例:
# common-db.yaml(共享配置)
spring:
datasource:
url: jdbc:mysql://rm-xxxx.mysql.rds.aliyuncs.com:3306/order_db?useSSL=false
username: ${db.user}
password: ${db.pass}
然后在服务里通过 @RefreshScope 实现动态刷新:
@RestController
@RefreshScope
public class ConfigController {
@Value("${feature.enable-new-discount:false}")
private boolean enableNewDiscount;
@GetMapping("/config")
public String getConfig() {
return "新折扣功能开关: " + enableNewDiscount;
}
}
这样,运营同学临时要关掉某个促销活动,运维在 Nacos 控制台点一下就行,不用重启服务——再也不用求着运维大哥“加个班”。
服务熔断:Sentinel 救我狗命
上个月,上游支付系统突发高延迟,我们订单服务因为没做熔断,线程池被占满,整个服务雪崩。那晚我通宵排查,第二天顶着黑眼圈改代码。
引入 Sentinel 后,几行注解搞定:
@SentinelResource(
value = "createOrder",
blockHandler = "handleCreateOrderBlock",
fallback = "createOrderFallback"
)
public Order createOrder(OrderRequest request) {
// 调用库存、用户等下游服务
}
// 限流/熔断时触发
public Order handleCreateOrderBlock(OrderRequest request, BlockException ex) {
log.warn("创建订单被限流", ex);
throw new BusinessException("系统繁忙,请稍后再试");
}
// 业务异常 fallback
public Order createOrderFallback(OrderRequest request, Throwable t) {
log.error("创建订单失败", t);
return buildDefaultOrder();
}
在 Sentinel 控制台,我们设置了:
- QPS 阈值:200(根据压测结果)
- RT 阈值:500ms
- 熔断策略:慢调用比例 > 60% 持续 5 秒则熔断
上线后,即使支付系统挂了,订单服务也能快速失败,不影响用户浏览商品——用户体验提升明显,产品经理居然夸了我一次(虽然可能是客套)。
分布式事务:Seata 的取舍
最头疼的是分布式事务。订单创建涉及:扣库存、生成订单、发消息。要么全成功,要么全回滚。
我们评估了 Seata 的 AT 模式,但发现:
- 需要所有表有主键(我们有些历史表没主键)
- 全局锁影响性能
- 对 DBA 要求高(要配置 undo_log 表)
最后妥协方案:核心链路用可靠消息最终一致性。
流程如下:
- 订单服务本地事务插入订单 + 发送“预占库存”消息到 RocketMQ
- 库存服务消费消息,执行扣减,成功则回执
- 订单服务收到回执,更新订单状态;超时未收到则自动取消
虽然复杂度高了点,但避开了 Seata 的侵入性,也兼容我们已有的 Python 数据同步脚本(它们只认 MQ,不认 Seata)。
吐槽:Seata 文档写得跟天书一样,GitHub issue 里一堆人问“怎么集成 Spring Boot 3”,官方回复“等适配”。建议中小厂慎用,除非你有专职中间件团队。
资源优化:别让微服务变成“微浪费”
微服务拆分后,服务数量从 1 个暴涨到 12 个。每个服务都要 JVM、内存、连接池……资源消耗翻倍。
我们做了几件事:
- JVM 调优:堆内存从默认 1G 降到 512M,Young GC 时间从 200ms 降到 30ms
- 连接池精简:HikariCP 最大连接数从 20 改为 10,配合 Sentinel 限流,足够扛住峰值
- 日志瘦身:关闭 debug 日志,JSON 格式改用更紧凑的 layout
效果立竿见影:服务器成本月省 3000+(老板笑开花),P99 延迟从 1.2s 降到 400ms。
附上我们的基础资源配置参考:
| 组件 | CPU | 内存 | JVM 参数 |
|---|---|---|---|
| Nacos Server | 2C | 4G | -Xms2g -Xmx2g |
| Order Service | 1C | 1G | -Xms512m -Xmx512m -XX:+UseG1GC |
| Sentinel Dashboard | 1C | 1G | 默认即可 |
技术分享会上的反思
上周五晚上,我在公司内部搞了场技术分享,主题就是《SCA 在小厂的生存指南》。没想到来了二十多人,连测试组的同事都来听(估计是想看看我们又埋了什么坑)。
分享时我说:“微服务不是银弹,SCA 也不是万能胶水。它解决的是‘协作复杂度’,但带来了‘运维复杂度’。如果你的团队连 CI/CD 都没跑通,别急着上微服务。”
底下有人问:“你们为啥不用 Kubernetes?”
我苦笑:“兄弟,我们连专职运维都没有,K8s 对我们来说就像 F1 赛车——性能猛,但不会修啊!”
其实吧,作为学生党,能参与这种架构升级,已经是天大的运气。很多同学还在刷 LeetCode,我已经在处理线上熔断配置了。虽然经常加班到凌晨,但每次看到监控图上平稳的曲线,心里还是有点小骄傲。
最后几句真心话
- 别为了用新技术而用:SCA 适合已有 Spring Boot 基础、需要快速落地微服务的团队。纯 Python 项目?老老实实用 gRPC + Consul 吧。
- 安全第一:Nacos 默认没开鉴权!我们差点被扫到配置泄露。生产环境务必开启认证:
nacos.core.auth.enabled=true - 文档比源码重要:SCA 版本迭代快,一定要看对应版本的官方文档。别信 CSDN 上两年前的教程,坑死你。
- 留点退路:我们保留了单体模式的开关,万一微服务崩了,还能一键切回旧架构——这是被线上事故教育出来的智慧。
写这篇文章时,窗外下着雨,宿舍网速卡得要死。但想到自己写的代码正在支撑公司每天百万级的订单,突然觉得,双非又怎样?自学又怎样?只要肯折腾,草根也能玩转云原生。
下次技术分享,我打算讲讲 Rust 怎么和 Java 微服务混搭——听说用 Rust 写个高性能的 sidecar,能省不少资源。不过那是后话了。
(全文约 2930 字,纯手打,无 AI 味,如有雷同,算我抄你 😏)

评论 0