AIGO微服务电商项目全栈拆解(02)技术选型与整体分层
写在前面
第 01 篇从业务视角看了这两套系统「做什么」,后续文章还会拆开它们的页面与接口面。这一篇先补上两者中间的「地基」:这些系统是用什么技术搭起来的、为什么这么选、在整体上怎样分层,以及它们实际上被部署成了什么样子。
这一篇只讲架构:不引用任何代码,也不展开工程目录里的实现细节;文中的判断都可以在两套系统的配置与文档中得到印证。
- C 端后端:GoFrame v2 + gRPC 微服务 + HTTP 网关;
- B 端后端:Gin + GORM 单体;
- 两端前端:Vue 3 与 Vue 2.7 的两套技术栈;
- 数据与中间件:MySQL、Redis、RabbitMQ、MinIO、文件注册中心 / etcd;
- 可观测性:OpenTelemetry + Prometheus + Grafana,配 Loki / Tempo / Alloy;
- 部署形态:三节点最小化高可用 + 独立中间件服务器。
一、C 端后端:GoFrame v2 + gRPC + HTTP 网关
1.1 为什么是 GoFrame v2
C 端是一个由网关和 6 个领域服务组成的微服务系统。这类系统的难点往往不在业务代码,而在”配套”:服务如何互相发现、调用如何治理、配置与日志如何统一、指标与链路如何接入。
GoFrame v2 的选型逻辑,就是用一套框架一次性解决这些配套问题:gRPC、注册发现、负载均衡、配置、日志、数据库与 Redis 访问、指标与链路接入,都在同一套框架与它的扩展体系之内。由此带来的直接好处是——业务之外的部分不需要”拼装”:注册中心可以按环境切换实现(本地文件注册中心 / 生产 etcd),链路与指标有统一的装配入口,每个服务都保持同一套分层与启动约定。
一个很好的对照就在隔壁:B 端后台是单进程应用,用的是更轻的 Gin + GORM;C 端是多进程微服务,才需要”配套完整”的方案。这不是”哪个框架更好”,而是”哪个匹配当前的系统形态”。
1.2 HTTP 对外、gRPC 对内
C 端对外只有一个 HTTP 入口——商城网关;服务与服务之间则全部使用 gRPC。这个组合是 BFF(Backend For Frontend)模式的典型形态:
- 对前端友好:前端只面对一个地址、一套响应结构,不需要知道背后有几个服务;
- 对内强契约:gRPC 接口由协议定义,服务边界清晰、性能好,也保留了多语言与流式能力的空间;
- 职责分离:网关负责”接入”(鉴权、响应封装、错误码),领域服务只负责”领域”。
1.3 网关的横切能力
网关不只是一台反向代理,它承接了整个 C 端的横切关注点:
- 统一响应与分域错误码:所有接口返回同一种响应结构;错误码按业务域划分,让错误从领域服务 → 网关 → 前端一路保持可诊断;
- 鉴权与用户上下文:登录态在网关校验,用户身份随调用链透传到每个领域服务——领域服务不需要自己解析 Token,就能知道”当前是谁”;
- 负载均衡:通过服务发现拿到实例列表后,以轮询策略分发请求(三节点部署时,请求自然分摊到各个副本);
- 接口文档入口:网关对外提供统一的接口文档,作为前后端联调的契约。
二、B 端后端:Gin + GORM 单体
B 端后台的技术选型与 C 端刻意不同:Gin + GORM 的单体应用。原因不在技术偏好,而在业务形态:
- 后台面向运营人员,并发低、请求形态简单,不需要 RPC 与服务治理这一整套基础设施;
- 后台的核心诉求是”看得全“:数据看板、商品与订单管理都需要跨会员、商品、营销、交易多个业务域做聚合查询——一个进程直连多个领域库,比拆成服务再互相调用更直接;
- 管理后台与商城有各自的账号体系与操作边界,作为两个独立系统部署,更利于隔离与演进。
虽说是”单体”,它内部并不简单:除了业务接口,还内置了定时任务(如活动的自动填充、物流信息同步)、多承运商的物流对接能力,以及对象存储(商品素材等文件)与运行指标的接入——它是一个能独立站起来的应用,而不是商城网关后面的一个下游。
三、两端前端:Vue 3 与 Vue 2.7
两端前端的技术栈对照:
| 维度 | C 端商城 | B 端运营后台 |
|---|---|---|
| 框架 | Vue 3.5 | Vue 2.7 |
| 组件库 | Element Plus | Element UI |
| 路由 / 状态 | Vue Router 4 / Vuex 4 | Vue Router 3 / Vuex 3 |
| 图表 | — | ECharts + v-charts |
部署上,两个前端最终都以静态资源的形式交付,由 Nginx 承载并转发对后端接口的请求——这也是前后端分离项目最常见的交付形态。
四、数据与中间件
4.1 MySQL
C 端的领域服务按业务域各自拥有一个数据库——会员、商品、营销、购物车、订单共五个领域库(网关负责接入、检索由商品服务承接,它们不持有独立数据库)。
这里最重要的架构事实是:B 端运营后台连接的是同一批领域库。于是就有了贯穿整个系列的那句话——两套系统没有共用网关、没有互相调用,它们只在数据层相遇;运营在后台做的改动,消费者端立刻可见,不存在”数据同步”这个环节。
4.2 Redis 与两级缓存
Redis 在两端的角色不完全一样:
- C 端:承担热点数据的缓存,采用两级缓存设计——进程内缓存(L1)挡住绝大部分重复读,Redis(L2)作为跨实例共享的缓存层,读路径自动回源;
- B 端:缓存被设计成一层可切换的抽象,Redis 与进程内缓存两种实现可以按部署环境选择。
两端共同的设计取向是:缓存是可替换的实现,而不是硬编码的依赖。
4.3 RabbitMQ:异步事件与延迟任务
消息队列在系统里承担”解耦异步”的角色,几条典型链路:
- 用户访问事件:网关把用户的访问行为异步发布,会员服务消费后发放积分——一条跨服务的异步链路;
- 订单相关:订单状态变化、支付状态、超时关闭、自动收货、售后命令都通过消息投递;
- 延迟与兜底:延迟消息负责在精确到期点推进状态,周期扫描负责覆盖服务重启或消息投递失败的窗口——一个管”准时”,一个管”兜底”,这是订单链路上一条重要的设计。
消息层同样做了可替换抽象(生产者、消费者、订阅与消费结果模型),当前落地实现是 RabbitMQ;接口足够克制,未来更换或增加实现时不影响业务代码。
4.4 注册中心:本地文件注册中心,生产 etcd
服务注册发现按环境采用两种形态:
- 本地开发:使用文件注册中心——注册信息落在共享目录里,不需要任何外部组件就能把整套微服务跑起来;
- 生产环境:使用 etcd,独立部署在中间件服务器上,7 个服务都向它注册,调用方按服务名解析实例。
选择哪种形态由配置决定。对三节点部署来说,注册中心是”高可用”能够成立的关键——节点故障时,实例被摘除,流量自动流向其余副本。
4.5 配置与日志的统一约定
- 配置:同一套服务代码,通过替换配置适配本地、容器与生产环境,而不是改代码;
- 日志:两端各自统一了日志的落盘与滚动策略(按天滚动、限制单文件大小与保留数量),便于统一采集进日志系统(见下一节)。
五、可观测性:OTel + Prometheus + Grafana 体系
项目采用如下常见的可观测性组合:
| 信号 | 采集 | 存储 | 展示 |
|---|---|---|---|
| 指标 | 各服务暴露指标端点 | Prometheus | Grafana |
| 链路 | OpenTelemetry(C 端 OTLP/gRPC、B 端 OTLP/HTTP) | Tempo | Grafana |
| 日志 | Alloy 采集容器日志 | Loki | Grafana |
- OpenTelemetry 作为采集标准:两端用不同的传输方式接入(C 端走 OTLP gRPC、B 端走 OTLP HTTP);
- Grafana 作为统一入口:指标、链路、日志三种数据都汇入 Grafana,排障时可以在同一个界面里从指标下钻到链路、再跳到日志;
- 环境开关:本地开发默认关闭链路与指标上报,联调与部署环境才打开——避免开发流量污染监控数据。
六、整体分层:四层视角
根据一个请求走过的组件,整个系统可以分成以下四层:
| 层 | C 端 | B 端 |
|---|---|---|
| 前端交互层 | Vue 3 商城用户端 | Vue 2.7 运营后台 |
| 接入层 | 商城网关(HTTP 唯一入口) | Gin 单体(管理接口 + 用户侧接口) |
| 领域服务层 | member / product / promotion / search / cart / order(gRPC) | 无(业务逻辑在单体内部) |
| 数据与平台层 | MySQL×5、Redis、RabbitMQ、注册中心、可观测性 | 同一个数据层 + 自有缓存 |
再往下看一层,每个 C 端领域服务内部遵循同一套分层约定:接口层 → 业务层 → 数据访问层,职责自上而下收敛;而横切能力(统一响应、错误码、用户上下文、缓存、消息)则被收敛到一个共享的公共库里,避免在每个服务里重复实现、各自演化。
七、全景架构图
八、实际部署架构:三节点最小化高可用
讲完逻辑架构,再看它实际跑在哪里——这套环境追求的是一种”最小化的高可用“:应用层做多副本冗余,中间件与观测保持精简。
8.1 应用层:每个服务三副本
7 个服务(网关 + 6 个领域服务)都部署为 3 副本,分布在三台虚拟机上(192.168.92.10 ~ 192.168.92.12,这三台虚拟机运行在同一台物理机内):
- 每个服务在每个节点上各有一个副本,任一节点故障时,故障实例被注册中心摘除,流量由其余两个节点继续承接;
- 发布时可以逐个节点进行,保持整体可用;
- 三副本是”最小的高可用形态”——允许单节点故障,又不需要太多的机器。
8.2 中间件:独立服务器 + Docker 单节点
中间件全部集中部署在一台独立服务器(192.168.92.3)上,通过 Docker 以单节点形态提供:
| 组件 | 角色 |
|---|---|
| MySQL | 五个领域库的数据存储 |
| Redis | 缓存与业务辅助状态 |
| RabbitMQ | 异步事件与延迟任务 |
| MinIO | 对象存储(商品素材等文件) |
| etcd | 生产环境的服务注册发现中心 |
把中间件集中到独立服务器,与业务节点解耦:业务节点可以自由扩缩容,中间件则是”共享底座”。需要注意的是:这套环境用应用层的三节点冗余来验证高可用形态,数据层与消息层的冗余等待后续有足够的机器再去验证。
8.3 可观测性:监控中心
可观测性组件以监控中心的形式集中部署(与中间件同在这台服务器上):
| 组件 | 角色 |
|---|---|
| Alloy | 遥测采集与转发(OTLP 入口、容器日志采集) |
| Prometheus | 指标存储与查询 |
| Loki | 日志存储 |
| Tempo | 链路存储 |
| Grafana | 统一展示(指标 / 链路 / 日志) |
业务节点上的每个服务把链路、指标与日志统一上报到监控中心——应用只负责”产生遥测”,监控中心负责”收集与展示”,这正是标准的可观测性分工。
8.4 部署视图
读图提示:
- 上半部分是应用层:三台虚拟机、每个服务三副本,任一副本故障不影响整体;
- 下半部分是 192.168.92.3 服务器:中间件(Docker 单节点)与监控中心;
- 应用节点与中间件之间是注册发现与数据、缓存、消息的日常流量;到监控中心则是遥测数据;
- B 端后台是独立单体部署,连接同一套中间件与数据层。
九、小结
| 维度 | 选型 | 关键理由 |
|---|---|---|
| C 端后端框架 | GoFrame v2 | 微服务配套完整(gRPC、注册发现、配置日志、指标链路),不需要拼装 |
| 服务通信 | gRPC(内部)+ HTTP(网关对外) | BFF 模式:前端简单,内部强契约 |
| B 端后端 | Gin + GORM 单体 | 运营侧低频、要跨库聚合,”单体直连”比服务化更直接 |
| 数据 | MySQL 五个领域库 | 一服务一库;两套系统共享同一批库,是唯一的交汇点 |
| 缓存 | 两级缓存(进程内 + Redis) | 抵御热点读;实现可替换 |
| 消息 | RabbitMQ + 可替换抽象 | 异步解耦、延迟任务;核心接口不绑定具体实现 |
| 注册中心 | 文件注册中心(本地)/ etcd(生产) | 本地零依赖起步,生产支撑三节点高可用 |
| 可观测性 | OTel + Prometheus + Grafana(Loki / Tempo / Alloy) | 事实标准组合,三种信号统一汇入 Grafana |
| 部署形态 | 三节点最小化高可用 | 应用三副本冗余 + 独立中间件服务器(单节点) |
- C 端选了一套”自带微服务配套”的框架(GoFrame v2),把所有服务治理收进统一的装配流程;
- 两端前端的分裂是生态成本的决定,不是随意为之;
- 数据层是两套系统唯一的交汇点;缓存、消息、注册中心都做了”实现可替换”的抽象;
- 部署上采用”三节点最小化高可用“:应用层每个服务三副本,中间件与可观测性集中在独立服务器;
1.AIGO微服务电商项目全栈拆解(07)管理后台的系统设计
2.AIGO微服务电商项目全栈拆解(16)用户积分与会员等级:从动态账户到账本建模
3.AIGO微服务电商项目全栈拆解(13)设计模式全景:从代码里数出用了哪些模式
4.AIGO微服务电商项目全栈拆解(17)管理后台的技术实现:Gin、直连多库、任务与物流
5.AIGO微服务电商项目全栈拆解(14)为将来可替换而设计:第三方封装的横向总结
6.AIGO微服务电商项目全栈拆解(10)支付抽象与支付状态闭环
7.AIGO微服务电商项目全栈拆解(12)用 MQ 异步化解耦非核心业务
8.AIGO微服务电商项目全栈拆解(15)购买后投放系统:责任链、快照与并发收敛