从零开始搭建微服务系统:我在 Spring Cloud 实战中的成长之路

CD还没发
2025-06-29 20:57
阅读 423

开篇背景

我是一名后端开发工程师,目前在一家中型互联网公司工作。我们公司早期的项目是一个典型的单体架构系统,所有的业务逻辑、数据库、接口都在一个代码仓库里维护,部署也只有一个 WAR 包。随着用户量逐渐上涨,团队成员越来越多,系统的耦合度越来越高,每次上线都变得非常谨慎。

特别是在做一次版本迭代的时候,一个小功能的改动导致整个支付模块出问题,最终不得不回滚整个 release,影响了好几个产品线。这让我们意识到,必须进行架构升级,尝试向微服务架构转型。

于是我和几位同事一起承担起搭建微服务架构的任务,选择了当前主流的 Spring Cloud Alibaba 技术栈作为主框架。今天就来聊聊这段从零开始的旅程。


我们面临的挑战

刚接触微服务时,虽然理论知识学了不少,但在实际落地过程中遇到不少现实问题:

  1. 服务拆分没有明确边界:一开始不知道怎么划分微服务,是按模块?还是按业务功能?有时候拆得过细反而更麻烦。
  2. 服务之间如何通信:RESTful 接口调用简单直观,但性能不高;Feign 和 Dubbo 到底该选哪个?
  3. 服务注册与发现机制混乱:多个实例怎么管理?重启服务之后别人能发现吗?
  4. 配置中心怎么做:不同环境(dev / test / prod)下的配置差异巨大,手动改配置太容易出错。
  5. 限流熔断没有保障:某个服务出问题是否会影响到其他服务?有没有熔断保护机制?
  6. 分布式事务处理困难:下单涉及订单、库存、支付等多个服务,保证数据一致性是个大难题。
  7. 日志和链路追踪缺失:排查线上问题像大海捞针,缺乏统一的日志追踪系统。

这些问题并不是纸上谈兵就能解决的,我们是在一个个真实场景中踩坑、填坑、复盘、总结出来的。


我们的解决方案

我们的技术路线大致如下:

  • 使用 Spring Boot + Spring Cloud Alibaba
  • 注册中心使用 Nacos
  • 网关使用 Spring Cloud Gateway
  • 配置中心同步使用 Nacos Config
  • 服务间通信采用 OpenFeign + LoadBalancer
  • 熔断降级采用 Sentinel
  • 链路追踪使用 SkyWalking
  • 日志聚合用的是 ELK + Filebeat

第一步:服务拆分

最开始我们犯了一个常见的错误:为了“微”而微,把本来应该在一起的功能硬拆出去,结果导致调用链条越来越长,调试复杂度飙升。

后来我们吸取教训,明确了按照核心业务能力划分服务边界的原则,比如:

  • 用户服务(User Service):负责用户注册、登录、权限等基础信息
  • 商品服务(Product Service):商品信息展示、分类目录
  • 订单服务(Order Service):下单、退货、订单状态流转
  • 库存服务(Stock Service):商品库存变动、预警提醒
  • 支付服务(Payment Service):支付发起、回调处理、交易记录

这样划分后,每个服务职责单一清晰,便于独立开发和测试。

第二步:注册中心 & 服务发现

服务多了以后,第一个要解决的问题就是服务之间的互相发现。最初我们想试试 Eureka,后来听社区反馈说 Spring Cloud Alibaba 对 Nacos 的集成更好,支持配置中心和服务注册一体化,所以我们选择了 Nacos

我们先搭好一个 Nacos Server,然后在各个服务的 pom.xml 中引入依赖:

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

然后在 application.yml 中加上:

spring:
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848

启动后自动注册到 Nacos 上。在 Gateway 网关中通过负载均衡访问各个服务:

@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
    return builder.routes()
        .route("order_route", r -> r.path("/api/order/**")
            .filters(f -> f.stripPrefix(1))
            .uri("lb://order-service"))
        .build();
}

这里 .uri("lb://order-service") 表示走负载均衡的方式去请求 Order Service 的某个节点,非常方便。

API接口文档-2

第三步:统一网关入口

我们使用了 Spring Cloud Gateway 做 API 网关,主要职责是:

  • 路由转发
  • 权限校验(JWT)
  • 限流(通过 Sentinel 粒度控制)
  • 日志记录(接入 SkyWalking)

