Një histori rreth mungesës së paketave DNS nga mbështetja teknike e Google Cloud

Nga Redaktori i Blogut të Google: A e keni pyetur ndonjëherë veten se si inxhinierët e Zgjidhjeve Teknike të Google Cloud (TSE) i trajtojnë kërkesat tuaja për mbështetje? Inxhinierët e Mbështetjes Teknike të TSE janë përgjegjës për identifikimin dhe korrigjimin e burimeve të problemeve të raportuara nga përdoruesit. Disa nga këto probleme janë mjaft të thjeshta, por ndonjëherë hasni në një biletë që kërkon vëmendjen e disa inxhinierëve njëherësh. Në këtë artikull, një nga punonjësit e TSE do të na tregojë për një problem shumë të ndërlikuar nga praktika e tij e fundit - rasti i mungesës së paketave DNS. Në këtë histori, ne do të shohim se si inxhinierët arritën të zgjidhnin situatën dhe çfarë gjërash të reja mësuan gjatë rregullimit të gabimit. Shpresojmë që kjo histori jo vetëm t'ju edukojë për një defekt të thellë, por gjithashtu t'ju japë informacion mbi proceset që shkojnë në paraqitjen e një bilete mbështetëse me Google Cloud.

Një histori rreth mungesës së paketave DNS nga mbështetja teknike e Google Cloud

Zgjidhja e problemeve është edhe shkencë edhe art. E gjitha fillon me ndërtimin e një hipoteze për arsyen e sjelljes jo standarde të sistemit, pas së cilës ai testohet për forcë. Megjithatë, përpara se të formulojmë një hipotezë, duhet ta përcaktojmë qartë dhe ta formulojmë saktë problemin. Nëse pyetja tingëllon shumë e paqartë, atëherë do t'ju duhet të analizoni gjithçka me kujdes; Ky është "arti" i zgjidhjes së problemeve.

Nën Google Cloud, procese të tilla bëhen në mënyrë eksponenciale më komplekse, pasi Google Cloud përpiqet maksimalisht të garantojë privatësinë e përdoruesve të tij. Për shkak të kësaj, inxhinierët e TSE nuk kanë akses për të modifikuar sistemet tuaja, as aftësi për të parë konfigurimet aq gjerësisht sa përdoruesit. Prandaj, për të testuar ndonjë nga hipotezat tona, ne (inxhinierët) nuk mund ta modifikojmë shpejt sistemin.

Disa përdorues besojnë se ne do të rregullojmë gjithçka si mekanikë në një shërbim makine dhe thjesht do të na dërgojmë ID-në e një makinerie virtuale, ndërsa në realitet procesi zhvillohet në një format bisedor: mbledhja e informacionit, formimi dhe konfirmimi (ose përgënjeshtrimi) i hipotezave, dhe, në fund, problemet e një vendimi bazohen në komunikimin me klientin.

Problemi në fjalë

Sot kemi një histori me një fund të mirë. Një nga arsyet për zgjidhjen e suksesshme të rastit të propozuar është një përshkrim shumë i detajuar dhe i saktë i problemit. Më poshtë mund të shihni një kopje të biletës së parë (e redaktuar për të fshehur informacionin konfidencial):
Një histori rreth mungesës së paketave DNS nga mbështetja teknike e Google Cloud
Ky mesazh përmban shumë informacione të dobishme për ne:

  • VM specifike e specifikuar
  • Vetë problemi tregohet - DNS nuk funksionon
  • Tregohet ku shfaqet problemi - VM dhe kontejneri
  • Tregohen hapat që ka ndërmarrë përdoruesi për të identifikuar problemin.

Kërkesa u regjistrua si “P1: Ndikimi Kritik - Shërbimi i papërdorshëm në prodhim”, që nënkupton monitorim të vazhdueshëm të situatës 24/7 sipas skemës “Ndiq Diellin” (mund të lexoni më shumë rreth prioritetet e kërkesave të përdoruesve), me transferimin e tij nga një ekip mbështetës teknik në tjetrin me çdo ndryshim të zonës kohore. Në fakt, në kohën kur problemi arriti në ekipin tonë në Cyrih, ai tashmë kishte rrethuar globin. Në këtë kohë, përdoruesi kishte marrë masa zbutëse, por kishte frikë nga një përsëritje e situatës në prodhim, pasi shkaku kryesor nuk ishte zbuluar ende.

Në kohën kur bileta arriti në Cyrih, ne kishim tashmë informacionin e mëposhtëm në dispozicion:

  • përmbajtje /etc/hosts
  • përmbajtje /etc/resolv.conf
  • Prodhim iptables-save
  • I mbledhur nga ekipi ngrep skedar pcap

Me këto të dhëna, ne ishim gati të fillonim fazën e “hetimit” dhe zgjidhjes së problemeve.

