O poveste despre pachetele DNS lipsă de la asistența tehnică Google Cloud

Din Google Blog Editor: V-ați întrebat vreodată cum gestionează inginerii Google Cloud Technical Solutions (TSE) solicitările dvs. de asistență? Inginerii de asistență tehnică TSE sunt responsabili pentru identificarea și corectarea surselor de probleme raportate de utilizator. Unele dintre aceste probleme sunt destul de simple, dar uneori dai peste un bilet care necesită atenția mai multor ingineri deodată. În acest articol, unul dintre angajații TSE ne va spune despre o problemă foarte dificilă din practica sa recentă - cazul lipsei pachetelor DNS. În această poveste, vom vedea cum au reușit inginerii să rezolve situația și ce lucruri noi au învățat în timp ce remediau eroarea. Sperăm că această poveste nu numai că vă educă despre o eroare adânc înrădăcinată, ci vă oferă și o perspectivă asupra proceselor care duc la depunerea unui bilet de asistență la Google Cloud.

O poveste despre pachetele DNS lipsă de la asistența tehnică Google Cloud

Depanarea este atât o știință, cât și o artă. Totul începe cu construirea unei ipoteze despre motivul comportamentului nestandard al sistemului, după care este testat rezistența. Cu toate acestea, înainte de a formula o ipoteză, trebuie să definim clar și să formulăm cu precizie problema. Dacă întrebarea sună prea vagă, atunci va trebui să analizezi totul cu atenție; Aceasta este „arta” depanării.

În cadrul Google Cloud, astfel de procese devin exponențial mai complexe, deoarece Google Cloud face tot posibilul pentru a garanta confidențialitatea utilizatorilor săi. Din acest motiv, inginerii TSE nu au nici acces pentru a vă edita sistemele și nici capacitatea de a vizualiza configurațiile la fel de larg ca utilizatorii. Prin urmare, pentru a testa oricare dintre ipotezele noastre, noi (inginerii) nu putem modifica rapid sistemul.

Unii utilizatori cred că vom repara totul ca mecanicii într-un service auto și pur și simplu ne vom trimite id-ul unei mașini virtuale, în timp ce, în realitate, procesul are loc într-un format conversațional: colectarea informațiilor, formarea și confirmarea (sau infirmarea) ipotezelor, iar, în final, problemele unei decizii se bazează pe comunicarea cu clientul.

Problema in cauza

Astăzi avem o poveste cu un final bun. Unul dintre motivele pentru rezolvarea cu succes a cazului propus este o descriere foarte detaliată și precisă a problemei. Mai jos puteți vedea o copie a primului bilet (editat pentru a ascunde informațiile confidențiale):
O poveste despre pachetele DNS lipsă de la asistența tehnică Google Cloud
Acest mesaj conține o mulțime de informații utile pentru noi:

  • Specific VM specificat
  • Problema în sine este indicată - DNS nu funcționează
  • Este indicat unde se manifestă problema - VM și container
  • Sunt indicați pașii urmați de utilizator pentru a identifica problema.

Solicitarea a fost înregistrată ca „P1: Impact Critic - Serviciu inutilizabil în producție”, ceea ce înseamnă monitorizare constantă a situației 24/7 conform schemei „Urmează Soarele” (puteți citi mai multe despre prioritățile solicitărilor utilizatorilor), cu transferul acestuia de la o echipă de asistență tehnică la alta cu fiecare schimbare de fus orar. De fapt, în momentul în care problema a ajuns la echipa noastră din Zurich, ea înconjurase deja globul. Până atunci, utilizatorul luase măsuri de atenuare, dar se temea de repetarea situației în producție, deoarece cauza principală nu fusese încă descoperită.

Când biletul a ajuns la Zurich, aveam deja următoarele informații la îndemână:

  • conținut /etc/hosts
  • conținut /etc/resolv.conf
  • Producție iptables-save
  • Asamblat de echipă ngrep fișierul pcap

