从踩坑到得心应手:我的 Spring Cloud Alibaba 生产实践总结

技术慢生活
2025-06-16 09:32
阅读 647

开篇

开篇

大家好,我是某互联网公司的一名后端开发工程师,主要负责中后台服务架构设计与核心功能开发。去年我们团队启动了一个新项目——一个面向企业客户的 SaaS 管理平台。这个平台需要支持高并发、弹性扩展、服务治理等能力,因此我们决定采用 Spring Cloud Alibaba(以下简称 SCNA)作为微服务架构的基础。

刚开始大家都对这套技术栈充满期待,但在实际落地过程中,也踩了不少坑。这篇文章我想以第一人称的方式,结合真实项目经历,分享我们在使用 SCNA 过程中的实战经验、遇到的挑战及应对策略,希望能帮助刚上手 SCNA 的小伙伴们少走一些弯路。


项目背景

项目背景

项目的初期阶段,我们的需求比较明确:

  • 多个业务模块解耦
  • 支持灰度发布和流量控制
  • 提供服务注册发现、配置管理、链路追踪等功能
  • 数据库分库分表,支持水平扩容
  • 部署在阿里云 Kubernetes 上

基于这些要求,我们选择了 Spring Cloud Alibaba 套件,主要包括:

  • Nacos(服务注册 + 配置中心)
  • Sentinel(限流降级)
  • Seata(分布式事务)
  • RocketMQ(异步消息)
  • Dubbo(RPC 框架)

接下来是我在开发过程中的真实经历,有些地方甚至让我们一度怀疑人生 😅。


第一坑:Nacos 集群部署和持久化问题

背景描述

最初我们在测试环境用的是单机版 Nacos,本地跑着很顺。但到了生产准备阶段,我们要部署集群时却发现官方文档中关于集群配置的说法有点模糊。

我们一开始按照网上的教程搭建了一个简单的伪集群(同一机器不同端口),结果压力测试还没开始,服务注册就开始出问题了。

遇到的问题

  • 服务注册偶尔失败
  • 配置更新不及时,客户端收不到推送
  • 集群节点间状态不一致

后来我们发现,伪集群模式并不适合生产环境,而且默认配置下,Nacos 使用的是内置的 derby 数据库,重启之后配置数据就丢失了!

解决方法

  1. 独立部署三台物理节点:每台机器单独运行 Nacos Server,确保 IP 可达。
  2. 配置 MySQL 持久化
    • 导入 Nacos 官方提供的 SQL 文件到 MySQL 中
    • application.properties 中配置数据库信息
  3. 使用集群配置文件: 修改 cluster.conf,写入三台机器的 IP 和通信端口,保证相互之间能正常通信
ip1:8848
ip2:8848
ip3:8848

这样部署完成后,我们做了一次全链路压测,Nacos 再没掉过链子。

小插曲

有一次我们误删了一个 namespace 的数据,结果整个配置中心瞬间“瘫痪”,多个服务直接失联。这件事让我们意识到:

“配置中心不是玩具,它的每一个操作都可能牵一发动全身。”

从此我们开启了 Nacos 的审计日志,并建立了定期备份机制。


第二坑:Sentinel 与 OpenFeign 的兼容问题

问题描述

我们用了 Sentinel 来做限流降级,本来一切正常,但在引入 OpenFeign 后,出现了奇怪的现象:某些接口虽然被限流了,但是并没有走 fallback 方法,而是直接抛异常,前端显示 500 错误。

这显然不符合预期。

分析过程

通过调试发现,Sentinel 的降级规则作用在 Controller 层是没有问题的,但是在调用 FeignClient 接口时,降级逻辑就没有生效。

原来我们漏掉了对 Feign 的适配器:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

但这个依赖只能处理 Controller 层,默认不拦截 Feign 请求。

于是我们加上了专门针对 Feign 的 Sentinel 适配包:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel-feign</artifactId>
</dependency>

然后在配置中开启 Feign 对 Sentinel 的支持:

feign:
  sentinel:
    enabled: true

再配合自定义的 FallbackFactory 实现,终于让 FeignClient 的限流和熔断有了保障。

感悟