Hapat tanë të parë

Para së gjithash, ne kontrolluam regjistrat dhe statusin e serverit të meta të dhënave dhe u siguruam që ai funksiononte si duhet. Serveri i meta të dhënave i përgjigjet adresës IP 169.254.169.254 dhe, ndër të tjera, është përgjegjës për kontrollin e emrave të domeneve. Ne gjithashtu kontrolluam dy herë nëse muri i zjarrit funksionon saktë me VM dhe nuk bllokon paketat.

Ishte një lloj problemi i çuditshëm: kontrolli nmap hodhi poshtë hipotezën tonë kryesore për humbjen e paketave UDP, kështu që mendërisht dolëm me disa opsione dhe mënyra të tjera për t'i kontrolluar ato:

  • A hidhen paketat në mënyrë selektive? => Kontrolloni rregullat iptables
  • A nuk është shumë i vogël? MTU? => Kontrollo daljen ip a show
  • A prek problemi vetëm paketat UDP ose TCP gjithashtu? => Largohuni dig +tcp
  • A kthehen paketat e gjeneruara nga dig? => Largohuni tcpdump
  • A funksionon libdns si duhet? => Largohuni strace për të kontrolluar transmetimin e paketave në të dy drejtimet

Këtu vendosim të thërrasim përdoruesin për të zgjidhur problemet drejtpërdrejt.

Gjatë telefonatës ne jemi në gjendje të kontrollojmë disa gjëra:

  • Pas disa kontrolleve ne përjashtojmë rregullat iptables nga lista e arsyeve
  • Ne kontrollojmë ndërfaqet e rrjetit dhe tabelat e rrugëzimit dhe kontrollojmë dy herë nëse MTU është e saktë
  • Ne e zbulojmë atë dig +tcp google.com (TCP) funksionon siç duhet, por dig google.com (UDP) nuk funksionon
  • Duke u larguar tcpdump është ende duke punuar dig, ne zbulojmë se paketat UDP po kthehen
  • Ne largohemi strace dig google.com dhe ne shohim se si gërmoj saktë thërret sendmsg() и recvms(), megjithatë i dyti ndërpritet me një timeout

Fatkeqësisht, fundi i turnit vjen dhe ne jemi të detyruar ta përshkallëzojmë problemin në zonën tjetër kohore. Kërkesa, megjithatë, zgjoi interes në ekipin tonë dhe një koleg sugjeron krijimin e paketës fillestare DNS duke përdorur modulin scrapy Python.

from scapy.all import *

answer = sr1(IP(dst="169.254.169.254")/UDP(dport=53)/DNS(rd=1,qd=DNSQR(qname="google.com")),verbose=0)
print ("169.254.169.254", answer[DNS].summary())

Ky fragment krijon një paketë DNS dhe dërgon kërkesën në serverin e meta të dhënave.

Përdoruesi ekzekuton kodin, përgjigja DNS kthehet dhe aplikacioni e merr atë, duke konfirmuar se nuk ka asnjë problem në nivelin e rrjetit.

Pas një tjetër "udhëtimi rreth botës", kërkesa kthehet në ekipin tonë dhe unë e transferoj plotësisht tek vetja, duke menduar se do të jetë më i përshtatshëm për përdoruesin nëse kërkesa ndalon të qarkullojë nga një vend në tjetrin.

Ndërkohë, përdoruesi pranon me mirësi të sigurojë një fotografi të imazhit të sistemit. Ky është një lajm shumë i mirë: aftësia për të testuar vetë sistemin e bën zgjidhjen e problemeve shumë më të shpejtë, sepse nuk duhet t'i kërkoj më përdoruesit të ekzekutojë komanda, të më dërgojë rezultatet dhe t'i analizoj ato, unë mund të bëj gjithçka vetë!

Kolegët e mi kanë filluar të më kenë zili pak. Gjatë drekës diskutojmë konvertimin, por askush nuk e ka idenë se çfarë po ndodh. Për fat të mirë, vetë përdoruesi tashmë ka marrë masa për të zbutur pasojat dhe nuk po nxiton, kështu që kemi kohë për të zbërthyer problemin. Dhe duke qenë se kemi një imazh, mund të bëjmë çdo test që na intereson. E shkëlqyeshme!

Duke bërë një hap prapa

Një nga pyetjet më të njohura të intervistës për pozicionet e inxhinierëve të sistemeve është: “Çfarë ndodh kur bëni ping www.google.com? Pyetja është e mrekullueshme, pasi kandidati duhet të përshkruajë gjithçka, nga shell-i te hapësira e përdoruesit, te kerneli i sistemit dhe më pas te rrjeti. Unë buzëqesh: ndonjëherë pyetjet e intervistës dalin të dobishme në jetën reale...

