为什么您的服务不应该在午休时“宕机”?
想象一下:周五,18:45。您刚刚发布了期待已久的 C# 服务更新。紧接着,支持聊天中消息纷至沓来:“网站无法访问”、“错误 503”、“购物车数据丢失”。熟悉吗?这是典型的“粗暴”部署破坏用户体验的场景。在现代世界,每小时的停机可能造成数百万损失,zero-downtime 部署 C# 服务 不是奢侈品,而是开发的基本素养。
在本文中,我们不会进行枯燥的讲座。我们将分析更新 .NET 应用程序而不中断运行的实际策略,编写 health checks 和 graceful shutdown 的代码,并展示如何在 Kubernetes 中配置 rolling update。如果您厌倦了每次提交后生产环境“神奇”地崩溃——这篇文章就是为您准备的。开始吧!
什么是 zero-downtime deployment,为什么 C# 开发者需要它?
Zero-downtime deployment(零停机部署)是一种应用程序更新方法,旧版本会持续处理请求,直到新版本完全可用。用户不会察觉到切换:没有错误、没有超时、没有会话丢失。
更新 C# 服务的主要问题
- Graceful shutdown 并不总是有效。 标准的
app.StopAsync()可能会中断活跃请求,如果没有配置超时。 - 连接挂起。 旧版本持有打开的 WebSocket 或长 HTTP 请求。
- 数据库迁移。 新版本需要更改模式,而旧版本不兼容。
- 缓存和会话。 切换后,用户丢失内存中的数据。
好消息是:C# 和 .NET 生态系统提供了所有解决这些问题的工具。我们的任务是将它们整合成一个可运行的系统。
策略 #1:C# 的 Blue-Green Deployment
这是最简单可靠的方案。您有两个相同的环境:Blue(当前版本)和 Green(新版本)。您将新版本部署到 Green,运行 smoke 测试,然后立即将负载均衡器从 Blue 切换到 Green。如果出现问题,可以在一秒钟内回滚。
如何为 .NET 实现?
我们需要一个负载均衡器(NGINX、HAProxy 或云负载均衡器)和两个 C# 服务实例。NGINX 配置示例:
upstream backend { server blue-server:5000 weight=100; server green-server:5000 weight=0; # 备用}
server { listen 80; location / { proxy_pass http://backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; }}部署 Green 版本后,更改权重:blue:0, green:100。用户会不知不觉地流向新版本。
优点:简单,即时回滚。
缺点:需要两倍的资源(服务器)。
策略 #2:使用 Kubernetes 的 Rolling Update(微服务理想选择)
Kubernetes 原生支持 rolling update。它会逐步用新 Pod 替换旧 Pod,不中断流量。但要使其与 C# 正确配合,需要配置 health probes 和 graceful shutdown。
.NET 6/8 中的 Health Checks
在您的 Program.cs 中添加用于检查就绪性(readiness)和存活(liveness)的端点:
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHealthChecks() .AddCheck<DatabaseHealthCheck>("database") .AddCheck<CacheHealthCheck>("redis");
var app = builder.Build();
app.MapHea