Spring Cloud Alibaba 在生产环境中的实战踩坑与优化
凌晨两点,娃终于睡了。我轻手轻脚地关上儿童房的门,坐回书桌前,打开 IDE——这才是我真正的“第二人生”开始的时间。作为一个坐标杭州、白天带娃晚上写代码的全职妈妈,深夜是我唯一能专注 coding 的黄金时段。最近半年,我接了一个外包项目,帮一家做区块链资产登记的创业公司重构他们的微服务架构。说白了,就是把他们原来一堆乱七八糟的 Spring Boot 单体应用,用 Spring Cloud Alibaba 拆成云原生友好的微服务。今天就来聊聊这段“边哄睡娃边调 Nacos 配置”的血泪史。
为什么选 Spring Cloud Alibaba?
先说背景。这家公司业务听起来挺高大上:用区块链做不动产数字权证登记,底层是联盟链(Hyperledger Fabric),但上层业务系统全是 Java 写的。他们原来的架构是典型的“快速上线型”——五个 Spring Boot 应用直接连同一个 MySQL,服务之间靠硬编码 IP 调用,配置全写在 application.yml 里。去年双11期间搞了个促销活动,用户量一上来,整个系统直接雪崩,运维半夜打电话给我:“姐,又挂了,救救孩子吧!”
老板一看不行,得上微服务。但他们技术栈全是 Java,团队没人懂 Istio 或 Consul,而阿里系出身的 CTO 一句话定调:“用 Spring Cloud Alibaba,文档多,社区熟,杭州这边人才也好找。”
于是,我这个“自由职业+带娃”的边缘人,被临时拉进了这个“救火项目”。
从 Nacos 开始:配置中心不是万能的
第一件事就是引入 Nacos 做注册中心和配置中心。本地跑起来贼快,demo 五分钟搞定。结果一上测试环境,问题就来了。
他们的区块链服务(叫 AssetChainService)需要频繁读取链上状态,每次启动都要加载几百个智能合约地址。这些地址不能写死,得动态配置。于是我把它挪到 Nacos 配置中心,用 @RefreshScope 动态刷新。
# nacos 配置 dataId: asset-chain-service-prod.yaml
blockchain:
contract:
addresses:
- "0xAbc..."
- "0xDef..."
结果某天产品经理改了个地址,点了“发布”,服务没重启,但 @RefreshScope 没生效!查了半天才发现:Nacos 的配置变更推送依赖长轮询,如果服务所在机器网络抖动,可能丢事件。更坑的是,@RefreshScope 只对被代理的 Bean 生效,如果你的配置是注入到非 Spring 管理的对象里(比如你手写了某个工具类单例),那根本不会刷新。
后来我们做了两件事:
- 所有关键配置变更后,手动触发一次
/actuator/refresh - 对于区块链这种强一致性场景,干脆放弃动态刷新,改成“配置变更 + 服务滚动重启”——虽然笨,但稳。
吐槽一句:产品经理总以为“改个配置立马生效”是天经地义,殊不知背后是无数程序员在给缓存、连接池、线程安全擦屁股。
Sentinel 流控:别让一个接口拖垮全家
上生产后最怕什么?雪崩。尤其是他们有个 /api/v1/query-asset 接口,前端疯狂轮询,QPS 能飙到 5000+。之前单体架构时数据库直接被打爆。
这次我们上了 Sentinel,基于 QPS 做流控。但一开始配错了策略:
// 错误示范:用资源名硬编码
SphU.entry("queryAssetApi");
结果发现 Sentinel 控制台里一堆 com.xxx.service.AssetService$$Lambda$... 这种鬼名字,根本没法管理。后来改成用 @SentinelResource 注解,并指定 value 为有意义的资源名:
@Sentinel_resource(value = "asset_query", blockHandler = "handleBlock")
public AssetInfo queryAsset(String id) {
// 调用区块链 SDK
}
然后在 Sentinel Dashboard 里配规则:
- QPS > 300 时直接拒绝
- 异常比例 > 20% 时熔断 30 秒
但新问题来了:区块链 SDK 调用超时默认是 10 秒!这意味着如果链节点卡住,一个请求占着线程 10 秒,Tomcat 线程池很快耗尽。于是我们在 FeignClient 层加了超时控制:
feign:
client:
config:
default:
connectTimeout: 2000
readTimeout: 3000
同时,Sentinel 的熔断规则也加上了慢调用比例(RT > 2s 的请求占比 > 40% 就熔断)。这才算稳住。
Seata 分布式事务:区块链+数据库的最终一致性
最头疼的是数据一致性。用户在前端提交资产登记,要同时:
- 写 MySQL(存用户信息、申请记录)
- 调区块链(发起链上交易)
这两个操作必须“要么都成功,要么都失败”。但区块链交易是异步的——你发了交易,只是拿到 txId,真正上链要等共识完成(可能几秒到几十秒)。
我们一开始想用 Seata 的 AT 模式,结果发现 Seata 不支持区块链这种非 JDBC 资源。AT 模式依赖数据库 undo log,而区块链根本没有“回滚”概念。
最后妥协方案:放弃强一致性,采用“本地消息表 + 补偿机制”。
流程如下:
- 用户提交 → 事务内写 MySQL(状态=“待上链”)+ 写消息表(msg_status=“pending”)
- 定时任务扫描消息表,调区块链 SDK 发交易
- 区块链回调服务收到上链成功通知 → 更新 MySQL 状态为“已上链”
- 如果超时未上链(比如 5 分钟),触发补偿:标记为“失败”,通知人工介入
虽然不完美,但在业务可接受范围内。毕竟不动产登记也不是秒级到账的场景。
这里插一句:很多教程吹 Seata 多牛,但现实是,90% 的分布式事务场景,最终都走向了最终一致性。别被“分布式事务”四个字唬住,先问业务能不能等。
性能优化:K8s + SCA 的隐藏坑
他们部署在阿里云 ACK(Kubernetes 服务),一开始我们直接把 SCA 应用打包成 Docker 镜像扔上去。结果发现 Nacos 注册的服务 IP 是 Pod IP,而 Pod 重建后 IP 变了,其他服务通过旧 IP 调用直接 Connection Refused。
查文档才发现:Spring Cloud Alibaba 默认使用 hostName 注册,但如果你没配 spring.cloud.inetutils.preferred-networks,它可能注册成内网 IP 或 Docker 网桥 IP。
解决方案是在 deployment.yaml 里显式指定:
env:
- name: SPRING_CLOUD_INETUTILS_PREFERRED_NETWORKS
value: "10.244" # Pod CIDR 网段
同时,在 Nacos 客户端配置里开启健康检查:
spring:
cloud:
nacos:
discovery:
ip: ${POD_IP} # 从 Downward API 注入
heart-beat-interval: 5
heart-beat-timeout: 15
另外,区块链 SDK 初始化很重(要加载 TLS 证书、连接 Peer 节点),每次服务启动都要 10 秒。我们把它做成 Singleton Bean,并加了懒加载:
@Component
@Lazy
public class FabricClient {
// 初始化逻辑
}
这样冷启动时间从 15s 降到 5s,HPA(水平扩缩容)时不至于因为启动慢被反复 kill。
对比表格:SCA vs 原生 Spring Cloud
| 能力 | Spring Cloud Alibaba | Spring Cloud Netflix |
|---|---|---|
| 注册中心 | Nacos(AP + CP 切换) | Eureka(纯 AP) |
| 配置中心 | Nacos(支持灰度、监听) | Spring Cloud Config(需 Git + Bus) |
| 限流熔断 | Sentinel(实时监控 + 热点参数) | Hystrix(已停更) |
| 分布式事务 | Seata(AT/TCC/Saga) | 无官方方案 |
| 国产化支持 | 阿里云深度集成,中文文档全 | 社区维护,文档英文为主 |
| 学习曲线 | 对阿里生态友好,杭州岗位多 | Netflix 组件逐渐淘汰 |
对我们这种小团队来说,SCA 最大的优势不是技术多牛,而是省事。Nacos 一个组件干两件事(注册+配置),Sentinel 控制台开箱即用,Seata 虽然复杂但至少有个参考实现。不像原生 Spring Cloud,你要自己搭 Config Server、Eureka、Hystrix Dashboard、Zipkin……光运维成本就能劝退三人团队。
写在最后:妈妈程序员的深夜感悟
上周五晚上,我正调试 Seata 的 undo log,娃突然发烧到 39 度。一边用物理降温贴敷额头,一边远程连服务器看日志,那一刻真的想砸电脑。但第二天早上,看到监控图表上平稳的 QPS 曲线,又觉得值了。
Spring Cloud Alibaba 不是银弹,但它确实让中小团队能用较低成本拥抱微服务。尤其在杭州,阿里网易系出来的工程师对这套技术栈非常熟悉,招聘也方便。如果你也在做 Java 微服务,又不想折腾 Consul + Envoy + Linkerd 那一套,SCA 是个务实的选择。
至于区块链?说实话,在这个项目里它更像是个“合规性装饰品”。真正扛流量的还是 MySQL + Redis + SCA 这套老组合。技术选型永远要服务于业务,别被 buzzword 带偏了节奏。
好了,娃醒了,又该去冲奶粉了。代码可以晚点再写,但孩子的成长只有一次。共勉,各位在深夜敲键盘的同行们。

评论 0