Spring Cloud从零开始:一个五年后端工程师的实战笔记

徐华_技术
2025-06-22 22:29
阅读 313

引言:微服务不是银弹,但它是现代架构的标配

我在五年前刚接触Spring Cloud的时候,它还是Spring Boot刚火起来时的“附属品”。而现在,微服务几乎成了中大型项目的标配。作为后端工程师,我经历过单体应用的痛苦——部署慢、修改影响大、版本管理复杂。当公司决定要将原来的ERP系统拆分重构为微服务架构时,我几乎是“被推上前线”的。

说实话,刚开始我是抗拒的。因为我知道这意味着需要重新设计架构、引入新工具、学习一堆框架组件。更重要的是,团队里没有一个人有实际的Spring Cloud项目经验。

但我很快意识到,这是一次难得的机会:我可以从0开始实践Spring Cloud生态,真正理解其核心理念和落地细节。现在回过头来看,那些踩过的坑、掉过的陷阱、深夜调试的日志,都变成了最宝贵的经验。

今天,我就以第一人称的角度,带你一起从零开始构建Spring Cloud微服务系统,聊聊我们在真实项目中的思考、决策与实现。


项目背景:为什么选择Spring Cloud?

项目背景:为什么选择Spring Cloud?

我们当时负责的是一家传统制造业企业的ERP系统改造。原来是一个基于JSP + Struts + Hibernate的老旧单体应用,已经运行了七八年,代码臃肿、耦合严重,每次上线都像在走钢丝。

业务需求不断增长,开发效率却持续下降。技术上,我们需要解决几个关键问题:

  • 模块之间高度耦合,一个小功能改动容易引发连锁反应
  • 系统负载不均衡,有些模块并发量高,有些模块资源浪费严重
  • 扩展性差,新需求无法快速迭代上线
  • 技术栈老旧,团队成员流失严重

于是我们决定尝试微服务化改造,使用Spring Cloud作为技术选型的核心。


初期挑战:从哪里下手?

数据流转过程-1

初期挑战:从哪里下手?

第一个问题就来了:怎么拆?

我们尝试按照业务领域划分微服务,比如订单服务、库存服务、用户服务等。但现实是残酷的:

  • 原来的数据库是单库多表,拆成多个数据库怎么办?
  • 各个服务之间的依赖关系错综复杂,接口调用如何管理?
  • 跨服务事务如何处理?(比如下单减库存这种场景)
  • 如何保证服务之间的通信可靠性和可观测性?

我们当时也走过弯路。比如一开始只用了Spring Boot搭建了几个独立的服务,但没有任何注册发现机制,服务配置写死在每个应用里,结果就是运维极其麻烦,改一个IP得重启所有服务。

后来我们意识到:必须有一套完整的微服务治理体系,不能只靠Spring Boot。


技术选型与方案设计:Spring Cloud全家桶上手

技术选型与方案设计:Spring Cloud全家桶上手

我们最后确定的技术栈如下:

组件 用途
Spring Boot 2.7.x 快速构建服务基础
Spring Cloud 2021.x 微服务核心组件
Nacos 服务注册与发现、配置中心
OpenFeign & Ribbon 服务间通信
Gateway API网关
Sentinel 流量控制、熔断降级
Seata 分布式事务
Zipkin / SkyWalking 链路追踪
RocketMQ 异步消息队列

📌 Tips:Nacos现在已经是国产开源明星项目,社区活跃度很高,而且兼容性好;而Gateway相比Zuul更轻量高效,已经成为主流API网关的选择之一。

接下来,我将分享我们的具体实现思路和技术细节。


实战演练:一步步构建你的第一个Spring Cloud微服务系统

数据流转过程-2

第一步:搭建注册中心(使用Nacos)

首先安装Nacos Server(推荐用Docker):

docker run -d \
-e MODE=standalone \
-p 8848:8848 \
--name nacos nacos/nacos-server

访问 http://localhost:8848/nacos 即可看到控制台,默认账号密码均为 nacos

然后创建一个Spring Boot项目,并添加Nacos客户端依赖:

<!-- 在pom.xml中添加 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <version>2021.0.5.0</version>
</dependency>

并在 application.yml 中配置:

server:
  port: 8080

spring:
  application:
    name: user-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848

management:
  endpoints:
    web:
      exposure:
        include: "*"

启动类加上注解:

@EnableDiscoveryClient
@SpringBootApplication
public class UserServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }
}

这样你就有了一个注册到Nacos的服务。


第二步:服务间调用(OpenFeign + LoadBalancer)

我们有两个服务:user-service 和 order-service,order-service 需要调用 user-service 的用户信息接口。

在order-service中添加Feign依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

定义Feign Client:

@FeignClient(name = "user-service")
public interface UserFeignClient {

    @GetMapping("/user/{id}")
    ResponseEntity<UserDTO> getUserById(@PathVariable Long id);
}

Feign会自动集成Ribbon,实现客户端负载均衡。

需要注意:Feign 默认使用 JDK 原生的 URLConnection 发送 HTTP 请求,性能不高。我们后来换成了OkHttp并启用连接池:

feign:
  client:
    config:
      default:
        http:
          connect-timeout: 3s
          read-timeout: 5s
  okhttp:
    enabled: true

第三步:统一API网关(Spring Cloud Gateway)

引入Gateway依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

配置路由规则:

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

这样 /api/user/123 就会被转发到 user-service 的 /user/123 接口上。


第四步:分布式配置管理(Nacos Config)

创建 bootstrap.yml

