LinuxNotes

第 29 章:高负载服务部署

zjc 于 2026-01-29 发布

这是《Linux 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 高负载服务的 Linux 部署不只是把进程启动,还要规划用户、目录、版本、服务、日志、端口、资源限制、安全边界、健康检查、发布回滚和容量。本章把这些要求组合成一套可执行方案。

29.1 部署目标

1. 可重复安装
2. 配置可版本化
3. 服务可观测
4. 发布可回滚
5. 资源有边界
6. 安全最小化
7. 故障可恢复
8. 容量可扩展

非目标:

  1. 手工修改单台机器;
  2. 依赖登录 Shell 环境变量;
  3. 日志无上限;
  4. root 运行;
  5. 单机部署且无备份。

29.2 用户与目录

创建服务用户:

sudo useradd -r -s /sbin/nologin -d /opt/order app

目录:

/opt/order
  |-- releases/
  |   |-- 202608251200/
  |   +-- 202608260900/
  |-- shared/
  |   |-- conf/
  |   +-- data/
  |-- logs/
  |-- run/
  +-- current -> releases/202608260900

权限:

sudo mkdir -p /opt/order/{releases,shared/{conf,data},logs,run}
sudo chown -R app:app /opt/order
sudo chmod -R 750 /opt/order
sudo chmod 640 /opt/order/shared/conf/*

发布产物与可变数据分离,回滚时只切换符号链接。

29.3 systemd 服务

/etc/systemd/system/order.service

[Unit]
Description=Order Service
Wants=network-online.target
After=network-online.target

[Service]
Type=simple
User=app
Group=app
WorkingDirectory=/opt/order/current
Environment=APP_ENV=production
Environment=JAVA_OPTS=-XX:MaxRAMPercentage=65.0
EnvironmentFile=-/etc/order/env
ExecStart=/usr/bin/java $JAVA_OPTS -jar app.jar
ExecStop=/bin/kill -TERM $MAINPID
Restart=on-failure
RestartSec=5s
TimeoutStopSec=30s
KillMode=mixed
LimitNOFILE=65535
LimitNPROC=4096
UMask=0027

NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ReadWritePaths=/opt/order/logs /opt/order/shared/data

[Install]
WantedBy=multi-user.target

启用:

sudo systemctl daemon-reload
sudo systemctl enable --now order.service
systemctl status order --no-pager

29.4 日志与轮转

/etc/logrotate.d/order

/opt/order/logs/*.log {
    daily
    rotate 14
    missingok
    notifempty
    compress
    delaycompress
    dateext
    create 0640 app app
    copytruncate
}

应用日志也可以输出 journald 或 stdout,由采集器处理。无论哪种方式,必须有:

  1. 留存周期;
  2. 大小上限;
  3. 结构化格式;
  4. trace_id;
  5. 敏感信息脱敏;
  6. 采集监控。

29.5 健康检查

健康端点:

curl -sf http://127.0.0.1:8080/healthz
curl -sf http://127.0.0.1:8080/readyz

分层:

检查 用途
liveness 进程是否需要重启
readiness 是否可以接流量
dependency 依赖是否异常
version 版本确认
metrics 指标采集

不要把所有慢依赖都放入 liveness,否则依赖抖动可能引发服务重启风暴。

29.6 资源边界

systemd:

CPUQuota=300%
MemoryHigh=5G
MemoryMax=6G
TasksMax=2048
IOWeight=100

容量检查:

systemctl show order -p CPUQuota -p MemoryMax -p TasksMax
cat /proc/$(systemctl show -p MainPID --value order)/limits

Java 内存:

容器或服务内存上限 6G
  -> 堆约 65%
  -> 元空间、线程栈、直接内存预留
  -> 系统和页缓存预留

29.7 发布流程

1. 构建产物并生成校验值
2. 上传到制品库
3. 预检查:磁盘、端口、依赖、配置
4. 分发到批次实例
5. 解压到 release 目录
6. 校验版本和配置
7. 更新 current 链接
8. 重启或热加载
9. readiness 通过
10. 接回流量
11. 观察错误率、延迟、资源
12. 继续下一批

单机脚本:

#!/usr/bin/env bash
set -euo pipefail

release_id="${1:?release id required}"
release_dir="/opt/order/releases/${release_id}"

[[ -d "$release_dir" ]] || { echo "release not found" >&2; exit 1; }
ln -sfn "$release_dir" /opt/order/current.next
mv -T /opt/order/current.next /opt/order/current
sudo systemctl restart order
curl -sf --retry 10 --retry-delay 1 \
  http://127.0.0.1:8080/readyz

29.8 回滚

1. 判定停止条件
2. 摘除异常实例
3. current 指向上一版本
4. 重启服务
5. readiness 验证
6. 接回流量
7. 保留现场日志和配置

可回滚前提:

  1. 数据库变更向后兼容;
  2. 配置版本可切换;
  3. 上一制品仍在;
  4. 健康检查可信;
  5. 回滚步骤演练过。

29.9 容器化部署

Kubernetes 示例:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: order
spec:
  replicas: 6
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0
      maxSurge: 1
  selector:
    matchLabels:
      app: order
  template:
    metadata:
      labels:
        app: order
    spec:
      terminationGracePeriodSeconds: 30
      containers:
        - name: order
          image: registry.example.internal/order:1.0.0
          ports:
            - containerPort: 8080
          envFrom:
            - configMapRef:
                name: order-config
          resources:
            requests:
              cpu: "1"
              memory: 2Gi
            limits:
              cpu: "2"
              memory: 3Gi
          readinessProbe:
            httpGet:
              path: /readyz
              port: 8080
            initialDelaySeconds: 10
            periodSeconds: 5
          livenessProbe:
            httpGet:
              path: /healthz
              port: 8080
            initialDelaySeconds: 20
            periodSeconds: 10

镜像要求:

  1. 固定基础镜像版本;
  2. 非 root 用户;
  3. 只包含必要文件;
  4. 健康检查;
  5. 正确处理 SIGTERM;
  6. 不写可写层。

29.10 监控接入

主机:

CPU、内存、磁盘、IO、网络

进程:

进程存活、重启次数、FD、线程数、RSS

应用:

QPS、成功率、P95 / P99、队列、依赖耗时

发布:

版本、发布批次、配置版本、变更时间

日志:

ERROR、WARN、GC、连接失败、认证失败

29.11 上线检查清单

[ ] 服务用户和目录权限正确
[ ] systemd unit 通过语法和启动验证
[ ] 健康检查和指标端点可用
[ ] 日志轮转和采集验证
[ ] ulimit、内存、CPU、任务数设置
[ ] 防火墙只开放必要端口
[ ] sudo 和 SSH 权限审计
[ ] 备份和恢复流程确认
[ ] 发布与回滚演练
[ ] 监控告警配置
[ ] 值班和升级路径
[ ] 文档和 Runbook

本章小结

高负载服务部署要以可重复和可回滚为核心:独立用户、版本目录、systemd 边界、日志轮转、资源限制、健康检查、监控和灰度发布。容器化后同样要保留这些要求,只是由镜像和编排系统承载。

思考题

  1. releases 目录加 current 链接有什么好处?
  2. readiness 和 liveness 应该如何设计?
  3. Java 服务内存上限如何分配?
  4. 哪些数据库变更会导致无法回滚?
  5. 设计一套 20 台机器的灰度发布方案。