这次经历让我明白了两个道理:

  1. 微服务之间的调用链越复杂,越要关注“容错”的一致性;
  2. 有时候不是框架不靠谱,只是你没用对姿势 😂。

第三坑:Seata 的分布式事务卡顿问题

我们有一个核心流程涉及到订单创建、库存扣减、用户积分更新等多个服务操作,天然需要分布式事务的支持。

当时我们选择了 Seata(AT 模式),因为它是侵入性最小的一种方式,只需加一个注解即可开启全局事务。

出现的问题

上线后不久,我们发现每次执行这个流程时响应时间都变长了许多,甚至有时候会超时。初步排查发现 Seata 的事务协调器 TC 有大量锁竞争,导致性能下降严重。

调查结果

进一步分析发现以下几个原因:

  1. 我们的数据库隔离级别为 RR(可重复读),而 Seata 默认使用 RC(读已提交)进行事务控制,存在冲突;
  2. 全局事务开启后,Seata 会自动代理所有涉及事务的数据源,造成额外性能开销;
  3. 业务流程中有些操作其实不需要严格保证强一致性。

解决方案

  1. 调整事务边界:将真正需要强一致性的操作保留在全局事务内,其他非关键操作改为最终一致;
  2. 升级数据库隔离级别:统一调整为 RC,避免事务冲突;
  3. 优化数据访问频率:合并不必要的多次 DB 操作,减少事务粒度;
  4. 增加 TC 集群节点:由原来的单节点扩展为双节点,提高吞吐量。

最终效果

经过上述优化,接口平均响应时间从原来的 1.2s 缩短至 350ms,TPS 提升了近 3 倍。


数据库设计的小故事

在这个项目里,我们的数据库选型是 MySQL 分库分表 + MyCat 中间件。

早期为了方便,每个服务都有自己独立的数据库实例,但随着业务发展,跨服务查询越来越多,维护成本越来越高。

于是我们进行了一次架构调整:

  • 所有核心服务共享一套分库分表结构;
  • 表设计上做到“按租户 ID”分片;
  • 引入影子表做归档和冷热分离;
  • 接口设计方面,尽量避免跨库 Join 操作;

这种变化带来的好处是非常明显的:

  • 查询效率提升
  • 数据一致性更好
  • 易于横向扩展

不过也要注意一点:数据库的设计一定要提前规划,不要等到后期再来重构!


运维层面的经验分享

负载均衡配置-1

SCNA 并不是一个“拿来即用”的东西,它背后还有很多细节需要运维去支撑。

比如我们在线上环境中做了以下几件事:

  • 使用 Prometheus + Grafana 监控整个微服务生态系统的健康状况;
  • 结合 ELK(Elasticsearch、Logstash、Kibana)做日志集中收集;
  • 使用 Arthas 分析线上堆栈情况,快速定位 CPU 或内存瓶颈;
  • 所有服务接入 SkyWalking,实现完整的调用链追踪;
  • 自动化流水线使用 Jenkins + Harbor + K8s Helm Chart 发布;

这些工具极大地提升了我们排查问题的速度,也让我们的系统具备了更好的可观测性。


总结与建议

回顾整个项目的过程,我有几点想送给各位朋友:

  1. 技术选型要慎重:Spring Cloud Alibaba 是个很好的技术栈,但它更适合有一定中间件基础的团队;
  2. 不要迷信配置:多看日志,多调代码,配置不对往往就是各种诡异现象;
  3. 微服务不是银弹:拆分服务要有清晰的边界,别把复杂度搞反了;
  4. 监控永远是最先要做的事情:没有监控的服务就像没有刹车的车,跑得越快越危险;
  5. 文档不能代替经验:很多问题在文档里不一定写清楚,多参考社区资料和 GitHub issue;
  6. 保持敬畏之心:每一次上线都要认真对待,哪怕只是一个配置项的改动。

写在最后

如果你现在正在使用或打算使用 Spring Cloud Alibaba,希望这篇文章能带来一点点启发。我也还在学习的路上,欢迎大家交流讨论。

最后送大家一句话:

技术的深度,取决于你踩过的坑有多少。

祝各位编码愉快,永无 bug 💪。


如需获取本文提到的技术栈示例项目、配置模板或脚本,请留言告诉我,我可以整理一份分享出去。

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