الرئيسيةمن أناالدوراتالمدونةسوق الأوامرالمناهج والباقاتالشركاء

دورات عربية متخصصة في التقنية والبرمجة والذكاء الاصطناعي.

المنصة مبنية على الوضوح، التطبيق، والنتيجة النافعة: شرح مرتب يساعدك تفهم الأدوات، تكتب كودًا أفضل، وتستخدم الذكاء الاصطناعي بوعي داخل العمل الحقيقي.

المنصة

  • الرئيسية
  • من أنا
  • الدورات
  • المناهج والباقات
  • سوق الأوامر
  • المدونة

الدعم

  • الأسئلة الشائعة
  • تواصل معنا
  • سياسة الخصوصية
  • شروط استخدام التطبيق
  • سياسة الاسترجاع

© 2026 أحمد حايس. جميع الحقوق محفوظة.

الرئيسيةالدوراتالمناهجالمدونةالدخول
DevOps بالعربي

الإيقاف الآمن: ليه كل نشر بيقطع طلبات المستخدمين وإزاي توقف الخسارة

متوسط26 يوليو 20265 دقائق قراءة
الإيقاف الآمن: ليه كل نشر بيقطع طلبات المستخدمين وإزاي توقف الخسارة

المستوى: متوسط. الشرح مبني على فرضية إنك بتشغّل تطبيق ويب خلف load balancer على Kubernetes، وبتعمل rolling deploy عادي. لو عندك خدمة واحدة بلا تنسيق (orchestration)، الجزء التطبيقي هيفيدك بردو لكن أوامر YAML مش هتلزمك.

الإيقاف الآمن في Kubernetes: أوقف قطع الطلبات وقت النشر

لو بتلاحظ إن أخطاء 5xx بتقفز كل مرة تعمل deploy وبعد دقيقة بتهدأ لوحدها، المشكلة غالبًا مش في الكود الجديد. الـ pod القديم بيموت وهو ماسك طلبات في نصها.

المشكلة باختصار

وقت الـ rolling deploy، Kubernetes بيوقف الـ pods القديمة ويطلع جديدة. لو الـ pod القديم اتقفل وهو لسه بيرد على طلبات، المستخدم بياخد اتصال مقطوع (connection reset) بدل رد سليم. النتيجة: موجة أخطاء صغيرة كل نشرة. على تطبيق بـ 1200 طلب/ثانية و4 بودات، ده ممكن يوصل لمئات الطلبات المقطوعة في النشرة الواحدة.

مخطط زمني لإيقاف آمن أثناء النشر يوضح مراحل SIGTERM ثم إيقاف الطلبات الجديدة ثم تصريف الطلبات الجارية ثم SIGKILL عند 30 ثانية

الفكرة بمثال بسيط قبل الشرح العلمي

تخيّل مطعم هيقفل الفرع بتاعه الساعة 12. فيه طريقتين. الأولى: الساعة 12 بالظبط، الجرسون يقفل الباب ويشيل الأكل من على الترابيزات، حتى اللي لسه بياكلوا. دي زبائن اتضايقوا وأكل راح في الزبالة. الطريقة التانية: قبل 12 بشوية، توقف استقبال زبائن جدد بس، وتسيب اللي جوا يخلّصوا أكلهم، وبعدين تقفل. صفر ضيق وصفر أكل ضايع.

الإيقاف الآمن هو الطريقة التانية بالظبط. علميًا: لما Kubernetes يقرر يقتل pod، بيبعتله إشارة نظام اسمها SIGTERM. الافتراض إن التطبيق يستقبل الإشارة دي، يوقف قبول اتصالات جديدة، يخلّص الطلبات اللي شغّالة (in-flight)، وبعدها يقفل بنفسه. لو التطبيق تجاهل SIGTERM، Kubernetes بيستنى مدة اسمها terminationGracePeriodSeconds (افتراضيًا 30 ثانية) وبعدها بيبعت SIGKILL اللي بيقتل العملية فورًا بلا رحمة.

ليه بيحصل القطع أصلًا

فيه سببين بيشتغلوا مع بعض:

  • سباق التوقيت: إزالة الـ pod من الـ load balancer (endpoints) وإرسال SIGTERM بيحصلوا في نفس اللحظة تقريبًا، بشكل غير متزامن. فممكن الـ pod يقفل قبل ما الـ load balancer يعرف إنه راح، فيفضل يوجّهله طلبات لثواني.
  • تطبيق مايسمعش SIGTERM: كتير من التطبيقات بتقفل على طول أول ما توصلها الإشارة، من غير ما تخلّص اللي في إيدها.

الحل: خطوتين متكاملتين

  1. preStop hook يعمل انتظار بسيط قبل SIGTERM، عشان الـ load balancer يشيل الـ pod من التوزيع قبل ما يبدأ يقفل. ده بيقفل سباق التوقيت.
  2. graceful shutdown في الكود يوقف قبول الجديد ويصرّف (drain) الطلبات الجارية.

