Spring Cloud从零开始:微服务入门指南

独立开发练习生
2025-06-17 22:27
阅读 558

引子:为什么我决定写这篇文章?

引子:为什么我决定写这篇文章?

还记得去年刚接手那个项目的时候,我也是个刚接触Spring Cloud不久的新手。彼时我们的团队正在做一个企业级的订单管理系统改造项目,原来的单体架构已经撑不住每天上万次的请求,系统频繁出现性能瓶颈、部署繁琐、扩展困难等问题。

为了解决这些痛点,我们决定尝试将系统拆分为多个微服务,并逐步引入Spring Cloud生态来支撑整个架构转型。刚开始,我也和很多开发同学一样,面对一堆陌生的组件名词(Eureka、Feign、Hystrix、Zuul、Config)一头雾水,看着文档也不知道从哪下手,踩了不少坑。

后来在项目过程中,我和团队一边实践一边摸索总结出了一套相对完整的微服务架构体系,不仅解决了系统的高可用和可扩展性问题,也让后续的功能迭代变得高效起来。现在回想起来,那些“摸着石头过河”的日子虽然辛苦,但也让我对Spring Cloud有了更深的理解。

所以我想把我这一路走来的经验整理成一篇接地气、有实战背景的文章,给那些准备或者正要开始学习Spring Cloud的朋友一些参考。如果你是刚入行后端开发的同学,或者已经在使用Spring但想尝试微服务的开发者,希望这篇文章能帮到你。


项目背景:一次典型的架构升级需求

项目背景:一次典型的架构升级需求

项目的前身是一个典型的单体应用,用的是Spring Boot + MyBatis + MySQL的老一套,前后端分离,前端是Vue.js。

随着业务增长,系统出现了几个明显的问题:

  1. 部署效率低:每次上线都要重启整个服务,哪怕只是一个很小的修改。
  2. 代码臃肿难维护:所有模块混在一起,一个类动不动就上千行,改bug风险极大。
  3. 性能瓶颈:高峰期经常出现接口响应慢,甚至超时,数据库连接池被打满。
  4. 难以扩展新功能:比如加一个支付模块,需要改动原系统,牵一发动全身。

于是公司决定进行架构重构,目标很明确:

  • 将原有模块按职责划分,拆成多个独立服务
  • 实现服务之间的解耦与通信标准化
  • 提升系统整体的可伸缩性和稳定性
  • 支持未来横向扩展和快速迭代

考虑到我们团队对Java生态比较熟悉,加上Spring Cloud社区活跃度很高,最终选型定在了Spring Cloud Alibaba + Nacos + Sentinel 等一系列组件组合上(后面我会讲具体选型原因)。


挑战来了:第一次接触微服务带来的阵痛

挑战来了:第一次接触微服务带来的阵痛

说实话,在刚开始拆分的时候,我完全没意识到会遇到这么多问题。比如说:

  • 微服务之间怎么调用?传统HTTP API可以吗?
  • 服务注册中心选哪个?Eureka还是Consul还是Nacos?
  • 多个服务共享配置怎么办?有没有统一管理方式?
  • 服务挂了怎么办?如何实现自动熔断和降级?
  • 日志怎么收集?不同服务的日志分散在各个节点上……

还有一个更现实的问题——团队内部技术储备参差不齐,有些小伙伴甚至连Spring Boot都没写过完整项目。而我们的时间又非常紧,领导要求两个月内完成初步拆分并上线试运行。

那段时间真是焦头烂额,晚上回家还要翻文档、看视频、调试demo。有一次为了测试一个Feign调用的问题,折腾到凌晨三点才搞清楚是因为负载均衡器Ribbon配置不对导致找不到服务实例。

但也是在那一阶段,我逐渐理清了微服务的核心逻辑和Spring Cloud各组件的角色分工。


技术方案:我们是怎么一步一步搭建起来的

我们采用的Spring Cloud生态核心组件如下:

组件 功能作用
Spring Cloud Alibaba 选择它的主要原因是国内生态支持好,文档也更容易理解
Nacos 服务注册发现 + 配置中心
Sentinel 流控、熔断降级
Feign/OpenFeign 声明式服务调用
Gateway 统一API网关
Seata 分布式事务(后期引入)
Sleuth+Zipkin 分布式链路追踪

接下来我以我们订单服务为例,讲讲我们是怎么一步步构建起微服务体系的。

第一步:服务拆分设计

我们先对原有系统做了领域模型梳理,把原有的代码按业务逻辑划分为几个核心服务:

  • 用户服务:负责处理用户相关操作,如登录、基本信息等
  • 订单服务:订单创建、状态变更、查询等
  • 库存服务:商品库存管理、扣减等
  • 支付服务:对接第三方支付渠道,处理支付回调等

这四个服务构成了我们最初的微服务架构雏形。每个服务都是独立部署、独立数据库,通过Restful API进行通信。

第二步:引入Nacos做服务注册与配置中心

最初我们考虑用Eureka,但发现它在国内文档资源不够丰富,而且Netflix官方已经不再主推。最终选择了阿里开源的Nacos,既可以做注册中心,也可以作为配置中心,配合Spring Cloud整合也很方便。

pom.xml中添加如下依赖:

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

配置文件application.yml里加上注册信息:

server:
  port: 8081
spring:
  application:
    name: order-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 # Nacos服务地址

启动后就能自动注册到Nacos控制台看到服务列表了。

第三步:服务间调用 —— Feign + 负载均衡

一开始我们用的是原始的RestTemplate去发HTTP请求调用其他服务,后来发现代码太丑了,也不容易维护。

于是改用了OpenFeign,结合Ribbon做客户端负载均衡。

例如订单服务要调用用户服务获取用户信息:

@FeignClient(name = "user-service")
public interface UserServiceClient {
    
    @GetMapping("/users/{userId}")
    User getUserById(@PathVariable Long userId);
}

这样就可以像调用本地方法一样调用远程服务,Spring底层会自动完成服务发现、负载均衡等过程。

不过这里有个小坑:默认情况下Feign不支持GET请求带POJO参数,需要手动启用配置:

feign:
  client:
    config:
      default:
        http-method-overriding: true

第四步:引入Sentinel做流控与熔断

服务多了以后,如果其中一个服务宕机或者响应变慢,可能会导致整个系统雪崩。所以我们决定引入Sentinel来做限流和熔断。

集成非常简单,在服务中引入依赖:

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

然后配置Sentinel Dashboard地址:

spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080

通过Sentinel控制台可以很方便地设置:

  • 接口级别的QPS限制
  • 线程数限制
  • 出错率触发熔断机制

举个例子:订单创建接口每秒只能处理100个请求,超过则直接返回错误提示,避免压垮下游服务。

第五步:网关聚合路由 —— Gateway初体验

为了统一API入口,我们使用了Spring Cloud Gateway作为网关,替代了之前的Zuul。

Gateway的优点很明显:轻量、非阻塞、兼容WebFlux,性能比Zuul更好。

比如在网关服务中定义一个简单的路由规则:

spring:
  cloud:
    gateway:
      routes:
        - id: order-route
          uri: lb://order-service
          predicates:
            - Path=/api/order/**
          filters:
            - StripPrefix=1

这样所有以/api/order/xxx开头的请求都会被转发到order-service服务,且去掉第一层路径。

同时我们也在网关中集成了权限验证、限流等功能,进一步提升安全性和可控性。


实战踩坑记录:那些让人抓狂的瞬间

系统架构设计图-1

在这次重构过程中,踩过的坑真的不少,这里列几个印象深刻的给大家提个醒。

❌ 问题一:服务注册不到Nacos,报错“Connection refused”

场景复现: 服务启动后,日志里一直报错说连接不上Nacos Server,控制台看不到服务注册成功。

排查思路

  • 检查Nacos服务是否正常运行(可以用浏览器访问 http://localhost:8848
  • 检查application.yml中的server-addr配置是否正确,尤其是端口号
  • 查看防火墙是否放行对应端口

解决办法: 最后发现是Docker环境下Nacos服务没有暴露8848端口,补上 -p 8848:8848 参数重新启动即可。

❌ 问题二:Feign调用时出现“LoadBalancerException”

场景复现: 两个服务都能正常注册到Nacos,但在Feign调用时报错找不到服务实例,或实例为空。

排查思路

  • 是否引入了正确的Feign starter包?
  • 是否开启了Feign和负载均衡注解?

解决办法: 在启动类上加上 @EnableFeignClients,并在配置类中显式注入 LoadBalancerClient bean,确保Feign调用能正常使用负载均衡策略。

❌ 问题三:Sentinel仪表盘无法查看实时数据

场景复现: Sentinel控制台可以正常访问,但打开某个服务的应用监控页面时显示“无可用节点”。

排查思路: 检查服务是否启用了Sentinel自动上报功能:

  • 服务中是否有引入正确的starter
  • 是否配置了dashboard地址
  • 是否打开了客户端心跳上报(默认是关闭的)

解决办法: 在配置文件中增加:

spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080
        port: 8719 # Sentinel默认使用的端口

然后重启服务,仪表盘就会自动连接上并展示数据了。


成果与收获:重构后的变化有多大?

三个月后,我们的系统完成了基础的微服务拆分,顺利上线稳定运行至今,效果非常明显:

  • 部署效率提升:单个服务可以独立打包部署,不需要再影响全局
  • 故障隔离能力增强:某个服务挂了不会波及整个系统
  • 可扩展性强:新增功能只需要新建一个服务模块,接入现有体系即可
  • 运维成本降低:配合Prometheus + Grafana做了监控告警,定位问题快很多

更重要的是,团队整体的技术能力得到了很大提升。我们开始有意识地讨论服务粒度、数据库分库分表、接口幂等、分布式事务等更高阶的话题,而不是仅仅关注CRUD写了几行代码。


我的几点建议:给想要学微服务的同学

缓存策略对比-2

如果你是刚接触微服务的新人,我真诚地给你以下几点建议:

  1. 别急着全栈搭建:先掌握Spring Boot的基本开发流程,再去学Spring Cloud。否则你会像我在最开始那样,连服务都注册不上去都不知道为啥。

  2. 多动手,少空谈:网上有很多教程教你搭环境,但真正重要的是理解背后的原理。比如Feign底层是怎么封装HTTP调用的?为什么加了一个注解就能自动注册到Nacos?

  3. 从实际项目出发:找一个小项目练手,哪怕只是拆分成两个服务,自己模拟调用、测试、部署一遍。真实场景会让你学到更多。

  4. 善用可视化工具:比如Nacos控制台、Sentinel仪表盘、SkyWalking链路追踪平台,这些工具在日常开发和排障中非常重要。

  5. 不要过度设计:刚拆分的时候,没必要上来就把服务拆得特别细。先把大的业务模块拎出来,后续再根据实际发展慢慢优化。

  6. 做好技术选型评估:Spring Cloud有很多组件可以选择,比如服务注册除了Nacos还可以用Consul、ETCD,你要根据自己的团队能力和项目实际情况做出判断。


写在最后:技术这条路,贵在坚持和热爱

回首这段微服务的旅程,其实并不轻松。有时候也会质疑自己是不是走错了方向,是不是应该继续维护原来的单体结构。但每当看到系统越来越稳定,团队协作越来越顺畅,我就觉得这一切都很值得。

微服务不是银弹,但它确实为我们提供了更好的架构可能性。Spring Cloud作为一个成熟的生态,已经成为当前企业级后端开发的标配之一。

我希望这篇文章不仅仅是一份技术指南,更是一种经验分享。它来自真实的项目,带着我的思考和成长,也希望你们在阅读的过程中,能感受到一些温度。

愿你在学习Spring Cloud的路上少走弯路,不断进步,写出更优雅、更健壮的代码。

评论 0

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