从单体到分布式再到微服务的架构解析之路

一、前言

从最初接触SpringBoot的单体架构,到能够熟练地从零搭建一个项目,我的开发过程逐渐变得规范且高效。前段时间开始学习分布式架构,并了解了微服务,随之而来的疑惑也越来越多:无论是分布式还是基于分布式的微服务,其应用场景都难以模拟,而微服务所依赖的中间件又非常多,如果没有实际项目经验,很难真正掌握。尝试自己从零搭建微服务时,总是手忙脚乱。于是,我写下这篇文章,来帮助我们理清从单体架构到微服务架构其中的门道,进行快速升级或构建。(想到什么写什么,可能会有点乱,见谅( ̄_ ̄))

二、从单体开始:最常见的项目架构

2.1 什么是单体架构

一种所有模块都打包在同一个应用里的架构方式。整个系统是一个整体,运行在一个进程中,打成一个jar包部署

2.2 单体架构的特点

  • 所有模块(业务逻辑、数据访问、远程调用)在同一个应用里运行
  • 一个jar包就能启动整个系统,系统维护和复杂程度不高
  • 模块间无网络调用,调试容易

2.3 常见的痛点(相比于分布式)

  • 不能按照不同业务选择不同技术栈或独立升级
  • 模块间依赖严重,修改某个模块可能影响其他模块
  • 系统可靠性不高,系统崩溃就是整个应用不可用

三、走向分布式:系统层面的拆分与并行

3.1 什么是分布式

  • 把一个系统拆分成多个节点,部署在不同机器上
  • 核心目标:解决单机性能瓶颈,提升系统可靠性

本文重点讲微服务,因为微服务本身也只是分布式的一种实现风格和标准,所以可能会有重复表达

3.2 单体到分布式变化

3.2.1 模块拆分

  • 单体系统所有功能都在一个进程里运行
  • 分布式根据技术拆分的思路:如用户管理、订单处理、支付等分布在不同节点

3.2.2 服务独立部署

  • 单体是一个包,分布式要求每个模块能单独运行
  • 关键点:模块化改造 → 独立 JAR 包 → 多系统部署,保障服务可靠性

3.2.3 服务通信

  • 单体里模块调用是方法调用(本地调用)
  • 分布式后,模块之间跨进程,需要远程调用
    • HTTP (RestTemplate / OpenFeign)
    • RPC (Dubbo / gRPC)

3.2.4 数据拆分

  • 单体通常一个数据库,分布式后分库分表:
    • 每个服务独立数据库
    • 至少独立数据表,减少跨服务直接访问
  • 引入分布式事务处理(Seata)

3.2.5注册发现与配置

  • 单体架构只有一个应用,不需要发现

  • 分布式需要服务注册中心(Nacos),来支持自动发现

    • 服务启动时,自动把自己的信息(服务名、IP、端口)注册到注册中心
    • 其他服务或网关需要调用时,不直接找 IP,而是去注册中心查询
  • 单体架构配置文件集中

  • 分布式要用统一配置中心(Nacos Config),多服务配置统一调控

3.2.6 统一入口

  • 单体架构只有一个应用,一个端口,比如 http://localhost:8080,前端直接请求即可

  • 分布式需要网关,让前端像单体架构一样,不需要知道后面有多少服务,只需要知道一个入口即可

    • 配合上面的服务中心功能够实现网关通过注册中心自己找到订单服务的可用实例,自动负载均衡
    - id: order-service
      uri: lb://order-service
    
    • 如果不使用网关,因为系统被拆分成很多服务(用户服务、订单服务、支付服务等),每个服务都有自己的地址和端口,比如:
      • 用户服务:http://localhost:8081
      • 订单服务:http://localhost:8082http://localhost:8083
      • 支付服务:http://localhost:8084
    • 前端要知道所有服务地址
    • 跨域问题(多个端口)
    • 安全风险(每个服务都要自己做鉴权、限流)

四、实现微服务:单体架构升级微服务架构

4.1 微服务与分布式的关系

  • 分布式是基础,微服务是在其上的一种架构风格
  • 想要做微服务,就一定是分布式(服务跑在多机器上)
  • 但不是所有分布式系统都是微服务:
    • Hadoop 是分布式的,但不是微服务
    • Redis 集群是分布式的,但不是微服务

4.2 该以什么标准去拆分服务

  • 满足高内聚,低耦合

    • 高内聚:一个服务只关注单一业务领域。
    • 低耦合:服务之间通过 API 调用,而不是直接共享代码
  • 可以按照领域驱动设计(DDD)标准或业务功能来拆分,不能胡乱切割代码

  • 拆出来的服务要能独立运行、独立部署,而不是还依赖单体核心

Q:领域驱动设计(DDD)是什么