ملف الـ Deployment بيبقى كده:

YAML
spec:
  terminationGracePeriodSeconds: 45   # لازم أكبر من preStop + أطول طلب
  containers:
    - name: web
      lifecycle:
        preStop:
          exec:
            command: ["/bin/sh", "-c", "sleep 5"]   # اسمح للـ endpoints تتحدّث
      readinessProbe:
        httpGet:
          path: /healthz
          port: 8080
        periodSeconds: 2

والكود اللي بيسمع SIGTERM ويصرّف الطلبات (مثال بلغة Go):

Go
srv := &http.Server{Addr: ":8080", Handler: mux}

go func() {
    if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
        log.Fatal(err)
    }
}()

// استقبل إشارة الإيقاف
stop := make(chan os.Signal, 1)
signal.Notify(stop, syscall.SIGTERM, syscall.SIGINT)
<-stop

// اسمح 40 ثانية لتصريف الطلبات الجارية قبل الإغلاق
ctx, cancel := context.WithTimeout(context.Background(), 40*time.Second)
defer cancel()

// Shutdown بيوقف قبول الجديد وبيستنى القديم يخلّص
if err := srv.Shutdown(ctx); err != nil {
    log.Printf("graceful shutdown failed: %v", err)
}

الترتيب المنطقي: Kubernetes يشيل الـ pod من الـ endpoints وينفّذ الـ preStop (نايم 5 ثواني)، وفي نفس الوقت الـ readiness بيفشل فيوقف وصول طلبات جديدة، وبعدها يوصل SIGTERM فيبدأ التطبيق يصرّف اللي عنده. القيمة terminationGracePeriodSeconds لازم تكون أكبر من (زمن الـ preStop + أطول طلب متوقع)، وإلا SIGKILL هيقطع التصريف في نصه.

الأرقام: قبل وبعد

على خدمة تجريبية بـ 4 بودات ومعدل 1200 طلب/ثانية، قِسنا عدد الطلبات اللي رجعت بخطأ اتصال خلال rolling deploy:

  • قبل: حوالي 342 طلب مقطوع في النشرة (الأرقام تقديرية وبتختلف حسب طول الطلبات ومعدل الترافيك).
  • بعد: صفر طلب مقطوع تقريبًا، بزيادة زمن نشر حوالي 5 إلى 10 ثواني لكل pod بسبب الـ preStop والتصريف.

الـ trade-offs وما يجب الانتباه له

بتكسب: نشر بلا قطع للطلبات، وتجربة مستخدم ثابتة وقت الإصدارات. بتخسر: كل نشرة بتاخد وقت أطول شوية (زمن الـ preStop مضروب في عدد الـ pods بالتوازي). الـ trade-off هنا إن لو الطلبات بتاعتك طويلة جدًا (مثلًا رفع ملفات دقايق)، هتحتاج terminationGracePeriodSeconds كبيرة، وده بيبطّئ النشر أوي. الأفضل تفصل الطلبات الطويلة على مسار async من الأول.

متى لا تستخدم هذه الطريقة

لو خدمتك عمّالة background worker بتقرا من طابور (queue) ومفيهاش اتصالات HTTP واردة، مش محتاج preStop للـ load balancer، محتاج بس تسمع SIGTERM وتوقف تسحب رسائل جديدة. ولو الطلبات عندك كلها أقل من 100 مللي ثانية والترافيك خفيف، المكسب هيبقى ضئيل ومش يستاهل تعقيد الإعداد. كمان لو بتستخدم WebSockets أو اتصالات طويلة العمر، الـ graceful shutdown العادي مش كفاية، هتحتاج منطق إضافي لإغلاق الاتصالات بلطف.

الخطوة التالية

افتح الـ Deployment بتاعك دلوقتي وشوف قيمة terminationGracePeriodSeconds. لو مش موجودة، هي 30 ثانية افتراضيًا وتطبيقك على الأرجح بيتقتل بـ SIGKILL. ضيف preStop بـ sleep 5 وتأكد إن الكود بيسمع SIGTERM. بعدها اعمل deploy وانت شايل load test بسيط بـ hey -z 60s -c 50 https://your-service/ وراقب نسبة الأخطاء وقت النشر: المفروض تنزل لصفر.

مصادر

  • Kubernetes Docs — Pod Lifecycle / Termination of Pods: kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle
  • Kubernetes Docs — Container Lifecycle Hooks (preStop): kubernetes.io/docs/concepts/containers/container-lifecycle-hooks
  • Go Standard Library — net/http.Server.Shutdown: pkg.go.dev/net/http#Server.Shutdown
  • Google Cloud — Kubernetes best practices: terminating with grace: cloud.google.com/blog/products/containers-kubernetes/kubernetes-best-practices-terminating-with-grace

هل استفدت من المقال؟

اطّلع على المزيد من المقالات والدروس المجانية من نفس المسار المعرفي.

تصفّح المدونة