Cu aceste date, eram gata să începem faza de „investigație” și de depanare.

Primii noștri pași

În primul rând, am verificat jurnalele și starea serverului de metadate și ne-am asigurat că funcționează corect. Serverul de metadate răspunde la adresa IP 169.254.169.254 și, printre altele, este responsabil pentru controlul numelor de domenii. De asemenea, am verificat dublu dacă firewall-ul funcționează corect cu VM și nu blochează pachetele.

A fost un fel de problemă ciudată: verificarea nmap a respins ipoteza noastră principală despre pierderea pachetelor UDP, așa că am venit mental cu mai multe opțiuni și modalități de a le verifica:

  • Pachetele sunt aruncate selectiv? => Verificați regulile iptables
  • Nu este prea mic? MTU? => Verificați ieșirea ip a show
  • Problema afectează doar pachetele UDP sau TCP? => Conduceți dig +tcp
  • Sunt returnate pachetele generate de dig? => Conduceți tcpdump
  • Funcționează libdns corect? => Conduceți strace pentru a verifica transmiterea pachetelor în ambele sensuri

Aici decidem să sunăm utilizatorul pentru a depana problemele în direct.

În timpul apelului, putem verifica mai multe lucruri:

  • După mai multe verificări, excludem regulile iptables din lista de motive
  • Verificăm interfețele de rețea și tabelele de rutare și verificăm de două ori corectitudinea MTU
  • Descoperim asta dig +tcp google.com (TCP) funcționează așa cum ar trebui, dar dig google.com (UDP) nu funcționează
  • După ce a plecat tcpdump în timpul lucrului dig, constatăm că pachetele UDP sunt returnate
  • Conducem strace dig google.com și vedem cum dig apeluri corect sendmsg() и recvms(), cu toate acestea, al doilea este întrerupt de un timeout

Din păcate, sosește sfârșitul turei și suntem nevoiți să escaladăm problema la următorul fus orar. Cererea, însă, a stârnit interes în echipa noastră, iar un coleg sugerează crearea pachetului DNS inițial folosind modulul 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())

Acest fragment creează un pachet DNS și trimite cererea către serverul de metadate.

Utilizatorul rulează codul, răspunsul DNS este returnat, iar aplicația îl primește, confirmând că nu există nicio problemă la nivel de rețea.

După o altă „călătorie în jurul lumii”, solicitarea revine echipei noastre și mi-o transfer complet, gândindu-mă că va fi mai convenabil pentru utilizator dacă cererea nu mai circulă dintr-un loc în altul.

Între timp, utilizatorul este de acord să furnizeze un instantaneu al imaginii sistemului. Aceasta este o veste foarte bună: capacitatea de a testa singur sistemul face depanarea mult mai rapidă, deoarece nu mai trebuie să cer utilizatorului să execute comenzi, să-mi trimită rezultatele și să le analizez, pot face totul singur!

Colegii mei încep să mă invidieze puțin. La prânz discutăm despre conversie, dar nimeni nu are idee despre ce se întâmplă. Din fericire, utilizatorul însuși a luat deja măsuri pentru a atenua consecințele și nu se grăbește, așa că avem timp să disecăm problema. Și din moment ce avem o imagine, putem rula orice teste care ne interesează. Grozav!

Făcând un pas înapoi

Una dintre cele mai populare întrebări de interviu pentru posturile de inginer de sisteme este: „Ce se întâmplă când dai ping www.google.com? Întrebarea este grozavă, deoarece candidatul trebuie să descrie totul, de la shell la spațiul utilizatorului, la nucleul de sistem și apoi la rețea. Zâmbesc: uneori întrebările de la interviu se dovedesc utile în viața reală...

