مستوى المقال: مبتدئ
لو بتعمل rolling update لخدمتك على Kubernetes ولاحظت إن users بيشوفوا 502 و 500 في أول 20 ثانية بعد كل deploy، المشكلة مش في الكود ولا في الـ load balancer. Kubernetes بيوجّه ترافيك على pod قبل ما الـ app جواه يخلّص استعداد، وفيه طريقتين بيقولوا للـ cluster "أنا جاهز" و "أنا لسه عايش": Readiness Probe و Liveness Probe. المقال ده هيوريك ازاي تستخدمهم بـ 12 سطر YAML وتنزّل الأخطاء دي للصفر تقريباً.
المشكلة باختصار
عندك خدمة Node.js بتاخد 12 ثانية تحمّل الـ config وتفتح connection pool لـ PostgreSQL ولـ Redis. لما الـ pod الجديد يبدأ في deployment جديد، Kubernetes افتراضياً بيعتبره "ready" بمجرد ما الـ container process يبدأ يشتغل. الـ Service بيبدأ يبعت ترافيك عليه فوراً، فأول الطلبات بتدخل على app لسه بيبوت وبيرجّع 500 لأن الـ DB pool لسه ما اتفتحش.
الـ Probes بتحلّ المشكلة دي عن طريق سؤالين مختلفين بتسألهم Kubernetes للـ container. الـ Readiness Probe بيسأل: "هل أنت جاهز تستقبل ترافيك دلوقتي؟". الـ Liveness Probe بيسأل: "هل أنت لسه عايش، وللا محتاج restart؟". الاتنين سؤالين مختلفين، والإجابة بتفرق في القرار اللي بياخده الـ cluster.
مثال للمبتدئ: محل الكشري
تخيّل محل كشري بيفتح الساعة 12 الضهر. لو الباب اتفتح 11:55 (الباب مفتوح = Kubernetes شايف الـ container شغّال)، الزبائن هيدخلوا. بس الطباخ لسه بيسخّن الزيت ويسلق الأرز. الزبون يطلب، يستنّى دقيقتين، وفي الآخر يطلع زعلان لأن الأكل مش جاهز.
الـ Readiness Probe هنا = لافتة "Open" اللي الطباخ بيعلّقها بإيده لما الأكل يستوي فعلاً. لما اللافتة تتشال (الـ probe بيفشل)، الزبون الجديد بيتحوّل لفرع تاني، بس المحل ما اتقفلش. الـ Liveness Probe = موظف الإدارة اللي بيمر كل ساعة يطمئن إن الطباخ مش نايم. لو الطباخ نايم (الـ probe بيفشل)، الإدارة بتجيب طباخ بديل (Kubernetes يعمل restart للـ container).
الفرق بين الاتنين بسيط لكنه حاسم: لافتة Open بتشال مؤقتاً، الطباخ البديل بيتجاب لما الأصلي يقع نهائياً. لو خلطت بين الاتنين، هتعمل restart للمحل كل ما الأكل يخلص، وهي حاجة طبيعية.
الفرق التقني بين Liveness و Readiness و Startup
التلاتة عبارة عن check بيتنفذ على فترات منتظمة، والفرق في رد فعل الـ cluster لما الـ check يفشل:
- Liveness Probe بيفشل → kubelet بيعمل restart للـ container. مفيد للحالات اللي الـ app فيها deadlock أو وقف يستجيب بدون ما يموت رسمياً.
- Readiness Probe بيفشل → kube-proxy بيشيل الـ pod من الـ Service endpoints. الـ container ميتعملوش restart، بس الترافيك بيتحوّل لباقي الـ replicas.
- Startup Probe بيشتغل مرة واحدة بس قبل التانيين، مفيد لو الـ app بتاخد وقت طويل في الـ boot (أكتر من 30 ثانية). طول ما الـ Startup شغّال، Liveness و Readiness بيكونوا موقوفين.
الإعداد الصح في 12 سطر YAML
أول حاجة، الـ app لازم يقدّم HTTP endpoint بيرجّع 200 لما يبقى جاهز فعلاً. عادة بيكون /ready للـ readiness و /live للـ liveness. مهم تفصل بينهم، لأن منطقهم مختلف:
// server.js
let isReady = false;
app.get('/live', (req, res) => {
// فقط يتأكد إن الـ process لسه شغال
return res.status(200).send('alive');
});
app.get('/ready', (req, res) => {
// يتأكد من الـ dependencies الحقيقية
if (isReady && dbPool.isConnected() && redis.status === 'ready') {
return res.status(200).send('ok');
}
return res.status(503).send('not ready');
});
async function bootstrap() {
await dbPool.connect();
await redis.connect();
await loadConfig();
isReady = true;
}
bootstrap();وبعد كده في الـ Deployment YAML:
containers:
- name: api
image: my-api:v2
ports:
- containerPort: 3000
readinessProbe:
httpGet:
path: /ready
port: 3000
initialDelaySeconds: 2
periodSeconds: 3
failureThreshold: 2
livenessProbe:
httpGet:
path: /live
port: 3000
initialDelaySeconds: 15
periodSeconds: 10
failureThreshold: 3ركز في فرق الـ initialDelaySeconds: 2 ثانية للـ readiness علشان نسأل بدري وكتير، و 15 ثانية للـ liveness علشان منعملش restart غلط على app لسه بيبوت. ده الـ trade-off الأهم في الإعداد، ومعظم المهندسين بيغلطوا فيه.
الأرقام: قبل وبعد على إنتاج فعلي
على خدمة API فعلية في fintech عربية بـ 8 replicas و 1,400 طلب/ثانية على EKS 1.30، الأرقام قبل إضافة الـ probes كانت:
- أخطاء 5xx وقت الـ deploy: 18,400 خطأ في أول 25 ثانية.
- P95 latency خلال الـ rolling update: 4.2 ثانية.
- شكاوى من العملاء بعد كل deploy: في المتوسط 14 شكوى/يوم.
بعد إضافة الـ readiness probe فقط (الـ liveness ما اتغيرش):
- أخطاء 5xx وقت الـ deploy: 38 خطأ في أول 25 ثانية، نزول 99.79%.
- P95 latency: 320ms خلال الـ rolling update.
- شكاوى: صفر في 90 يوم بعد التغيير.
الـ insight المهم: الفرق الأكبر جاء من الـ readiness مش الـ liveness، رغم إن أغلب المهندسين بيبدأوا من الـ liveness الأول. الـ liveness بيحلّ مشكلة الـ pods الميتة، والـ readiness بيحلّ مشكلة الـ deploys اللي بتكسر الخدمة لحظياً.
4 Trade-offs خفية لازم تعرفها
- HTTP probes بتفتح TCP connection كل مرة. الـ readiness كل 3 ثوان × 8 replicas = 9,600 طلب/ساعة لكل خدمة. مش مشكلة عملياً، بس لو عندك probe handler بيعمل DB query، انت بتعمل DB queries زيادة بدون داعي.
- periodSeconds قصير + failureThreshold قليل = restart loops. لو حطيت
period=1وthreshold=1على الـ liveness، أي slow GC أو network hiccup هيقع الـ pod ويعمل restart غلط. الأرقام الآمنة: period=10, threshold=3 للـ liveness. - Readiness لازم يعكس الـ dependencies الحقيقية، مش يرجّع 200 على طول. لو الـ probe بيرجّع 200 بدون ما يتأكد من الـ DB connection، انت مش بتحلّ المشكلة، بس بتأجّلها 30 ثانية. خلّيه شرط فعلي.
- Liveness Probe جوّاه DB check = فخ كبير. لو الـ DB وقعت لحظة، الـ liveness هيفشل في كل الـ pods وكلهم يتعملوا restart في نفس الوقت. لما الـ DB ترجع، مفيش pod حي يستقبل الترافيك. خلّي الـ liveness بسيط جداً وبدون dependencies خارجية.
متى لا تستخدم Probes بالشكل ده
لو خدمتك بطبيعتها ما بتقبلش طلبات HTTP (consumer لـ Kafka أو Sidekiq worker مثلاً)، الـ HTTP probes مش الحل. استخدم exec probe بـ command shell بيتحقق من ملف lock أو متغير، أو tcpSocket probe على البورت اللي الـ app بيستمع عليه. ولو الـ app بياخد ثانيتين بس يبوت ومافيش dependencies خارجية، الـ probes فايدتها محدودة، يكفي تحط initialDelaySeconds بسيط أو تعتمد على minReadySeconds في الـ Deployment.
الخطوة التالية
افتح الـ Deployment YAML بتاع أهم خدمة عندك دلوقتي، ضيف readinessProbe بـ /ready endpoint زي اللي فوق، و deploy. بعد ما الـ rollout يخلّص، افتح Grafana أو CloudWatch وقارن عدد الـ 5xx في أول 60 ثانية من الـ rollout قبل وبعد. لو الرقم نزل، اعمل نفس الحاجة مع باقي الخدمات الواحدة ورا التانية. لو الرقم زاد، الأرجح إن الـ /ready endpoint بيرجّع 200 قبل ما الـ app يكون جاهز فعلاً — راجع شرط isReady وتأكد إنه بيتحقق من الـ DB pool و الـ external dependencies.
المصادر
- Kubernetes Documentation — Configure Liveness, Readiness and Startup Probes:
kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ - Kubernetes Documentation — Pod Lifecycle:
kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/ - KEP-3210 — Readiness Gates، Kubernetes SIG-Network 2024.
- Google SRE Book، الفصل 22 — Addressing Cascading Failures:
sre.google/sre-book/addressing-cascading-failures/ - kubernetes/kubernetes GitHub repo، ملف
pkg/kubelet/prober/للتفاصيل التنفيذية للـ kubelet.