2. 单体应用架构回顾

在深入 Helm Chart 如何支撑微服务拆分之前,有必要先回顾单体应用架构的核心特征。单体应用(Monolithic Application)是指将所有功能模块打包在同一个进程内、部署为单一单元的软件架构。理解其定义、结构、优势与局限,是后续架构演进的基础。

2.1 单体应用的定义

单体应用将所有业务逻辑、数据访问、用户界面整合为一个可执行文件或部署包。无论是 Java 的 WAR/JAR、.NET 的 DLL、还是 Node.js 的单一入口文件,其本质特征在于:整个应用作为一个整体构建、测试、部署和扩展。

维度 单体应用特征
部署单元 单一进程 / 单一包
模块间通信 进程内方法调用(函数/类)
数据存储 通常共享同一个数据库实例
扩展粒度 整体复制,无法按需扩展单个模块
技术栈 全栈统一(语言、框架、中间件)

2.2 典型架构图:三层架构

单体应用最常见的组织方式是三层架构(Three-Tier Architecture),将职责划分为表现层、业务逻辑层和数据访问层。下图展示了这种经典结构:

单体应用三层架构示意图 表现层(UI) Web 页面 / REST API / 移动端接口 业务逻辑层(BLL) 订单服务 / 用户管理 / 支付处理 / 库存校验 数据访问层(DAL) ORM / Repository / SQL 查询 / 缓存访问 共享数据库(MySQL / PostgreSQL)
架构要点:三层之间通过进程内接口调用,数据访问层通常直接连接共享数据库。这种结构在项目初期开发效率极高,但随着业务增长,层与层之间的耦合会逐渐成为瓶颈。

2.3 优点分析

单体应用在早期阶段具有明显的工程优势,这也是它至今仍被广泛采用的原因:

  • 开发简单:单一代码库、单一构建脚本、单一 IDE 项目,新成员上手成本低。
  • 部署单一:只需构建一个包,复制到服务器即可运行,无需编排多个服务。
  • 调试直观:本地即可启动完整应用,端到端调试链路清晰。
  • 事务一致性强:共享数据库,ACID 事务天然支持,无需分布式协调。
  • 测试简便:集成测试只需启动一个进程,无需模拟外部服务。

2.4 缺点与局限性

当应用规模增长到一定程度,单体架构的缺点会逐渐暴露,成为团队交付效率的阻碍:

缺点 具体表现 影响
耦合度高 模块间通过类/函数直接依赖,修改一处可能影响全局 代码冲突频繁,回归测试范围大
扩展困难 只能整体水平扩展,无法单独扩容热点模块 资源浪费,高负载模块受限
技术栈锁定 全栈必须使用同一语言和框架 无法按模块选择最优技术
部署风险高 任何小修改都需要重新部署整个应用 发布频率低,故障影响面大
团队协作瓶颈 多人修改同一代码库,合并冲突和代码审查压力大 开发效率随团队规模线性下降
常见误区:并非所有项目都适合微服务。对于团队规模小、业务逻辑简单、变更频率低的项目,单体应用仍然是合理选择。盲目拆分微服务会引入分布式复杂性,反而降低交付效率。

2.5 单体应用的典型代码结构

以下是一个典型的 Java 单体应用项目结构,体现了三层架构的代码组织方式:

monolithic-app/
├── src/
│   ├── main/
│   │   ├── java/com/example/
│   │   │   ├── controller/          # 表现层 - REST 控制器
│   │   │   │   ├── OrderController.java
│   │   │   │   └── UserController.java
│   │   │   ├── service/             # 业务逻辑层
│   │   │   │   ├── OrderService.java
│   │   │   │   └── UserService.java
│   │   │   ├── repository/          # 数据访问层
│   │   │   │   ├── OrderRepository.java
│   │   │   │   └── UserRepository.java
│   │   │   └── model/               # 领域模型
│   │   │       ├── Order.java
│   │   │       └── User.java
│   │   └── resources/
│   │       ├── application.yml      # 统一配置
│   │       └── schema.sql           # 数据库 DDL
│   └── test/
│       └── java/com/example/
│           ├── OrderServiceTest.java
│           └── UserServiceTest.java
├── pom.xml                          # 单一构建文件
└── Dockerfile                       # 单一容器镜像
关键观察:所有模块共享同一个 pom.xml(或 build.gradle),所有代码打包进同一个 JAR/WAR 文件。数据库 DDL 集中管理,任何表结构变更都会影响所有模块。这种结构在 Helm Chart 中对应一个 Chart.yaml 和一个 templates/ 目录,部署时生成一个 Deployment 和一个 Service。

2.6 单体应用的部署拓扑

下图展示了单体应用在 Kubernetes 环境中的典型部署形态:

单体应用 Kubernetes 部署拓扑 用户 Ingress example.com Service ClusterIP: 80 Pod(单体应用) Container: monolithic-app:1.2.3 Container: sidecar (可选) 数据库 StatefulSet Replicas: 3(整体水平扩展)
Helm 视角:单体应用的 Helm Chart 通常只有一个 Deployment 模板、一个 Service 模板和一个 Ingress 模板。values.yaml 中主要控制副本数、镜像版本、环境变量和资源限制。这种简洁的 Chart 结构在微服务拆分后,会演变为每个微服务拥有独立的 Chart 或统一管理的子 Chart 集合。