Mă hotărăsc să aplic această întrebare de resurse umane la o problemă curentă. În linii mari, când încercați să determinați un nume DNS, se întâmplă următoarele:

  1. Aplicația apelează o bibliotecă de sistem, cum ar fi libdns
  2. libdns verifică configurația sistemului la care server DNS ar trebui să îl contacteze (în diagramă acesta este 169.254.169.254, serverul de metadate)
  3. libdns folosește apeluri de sistem pentru a crea un socket UDP (SOKET_DGRAM) și a trimite pachete UDP cu o interogare DNS în ambele direcții
  4. Prin interfața sysctl puteți configura stiva UDP la nivel de kernel
  5. Nucleul interacționează cu hardware-ul pentru a transmite pachete prin rețea prin interfața de rețea
  6. Hypervisorul prinde și transmite pachetul către serverul de metadate la contactul cu acesta
  7. Serverul de metadate, prin magia sa, determină numele DNS și returnează un răspuns folosind aceeași metodă

O poveste despre pachetele DNS lipsă de la asistența tehnică Google Cloud
Permiteți-mi să vă reamintesc ce ipoteze am luat în considerare deja:

Ipoteza: biblioteci sparte

  • Testul 1: rulați Strace în sistem, verificați dacă dig apelează apelurile de sistem corecte
  • Rezultat: Apelurile de sistem corecte sunt apelate
  • Testul 2: folosind srapy pentru a verifica dacă putem determina nume care ocolesc bibliotecile de sistem
  • Rezultat: putem
  • Testul 3: rulați rpm –V pe pachetul libdns și fișierele de bibliotecă md5sum
  • Rezultat: codul bibliotecii este complet identic cu codul din sistemul de operare de lucru
  • Testul 4: montați imaginea sistemului rădăcină a utilizatorului pe o VM fără acest comportament, rulați chroot, vedeți dacă DNS funcționează
  • Rezultat: DNS funcționează corect

Concluzie bazată pe teste: problema nu este la biblioteci

Ipoteza: Există o eroare în setările DNS

  • Testul 1: verificați tcpdump și vedeți dacă pachetele DNS sunt trimise și returnate corect după rularea dig
  • Rezultat: pachetele sunt transmise corect
  • Testul 2: verificați de două ori pe server /etc/nsswitch.conf и /etc/resolv.conf
  • Rezultat: totul este corect

Concluzie bazată pe teste: problema nu este cu configurația DNS

Ipoteza: miez deteriorat

  • Test: instalați un nucleu nou, verificați semnătura, reporniți
  • Rezultat: comportament similar

Concluzie bazată pe teste: nucleul nu este deteriorat

Ipoteza: comportament incorect al rețelei de utilizator (sau interfață de rețea hypervisor)

  • Testul 1: verificați setările firewall-ului
  • Rezultat: firewall-ul transmite pachete DNS atât pe gazdă, cât și pe GCP
  • Testul 2: interceptați traficul și monitorizați corectitudinea transmiterii și returnării cererilor DNS
  • Rezultat: tcpdump confirmă că gazda a primit pachete returnate

Concluzie bazată pe teste: problema nu este in retea

Ipoteza: serverul de metadate nu funcționează

  • Testul 1: verificați jurnalele serverului de metadate pentru anomalii
  • Rezultat: nu există anomalii în jurnalele
  • Testul 2: Ocoliți serverul de metadate prin dig @8.8.8.8
  • Rezultat: Rezoluția este întreruptă chiar și fără a utiliza un server de metadate

Concluzie bazată pe teste: problema nu este cu serverul de metadate

Linia de jos: am testat toate subsistemele cu excepția setări de rulare!

Scufundarea în Setările Kernel Runtime

Pentru a configura mediul de execuție a nucleului, puteți utiliza opțiunile liniei de comandă (grub) sau interfața sysctl. M-am uitat înăuntru /etc/sysctl.conf și gândește-te, am descoperit câteva setări personalizate. Simțindu-mă de parcă m-am apucat de ceva, am eliminat toate setările non-network sau non-tcp, rămânând cu setările de munte net.core. Apoi m-am dus acolo unde erau permisiunile de gazdă în VM și am început să aplic setările una câte una, una după alta, cu VM-ul stricat, până am găsit vinovatul:

