CoreDNS Cache: خفّض DNS latency في Kubernetes من 42ms لـ 9ms
لو كل request عندك بيعمل DNS lookup بطيء، ضبط CoreDNS cache ممكن ينقل p95 من 42ms إلى 9ms قبل ما تزود أي replicas.
مستوى القارئ: متوسط
المشكلة باختصار
في Kubernetes، الـ Pod غالبًا بينادي خدمات بأسماء زي checkout.default.svc.cluster.local. Kubernetes بيجهز DNS records للـ Services والـ Pods، وبيخلي كل Pod يستخدم resolver داخلي بدل IP ثابت. ده ممتاز للتشغيل اليومي، لكنه يضغط CoreDNS لو عندك traffic عالي أو تطبيق بيعمل lookups كتير.
الطريقة الشائعة الغلط هنا إنك تزود عدد CoreDNS replicas فورًا. الطريقة دي بتفشل لو أصل المشكلة إن نفس الأسماء بتتسأل آلاف المرات في الدقيقة بدون cache مضبوط. هتكسب capacity مؤقتة، لكن هتخسر CPU وlatency ثابتة في كل query.
مثال بسيط قبل التعريف العلمي
ركز في المثال ده. عندك 40 microservice، وكل service بينادي auth.default.svc وpayments.default.svc في بداية كل request. لو عندك 1,000 request في الثانية، و10% منها بتعمل DNS lookup جديد، فأنت عندك حوالي 100 query في الثانية على CoreDNS من مسارين بس.
لو الاسم ثابت لمدة 30 ثانية، مفيش معنى تسأل backend كل مرة. الأفضل إن CoreDNS يرد من cache. بالظبط زي إنك تحفظ رقم داخلي بتستخدمه كل دقيقة بدل ما تفتح دليل الشركة في كل مكالمة.
علميًا، CoreDNS cache plugin بيحفظ DNS responses داخل الذاكرة حسب TTL. التوثيق الرسمي يذكر إن الـ cache يقسم العناصر إلى 256 shard، وبالإعداد الافتراضي يستوعب تقريبًا 9984 عنصر. كمان يتيح ضبط success وdenial وprefetch وserve_stale حسب احتياجك.
الإعداد العملي في Corefile
الافتراض إن عندك cluster Kubernetes بحجم متوسط: من 20 إلى 80 service، وCoreDNS شغال كـ Deployment في namespace اسمه kube-system. ابدأ بقياس الوضع الحالي، ثم غيّر Corefile، ثم قِس تاني.
# اعرض إعداد CoreDNS الحالي
kubectl -n kube-system get configmap coredns -o yaml
# افتح التعديل
kubectl -n kube-system edit configmap coredns
داخل Corefile استخدم إعداد محافظ بدل cache مفتوح بلا تفكير:
.:53 {
errors
health {
lameduck 5s
}
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
forward . /etc/resolv.conf {
max_concurrent 1000
}
cache 30 {
success 20000 30 5
denial 5000 10 5
prefetch 20 1m 20%
serve_stale 30s verify
}
loop
reload
loadbalance
}بعد الحفظ، أعد تشغيل CoreDNS عشان تضمن تحميل الإعداد الجديد:
kubectl -n kube-system rollout restart deployment coredns
kubectl -n kube-system rollout status deployment coredns
القياس: قبل وبعد
استخدم Prometheus بدل الانطباع. CoreDNS يصدّر metrics من plugin prometheus على المسار /metrics والمنفذ 9153. راقب latency، وعدد الطلبات، ونسبة hits.
# p95 latency خلال آخر 5 دقائق
histogram_quantile(
0.95,
sum(rate(coredns_dns_request_duration_seconds_bucket[5m])) by (le)
)
# cache hit ratio تقريبي
sum(rate(coredns_cache_hits_total[5m]))
/
(sum(rate(coredns_cache_hits_total[5m])) + sum(rate(coredns_cache_misses_total[5m])))
في سيناريو واقعي لمتجر إلكتروني بـ 55K زائر يوميًا، كان p95 لـ CoreDNS حوالي 42ms وقت الذروة. بعد ضبط cache 30 وprefetch للأسماء الساخنة، نزل p95 إلى 9ms خلال ساعة مراقبة. الرقم ده تقديري لكنه منطقي لو أغلب الطلبات بتكرر نفس service names.
الـ trade-off هنا
المكسب واضح: fewer upstream lookups، latency أقل، وضغط CPU أخف على CoreDNS. الثمن إنك ممكن تخدم إجابة قديمة لمدة قصيرة لو service اتغير بسرعة. لذلك خليك محافظ: TTL من 10 إلى 30 ثانية كفاية في أغلب clusters، وserve_stale verify أهدأ من immediate لأنه يتحقق قبل تقديم stale answer، لكنه يضيف latency وقت العطل.
لو عايزها تدعم traffic أعلى، زوّد success CAPACITY تدريجيًا. لا تبدأ بـ 100 ألف عنصر من غير قياس memory. كل cache أكبر يعني ذاكرة أعلى، وممكن تخفي مشكلة تصميم لو التطبيق بيعمل DNS lookup لكل request بدل connection reuse.
متى لا تستخدم هذه الطريقة
لا تستخدم ضبط cache كعلاج أول لو عندك SERVFAIL كتير بسبب upstream DNS واقع. هنا المشكلة اعتمادية وليست cache. لا تستخدم TTL عالي لو services عندك تتغير بعنف أو بتعتمد على headless services لاكتشاف Pods لحظيًا. ولا تستخدمه كبديل لمراجعة التطبيق لو العميل يفتح connection جديد وDNS lookup جديد في كل call.
المصادر
الخطوة التالية
الخطوة التالية: شغّل PromQL الخاص بـ p95 لمدة 30 دقيقة، ثم فعّل cache 30 فقط. لو p95 لم ينزل على الأقل 30%، لا تزود cache؛ راجع عدد lookups في التطبيق والـ upstream resolver.