一个典型的路由配置如下:

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

这样所有对 /api/user/** 的访问都会被转发到 User Service 去处理。

第四步:熔断限流用 Sentinel

有一次我们在压测订单服务的时候发现,当并发达到一定量之后,下游的库存服务直接挂掉了,进而导致整个下单流程失败。

后来我们引入了 Sentinel 做熔断限流:

  • 控制每个服务的 QPS
  • 在异常情况下快速熔断,防止雪崩效应
  • 提供 Dashboard,可以动态调整规则

引入方式很简单:

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

然后加一个全局异常处理器:

@Component
public class SentinelConfig {
    @PostConstruct
    public void init() {
        BlockExceptionHandler blockExceptionHandler = (request, response, e) -> {
            // 处理限流逻辑
        };
        WebCallbackManager.setUrlBlockHandler(blockExceptionHandler);
    }
}

这样就可以在 Sentinel 控制台配置针对每个接口的规则,比如 /api/order/create 每秒最多允许 100 次请求,超过就拒绝。

第五步:链路追踪 SkyWalking

我们之前排查一个问题花了整整半天时间,根本搞不清楚是哪个服务出了问题。后来我们接入了 Apache SkyWalking,它可以帮你分析请求链路上每一个服务的耗时、出错点,甚至看到 SQL 语句的执行情况。

接入非常方便,在每个服务启动脚本中加入 agent:

java -javaagent:/path/to/skywalking-agent.jar -Dskywalking.agent.name=user-service -jar your_app.jar

然后在 SkyWalking 的 Web UI 中就可以看到完整的调用链:

这张图上可以看到每个环节的耗时,哪个接口慢了、哪个服务出现了异常都非常清晰。


实施效果与收益

经过几个月的逐步改造和优化,我们取得了以下几个关键成果:

  • 系统稳定性提高:通过 Sentinel 的限流和熔断机制,服务之间相互影响大大减少;
  • 部署效率提升:每个服务都可以单独打包发布,不再需要整体构建;
  • 运维成本降低:配合 Nacos + SkyWalking,排障效率提高了 70%;
  • 可扩展性强:新功能可以通过增加服务模块来实现,而不会影响旧功能;
  • 团队协作顺畅:不同团队可以负责不同的服务,减少了沟通成本。

另外值得一提的是,我们还实现了基于 MySQL 分库分表 的方案,并结合 MyBatis Plus 做了读写分离,有效缓解了高并发下的数据库压力。


给读者的建议与注意事项

服务器部署方案-1

如果你也在准备或已经开始微服务架构的搭建,我想分享几点个人经验:

1. 拆服务前一定要设计好业务边界

微服务不是越小越好,也不是越多越好,要以业务领域为核心去做拆分。否则你会陷入“微服务比单体还复杂”的困境。

2. 注册中心选型一定要稳定可靠

Nacos 是个不错的选择,尤其适合 Java 生态。但如果你们已经用上了 Kubernetes,那也可以考虑 Consul 或 Etcd,但注意生态兼容性。

3. 不要用 Feign 无脑远程调用

服务间调用尽量保持幂等性,同时要有失败重试机制。如果是强一致性操作,要考虑是否有分布式事务的需求。

4. 先做好监控再谈运维

没有 SkyWalking、Prometheus、ELK 这类工具,微服务的维护会非常痛苦。上线之前就要准备好这些基础设施。

5. 适当保留部分单体逻辑

有些业务逻辑不需要拆成微服务,比如简单的后台任务、定时任务,保留为单体也是可以的,不要为了拆而拆。


结语

微服务不是银弹,但它确实是我们应对复杂业务、高并发场景的一种成熟解决方案。从最初的一头雾水,到现在的熟练驾驭,这条路并不平坦,但每一步踩过的坑都成了宝贵的经验。

如果你也正在尝试搭建微服务系统,希望这篇文章能给你一些启发。无论你现在是从头开始,还是正处在微服务演进的过程中,记住一句话:架构是服务于业务的,不是炫技的工具。

持续学习,不断实践,才是通向技术成熟的唯一路径。


如果你对这篇文章感兴趣,或者有类似的技术实践想交流,欢迎留言或私信,我们一起进步 😊

评论 0

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