spring:
  application:
    name: user-service
  cloud:
    nacos:
      config:
        server-addr: localhost:8848
        file-extension: yaml
        namespace: your-namespace-id
        extension-configs:
          - data-id: user-service.yaml
            group: DEFAULT_GROUP
            refresh: true

在Nacos控制台创建一个data-id为 user-service.yaml 的配置项,内容即可动态刷新而无需重启服务。


第五步:流量防护(Sentinel)

引入依赖:

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

启动Sentinel Dashboard:

docker run --name sentinel-dashboard -p 8858:8858 -d bladex/sentinel-dashboard

在Nacos中配置流控规则(略)。也可以通过Dashboard界面手动配置实时规则。

我们还实现了自定义限流异常处理器:

@Component
public class CustomBlockHandler implements BlockExceptionHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
        response.setStatus(429);
        response.getWriter().write("Too many requests.");
    }
}

第六步:链路追踪(SkyWalking)

为了实现全链路跟踪,我们选择了SkyWalking。

安装SkyWalking OAP和UI(建议使用Docker):

docker run --name oap -d -e COLLECTOR_BACKEND_SERVICES=127.0.0.1:11800 -p 11800:11800 -p 12800:12800 apache/skywalking-oap-server
docker run --name ui -d -p 8080:8080 -e SW_HOST=127.0.0.1 apache/skywalking-ui

然后在每个微服务中加入Agent:

-javaagent:/path/to/skywalking-agent.jar
-Dskywalking.agent.service_name=your-service-name

这样就能在SkyWalking UI中看到完整的服务拓扑、接口响应时间、SQL耗时分析等内容,极大提升了定位线上问题的效率。


踩坑总结:那些你可能也会遇到的问题

1. Nacos集群部署坑太多?

初期我们图省事用了Standalone模式,但生产环境一定要部署集群。否则一旦挂掉,整个服务发现机制就会瘫痪。我们吃过亏,在一次服务器断电后,服务注册全都丢失了。

✅ 解决方法:使用Nacos集群 + 外部MySQL持久化数据。注意不要忘记配置持久化插件。


2. Feign调用超时怎么办?

曾经有一次,服务A调用服务B的某个接口频繁出现超时,但直接调用服务B又没问题。

排查下来发现,Ribbon + Feign默认的超时时间太短,而且没有重试机制。后来我们在配置中设置了合理的超时时间和重试策略:

ribbon:
  ConnectTimeout: 3000
  ReadTimeout: 5000
  OkToRetryOnAllOperations: true
  MaxAutoRetriesNextServer: 2

3. 微服务启动慢如蜗牛?

Spring Boot启动本身就不算快,再加上各种Spring Cloud组件,动辄十几秒甚至几十秒的启动时间让人崩溃。

✅ 优化技巧:

  • 使用懒加载(Lazy Initialization):

    spring:
      main:
        lazy-initialization: true
    
  • 排除不必要的自动注入组件

  • 使用GraalVM Native Image(如果你愿意接受更高成本)


4. 分布式事务Seata不好用?

Seata在最初确实给我们带来了很多困扰,尤其是在事务回滚日志过多、性能瓶颈等问题。

✅ 最终折中方案:

  • 对于非强一致性要求的场景,采用最终一致性的异步补偿机制(如RocketMQ事务消息)
  • Seata仅用于核心交易场景
  • 使用Saga模式替代AT模式,减少锁竞争

成果展示:架构升级后的收益

经过半年的重构和灰度迁移,我们成功将原有单体系统逐步拆分为十几个微服务,取得了不错的成果:

指标 拆分前 拆分后
上线频率 每月1~2次 每周1~2次
平均部署时间 30分钟以上 5分钟以内
故障隔离效果 一处故障影响全局 仅影响相关服务
系统扩展能力 固定部署 动态扩缩容
开发协同难度 中低
运维复杂度 稍高
性能监控能力 完善(链路+日志+指标)

我的一些建议:从血泪教训中学到的

✅ 不要一开始就追求“高大上”的架构

我见过不少新手一上来就想用 Istio、Kubernetes,结果最后连最基本的Feign调用都没搞明白。

微服务不是灵丹妙药。先想清楚业务是否真的需要拆分、数据模型是否能支撑,再决定是否要用这套体系。

✅ 做好运维准备

微服务意味着更多的节点、更多的服务实例、更多潜在的故障点。如果没有完善的监控告警系统,你会陷入无尽的debug地狱。

我们后期上了Prometheus + Grafana + ELK做监控,每天定时巡检日志,发现问题及时通知。

✅ 关注数据库的设计

微服务拆分不仅仅是代码层面的拆分,数据层面的去中心化才是难点。每个服务要有自己独立的数据源,避免共享数据库。

可以考虑使用 Event Sourcing 或 CQRS 模式,把数据同步问题转化为事件驱动的异步流程。


结语:微服务之路才刚刚开始

这篇文章除了教你如何从零开始搭建Spring Cloud微服务系统外,更重要的是一种工程思维的转变:从“我只需要完成这个接口”转向“我需要确保这个服务长期稳定地运转”。

微服务并不是终点,未来也许会有更好的架构方式,比如Service Mesh、边缘计算等方向。但不管怎样,Spring Cloud仍然是当下最适合大多数公司的微服务解决方案。

希望这篇文章能够帮助你少走一些弯路。记住一句话:

“微服务不是写出来的,是演进出来的。”

愿你在微服务的世界里,越走越远,越走越稳。

如果你在学习过程中遇到了什么问题,欢迎留言或私信交流。咱们程序员之间,就是要相互照应。

评论 0

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