以业务领域为核心来设计系统,而不是以技术或数据库表来拆分应用

  • 如电商系统里,单体架构的划分为:

    • utils
    • dao
    • controller等,
  • 而微服务架构划分为:

    • 用户领域

    • 订单领域

    • 商品领域

    • 支付领域

  • 怎么样算是一个领域?

    • 对业务逻辑的抽象,把业务核心组织在一起

    • 例如订单领域包含:

      相关实体

      • Order
      • OrderItem
      • PaymentInfo

      值对象

      • 地址、价格、优惠券规则等不可变对象。

      服务

      • 订单价格计算
      • 订单校验等功能
  • 说了这么多概念,其实也就是保证订单的业务规则完整,业务逻辑不分散到别的地方,成为一个独立、可演进的微服务

4.3 升级架构小指南

4.3.1 准备工作

  • 梳理单体项目的业务模块
  • 按照上面的服务拆分部分试着摸清业务的边界
  • 理清服务间的调用关系(可以试试借助画图的方法来梳理)
  • 选定微服务需要的组件栈(如Nacos + Gateway + OpenFeign + Sentinel

4.3.2 基础搭建

  • 引入 注册中心和配置中心(Nacos),让服务可以互相发现,统一管理配置
  • 搭建 网关(Spring Cloud Gateway),作为统一入口
  • 可选搭建日志、接口文档生成工具等

4.3.3 模块拆分

  • 将单体的不同模块,拆分成独立的SpringBoot服务:
  • user-service(用户服务)
  • order-service(订单服务)
  • product-service(商品服务)
  • payment-service(支付服务)
  • 每个服务保留自己的 pom.xml,只引入本服务需要的依赖
  • 公共类(DTO、工具类、异常处理等)抽取到 common 模块
  • 模块结构示例:

4.3.4 服务间通信改造

  • 原来的本地方法调用改为OpenFeign远程调用
  • 异步交互场景接入消息队列(RabbitMQ)
  • 服务结构示例:

4.3.5 分库分表

  • 拆分数据库,保证每个服务独立维护自己的数据

  • 如需跨库查询,可通过服务调用异步消息解决

  • 公共数据(如字典表)可放到独立的basic-service

  • 数据库结构示例:

4.3.6 可选增强

  • 引入熔断限流(Sentinel)用于保证系统稳定性
  • 搭建分布式事务(Seata)解决多服务数据一致性问题
  • 添加认证鉴权(JWT/OAuth2)用于网关和认证服务

五、构建微服务模板解释

5.1 构建步骤

因为篇幅有限,这里只是先解释基本结构,深入了解各模块运作后面会写(应该?)

5.1.1 定义业务模块

share-modules 下:

  • share-device → 业务模块
  • share-file → 文件上传/下载服务
  • share-gen → 代码生成服务
  • share-job → 定时任务调度
  • share-order → 订单服务
  • share-payment → 支付服务
  • share-rule → 规则引擎/策略服务
  • share-statistics → 统计报表
  • share-system → 系统管理(用户、角色、菜单、字典等后台管理功能)
  • share-user → 用户服务

share-common 下:

  • share-common-core → 公共代码(工具类、基础封装)
  • share-common-datascope → 数据权限(可用sa-token简化)
  • share-common-datasource → 多数据源管理
  • share-common-rabbit → RabbitMQ消息队列
  • share-common-redis → Redis缓存
  • share-common-seata → 分布式事务Seata
  • share-common-security → 鉴权相关组件(可用sa-token简化)

5.1.2 注册中心与配置中心、网关、调用

  • 网关share-gateway
  • nacos集成配置:·
    nacos:
      discovery:
        # 服务注册地址
        server-addr: http://service:8848
        namespace: e5b3d857-7ca2-4d92-8a8e-e5f3b3f47a91
      config:
        # 配置中心地址
        server-addr: http://service:8848
        namespace: e5b3d857-7ca2-4d92-8a8e-e5f3b3f47a91
        # 配置文件格式
        file-extension: yml
        # 共享配置
        shared-configs:
          - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
  • 远程调用

    share-api 下:

    • share-api-order → 订单相关的 API 接口
    • share-api-rule → 规则服务的 API 接口
    • share-api-system → 系统服务的 API 接口
    • share-api-user → 用户服务的 API 接口

5.1.3 运维模块

可视化监控

share-visual下:

share-visual-monitor

  • 系统运行状态监控、性能指标面板。
  • 类似SpringBoot Admin这种功能

日志模块

share-common下:

share-common-log → 日志模块

六、小结

单体架构适合小型项目,分布式能解决可靠性问题,微服务以分布式为基础的架构实现,更关注业务边界、独立部署和高内聚低耦合。如果你正准备升级项目架构,可以先从服务拆分 + 注册配置中心入手,逐步引入网关、服务通信,慢慢增加


欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1701220998@qq.com
导航页 GitHub