net.core.rmem_default = 2147483647

Iată, o configurație care distruge DNS! Am găsit arma crimei. Dar de ce se întâmplă asta? Mai aveam nevoie de un motiv.

Dimensiunea de bază a bufferului de pachete DNS este configurată prin net.core.rmem_default. O valoare tipică este undeva în jur de 200 KiB, dar dacă serverul dvs. primește o mulțime de pachete DNS, este posibil să doriți să măriți dimensiunea bufferului. Dacă tamponul este plin când sosește un nou pachet, de exemplu pentru că aplicația nu îl procesează suficient de rapid, atunci vei începe să pierzi pachete. Clientul nostru a mărit corect dimensiunea bufferului pentru că îi era frică de pierderea datelor, deoarece folosea o aplicație pentru colectarea de valori prin pachete DNS. Valoarea pe care a stabilit-o a fost maxima posibilă: 231-1 (dacă este setată la 231, nucleul va returna „ARGUMENT INVALID”).

Deodată mi-am dat seama de ce nmap și scapy au funcționat corect: foloseau socketuri brute! Socket-urile brute sunt diferite de socket-urile obișnuite: ocolesc iptable-urile și nu sunt tamponate!

Dar de ce „tamponul prea mare” cauzează probleme? În mod clar nu funcționează așa cum a fost prevăzut.

În acest moment, aș putea reproduce problema pe mai multe nuclee și mai multe distribuții. Problema a apărut deja pe nucleul 3.x și acum a apărut și pe kernel-ul 5.x.

Într-adevăr, la pornire

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

DNS a încetat să funcționeze.

Am început să caut valori de lucru printr-un algoritm simplu de căutare binar și am descoperit că sistemul funcționează cu 2147481343, dar acest număr era un set de numere fără sens pentru mine. I-am sugerat clientului să încerce acest număr și mi-a răspuns că sistemul funcționează cu google.com, dar tot a dat o eroare cu alte domenii, așa că mi-am continuat investigația.

am instalat dropwatch, un instrument care ar fi trebuit folosit mai devreme: arată exact unde ajunge în nucleu un pachet. Vinovatul a fost funcția udp_queue_rcv_skb. Am descărcat sursele nucleului și am adăugat câteva funcție printk pentru a urmări unde exact ajunge pachetul. Am găsit rapid starea potrivită if, și pur și simplu m-am uitat la el o vreme, pentru că atunci totul s-a reunit într-o imagine întreagă: 231-1, un număr fără sens, un domeniu nefuncțional... Era o bucată de cod în __udp_enqueue_schedule_skb:

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

Vă rugăm să rețineți:

  • rmem este de tip int
  • size este de tip u16 (unsigned sixteen-bit int) și stochează dimensiunea pachetului
  • sk->sk_rcybuf este de tip int și stochează dimensiunea bufferului care, prin definiție, este egală cu valoarea în net.core.rmem_default

Când sk_rcvbuf se apropie de 231, însumarea dimensiunii pachetului poate avea ca rezultat overflow întreg. Și, deoarece este un int, valoarea sa devine negativă, așa că condiția devine adevărată atunci când ar trebui să fie falsă (puteți citi mai multe despre asta la legătură).

Eroarea poate fi corectată într-un mod banal: prin turnare unsigned int. Am aplicat remedierea și am repornit sistemul și DNS a funcționat din nou.

Gust de victorie

Am transmis concluziile mele clientului și am trimis LKML patch-ul nucleului. Sunt mulțumit: fiecare piesă a puzzle-ului se potrivește, pot să explic exact de ce am observat ceea ce am observat și, cel mai important, am reușit să găsim o soluție la problemă datorită muncii noastre în echipă!

Merită să recunoaștem că cazul s-a dovedit a fi rar și, din fericire, primim rar solicitări atât de complexe de la utilizatori.

O poveste despre pachetele DNS lipsă de la asistența tehnică Google Cloud


Sursa: www.habr.com

Adauga un comentariu