部署架构:从代码到运行环境的映射术

2026-06-01 19 预计阅读时间:1 分钟
来源:my.oschina.net AI 摘要 原文链接

免责声明:本文为 AI 摘要整理,建议结合原文阅读。摘要可能省略上下文、版本差异或边界条件,不作为官方说明。

预计阅读时间:10 分钟

写完代码,跑通测试,离"上线"还有一道硬坎——你的服务到底部署在什么环境上?一台物理机、一个机房、还是云上的几个可用区?网络怎么打通、资源怎么分配、数据库和 Redis 放哪里?这些问题全归"部署架构"管。它不是画几张拓扑图交差,而是把软件的每一层需求映射到物理环境的每一层能力上。

部署架构覆盖的三层现实

部署架构要回答的核心问题:软件需要什么,物理环境能给什么,中间怎么对齐?

1. 网络层——连通性与隔离

网络是部署架构的地基。你需要决定:

  • VPC / 子网划分:哪些服务对公网暴露,哪些只在内部通信。
  • 跨可用区 / 跨机房链路:同城双活还是异地灾备,延迟容忍多少。
  • 安全组与防火墙规则:入站出站端口白名单,避免"全开"的惯性操作。

一个常见失误:应用层和数据库层放在同一个子网,公网流量直达数据库端口。正确做法是至少分出前端子网(挂负载均衡)和后端子网(只允许内部访问),数据库子网再单独隔离。

2. 主机层——CPU、内存与密度

每台主机(无论物理机还是云虚拟机)的 CPU 核数和内存大小,决定了你能在这台机器上塞多少进程。关键决策点:

  • 大机器 vs 小机器:一台 64 核 256GB 的机器跑所有服务,还是 8 台 8 核 32GB 的机器各跑一个?前者运维简单但单点风险大;后者资源碎片多但故障域小。
  • 混部与独占:日志收集 Agent 可以和业务进程混部;Redis 如果做持久化存储,最好独占一台机器,避免内存被挤占后触发 OOM。
  • 超卖比例:云上通常允许 CPU 超卖 2-4 倍,内存一般不超卖。如果你自建集群,要明确每台机器的实际可用量,而不是看标称值。

3. 基础软件服务层——数据库、Redis 及中间件

数据库和缓存不是"装上就行",它们的位置直接影响部署架构的可靠性:

  • 数据库主从分布:主库放在可用区 A,从库放在可用区 B,写流量走 A,读流量可以就近走 B。
  • Redis 集群模式:单实例只适合缓存场景;如果用作会话存储或分布式锁,至少 Sentinel 三节点,甚至 Cluster 六节点起步。
  • 中间件依赖方向:服务 A → Redis → MySQL,依赖链不能成环,否则故障会级联放大。

用 Docker Compose 画一张小型部署架构图

纸上谈兵不如动手落地。下面是一个典型中小项目的部署架构,用 docker-compose.yaml 把网络隔离、资源限制、基础服务位置全部声明出来——这就是部署架构的可执行版本。

# docker-compose.yaml — 小型项目部署架构声明
version: "3.9"

networks:
  frontend:   # 对外网络,挂反向代理
    driver: bridge
  backend:    # 内部网络,应用与基础服务通信
    driver: bridge
    internal: true  # 不暴露到宿主机

services:
  # ── 前端网关 ──
  nginx:
    image: nginx:1.27-alpine
    ports:
      - "80:80"
      - "443:443"
    networks:
      - frontend
      - backend        # 能访问后端应用,但不能直连数据库
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d:ro
    deploy:
      resources:
        limits:
          cpus: "1.0"
          memory: 512M

  # ── 业务应用 ──
  app:
    image: myapp:latest
    networks:
      - backend         # 只在内部网络,不对外
    environment:
      - DB_HOST=mysql
      - DB_PORT=3306
      - REDIS_HOST=redis
      - REDIS_PORT=6379
    deploy:
      resources:
        limits:
          cpus: "2.0"
          memory: 1G
      replicas: 2       # 两个实例,故障域缩小

  # ── 数据库(独占资源) ──
  mysql:
    image: mysql:8.0
    networks:
      - backend
    volumes:
      - mysql-data:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=${DB_ROOT_PWD}
      - MYSQL_DATABASE=myapp
    deploy:
      resources:
        limits:
          cpus: "2.0"
          memory: 2G    # 独占 2GB,不与其他进程挤占

  # ── Redis 缓存 ──
  redis:
    image: redis:7-alpine
    networks:
      - backend
    command: ["redis-server", "--maxmemory", "512mb", "--maxmemory-policy", "allkeys-lru"]
    deploy:
      resources:
        limits:
          cpus: "0.5"
          memory: 768M  # 预留 256M 给 Redis 进程自身开销

