Linux 发布过程中如何避免服务中断

5次阅读

滚动更新需确保老连接自然结束而非简单停服:nginx reload 逐步关闭worker,自建服务监听SIGUSR2/SIGHUP优雅启停;数据库迁移用pt-online-schema-change或CONCURRENTLY避免锁表;部署脚本须显式处理超时与信号;K8s需配置progressDeadlineSeconds和maxUnavailable保障可用性。

Linux 发布过程中如何避免服务中断

滚动更新时如何保证 http 服务不丢请求

直接替换进程或重启 nginx / gunicorn 很容易触发 TCP 连接重置,客户端收到 ECONNRESET 或超时。关键不是“停不停”,而是“老连接是否被允许自然结束”。

  • systemdRestart=on-failure 配合 StartLimitIntervalSec,避免崩溃后疯狂拉起新实例干扰旧连接
  • nginx 更新配置后执行 nginx -s reload,它会 fork 新 worker、逐步关闭旧 worker(默认等待 worker_shutdown_timeout,建议设为 30s
  • go/python 等自建 HTTP server,需监听 SIGUSR2SIGHUP,在新进程 bind 成功后再 graceful shutdown 旧进程;别依赖简单 kill -9

数据库迁移怎么绕过锁表和主从延迟

DDL 操作(如 ALTER table)在 mysql 5.7+ 默认是 inplace,但加索引、改列类型仍可能锁表;postgresql 虽支持并发创建索引,但 ADD column ... NOT NULL 仍需全表扫描。

  • MySQL:用 pt-online-schema-change 工具,它通过触发器双写 + 增量同步,全程不锁原表
  • PostgreSQL:优先用 CREATE INDEX CONCURRENTLY;修改列默认值先 ADD COLUMN 再用后台 job 分批 update,最后 ALTER COLUMN SET default
  • 所有 DML 迁移(如数据清洗)必须加 WHERE id BETWEEN ? AND ? 分页,配合 FOR UPDATE SKIP LOCKED 避免长事务阻塞复制

部署脚本里哪些信号和超时必须显式处理

自动化发布最常栽在“以为命令结束了,其实还在后台跑”——比如 docker-compose up -d 返回不代表容器 ready,systemctl start 返回也不代表服务已响应 HTTP。

  • timeout 60s bash -c 'while ! curl -f http://localhost:8000/health; do sleep 1; done' 等待服务就绪,别只靠 systemctl is-active
  • ssh 命令加 -o ConnectTimeout=10 -o BatchMode=yes,防止卡在密码提示或 dns 解析
  • 所有 kill 操作必须带超时:先 kill $PID,再 sleep 5,最后 kill -9 $PID 2>/dev/null || true,否则 kill -9 可能误杀其他进程

kubernetes 中滚动更新失败的兜底动作

kubectl rollout restart 或镜像更新触发的滚动更新,若新 Pod 卡在 CrashLoopBackOffImagePullBackOff,默认会一直尝试,旧 Pod 却已被删光。

  • Deployment 里设置 spec.progressDeadlineSeconds: 600(默认 600 秒),超时后标记为 ProgressDeadlineExceeded,但不会自动回滚
  • 必须配 spec.strategy.rollingUpdate.maxSurge: 1maxUnavailable: 0,确保任何时候至少有一个旧 Pod 在线
  • 上线前跑 kubectl apply --dry-run=client -o wide -f deploy.yaml 检查字段合法性,比等 CI 推到集群再报错快得多

真正难的不是“怎么做到零中断”,而是判断哪一层该承担中断——DNS 缓存、LB 连接池、应用层重试、客户端降级,每个环节的容忍度和修复成本都不同。漏掉任意一层,前面所有滚动逻辑都白搭。

text=ZqhQzanResources