لماذا لا يجب أن "تتوقف" خدمتك لتناول الغداء؟
تخيل: الجمعة، الساعة 6:45 مساءً. لقد قمت للتو بتشغيل التحديث المنتظر لخدمة C#. وفجأة، تصل رسائل إلى دعم الدردشة: "الموقع لا يعمل"، "خطأ 503"، "فقدت بيانات سلة التسوق". هل هذا مألوف؟ هذا هو السيناريو الكلاسيكي عندما يقتل النشر "المفاجئ" تجربة المستخدم. في عالم اليوم، حيث يمكن أن تكلف كل ساعة توقف الملايين، فإن نشر خدمات C# بدون توقف ليس ترفًا، بل هو أساسيات النظافة في التطوير.
في هذه المقالة، لن نلقي محاضرات مملة. سنقوم بتحليل استراتيجيات حقيقية لتحديث تطبيقات .NET دون إيقاف العمل، وسنكتب كود فحوصات الصحة والإغلاق التدريجي، وسنوضح كيفية إعداد التحديث التدريجي في Kubernetes. إذا كنت قد سئمت من الأعطال "السحرية" للإنتاج بعد كل commit، فهذه المادة لك. هيا بنا!
ما هو النشر بدون توقف ولماذا هو مهم لمطور C#؟
النشر بدون توقف (Zero-downtime deployment) هو أسلوب لتحديث التطبيق، حيث يستمر الإصدار القديم في خدمة الطلبات حتى يصبح الإصدار الجديد جاهزًا للعمل بشكل كامل. لا يلاحظ المستخدم أي تبديل: لا أخطاء، ولا مهلات، ولا فقدان للجلسة.
المشاكل الرئيسية عند تحديث خدمات C#
- الإغلاق التدريجي لا يعمل دائمًا. قد يؤدي
app.StopAsync()القياسي إلى قطع الطلبات النشطة إذا لم يتم ضبط المهلات. - الاتصالات المعلقة. الإصدار القديم يحتفظ باتصالات WebSocket مفتوحة أو طلبات HTTP طويلة.
- ترحيل قواعد البيانات. الإصدار الجديد يتطلب تغييرات في المخطط، بينما الإصدار القديم غير متوافق معها.
- ذاكرة التخزين المؤقت والجلسات. بعد التبديل، يفقد المستخدم البيانات المخزنة في الذاكرة.
الخبر السار: توفر C# والنظام البيئي .NET جميع الأدوات لحل هذه المشاكل. مهمتنا هي تجميعها في نظام عملي.
الاستراتيجية رقم 1: نشر Blue-Green لـ C#
هذا هو أبسط وأكثر المخططات موثوقية. لديك بيئتان متطابقتان: Blue (الإصدار الحالي) و Green (الإصدار الجديد). تقوم بنشر الإصدار الجديد على Green، وتجري اختبارات سريعة، ثم تقوم بتحويل موازن التحميل فورًا من 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 (مثالي للخدمات المصغرة)
يمكن لـ Kubernetes إجراء التحديث التدريجي "خارج الصندوق". يقوم تدريجيًا باستبدال Pods القديمة بأخرى جديدة، دون انقطاع حركة المرور. ولكن لكي يعمل هذا بشكل صحيح مع C#، تحتاج إلى ضبط فحوصات الصحة والإغلاق التدريجي.
فحوصات الصحة في .NET 6/8
أضف إلى ملف 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