Kubernetes DNS: Latency Daň ndots:5
Ked sa DNS lookupy strojnasobili, ndots bol to posledne, co som cakal. “Naše service-to-service volania majú 100ms baseline latenciu.” Tím bol zmätený. Ich servisy bežali na tom istom node, komunikácia mala byť sub-milisekundová. Napriek tomu každý HTTP call niesol nevysvetliteľnú 100ms daň. Debugging siete ukázal že packety sú rýchle. Servisy samotné sú rýchle. Niečo iné pridávalo latenciu.
Po hodinách tcpdump záchytov sme našli vinníka: DNS. Každý jeden externý API call triggeroval nie jeden, nie dva, ale štyri DNS queries—tri z ktorých zlyhali s NXDOMAIN pred tým ako štvrtý konečne uspel. Toto je skrytá cena Kubernetes defaultného nastavenia ndots:5.
Problém ndots je jedna z tých Kubernetes pascí, ktorá ovplyvňuje prakticky každý cluster ale zriedka sa dostane do titulkov. Tímy obviňujú network latenciu, ladia connection pools, pridávajú timeouty—nikdy nepodozrievajú že DNS resolution ticho násobí ich počet queries štyri a viackrát.
Testované na: Kubernetes 1.28, CoreDNS 1.11, Go a Python aplikácie
Pochopenie ndots
Vysvetlím vám presne čo ndots robí a prečo Kubernetes defaultne na takú vysokú hodnotu.
DNS Search Path
Keď vytvoríte pod v Kubernetes, kubelet automaticky nakonfiguruje DNS zápisom do /etc/resolv.conf. Typická konfigurácia vyzerá takto:
Default pod DNS config:
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
Čo ndots:5 znamená:
- Ak hostname má < 5 bodiek, najprv pripoj search domény
- "api.example.com" má 2 bodky (< 5)
- Skús v tomto poradí:
1. api.example.com.default.svc.cluster.local → NXDOMAIN
2. api.example.com.svc.cluster.local → NXDOMAIN
3. api.example.com.cluster.local → NXDOMAIN
4. api.example.com → SUCCESS
Výsledok: 4 DNS queries namiesto 1!
Možnosť ndots kontroluje ako resolver rozhoduje či je meno “absolútne” (plne kvalifikované) alebo “relatívne” (potrebuje pripojiť search domény). Ak má meno menej bodiek ako hodnota ndots, resolver skúša pripájať každú search doménu pred tým ako sa vráti k holému menu.
Prečo Kubernetes Používa ndots:5
Default 5 existuje z dobrého dôvodu: Kubernetes service discovery. V rámci clustra chcete byť schopní referencovať servisy krátkymi menami:
# Všetky tieto by mali resolvovať na rovnaký servis:
my-service # Len meno
my-service.default # Meno + namespace
my-service.default.svc # Meno + namespace + svc
my-service.default.svc.cluster.local # Plné FQDN (5 bodiek)
S ndots:5 všetky tieto krátke formy fungujú pretože majú menej ako 5 bodiek, takže resolver skúša pripájať search domény. Prvý match vyhráva. Toto je veľmi pohodlné pre cluster-internú komunikáciu.
Problém nastáva keď voláte externé domény. api.stripe.com má len 2 bodky, takže resolver poslušne skúša pripájať všetky search domény pred tým ako konečne skúsi holé meno.
Dopad na Latenciu
Dopad na externé API volania môže byť závažný:
Jeden externý API call na api.stripe.com:
DNS resolution:
api.stripe.com.default.svc.cluster.local → 8ms (NXDOMAIN)
api.stripe.com.svc.cluster.local → 7ms (NXDOMAIN)
api.stripe.com.cluster.local → 8ms (NXDOMAIN)
api.stripe.com → 9ms (SUCCESS)
Celkový DNS čas: 32ms za request (vs 9ms optimálne)
S connection timeout/retry: môže byť 100ms+
Pre 100 requestov/sekundu = 3,200 zbytočných DNS queries/sekundu
Každý neúspešný NXDOMAIN query trvá čas—typicky 5-15ms v závislosti od vašej siete a záťaže CoreDNS. S 3 neúspešnými queries plus 1 úspešným pozeráte na 25-60ms DNS overheadu na request. Ak je CoreDNS pod záťažou alebo vaša sieť má akúkoľvek kongescciu, tieto čísla rastú vyššie.
Videl som produkčné systémy kde DNS resolution tvorilo 80% celkovej request latencie pre externé API volania. Aplikačný kód bol rýchly, ale každý HTTP client čakal na DNS pred tým ako vôbec mohol otvoriť spojenie.
Skrytá Záťaž na CoreDNS
Okrem latencie, extra queries násobí záťaž na CoreDNS. Ak váš cluster robí 1000 externých API volaní za sekundu, generujete 4000 DNS queries za sekundu—3000 z ktorých je garantované že zlyhajú.
CoreDNS zvláda NXDOMAIN odpovede efektívne, ale stále konzumujú CPU, pamäť a sieťové zdroje. Videl som CoreDNS pody stať sa CPU-bound čisto zo spracovania search domain queries pre externé domény.
Meranie Problému
Pred aplikovaním opráv zmerajte aktuálny stav:
# Skontroluj aktuálne ndots nastavenie v pode
cat /etc/resolv.conf
# Trasuj DNS resolution
apt-get update && apt-get install -y dnsutils
time nslookup api.stripe.com
# Alebo s dig ukazujúcim všetky queries
dig +trace +all api.stripe.com
# Skontroluj CoreDNS NXDOMAIN rate
kubectl top pods -n kube-system | grep coredns
Ak vidíte vysoké NXDOMAIN rates v CoreDNS metrikách (často 50-80% všetkých queries), nastavenie ndots je pravdepodobne príčina. Tieto neúspešné queries sú pokusy search domén pre externé mená.
Riešenia
Existuje niekoľko prístupov na opravu ndots problému, od aplikačných zmien po cluster-wide infraštruktúrne vylepšenia.
1. Použi FQDN (Trailing Dot)
Najjednoduchšia oprava je pridanie trailing dot k externým doménovým menám. Trailing dot signalizuje DNS resolveru že meno je plne kvalifikované a nemalo by mať pripojené search domény:
// Go - pridaj trailing dot pre externé domény
resp, err := http.Get("https://api.stripe.com./v1/charges")
// ^ trailing dot = FQDN
// Toto obíde search domain logiku úplne
// Len 1 DNS query namiesto 4
# Python - rovnaký prístup
import requests
# S trailing dot - jediný DNS query
response = requests.get("https://api.stripe.com./v1/charges")
Trailing dot je súčasťou DNS špecifikácie—explicitne označuje meno ako absolútne. Väčšina HTTP knižníc a DNS resolverov s ním pracuje správne. Avšak niektoré CDN, load balancery alebo striktné hostname validátory nemusia akceptovať trailing dots, takže dôkladne testujte.
Tento prístup je chirurgická oprava—aplikujte ju na špecifické externé domény vo vašom kóde bez zmeny konfigurácie clustra.
2. Nastav Nižšie ndots v Pod Spec
Pre pody, ktoré primárne volajú externé API, znížte ndots v pod špecifikácii:
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
dnsConfig:
options:
- name: ndots
value: "2" # Externé domény majú 2+ bodky aj tak
containers:
- name: app
# ...
S ndots:2 je akýkoľvek hostname s 2 alebo viac bodkami okamžite považovaný za absolútny. Keďže väčšina externých domén ako api.stripe.com má presne 2 bodky, resolvujú priamo bez skúšania search domén.
Kompromis je že niektoré Kubernetes krátke mená prestanú fungovať. my-service.default (1 bodka) by stále fungovalo, ale ak máte servisy s pomlčkami, ktoré vyzerajú ako by mali 2+ komponenty, správanie sa môže zmeniť. Testujte vaše interné service discovery po vykonaní tejto zmeny.
Bezpečný stredný základ je ndots:3—toto zachováva väčšinu Kubernetes service discovery vzorov zatiaľ čo eliminuje search domain queries pre typické externé API domény.
3. Použi dnsPolicy: Default
Pre servisy, ktoré výlučne volajú externé API a nikdy nepoužívajú cluster service discovery, môžete obísť cluster DNS úplne:
# Pre servisy ktoré hlavne volajú externé API
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
dnsPolicy: "Default" # Použi DNS node, nie cluster DNS
containers:
- name: external-api-caller
# ...
S dnsPolicy: Default pod používa /etc/resolv.conf node namiesto cluster DNS. Toto typicky znamená žiadne search domény a priamu resolution cez akýkoľvek DNS, ktorý node používa (často cloud provider DNS alebo firemné DNS servery).
Zjavná nevýhoda je že Kubernetes service discovery nefunguje—nemôžete použiť my-service alebo my-service.namespace na dosiahnutie iných podov. Použite toto len pre pody, ktoré skutočne nepotrebujú cluster DNS.
4. NodeLocal DNS Cache
Pre cluster-wide zlepšenie nasaďte NodeLocal DNSCache. Toto beží DNS cache na každom node, znižujúc latenciu a záťaž na CoreDNS:
# Nainštaluj NodeLocal DNSCache
kubectl apply -f https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/dns/nodelocaldns/nodelocaldns.yaml
# Výhody:
# - Cachuje DNS odpovede lokálne na každom node
# - Znižuje latenciu pre opakované queries
# - Znižuje záťaž na CoreDNS
# - NXDOMAIN odpovede sú tiež cachované!
NodeLocal DNS je obzvlášť užitočné pre ndots problém pretože cachuje NXDOMAIN odpovede. Po prvom query pre api.stripe.com.default.svc.cluster.local, ktoré vráti NXDOMAIN, následné queries zasiahnu lokálnu cache namiesto ísť do CoreDNS.
Konfigurácia na použitie NodeLocal DNS:
# Over že NodeLocal DNS funguje
# Pody by mali resolvovať cez 169.254.20.10 (link-local)
apiVersion: v1
kind: Pod
spec:
dnsConfig:
nameservers:
- 169.254.20.10
searches:
- default.svc.cluster.local
- svc.cluster.local
- cluster.local
options:
- name: ndots
value: "2"
Kombinácia NodeLocal DNS s nižším ndots vám dáva to najlepšie z oboch svetov: rýchle lokálne cachovanie plus menej queries na začiatok.
5. Aplikačné DNS Cachovanie
Pre maximálnu kontrolu implementujte DNS cachovanie vo vašej aplikácii:
// Go - custom resolver s cachovaním
package main
import (
"context"
"net"
"sync"
"time"
)
type CachingResolver struct {
cache map[string]cachedResult
mu sync.RWMutex
ttl time.Duration
}
type cachedResult struct {
addrs []string
expires time.Time
}
func (r *CachingResolver) LookupHost(ctx context.Context, host string) ([]string, error) {
r.mu.RLock()
if cached, ok := r.cache[host]; ok && time.Now().Before(cached.expires) {
r.mu.RUnlock()
return cached.addrs, nil
}
r.mu.RUnlock()
addrs, err := net.DefaultResolver.LookupHost(ctx, host)
if err != nil {
return nil, err
}
r.mu.Lock()
r.cache[host] = cachedResult{addrs: addrs, expires: time.Now().Add(r.ttl)}
r.mu.Unlock()
return addrs, nil
}
Aplikačné cachovanie je najagresívnejšia optimalizácia. Keď raz resolvujete externú doménu, cachujete IP adresu a znovupoužívate ju pre následné requesty. Toto kompletne eliminuje DNS latenciu pre opakované volania na rovnakú doménu.
Buďte opatrní s TTL—cachujte príliš dlho a môžete minúť legitímne IP zmeny. Väčšina externých API má stabilné IP, ale CDN a load balancery môžu rotovať adresy.
CoreDNS Ladenie
Bez ohľadu na to, ktoré opravy aplikujete, ladenie CoreDNS zlepšuje celkový DNS performance:
# CoreDNS ConfigMap optimalizácia
apiVersion: v1
kind: ConfigMap
metadata:
name: coredns
namespace: kube-system
data:
Corefile: |
.:53 {
errors
health
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
}
cache 30 # Zvýš cache TTL
forward . /etc/resolv.conf {
max_concurrent 1000 # Zvýš concurrent queries
}
loop
reload
loadbalance
}
Kľúčové ladiace možnosti:
- cache: Zvýšte TTL pre cachované odpovede. Default je 30 sekúnd; môžete bezpečne zvýšiť na 60-300 pre stabilné externé domény.
- max_concurrent: Zvýšte limit na concurrent forwarded queries. Default je často príliš nízky pre zaneprázdnené clustre.
Monitoring
Nastavte alerty na zachytenie DNS problémov pred tým ako ovplyvnia používateľov:
# Alert na vysokú DNS latenciu
- alert: HighDNSLatency
expr: |
histogram_quantile(0.99,
rate(coredns_dns_request_duration_seconds_bucket[5m])
) > 0.1
for: 5m
annotations:
summary: "DNS p99 latencia > 100ms"
# Alert na vysoký NXDOMAIN rate (ndots problém)
- alert: HighNXDOMAINRate
expr: |
rate(coredns_dns_responses_total{rcode="NXDOMAIN"}[5m]) /
rate(coredns_dns_responses_total[5m]) > 0.5
for: 10m
annotations:
summary: "50%+ DNS queries vracia NXDOMAIN"
Alert na NXDOMAIN rate je obzvlášť hodnotný pre detekciu ndots problému. Ak viac ako polovica vašich DNS queries vracia NXDOMAIN, takmer určite pálite queries na search domain lookupy.
Checklist
## Kubernetes DNS Optimalizácia
### Diagnóza
- [ ] Skontroluj ndots hodnotu v podoch (cat /etc/resolv.conf)
- [ ] Zmeraj DNS resolution čas pre externé domény
- [ ] Skontroluj CoreDNS NXDOMAIN rate
- [ ] Monitoruj CoreDNS CPU usage
### Rýchle Riešenia
- [ ] Pridaj trailing dot k externým doménam v kóde
- [ ] Nastav ndots: 2 pre pody volajúce externé API
- [ ] Nasaď NodeLocal DNS Cache
### Infraštruktúra
- [ ] Vylaď CoreDNS cache nastavenia
- [ ] Zvýš max_concurrent pre forward
- [ ] Monitoruj DNS latency metriky
- [ ] Alert na NXDOMAIN rate spiky
Záver
Kubernetes default ndots:5 je skvelý pre service discovery ale hrozný pre externé API volania. Každá externá doména triggeruje viaceré neúspešné queries pred úspechom—skrytá daň na latencii, ktorá ovplyvňuje každý cluster.
Kľúčové poznatky:
- ndots:5 znamená 4 extra queries pre väčšinu externých domén—každý neúspešný query pridáva latenciu
- Používajte trailing dots v URL (ako
api.stripe.com.) pre okamžité, chirurgické opravy - Nastavte ndots:2 v dnsConfig pre pody, ktoré primárne volajú externé API
- Nasaďte NodeLocal DNS pre cluster-wide cachovanie a zníženú záťaž CoreDNS
- Monitorujte NXDOMAIN rate—vysoké rates odhalia ndots problém okamžite
Skontrolujte vaše CoreDNS metriky teraz. Ak vidíte 50%+ NXDOMAIN odpovede, ndots daň vás stojí latenciu na každom externom volaní.
Súvisiace články
- Kubernetes Conntrack Vyčerpanie - Ďalšia K8s networking pasca
- gRPC Deadline Propagácia - Latencia v mikroservisoch
Súvisiace články
CoreDNS vs NodeLocal DNS Cache: Zníženie Kubernetes DNS Latencie 10x
Vaše pody robia 100 DNS queries per request. CoreDNS je bottleneck. Benchmarkujem NodeLocal DNS cache a ukážem konfiguráciu pre produkciu.
Kubernetes CPU Throttling Pitva: Prečo p99 Latencia Exploduje pri 40% CPU Usage
CPU vyzerá OK, ale tail latencia je katastrofálna. Ukážem ako korelovať CFS throttling s latency spikes a prečo odstránenie CPU limitov môže paradoxne pomôcť.
Kubernetes conntrack Vyčerpanie: Tichý Zabijak Paketov
Náhodné DNS timeouty, dropped spojenia, služby timeout-ujú. Vaša nf_conntrack tabuľka je plná. Ukážem ako diagnostikovať, monitorovať a opraviť tento K8s networking problém.
Go cgo DNS Resolution Thread Explózia: Keď net.LookupHost Spawne Tisíce Threadov
Go aplikácia má zrazu 10,000 threadov konzumujúcich všetku pamäť. Príčina: cgo-based DNS resolution blokujúce v pomalých DNS prostrediach, obchádzajúce Go's goroutine scheduler.
Citujte tento článok
Ak na článok odkazujete, pridajte pôvodnú URL a uveďte autora.