零停机部署 TypeScript 服务:逐步指南

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

如何在不惊动用户的情况下更新服务?



想象一下:周五晚上,你决定快速将 bug 修复推送到生产环境。你点击部署——然后你的即时通讯软件、在线影院或 CRM 系统宕机了 30 秒。成千上万的用户在这段时间里看到 502 Bad Gateway。如果这是一个支付网关呢?算算损失吧。



零停机部署(Zero-downtime 部署)不是奢侈品,而是现代 TypeScript 服务的标准。在本文中,我们将剖析生产环境中使用的真实技术:从优雅关闭到蓝绿部署和滚动更新。你将获得可直接应用于 TypeScript 的现成模式。



为什么常规的 TypeScript 应用部署是危险的?



当你运行 npm run build && node dist/index.js 时,会发生几个问题:



  • 连接中断 — 旧进程被杀死,而新请求仍在发送。
  • 内存数据丢失 — 未保存的会话、缓存、队列。
  • 冷启动 — 新进程尚未预热,却已经开始接收流量。


在 TypeScript (Node.js) 中,异步性使情况更糟:你不知道哪些 Promise 仍在执行。但解决方案是存在的。



技术 #1:优雅关闭 (Graceful Shutdown)



零停机的基础 — 正确处理操作系统信号。当编排器(Kubernetes、PM2)决定停止你的服务时,它会发送 SIGTERM。你的代码应该停止接受新请求,等待当前请求完成,然后才退出。



使用 Express 在 TypeScript 中实现



import express, { Request, Response } from 'express';import http from 'http';

const app = express();let server: http.Server;

app.get('/health', (req: Request, res: Response) => { res.status(200).json({ status: 'ok' });});

// 来自 Docker/K8s 的信号process.on('SIGTERM', async () => { console.log('收到 SIGTERM,开始优雅关闭...'); // 1. 停止监听新连接 server.close(() => { console.log('HTTP 服务器已关闭'); // 2. 关闭数据库、Redis 等连接 // await db.disconnect(); process.exit(0); });

// 3. 给当前请求一些时间(超时 30 秒) setTimeout(() => { console.error('超时强制终止'); process.exit(1); }, 30000);});

const PORT = process.env.PORT || 3000;server = app.listen(PORT, () => { console.log(`服务已启动,端口 ${PORT}`);});


重要提示: 在 TypeScript 中,使用 http 模块的 http.Server,而不是 Express 类型。方法 server.close() 能正确处理 keep-alive 连接。



技术 #2:滚动更新 (Rolling Update)



如果你的服务有多个副本(运行 3-5 个实例),滚动更新会逐一更新它们。当一个实例重启时,其他实例继续处理流量。



Kubernetes Deployment 示例



# deployment.yamlapiVersion: apps/v1kind: Deploymentmetadata:  name: my-typescript-servicespec:  replicas: 3  strategy:    type: RollingUpdate    rollingUpdate:      maxUnavailable: 1      # 最多允许多少个 Pod 不可用      maxSurge: 1            # 最多可以额外创建多少个新 Pod  template:    spec:      containers:      - name: app        image: myregistry/service:v2        ports:        - containerPort: 3000        livenessProbe:          httpGet:            path: /health            port: 3000          initialDelaySeconds: 5          periodSeconds: 10        readinessProbe:          httpGet:            path: /ready            port: 3000          initialDelaySeconds: 3          periodSeconds: 5


在你的 TypeScript 应用中添加一个 /ready 端点,仅在服务就绪时返回 200。

博客

书籍推荐