从单体到云原生:后端架构演进实战指南

郭杰
2026-02-26 18:28
阅读 1342

大家好,我是小林,一名211高校计算机专业的研究生。过去三年,我一直在写技术博客,帮助零基础的同学快速上手后端开发。最近很多读者问我:“现在公司都在说微服务、云原生,但我不懂它们和传统单体应用到底有什么区别?”这个问题让我想起自己当初学的时候——面对一堆新名词,完全摸不着头脑。

今天,我就用最朴实的语言,带你亲手搭建一个从单体架构逐步演进到云原生的完整示例。不讲空洞理论,只讲你能跑起来的代码。哪怕你只会写“Hello World”,也能跟完这篇教程。


为什么你需要了解后端架构演进?

简单说:业务变复杂了,老办法扛不住了

  • 单体应用:所有功能(用户、订单、支付)写在一个项目里,部署成一个进程。
  • 微服务:把大项目拆成多个小服务,每个服务独立开发、部署、扩展。
  • 云原生:在云环境(如Kubernetes)中,用容器、声明式API、自动扩缩容等方式管理这些服务。

这就像你开小卖部 → 开连锁超市 → 用智能仓储系统管理全国门店的过程。


环境准备:5分钟搭好开发环境

我们用 JavaScript(Node.js)作为示例语言——它生态成熟、上手快,适合演示架构演进。你不需要成为JS专家,会基础语法即可。

步骤清单

  1. 安装 Node.js(推荐 v18+)

  2. 安装 Docker

  3. 安装 Codeium(可选但推荐)

    • 这是一个免费的AI编程助手,能自动补全代码、解释逻辑
    • 支持 VS Code、JetBrains 等主流编辑器
    • 官网:https://codeium.com
    • 我当初学微服务时,靠它快速生成了大量样板代码,省下不少查文档的时间
  4. 创建项目目录

mkdir backend-evolution
cd backend-evolution

第一阶段:单体应用(Monolith)

核心思想

所有功能塞进一个应用,像一块“大蛋糕”。

动手写一个单体版电商API

# 初始化项目
npm init -y
npm install express

创建 monolith.js

// monolith.js
const express = require('express');
const app = express();
app.use(express.json());

// 模拟数据库
let users = [{ id: 1, name: 'Alice' }];
let orders = [{ id: 101, userId: 1, product: 'Book' }];

// 用户服务
app.get('/users', (req, res) => {
  res.json(users);
});

app.post('/users', (req, res) => {
  const newUser = { id: users.length + 1, ...req.body };
  users.push(newUser);
  res.status(201).json(newUser);
});

// 订单服务
app.get('/orders', (req, res) => {
  res.json(orders);
});

app.listen(3000, () => {
  console.log('单体应用运行在 http://localhost:3000');
});

运行:

node monolith.js

测试:

curl http://localhost:3000/users
# 返回 [{"id":1,"name":"Alice"}]

优点:开发简单、部署方便
缺点:代码耦合、难以扩展、一处崩溃全挂

新手问题:为什么不用数据库?
答:为了聚焦架构,我们用内存数组模拟。真实项目当然要用MySQL/PostgreSQL。


第二阶段:拆分为微服务(Microservices)

核心思想

把大蛋糕切成小块,每块独立存在。

我们将拆成两个服务:

  • user-service:管理用户
  • order-service:管理订单

步骤1:创建 user-service

mkdir user-service
cd user-service
npm init -y
npm install express

user-service/server.js

const express = require('express');
const app = express();
app.use(express.json());

let users = [{ id: 1, name: 'Alice' }];

app.get('/users', (req, res) => res.json(users));
app.post('/users', (req, res) => {
  const user = { id: users.length + 1, ...req.body };
  users.push(user);
  res.status(201).json(user);
});

app.listen(3001, () => console.log('用户服务运行在 3001'));

步骤2:创建 order-service

cd ..
mkdir order-service
cd order-service
npm init -y
npm install express

order-service/server.js

const express = require('express');
const app = express();
app.use(express.json());

let orders = [{ id: 101, userId: 1, product: 'Book' }];

// 假设通过 HTTP 调用用户服务验证用户存在
app.post('/orders', async (req, res) => {
  const { userId, product } = req.body;
  // 简化:这里应调用 user-service 检查用户
  if (!userId) return res.status(400).json({ error: '需要用户ID' });
  
  const order = { id: Date.now(), userId, product };
  orders.push(order);
  res.status(201).json(order);
});

app.listen(3002, () => console.log('订单服务运行在 3002'));

启动两个服务

# 终端1
node user-service/server.js

# 终端2
node order-service/server.js

现在你可以分别访问:

  • http://localhost:3001/users
  • http://localhost:3002/orders

