从单体到微服务:一个电商产品的架构演进实战

Tokens燃烧中
2025-12-23 05:24
阅读 387

大家好,我是小林,一名211高校的计算机研究生,也是个爱写技术博客的后端开发者。最近在带实习生时发现,很多同学对“微服务”这个词耳熟能详,却不知道它到底解决了什么问题,更别说如何动手实践了。我当初学的时候也踩过不少坑——光看书《微服务设计》《Spring Cloud微服务实战》这些经典书籍,概念一堆,但一上手就懵。所以今天,我想用一个真实的产品案例,带你从零开始,把一个单体应用一步步拆成微服务,真正理解“为什么拆”和“怎么拆”。

为什么我们要从单体走向微服务?

想象一下,你正在开发一个小型电商系统,初期功能简单:用户注册、商品浏览、下单、支付。所有代码都塞在一个项目里,部署也只要一个JAR包。这叫单体架构(Monolithic Architecture)

但随着业务增长,问题来了:

  • 团队变大,10个人同时改同一个代码库,合并冲突不断
  • 商品模块频繁更新,但每次都要全量发布整个系统
  • 订单服务崩溃,整个网站都挂了
  • 技术栈被锁定,想用新语言重写某个模块?难!

微服务架构的核心思想就是:把一个大产品拆成多个独立的小服务,每个服务专注一个业务能力(比如用户服务、商品服务、订单服务),可以独立开发、部署、扩展。

📚 小贴士:如果你刚接触这个概念,推荐阅读 Sam Newman 的《微服务设计》。这本书不讲代码,只讲思想,特别适合建立认知框架。


环境准备:5分钟搭建开发基础

我们用 Java + Spring Boot 来演示(你也可以用其他语言,思路相通)。确保你已安装:

工具 版本要求 验证命令
JDK 17+ java -version
Maven 3.6+ mvn -v
IDE IntelliJ IDEA 或 VS Code
Docker 20.10+(可选,用于后续部署) docker --version

💡 新手注意:别一上来就装 Nacos、Sentinel、Seata 这些中间件!先理解核心逻辑,再加治理组件。


核心概念:微服务不是魔法,而是分工

微服务听起来高大上,其实本质很简单。我们用一个表格对比单体和微服务的区别:

维度 单体架构 微服务架构
代码结构 所有模块在一个项目 每个服务独立项目
部署方式 一次部署整个应用 每个服务独立部署
技术栈 统一(如全 Java) 可异构(用户服务用 Go,订单用 Java)
故障影响 一处崩溃,全站瘫痪 局部故障,其他服务可用
扩展性 整体扩容,资源浪费 按需扩容(如秒杀时只扩订单服务)

关键术语解释:

  • 服务注册与发现:服务A要调用服务B,得知道B在哪。于是有个“通讯录”(如 Eureka、Nacos)记录所有服务地址。
  • 远程调用:服务之间通过 HTTP/gRPC 通信,不再是函数调用。
  • API 网关:所有外部请求先经过网关,统一鉴权、路由、限流。

⚠️ 常见误区:微服务 ≠ 多个 Spring Boot 项目!如果它们之间还是强耦合、共享数据库,那只是“分布式单体”,反而更糟。


实战项目:把一个电商单体拆成3个微服务

我们以一个简化版电商产品为例,包含三个核心功能:

  1. 用户管理(注册/登录)
  2. 商品浏览
  3. 创建订单

第一步:原始单体结构(Before)

假设你已有如下单体项目结构:

ecommerce-monolith/
├── src/main/java
│   └── com.example.ecommerce
│       ├── controller
│       │   ├── UserController.java
│       │   ├── ProductController.java
│       │   └── OrderController.java
│       ├── service
│       │   ├── UserService.java
│       │   ├── ProductService.java
│       │   └── OrderService.java
│       └── EcommerceApplication.java
└── pom.xml

所有逻辑都在一起,数据库也共用一张 usersproductsorders 表。

第二步:拆分服务(After)

我们按业务边界拆成三个独立项目:

user-service/      → 负责用户注册登录
product-service/   → 负责商品查询
order-service/     → 负责创建订单

1. 创建 user-service

// UserController.java
@RestController
public class UserController {
    @GetMapping("/users/{id}")
    public User getUser(@PathVariable Long id) {
        // 模拟返回用户
        return new User(id, "张三", "zhangsan@example.com");
    }
}

