Warum Ihr Dienst nicht „Mittagspause“ machen sollte?
Stellen Sie sich vor: Freitag, 18:45 Uhr. Sie haben gerade das lang erwartete Update Ihres C#-Dienstes ausgerollt. Und sofort flattern Nachrichten in den Support-Chat: „Website funktioniert nicht“, „Fehler 503“, „Warenkorbdaten verloren“. Kommt Ihnen das bekannt vor? Dies ist das klassische Szenario, wenn ein Deployment „mit der Brechstange“ die Benutzererfahrung zerstört. In der heutigen Welt, in der jede Stunde Ausfallzeit Millionen kosten kann, ist Zero-Downtime-Deployment von C#-Diensten kein Luxus, sondern grundlegende Entwicklungshygiene.
In diesem Artikel werden wir keine langweiligen Vorträge halten. Wir werden reale Strategien zur Aktualisierung von .NET-Anwendungen ohne Betriebsunterbrechung analysieren, Code für Health Checks und Graceful Shutdown schreiben und zeigen, wie man Rolling Updates in Kubernetes konfiguriert. Wenn Sie die „magischen“ Produktionsausfälle nach jedem Commit leid sind – dieses Material ist für Sie. Los geht's!
Was ist Zero-Downtime-Deployment und warum braucht ein C#-Entwickler es?
Zero-Downtime-Deployment (Bereitstellung mit null Ausfallzeit) ist eine Methode zur Aktualisierung einer Anwendung, bei der die alte Version weiterhin Anfragen bedient, bis die neue Version vollständig betriebsbereit ist. Der Benutzer bemerkt den Wechsel nicht: keine Fehler, keine Timeouts, kein Sitzungsverlust.
Hauptprobleme bei der Aktualisierung von C#-Diensten
- Graceful Shutdown funktioniert nicht immer. Der Standard-
app.StopAsync()kann aktive Anfragen abbrechen, wenn keine Timeouts konfiguriert sind. - Hängende Verbindungen. Die alte Version hält offene WebSockets oder lange HTTP-Anfragen aufrecht.
- Datenbankmigrationen. Die neue Version erfordert Schemaänderungen, mit denen die alte Version nicht kompatibel ist.
- Cache und Sitzungen. Nach dem Wechsel verliert der Benutzer im Speicher gehaltene Daten.
Die gute Nachricht: C# und das .NET-Ökosystem bieten alle Werkzeuge, um diese Probleme zu lösen. Unsere Aufgabe ist es, sie zu einem funktionierenden System zusammenzufügen.
Strategie Nr. 1: Blue-Green-Deployment für C#
Dies ist das einfachste und zuverlässigste Schema. Sie haben zwei identische Umgebungen: Blue (aktuelle Version) und Green (neue Version). Sie stellen die neue Version auf Green bereit, führen Smoke-Tests durch und schalten dann den Load Balancer sofort von Blue auf Green um. Wenn etwas schief geht, können Sie innerhalb einer Sekunde zurückrollen.
Wie setzt man das für .NET um?
Sie benötigen einen Load Balancer (NGINX, HAProxy oder einen Cloud Load Balancer) und zwei Instanzen Ihres C#-Dienstes. Beispielkonfiguration für NGINX:
upstream backend { server blue-server:5000 weight=100; server green-server:5000 weight=0; # Reserviert}
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; }}Nach dem Bereitstellen der Green-Version ändern wir die Gewichte: blue:0, green:100. Die Benutzer wechseln nahtlos zur neuen Version.
Vorteile: Einfachheit, sofortiges Zurücksetzen.
Nachteile: Es werden doppelt so viele Ressourcen (Server) benötigt.
Strategie Nr. 2: Rolling Update mit Kubernetes (ideal für Mikrodienste)
Kubernetes kann Rolling Updates „out of the box“ durchführen. Es ersetzt nach und nach alte Pods durch neue, ohne den Datenverkehr zu unterbrechen. Damit dies jedoch mit C# richtig funktioniert, müssen Health Probes und Graceful Shutdown konfiguriert werden.
Health Checks in .NET 6/8
Fügen Sie in Ihrer Program.cs einen Endpunkt für Readiness- und Liveness-Prüfungen hinzu:
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