优点:独立开发、独立部署、技术栈可不同
缺点:网络调用增加、调试复杂、需处理服务发现

避坑指南:微服务不是银弹!小团队或简单业务用单体更高效。我见过太多人为了“时髦”强行拆微服务,结果维护成本翻倍。


第三阶段:容器化(Docker)

为什么需要容器?

确保“在我机器上能跑”的代码,在服务器、同事电脑、云平台都能跑。

为每个服务写 Dockerfile

user-service/Dockerfile

FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3001
CMD ["node", "server.js"]

order-service/Dockerfile 同理,只需改端口为3002。

构建并运行容器

# 构建镜像
docker build -t user-service ./user-service
docker build -t order-service ./order-service

# 运行容器
docker run -d -p 3001:3001 --name user-svc user-service
docker run -d -p 3002:3002 --name order-svc order-service

验证:

curl http://localhost:3001/users

技巧:用 Codeium 输入“Dockerfile for Node.js app”,它会自动生成标准模板,避免手写错误。


第四阶段:云原生(Cloud Native)

什么是云原生?

CNCF(云原生计算基金会)定义:使用容器、服务网格、微服务、不可变基础设施和声明式API构建的系统

我们用 Docker Compose 模拟云原生编排(比直接上K8s更友好)。

创建 docker-compose.yml

# docker-compose.yml
version: '3.8'
services:
  user-service:
    build: ./user-service
    ports:
      - "3001:3001"
    restart: unless-stopped

  order-service:
    build: ./order-service
    ports:
      - "3002:3002"
    restart: unless-stopped
    depends_on:
      - user-service

启动整个系统

docker-compose up --build

现在,一条命令启动全部服务!关闭时按 Ctrl+C

云原生关键特性实践

特性 本例体现
容器化 每个服务打包为Docker镜像
声明式配置 docker-compose.yml 描述期望状态
弹性 可轻松复制多份服务(加 scale 参数)
可观测性 日志集中输出(后续可接Prometheus)

学习建议:真实云原生会用 Kubernetes(K8s),但对新手太重。先掌握 Compose,再过渡到 K8s。


新手常见问题解答

Q1:微服务之间怎么通信?

  • 同步:HTTP/REST(如本例)、gRPC
  • 异步:消息队列(RabbitMQ、Kafka)
  • 初学者建议从 REST 开始,简单直观。

Q2:数据一致性怎么保证?

  • 单体:事务直接搞定
  • 微服务:用 Saga 模式(补偿事务)或 事件驱动
  • 示例:下单失败 → 发送“取消订单”事件回滚用户积分

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

  • VS Code Remote ContainersTelepresence
  • 或简单点:本地运行部分服务,其他连测试环境

Q4:一定要用云原生吗?

  • 不!评估你的需求:
    • 日活 < 1万:单体足够
    • 团队 < 5人:谨慎拆微服务
    • 需要快速迭代、高可用:考虑云原生

学习路径建议

第一步:夯实基础

  • 书籍推荐:《Node.js设计模式》(中文版)——讲解清晰,含架构案例
  • 实践:用 Express 写一个带数据库的博客系统

第二步:理解微服务

  • 书籍:《微服务架构设计模式》(Chris Richardson)
  • 工具:用 Postman 测试服务间调用
  • 关键概念:API 网关、服务注册中心、熔断器

第三步:拥抱云原生

  • 学习 Docker → Docker Compose → Kubernetes
  • 在线实验:Katacoda(提供免费K8s沙箱)
  • 用 Codeium 生成 YAML 配置,快速上手

第四步:工程化

  • 加入 CI/CD(GitHub Actions)
  • 日志收集(ELK Stack)
  • 监控告警(Prometheus + Grafana)

最后的话

我当初学架构演进时,最大的误区是“追求最新技术”。后来才明白:架构是为业务服务的,不是炫技的

这篇教程从单体→微服务→容器化→云原生,每一步都给你可运行的代码。希望你不仅能复制粘贴,更能思考:我的项目真的需要这么复杂吗?

记住:好的工程师,不是用最酷的技术,而是用最合适的方案解决问题。

如果你觉得有帮助,欢迎关注我的技术博客(文末有链接)。下期我们聊聊《如何用100行代码实现API网关》,敬请期待!

附:关键命令速查表

操作 命令
启动单体 node monolith.js
构建镜像 docker build -t <name> .
运行容器 docker run -p <宿主机端口>:<容器端口> <镜像>
启动Compose docker-compose up --build
查看日志 docker-compose logs -f

祝你编码愉快,少踩坑,多造轮子!

评论 0

最热最新
暂无评论
郭杰Lv.1
0
影响力
0
文章
0
粉丝