外观
一、项目整体架构
如果你只做过前端,可以把"微服务架构"想象成—— 你把一个巨大的 Monorepo 拆成了好几个独立部署的应用,它们各自有自己的端口、数据库,彼此之间像前端调后端一样通过 HTTP / 消息队列通信。
1.1 技术栈一句话概括
- 框架:Spring Cloud 微服务(Spring Boot + Spring Cloud)
- 语言:Java 17
- 数据库:MongoDB(主库,存业务数据)+ MySQL(辅助统计分析)
- 缓存:Redis
- 消息队列:RocketMQ
- 对象存储:OSS(云端文件存储)
- 部署:Docker / Kubernetes
1.2 用前端术语理解后端概念
如果你已经做过 React / Vue / Next.js 项目,这张表可以帮你快速建立映射:
| 后端概念 | 前端类比 | 在项目中长什么样 |
|---|---|---|
| 微服务 | 把一个大型 Monorepo 拆成多个可独立部署的应用 | gateway、user-service、ai-service 等各自独立启动 |
| 网关 (Gateway) | Nginx 反向代理 / 前端 BFF 统一入口 | 所有外部请求先到网关,再转发到具体服务 |
| Feign Client | 封装好的 axios 实例,调用远端接口就像调本地函数 | 在共享 API 模块中声明接口,自动发 HTTP 请求 |
| Controller | Next.js 的 app/api/ 路由 / Express 的 router.get() | 每个服务的 controller/ 目录 |
| Service | 前端 service 层 / 业务逻辑 composable / hook | 每个服务的 service/ 目录 |
| Repository | 前端对 localStorage / IndexedDB 的读写封装 | 每个服务的 repository/ 目录 |
| DTO / VO | TypeScript 的 interface / type | dto/、vo/ 目录中的 Java 类 |
| 消息队列 (MQ) | EventBus / Redux middleware / postMessage | RocketMQ——发一条消息出去,另一个服务在后台消费 |
| Redis 缓存 | 浏览器 sessionStorage / 前端内存缓存 | 速度快、常用于限流、缓存、分布式锁 |
| 组件模块 (component/) | @org/utils、@org/http-client 等共享 npm 包 | component/ 下的各种 cpt-* 基础模块 |
1.3 服务拆分总览
一个典型的 Spring Cloud 微服务项目长这样:
text
project-root (父工程,类似 Monorepo 根目录)
│
├── component/ ← 共享基础组件(类比你的 packages/ 或 libs/)
│ ├── cpt-api ← 所有服务间调用的客户端 + 共享 DTO
│ ├── cpt-common ← 通用工具类、统一响应格式
│ ├── cpt-mongodb ← MongoDB 连接与操作封装
│ ├── cpt-mysql ← MySQL 连接与 ORM 封装
│ ├── cpt-redis ← Redis 缓存封装
│ ├── cpt-rocketmq ← 消息队列封装
│ └── cpt-xxljob ← 定时任务框架
│
├── svc-gateway ← API 网关(唯一对外暴露的入口)
├── svc-auth ← 认证服务(登录 / token 颁发与校验)
├── svc-user ← 用户服务(注册 / 登录 / 配额 / 支付)
├── svc-ai ← AI 服务(图片生成 / 文字处理 / 人脸检测)
├── svc-canvas ← 画布服务(模板 / 作图 / 任务编排,最复杂)
├── svc-oss ← 文件存储服务(上传 / 下载 / 云 OSS)
└── svc-admin ← 管理后台(后台管理 / 数据统计)💡 前端类比:
component/就像你的packages/shared,而svc-*就像apps/web、apps/admin等可独立部署的应用。
1.4 三种服务间通信方式
微服务之间怎么"说话"?这个项目用了三种方式:
| 通信方式 | 用途 | 前端类比 | 什么时候用 |
|---|---|---|---|
| HTTP (Feign) | 服务之间同步调用 | axios.get('/api/xxx') | 需要立刻拿到结果的场景(如查询用户信息) |
| RocketMQ 消息队列 | 异步耗时任务 | postMessage + Web Worker | 不需要立刻拿到结果(如提交 AI 生图任务) |
| Redis | 缓存 + 分布式锁 | localStorage + 简易互斥锁 | 需要缓存热数据或防并发的场景 |
关于服务发现
你可能听说过"注册中心"(Nacos、Eureka)。在容器化部署(Docker / K8s)环境下,更常见的做法是 DNS 直连——每个服务通过容器名就能找到对方,不需要额外的注册中心。
yaml
# 示意:Feign 客户端的服务地址配置
@FeignClient(name = "ai-service", url = "${service.ai.url}")
# 实际运行时 service.ai.url 由环境变量注入,如 http://ai-service:80801.5 网关的作用(重点理解)
网关好比大楼的前台,所有外部请求必须经过它,它负责四件事:
text
客户端请求
│
▼
┌──────────────────────────────────┐
│ API 网关 (Gateway) │
│ │
│ 1. 路由转发 │
│ /api/user/** → 用户服务 │
│ /api/ai/** → AI 服务 │
│ /api/oss/** → 存储服务 │
│ │
│ 2. 身份认证 │
│ 读取 token → 调认证服务校验 │
│ 白名单路径跳过认证 │
│ │
│ 3. 限流 │
│ 基于 Redis 计数器限频 │
│ │
│ 4. 熔断 │
│ 某服务不可用时快速失败 │
│ 防止拖垮整个系统 │
└──────────────────────────────────┘
│
▼
目标微服务前端类比:你可以把网关理解为一个"超级 Nginx",它除了做反向代理(路由转发),还内置了登录校验中间件、限流中间件、熔断中间件。
