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

指针迷路了
2025-06-30 10:33
阅读 248

去年我们公司决定启动一个新项目,目标是重构一个原本单体的电商平台。这个平台在过去几年中功能越加越重,部署困难、维护成本高,团队协作效率也很低。为了应对这些痛点,我们决定转向微服务架构,并选用Spring Cloud作为技术栈。

我负责的是其中一个核心子系统的开发——订单中心。在参与整个微服务体系建设的过程中,我也踩了不少坑,但也积累了很多实战经验。今天就来分享一下,作为一个后端工程师如何从零开始搭建一个基于Spring Cloud的微服务系统,以及我在实际工作中的体会。


项目背景与技术选型

项目背景与技术选型

先介绍一下当时的项目背景。原始系统是一个单体Java应用,所有的业务逻辑和数据库操作都在一个WAR包里完成,代码结构混乱,耦合严重,每次上线都像“拆弹”一样小心翼翼。

我们希望做的新系统要满足几个基本要求:

  • 模块解耦,便于扩展
  • 独立部署,提高交付效率
  • 分布式能力支持高并发
  • 有统一的服务注册发现机制
  • 支持服务间通信、熔断降级等治理能力

最终我们的技术选型如下:

  • Spring Boot:用于快速构建独立运行的服务实例
  • Spring Cloud Alibaba(Nacos):代替Eureka做服务注册发现,Nacos还提供配置中心能力
  • OpenFeign + LoadBalancer:实现声明式服务调用
  • Sentinel:做熔断限流
  • MySQL分库分表+MyBatis Plus
  • Spring Cloud Gateway:统一API网关
  • RabbitMQ:用于异步消息通知
  • Seata:分布式事务方案(未最终采用,后面会解释)

遇到的第一个挑战:服务注册与发现怎么选?

遇到的第一个挑战:服务注册与发现怎么选?

最开始我们是按照经典的Spring Cloud方式准备使用Eureka和Zookeeper,但后来发现Nacos其实是更好的选择,特别是在国内环境,社区活跃度高、集成简单,还能做配置中心,非常适合我们这种中小型项目。

不过也踩了一个坑:一开始没搞清楚Nacos集群模式下的持久化问题,导致一次测试环境宕机之后服务注册信息全丢了。后来改成了MySQL持久化存储才解决了这个问题。

解决方法很简单:配置Nacos的数据源为MySQL,启用持久化模式:

spring:
  datasource:
    platform: mysql
    mysql:
      ip: 127.0.0.1
      port: 3306
      database: nacos_config
      username: root
      password: 123456

这个小插曲也提醒我,不要一味追求“轻量”,生产级别的服务注册中心必须考虑数据可靠性。


微服务划分实践:订单中心怎么切出去?

我们把原来的单体系统拆成了五个主要微服务:

  • 用户服务(User Service)
  • 商品服务(Product Service)
  • 订单服务(Order Service)
  • 支付服务(Payment Service)
  • 消息通知服务(Message Service)

订单服务是其中最复杂的,涉及用户下单、库存扣减、支付跳转等多个流程。这个时候我深刻体会到一点:

微服务的划分不是按功能,而是按照领域边界和一致性需求来设计。

举个例子:订单创建的时候需要访问库存服务。这个时候你可能会想直接远程调用,但我建议优先通过异步消息来处理。比如使用RabbitMQ发送一个“订单已生成”的事件,由库存服务监听并执行库存扣除。

这样可以降低服务间的直接耦合,也能避免分布式事务的复杂性。


关键实践:Feign、Gateway 和 Sentinel 怎么一起玩?

Feign 调用失败的问题

我们在服务间通信时最早使用了Feign,默认情况下是基于JDK的URLConnection进行HTTP请求,性能一般,而且一旦服务挂掉或者网络异常,很容易出现雪崩效应。

这时候我们引入了LoadBalancer(负载均衡器),并结合Sentinel做熔断降级。

一段典型的Feign客户端调用如下:

@FeignClient(name = "product-service")
public interface ProductServiceClient {
    @GetMapping("/products/{id}")
    Product getProductById(@PathVariable("id") Long id);
}

然后,在主类上开启FeignClients和Sentinel的支持:

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

同时,在application.yml中启用Sentinel熔断策略:

feign:
  sentinel:
    enabled: true

熔断降级的效果

有了Sentinel之后,一旦某个服务不稳定,Feign就会触发熔断规则,返回预设的fallback逻辑,比如返回一个缓存数据或者提示:“系统繁忙,请稍后再试”。

