微服务架构设计实战:从单体到分布式

周末写代码
2025-06-25 00:40
阅读 267

开篇:一场“痛并快乐着”的架构升级之路

开篇:一场“痛并快乐着”的架构升级之路

大家好,我是阿杰,目前在一家中型电商平台担任后端开发负责人。我们平台上线初期采用的是传统的单体架构,业务逻辑集中部署在一个Spring Boot项目里,前后端分离,接口调用也比较简单,整个系统结构清晰、易于维护。

但随着用户量的增长和功能的不断叠加,这套架构开始暴露出越来越多的问题。我清楚地记得有次大促活动,由于订单系统出了问题,导致整个应用卡死,连商品浏览也受到了影响,最终造成大量用户流失和客服电话被打爆。这让我深刻意识到,再不改造,系统随时可能会崩盘。

于是,我们启动了从单体架构向微服务架构迁移的项目。这是一段充满挑战但也收获满满的旅程。今天我想结合实际工作经历,跟大家分享一下我们是怎么一步步完成这次架构升级的,中间踩过哪些坑,最后又取得了哪些成果。


一、为什么选择微服务?我们遇到了什么问题?

一、为什么选择微服务?我们遇到了什么问题?

我们最初的项目是一个Spring Boot + MyBatis + MySQL的典型Java项目。早期一切都很顺利,直到:

1. 部署困难

每次发布新版本都要全量更新,动不动就卡顿几分钟。一个小模块改动也要重新部署整个系统,风险极高。

2. 负载不均

比如商品搜索是个重性能的模块,而用户中心相对轻量。但两者部署在一起,资源利用率严重不均衡。

3. 代码臃肿

一个项目里包含了订单、支付、库存、用户、CMS、促销等多个子系统,模块之间高度耦合,改一处往往牵一发动全身。

4. 故障扩散严重

如前文所说,订单模块出错会影响整个平台可用性,缺乏隔离机制。

当时我们团队也开始面临人员扩招带来的协作困境。多个小组同时修改同一个项目,Git冲突频繁,测试环境不够用,版本混乱,严重影响迭代效率。

这些问题促使我们下定决心进行架构改造。


二、我们的微服务方案设计思路

二、我们的微服务方案设计思路

微服务架构示意图-2

我们采用的微服务框架是 Spring Cloud Alibaba(Nacos + Feign + Sentinel + Gateway),配合Docker容器化部署,Kubernetes做调度。整体架构如下图所示:

网关(Gateway)
│
├── 用户服务(user-service)
├── 商品服务(product-service)
├── 订单服务(order-service)
├── 支付服务(payment-service)
├── 库存服务(stock-service)
├── 搜索服务(search-service)
└── CMS服务(cms-service)

每个服务都有独立的数据库(MySQL),服务之间通过Feign+OpenFeign调用,日志统一收集到ELK,监控使用Prometheus + Grafana,配置中心为Nacos。

架构设计要点说明:

1. 服务拆分原则

  • 业务边界清晰:按照核心领域模型划分,比如订单、用户、商品各成服务。
  • 高内聚低耦合:每个服务内部模块尽量自包含,对外暴露稳定接口。
  • 可独立部署与扩展:服务可以单独构建部署,方便水平扩容。

2. 数据库设计

我们采用了分库分表策略,每个服务都有自己独立的数据库实例,避免跨库事务。比如订单服务使用order_db,商品服务使用product_db。虽然这样做会牺牲一定的数据一致性能力,但在高并发场景下能显著提升性能。

3. 服务通信方式

初期我们考虑使用RabbitMQ做异步解耦,但因为团队成员对消息队列经验不足,且业务逻辑并不复杂,最终选择了更易上手的HTTP同步通信(Feign)。未来会逐步引入Kafka或RocketMQ实现更复杂的事件驱动模型。


三、实战代码片段与关键配置

三、实战代码片段与关键配置

为了让大家有更直观的感受,下面我会分享几个关键模块的代码和配置。

1. 服务注册与发现(Nacos)

我们在各个服务中添加如下依赖:

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

然后在application.yml中配置:

server:
  port: 8080

spring:
  application:
    name: order-service
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.1.10:8848

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

启动后,Nacos就能自动识别这些服务。

2. 网关路由(Spring Cloud Gateway)

我们使用Spring Cloud Gateway作为统一入口,配置示例如下:

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