Unë vendos ta zbatoj këtë pyetje të burimeve njerëzore për një problem aktual. Përafërsisht, kur përpiqeni të përcaktoni një emër DNS, ndodh sa vijon:

  1. Aplikacioni thërret një bibliotekë të sistemit siç është libdns
  2. libdns kontrollon konfigurimin e sistemit me cilin server DNS duhet të kontaktojë (në diagram ky është 169.254.169.254, serveri i meta të dhënave)
  3. libdns përdor thirrjet e sistemit për të krijuar një prizë UDP (SOKET_DGRAM) dhe për të dërguar pako UDP me një pyetje DNS në të dy drejtimet
  4. Nëpërmjet ndërfaqes sysctl ju mund të konfiguroni pirgun UDP në nivelin e kernelit
  5. Kerneli ndërvepron me harduerin për të transmetuar paketat në rrjet nëpërmjet ndërfaqes së rrjetit
  6. Hipervizori kap dhe transmeton paketën në serverin e meta të dhënave pas kontaktit me të
  7. Serveri i meta të dhënave, me magjinë e tij, përcakton emrin DNS dhe kthen një përgjigje duke përdorur të njëjtën metodë

Një histori rreth mungesës së paketave DNS nga mbështetja teknike e Google Cloud
Më lejoni t'ju kujtoj se cilat hipoteza kemi shqyrtuar tashmë:

Hipoteza: Bibliotekat e thyera

  • Testi 1: ekzekutoni strace në sistem, kontrolloni që dig thërret thirrjet e duhura të sistemit
  • Rezultati: thirren thirrjet e sakta të sistemit
  • Testi 2: duke përdorur srapy për të kontrolluar nëse mund të përcaktojmë emrat duke anashkaluar bibliotekat e sistemit
  • Rezultati: ne mundemi
  • Testi 3: ekzekutoni rpm –V në paketën libdns dhe skedarët e bibliotekës md5sum
  • Rezultati: kodi i bibliotekës është plotësisht identik me kodin në sistemin operativ të punës
  • Testi 4: montoni imazhin e sistemit rrënjë të përdoruesit në një VM pa këtë sjellje, ekzekutoni chroot, shikoni nëse DNS funksionon
  • Rezultati: DNS funksionon si duhet

Konkluzioni i bazuar në teste: problemi nuk është në biblioteka

Hipoteza: Ka një gabim në cilësimet e DNS

  • Testi 1: kontrolloni tcpdump dhe shikoni nëse paketat DNS dërgohen dhe kthehen saktë pas ekzekutimit të gërmimit
  • Rezultati: paketat transmetohen si duhet
  • Testi 2: kontrolloni dy herë në server /etc/nsswitch.conf и /etc/resolv.conf
  • Rezultati: gjithçka është e saktë

Konkluzioni i bazuar në teste: problemi nuk është me konfigurimin DNS

Hipoteza: bërthama e dëmtuar

  • Test: instaloni kernelin e ri, kontrolloni nënshkrimin, rinisni
  • Rezultati: sjellje e ngjashme

Konkluzioni i bazuar në teste: bërthama nuk është e dëmtuar

Hipoteza: sjellja e gabuar e rrjetit të përdoruesit (ose ndërfaqja e rrjetit të hipervizorit)

  • Testi 1: Kontrolloni cilësimet e murit të zjarrit
  • Rezultati: muri i zjarrit kalon paketat DNS si në host ashtu edhe në GCP
  • Testi 2: përgjoni trafikun dhe monitoroni korrektësinë e transmetimit dhe kthimit të kërkesave DNS
  • Rezultati: tcpdump konfirmon që hosti ka marrë paketa kthyese

Konkluzioni i bazuar në teste: problemi nuk është në rrjet

Hipoteza: serveri i meta të dhënave nuk funksionon

  • Testi 1: kontrolloni regjistrat e serverit të meta të dhënave për anomali
  • Rezultati: nuk ka anomali në regjistra
  • Testi 2: Anashkaloni serverin e meta të dhënave nëpërmjet dig @8.8.8.8
  • Rezultati: Rezolucioni prishet edhe pa përdorur një server metadata

Konkluzioni i bazuar në teste: problemi nuk është me serverin e meta të dhënave

Bottom line: ne testuam të gjitha nënsistemet përveç cilësimet e kohës së funksionimit!

Zhytja në cilësimet e kohës së funksionimit të kernelit

Për të konfiguruar mjedisin e ekzekutimit të kernelit, mund të përdorni opsionet e linjës së komandës (grub) ose ndërfaqen sysctl. shikova brenda /etc/sysctl.conf dhe thjesht mendo, zbulova disa cilësime të personalizuara. Duke u ndjerë sikur kisha kapur diçka, hodha të gjitha cilësimet jo-rrjetore ose jo tcp, duke mbetur me cilësimet e malit net.core. Pastaj shkova atje ku ishin lejet e hostit në VM dhe fillova të aplikoja cilësimet një nga një, njëri pas tjetrit, me VM-në e prishur, derisa gjeta fajtorin:

net.core.rmem_default = 2147483647

Këtu është, një konfigurim që thyen DNS! Kam gjetur armën e vrasjes. Por pse po ndodh kjo? Më duhej ende një motiv.

Madhësia bazë e tamponit të paketës DNS konfigurohet nëpërmjet net.core.rmem_default. Një vlerë tipike është diku rreth 200 KiB, por nëse serveri juaj merr shumë paketa DNS, mund të dëshironi të rrisni madhësinë e buferit. Nëse buferi është plot kur vjen një paketë e re, për shembull sepse aplikacioni nuk po e përpunon atë mjaft shpejt, atëherë do të filloni të humbni paketat. Klienti ynë e rriti saktë madhësinë e buferit sepse kishte frikë nga humbja e të dhënave, pasi përdorte një aplikacion për mbledhjen e metrikave përmes paketave DNS. Vlera që ai vendosi ishte maksimumi i mundshëm: 231-1 (nëse caktohet në 231, kerneli do të kthejë "ARGUMENT I PAVLEFSHËM").

Papritur kuptova pse nmap dhe scapy funksionuan si duhet: ata po përdornin bazat e papërpunuara! Prizat e papërpunuara janë të ndryshme nga prizat e zakonshme: ato i anashkalojnë iptables dhe nuk janë të buferuara!

Por pse “buffer shumë i madh” shkakton probleme? Është e qartë se nuk funksionon siç është menduar.

Në këtë pikë unë mund të riprodhoj problemin në kernele të shumta dhe shpërndarje të shumta. Problemi u shfaq tashmë në kernelin 3.x dhe tani u shfaq edhe në kernelin 5.x.

Në të vërtetë, pas fillimit

sysctl -w net.core.rmem_default=$((2**31-1))

DNS ndaloi së punuari.

Fillova të kërkoja vlerat e punës përmes një algoritmi të thjeshtë kërkimi binar dhe zbulova se sistemi funksiononte me 2147481343, por ky numër ishte një grup numrash të pakuptimtë për mua. I sugjerova klientit të provonte këtë numër dhe ai u përgjigj se sistemi funksiononte me google.com, por përsëri dha një gabim me domenet e tjera, kështu që vazhdova hetimin tim.

kam instaluar orë rënie, një mjet që duhet të ishte përdorur më herët: tregon saktësisht se ku përfundon një paketë në kernel. Fajtori ishte funksioni udp_queue_rcv_skb. Shkarkova burimet e kernelit dhe shtova disa funksione printk për të gjurmuar se ku përfundon saktësisht paketa. Gjeta shpejt gjendjen e duhur if, dhe thjesht e nguli sytë për ca kohë, sepse ishte atëherë që më në fund gjithçka u bashkua në një pamje të plotë: 231-1, një numër i pakuptimtë, një domen që nuk funksiononte... Ishte një pjesë kodi në __udp_enqueue_schedule_skb:

if (rmem > (size + sk->sk_rcvbuf))
		goto uncharge_drop;

Ju lutemi vini re:

  • rmem është i tipit int
  • size është i tipit u16 (i panënshkruar gjashtëmbëdhjetë-bit int) dhe ruan madhësinë e paketës
  • sk->sk_rcybuf është i tipit int dhe ruan madhësinë e buferit e cila, sipas përkufizimit, është e barabartë me vlerën në net.core.rmem_default

Kur sk_rcvbuf afrohet 231, duke përmbledhur madhësinë e paketës mund të rezultojë në tejkalim i numrit të plotë. Dhe meqenëse është një int, vlera e tij bëhet negative, kështu që kushti bëhet i vërtetë kur duhet të jetë false (mund të lexoni më shumë rreth kësaj në lidhje).

Gabimi mund të korrigjohet në një mënyrë të parëndësishme: duke hedhur unsigned int. Aplikova rregullimin dhe rifillova sistemin dhe DNS funksionoi përsëri.

Shija e fitores

I përcolla gjetjet e mia te klienti dhe i dërgova LKML arnimi i kernelit. Jam i kënaqur: çdo pjesë e enigmës përshtatet së bashku, mund të shpjegoj saktësisht pse vëzhguam atë që vëzhguam, dhe më e rëndësishmja, ne ishim në gjendje të gjenim një zgjidhje për problemin falë punës sonë ekipore!

Vlen të pranohet se rasti doli të ishte i rrallë dhe për fat të mirë ne rrallë marrim kërkesa të tilla komplekse nga përdoruesit.

Një histori rreth mungesës së paketave DNS nga mbështetja teknike e Google Cloud


Burimi: www.habr.com

Shto një koment