这大大提升了系统的整体健壮性。


数据库设计的心得:别盲目分库分表!

很多人一上来就想着要分库分表,但其实对于刚起步的微服务系统来说,这样做反而带来额外的复杂性。

我们在订单服务初期并没有立即分库,而是在MySQL层面做了一些优化:

  • 使用InnoDB引擎,设置合适的索引
  • 对高频查询字段如order_no建立唯一索引
  • 定期分析慢SQL,使用Explain查看执行计划
  • 引入Redis作为热点订单缓存

真正等到订单量突破百万级之后,才开始分库分表的设计,采用Sharding-JDBC进行垂直拆分和水平拆分。

我的建议是:

初期微服务应以快速迭代为主,数据库结构清晰、索引合理即可;后期再根据性能瓶颈逐步优化。


生产运维经验分享:日志、监控和灰度发布

微服务一旦上线,最重要的就是可观测性。我们做了以下几件事:

日志收集

使用Logback写入本地文件,配合Filebeat同步到Elasticsearch,然后Kibana可视化。这种方式简单有效,适合中小团队。

监控告警

Prometheus + Grafana实时监控各服务的QPS、响应时间、线程池状态等关键指标,结合AlertManager做钉钉/邮件报警。

灰度发布

在Spring Cloud Gateway中配置路由权重,将少量流量导向新版本,观察运行稳定后再全部切换。

例如:

spring:
  cloud:
    gateway:
      routes:
        - id: order-new
          uri: lb://order-service-v2
          predicates:
            - Path=/api/order/**
          filters:
            - StripPrefix=1
            - Weight=orderGroup, 30 # 新版本30%
        - id: order-old
          uri: lb://order-service
          predicates:
            - Path=/api/order/**
          filters:
            - StripPrefix=1
            - Weight=orderGroup, 70 # 旧版本70%

那些年我们一起踩过的坑

  1. 没有统一的日志追踪ID
    最早各服务日志无关联,查问题非常困难。后来我们引入MDC日志上下文跟踪,每个请求进来生成一个TraceId,贯穿所有服务。

  2. Feign默认超时太短
    默认情况下Feign的连接和读取超时只有1秒,根本不够用。后来调整到3秒左右,并且加上重试机制:

    feign:
      client:
        config:
          default-config:
            connectTimeout: 3000
            readTimeout: 3000
    
  3. Nacos配置更新不生效
    有时候修改了Nacos上的配置,服务那边并没有刷新。检查后发现遗漏了Spring Cloud的自动刷新注解 @RefreshScope,记得给每个Bean加上。


结果与收益

经过三个月的努力,整个微服务架构初步成型。虽然还有一些改进空间,但我们已经取得了明显的收益:

  • 各个模块职责清晰,开发效率显著提升
  • 故障范围被隔离在单一服务内,不会影响全局系统
  • 可以灵活地进行灰度发布、弹性扩缩容
  • 服务间通信稳定可控,依赖管理更加规范

特别是当遇到双十一压测压力时,系统的表现非常稳定,接口成功率保持在99.8%以上。


我的经验总结与建议

如果你现在正准备踏上微服务的道路,不妨记住这几个建议:

  1. 不要盲目复制大厂架构
    小团队或新项目更适合从简单做起,先把服务拆通、接口理清,再逐步加上高级功能。

  2. 重视服务治理
    服务注册、健康检查、熔断降级、链路追踪这些基础设施必须提前规划好。

  3. 别急着引入分布式事务
    Seata这类解决方案确实强大,但对业务侵入性大,运维成本高。能通过异步解耦解决的问题,尽量不用强一致性。

  4. 微服务不是银弹
    它带来的好处是以更高的运维复杂度为代价的。权衡利弊,选择适合自己业务阶段的架构。

  5. 多写文档、多沟通
    微服务意味着多个团队协同作战,接口定义、调用顺序、错误码标准这些必须统一并文档化,否则合作起来会很痛苦。


结语

一路走来,Spring Cloud帮我们打开了通往高可用架构的大门,也让我更深刻地理解了什么是真正的工程思维:不是堆砌最先进的技术,而是找到最适合当前场景的解决方案。

希望这篇文章能给正在摸索微服务的同学一些启发。如果你们也在用Spring Cloud,欢迎留言交流经验,一起进步!


如有需要,我可以继续深入讲解具体的模块实现、数据库迁移策略、服务注册细节等内容。

评论 0

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