![系统架构设计图-1](https://code-guide.oss.shanghai.autogptai.club/common/file/download?name=date2025062500/6e6b2970-f46c-46b0-82eb-6826523a78b5.jpg)


        - id: product-service
          uri: lb://product-service
          predicates:
            - Path=/api/product/**
          filters:
            - StripPrefix=1

这样外部请求 /api/user/1 就会被转发到 user-service:/1

3. 服务间调用(Feign)

在OrderService中调用UserService时,定义Feign客户端:

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

Feign会自动进行服务发现和负载均衡,非常方便。


四、迁徙过程中遇到的坑与解决方案

1. 服务间循环依赖

最初设计阶段,订单服务需要调用用户信息,而用户服务有时候也需要查询订单信息,导致出现循环依赖。后来我们做了两个调整:

  • 引入“事件总线”概念,重要数据变更通过消息广播出去。
  • 某些字段冗余存储,比如用户昵称等基础信息,在订单中保存快照,减少实时依赖。

2. 分布式事务问题

最开始我们尝试使用Seata,结果在一次压测中发现性能下降严重,响应时间增加了50%以上。最终我们放弃了全局事务,采用了以下几种替代方案:

  • 本地事务补偿机制:失败时异步回滚。
  • 幂等性处理:所有接口都支持重复提交,避免因超时等问题造成数据异常。
  • Saga模式:适用于长周期操作,比如下单 → 扣库存 → 支付 → 发货,每一步出错都触发反向动作。

3. 日志追踪困难

微服务拆分后,一个问题可能涉及多个服务,传统的日志排查方式效率太低。我们引入了Sleuth+Zipkin来实现分布式链路追踪。

在各服务中添加:

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

并在YAML配置中启用:

spring:
  zipkin:
    base-url: http://zipkin-server:9411/
  sleuth:
    enabled: true

现在在Zipkin界面中输入trace ID,就能看到完整的调用链路,大大提升了排查效率。

4. 配置管理混乱

服务多了以后,每个服务都需要自己的配置文件,容易出错。我们后来将所有配置统一托管到Nacos配置中心,并加上了自动刷新功能。

spring:
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848
        extension-configs:
          - data-id: common-config.yaml
            group: DEFAULT_GROUP
            refresh: true

五、效果评估与收益总结

经过大约三个月的努力,我们完成了核心系统的微服务化改造。上线后的效果明显改善:

维度 单体架构 微服务架构
部署效率 20分钟/次 5分钟/服务
故障隔离 全局崩溃 局部故障
水平扩展 只能全量扩容 按需扩容
版本管理 多人协作困难 各服务独立迭代
系统稳定性 平均每月一次重大事故 近半年无宕机记录

更重要的是,团队协作效率明显提升,新人也能快速找到归属的服务模块进行开发。运维方面,我们还借助Kubernetes实现了自动化弹性伸缩,节省了不少服务器成本。


六、一些掏心窝子的经验建议

如果你也在考虑要不要把单体项目拆分成微服务,以下几点是我的个人经验建议:

✅ 必须做的:

  • 做好服务边界设计,前期花再多时间也不为过。
  • 技术栈要统一,避免各服务差异太大增加运维成本。
  • 搞一套完善的日志追踪系统,否则你会天天加班。
  • 保留灰度发布能力,尤其是面向C端用户的系统。

❌ 不推荐一开始做的:

  • 盲目引入各种高级技术(比如Service Mesh),先搞通基础服务治理再说。
  • 一开始就追求强一致性,微服务天生更适合最终一致
  • 低估团队的学习曲线,最好边做边培训,不要一口吃成胖子。

💡 我的小感悟:

微服务不是银弹,它只是帮你解决特定规模下的问题。如果你们团队才几人,项目也还没做大,真的没必要急着转型。但如果你们已经遇到了部署难、维护难、扩展难的问题,那微服务确实是值得投资的方向。


结语:架构演进是一场马拉松

写到这里,我觉得这场微服务改造不仅是一次技术上的跃迁,更是一次团队协作能力和工程素养的提升。从最初面对复杂问题时的焦虑不安,到后来逐渐游刃有余地应对各种挑战,每一步都让我们更加成熟。

希望这篇结合我真实工作经验的文章,能够对你有所启发。如果你也经历过类似的系统重构,欢迎留言交流,我们一起成长!


如有任何疑问或想看更多细节代码,欢迎关注我的GitHub仓库,后续我会陆续开源部分案例代码用于学习参考。

评论 0

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