volumes:
  mysql-data:

运行前改什么:

  • myapp:latest 替换成你自己的应用镜像名。
  • ${DB_ROOT_PWD}.env 文件里设置,不要硬编码。
  • replicas: 2 在单机 Docker Compose 下会启动两个容器;如果切到 Swarm 或 Kubernetes,这个字段直接生效为多实例调度。
  • --maxmemory 512mbdeploy.resources.limits.memory: 768M 之间留了 256MB 缓冲,防止 Docker OOM Kill 先于 Redis 自身淘汰策略触发。

启动命令:

# 启动全部服务
docker compose up -d

# 查看各服务资源占用
docker stats --no-stream

# 验证网络隔离:从宿主机无法直连 mysql 3306
# (因为 backend 是 internal 网络,只有 nginx 和 app 能访问)
mysql -h 127.0.0.1 -P 3306 -u root -p  # 应该连接失败

这个 Compose 文件把部署架构的三层全部声明了:网络隔离(frontend/backend 分离)、主机资源(CPU/内存 limits)、基础服务位置(MySQL 和 Redis 只挂在 backend 网络)。从这张文件出发,你可以逐步替换为 Kubernetes 的 Deployment + Service + NetworkPolicy,架构骨架不变。

从单机到集群:部署架构的演进路线

上面的 Compose 例子跑在一台机器上,适合开发和小流量场景。当流量增长或可靠性要求提高,部署架构需要演进:

阶段 网络变化 主机变化 基础服务变化
单机 全部 bridge 网络 一台机器所有服务 MySQL/Redis 同机部署
多机同机房 前端子网 + 后端子网 应用 2-4 台,数据库独占 MySQL 主从分离,Redis Sentinel
跨可用区 两个 VPC 对等连接 每可用区至少 2 台应用 MySQL 跨 AZ 主从,Redis Cluster
多区域/异地 VPN / 专线打通 每区域独立集群 数据同步(异步复制或双写)

每次演进的核心动作都是先拆网络,再拆主机,最后拆基础服务。反过来做(先加机器但不改网络拓扑)往往导致流量绕路、安全边界模糊。

常见踩坑与决策清单

  1. 数据库和缓存放同一台机器——内存争抢,Redis 被 OOM Kill 后缓存雪崩。分开部署,哪怕是小规格机器。
  2. 所有端口对公网开放——至少数据库和 Redis 的端口绝不能暴露。用安全组或 internal: true 网络隔离。
  3. 只看 CPU 不看内存——Java 应用和 Redis 都是内存密集型,内存不够比 CPU 不够更致命。先算内存预算。
  4. 没有资源 limits——一个失控的进程可以吃掉整台机器的内存,拖垮同机所有服务。务必设置 limits。
  5. 忽略依赖方向——画一张依赖图,确保方向是单向的:应用 → 缓存 → 数据库,不能反过来。

上线前快速检查清单:

  • ✅ 网络是否分出前端和后端子网?
  • ✅ 数据库端口是否对公网不可达?
  • ✅ 每个服务是否设置了 CPU 和内存 limits?
  • ✅ Redis 是否配置了 maxmemory 和淘汰策略?
  • ✅ MySQL 数据目录是否挂了持久卷,重启不丢数据?
  • ✅ 应用是否至少两个实例,单实例挂掉不影响整体?

部署架构不是一次性画完就结束的文档,而是随流量、可靠性需求、成本约束持续演进的活设计。从一张 docker-compose.yaml 开始,把网络、资源、基础服务的位置写清楚,后续迁移到 Kubernetes 或多云时,这张文件就是你的架构起点。


相关推荐