这是《Linux 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 高负载服务的 Linux 部署不只是把进程启动,还要规划用户、目录、版本、服务、日志、端口、资源限制、安全边界、健康检查、发布回滚和容量。本章把这些要求组合成一套可执行方案。
29.1 部署目标
1. 可重复安装
2. 配置可版本化
3. 服务可观测
4. 发布可回滚
5. 资源有边界
6. 安全最小化
7. 故障可恢复
8. 容量可扩展
非目标:
- 手工修改单台机器;
- 依赖登录 Shell 环境变量;
- 日志无上限;
- root 运行;
- 单机部署且无备份。
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,由采集器处理。无论哪种方式,必须有:
- 留存周期;
- 大小上限;
- 结构化格式;
- trace_id;
- 敏感信息脱敏;
- 采集监控。
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. 保留现场日志和配置
可回滚前提:
- 数据库变更向后兼容;
- 配置版本可切换;
- 上一制品仍在;
- 健康检查可信;
- 回滚步骤演练过。
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
镜像要求:
- 固定基础镜像版本;
- 非 root 用户;
- 只包含必要文件;
- 健康检查;
- 正确处理 SIGTERM;
- 不写可写层。
29.10 监控接入
主机:
CPU、内存、磁盘、IO、网络
进程:
进程存活、重启次数、FD、线程数、RSS
应用:
QPS、成功率、P95 / P99、队列、依赖耗时
发布:
版本、发布批次、配置版本、变更时间
日志:
ERROR、WARN、GC、连接失败、认证失败
29.11 上线检查清单
[ ] 服务用户和目录权限正确
[ ] systemd unit 通过语法和启动验证
[ ] 健康检查和指标端点可用
[ ] 日志轮转和采集验证
[ ] ulimit、内存、CPU、任务数设置
[ ] 防火墙只开放必要端口
[ ] sudo 和 SSH 权限审计
[ ] 备份和恢复流程确认
[ ] 发布与回滚演练
[ ] 监控告警配置
[ ] 值班和升级路径
[ ] 文档和 Runbook
本章小结
高负载服务部署要以可重复和可回滚为核心:独立用户、版本目录、systemd 边界、日志轮转、资源限制、健康检查、监控和灰度发布。容器化后同样要保留这些要求,只是由镜像和编排系统承载。
思考题
- releases 目录加 current 链接有什么好处?
- readiness 和 liveness 应该如何设计?
- Java 服务内存上限如何分配?
- 哪些数据库变更会导致无法回滚?
- 设计一套 20 台机器的灰度发布方案。