启动类加上 @EnableDiscoveryClient(后续注册到服务中心)。

2. 创建 product-service

// ProductController.java
@RestController
public class ProductController {
    @GetMapping("/products/{id}")
    public Product getProduct(@PathVariable Long id) {
        return new Product(id, "iPhone 15", 5999.0);
    }
}

3. 创建 order-service(关键:远程调用)

订单服务需要调用用户服务和商品服务来验证信息:

// OrderService.java
@Service
public class OrderService {

    // 使用 RestTemplate 远程调用
    @Autowired
    private RestTemplate restTemplate;

    public Order createOrder(Long userId, Long productId) {
        // 调用 user-service
        User user = restTemplate.getForObject(
            "http://user-service/users/" + userId, User.class);

        // 调用 product-service
        Product product = restTemplate.getForObject(
            "http://product-service/products/" + productId, Product.class);

        if (user == null || product == null) {
            throw new RuntimeException("用户或商品不存在");
        }

        return new Order(userId, productId, product.getPrice());
    }
}

🔧 配置 RestTemplate Bean:

@Bean
@LoadBalanced // 启用负载均衡(配合服务发现)
public RestTemplate restTemplate() {
    return new RestTemplate();
}

第三步:加入服务注册中心(Nacos)

  1. 下载 Nacos:https://github.com/alibaba/nacos/releases
  2. 启动:sh startup.sh -m standalone(Linux/Mac)或 startup.cmd -m standalone(Windows)
  3. 在每个服务的 application.yml 中配置:
spring:
  application:
    name: user-service  # 服务名
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848

现在,三个服务启动后会自动注册到 Nacos。order-service 调用 http://user-service/... 时,会通过 Nacos 自动解析真实 IP 和端口。

✅ 验证步骤:

  1. 启动 Nacos
  2. 分别启动 user、product、order 服务
  3. 访问 http://localhost:8848/nacos,查看服务列表
  4. 调用订单接口:POST /orders?userId=1&productId=1001

新手常见问题解答

Q1:微服务一定要用 Spring Cloud 吗?

不一定!Spring Cloud 是 Java 生态的解决方案,但核心思想通用。Go 可用 go-micro,Node.js 可用 NestJS + Consul。关键是理解“服务拆分 + 通信 + 治理”的逻辑。

Q2:数据库要不要拆?

强烈建议拆! 每个服务应有自己独立的数据库(甚至不同数据库类型)。否则数据耦合会导致“拆了等于没拆”。例如:

  • user-service → users_db
  • product-service → products_db
  • order-service → orders_db

Q3:本地怎么调试多个服务?

  • 方案1:IDE 多开窗口,分别运行
  • 方案2:用 Docker Compose 一键启停(推荐学完基础后尝试)

Q4:性能会不会变差?(网络调用 vs 函数调用)

会!这是微服务的代价。但可通过以下方式优化:

  • 缓存(Redis 缓存商品信息)
  • 异步(订单创建后发消息通知库存服务)
  • 合理聚合(避免前端多次调用,用 BFF 层聚合)

学习建议:下一步该学什么?

  1. 深入服务治理
    学习熔断(Hystrix/Sentinel)、限流、链路追踪(SkyWalking)。推荐书籍:《Spring Cloud微服务实战》。

  2. 掌握 API 网关
    用 Spring Cloud Gateway 统一入口,做认证、路由、日志。

  3. 尝试容器化部署
    把每个服务打包成 Docker 镜像,用 docker-compose 编排。

  4. 理解事件驱动
    用 RabbitMQ/Kafka 解耦服务,比如“订单创建成功”后发消息给积分服务。

  5. 不要盲目拆分!
    如果你的产品只有3个功能、2个开发者,单体完全够用。微服务是为复杂度买单的,不是银弹。


最后的话

微服务不是终点,而是应对业务复杂度的一种手段。我见过太多团队为了“上微服务”而拆分,结果运维成本飙升,开发效率反而下降。记住:架构是演进而非设计出来的

希望这篇从真实产品出发的实战教程,能帮你避开我当年踩过的坑。如果你跟着做了一遍,恭喜你,已经跨过了微服务入门的最大障碍——动手实践!

📖 延伸阅读清单:

有问题欢迎在评论区留言,我会一一回复。下期我们聊聊“如何用 Docker 一键部署你的微服务全家桶”!

评论 0

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