Od urednika Google bloga: Jeste li se ikada zapitali kako inženjeri Google Cloud tehničkih rješenja (TSE) rukovode vašim zahtjevima za podršku? Na inženjerima tehničke podrške TSE je odgovornost otkrivanje i rješavanje problema koje su korisnici prijavili. Neki od tih problema su prilično jednostavni, ali ponekad naiđemo na zahtjev koji zahtijeva pažnju nekoliko inženjera. U ovom članku jedan od zaposlenika TSE-a ispričat će nam o jednom vrlo složenom problemu iz svoje nedavne prakse — . Tokom ove priče vidjet ćemo na koji su način inženjeri uspjeli riješiti situaciju i što su novo naučili tijekom rješavanja greške. Nadamo se da će ova priča ne samo otkriti duboko usađenu grešku, nego također pružiti uvid u procese koji se odvijaju prilikom podnošenja zahtjeva za podršku Google Cloudu.

Otklanjanje grešaka je istovremeno i znanost i umjetnost. Sve započinje izradom hipoteze o uzroku neobičnog ponašanja sustava, nakon čega se ona testira. Međutim, prije nego što formiramo hipotezu, moramo jasno definirati i precizno formulirati problem. Ako pitanje zvuči previše nejasno, morat ćete ga pažljivo analizirati; tu dolazi do izražaja „umjetnost“ otklanjanja grešaka.
U uvjetima Google Clouda, takvi se procesi višestruko kompliciraju, jer Google Cloud nastoji osigurati privatnost svojih korisnika. Zbog toga inženjeri TSE nemaju pristup uređivanju vaših sustava niti mogućnost tako širokog pregledavanja konfiguracija kao što to rade korisnici. Stoga, za provjeru bilo koje od naših hipoteza, (inženjeri) ne možemo brzo modificirati sustav.
Neki korisnici misle da ćemo sve ispraviti poput mehaničara u servisu, i jednostavno nam šalju ID virtualne mašine, dok u stvarnosti proces izgleda kao razgovor: prikupljanje informacija, izrada i potvrda (ili opovrgavanje) hipoteza, a na kraju se rješenje problema temelji na komunikaciji s klijentom.
Proučavani problem
Danas imamo priču s sretnim završetkom. Jedan od razloga uspješnog rješavanja predloženog slučaja leži u vrlo detaljnom i točnom opisu problema. Ispod možete vidjeti kopiju prvog tiketa (uređenog kako bi se sakrila povjerljiva informacija):

U ovoj poruci ima puno korisnih informacija za nas:
- Navedena je konkretna VM
- Navedeni je sam problem — ne radi DNS
- Navedeno je gdje se problem pojavljuje — VM i kontejner
- Navedeni su koraci koje je korisnik poduzeo kako bi identificirao problem
Poziv je registriran kao «P1: Kritični utjecaj — Usluga neupotrebljiva u produkciji», što znači stalno praćenje situacije 24/7 prema shemi «Follow the Sun» (ovdje možete pročitati više o ), s prijenosom od jednog tima tehničke podrške do drugog pri svakom pomaku vremenskih zona. U suštini, do trenutka kada je problem stigao do našeg tima u Zürichem, uspio je obići cijeli svijet. U to vrijeme korisnik je poduzeo mjere za smanjenje posljedica, no bojao se ponovnog događaja u produkciji, jer osnovni uzrok još uvijek nije bio otkriven.
U trenutku kada je tiket stigao u Zürich, već smo imali sljedeće informacije:
- Sadržaj
/etc/hosts - Sadržaj
/etc/resolv.conf - Izvještaj
iptables-save - Prikupio tim
ngreppcap datoteku
S ovim podacima bili smo spremni započeti fazu «istrage» i otklanjanja poteškoća.
Naši prvi koraci
Prvo smo provjerili logove i status servera metapodataka te se uvjerili da ispravno radi. Server metapodataka odgovara na IP adresu 169.254.169.254 i, osim toga, odgovara za kontrolu nad nazivima domena. Također smo provjerili da vatrozid ispravno radi s VM i da ne blokira pakete.
To je bio neki čudan problem: provjera nmap je opovrgla našu osnovnu hipotezu o gubitku UDP paketa, stoga smo mentalno iznijeli još nekoliko opcija i načina provjere:
- Gube li se paketi selektivno? => Provjeriti pravila iptables
- Je li možda previše mali ? => Проверить вывод
ip a show - Utječe li problem samo na UDP pakete ili i na TCP? => Provesti
dig +tcp - Vraćaju li se generirani dig paketi? => Provesti
tcpdump - Radi li ispravno libdns? => Provesti
straceza provjeru prijenosa paketa u oba smjera
Ovdje odlučujemo da se spojimo s korisnikom kako bismo otklonili poteškoće uživo.
Tijekom poziva uspijevamo provjeriti nekoliko stvari:
- Nakon nekoliko provjera isključujemo pravila iptables iz popisa mogućih uzroka
- Provjeravamo mrežne sučelje i tablice usmjeravanja, te ponovno provjeravamo ispravnost MTU-a
- Otkrivamo da
dig +tcp google.com(TCP) radi kako treba, alidig google.com(UDP) ne radi - Pokrenuvši
tcpdumptrenutno radidig, otkrivamo da UDP paketi dolaze natrag - Pokrećemo
strace dig google.comi vidimo kako dig ispravno pozivasendmsg()irecvms(), međutim, drugi se prekida zbog isteka vremena
Nažalost, smjena se završava i prisiljeni smo prenijeti problem u sljedeću vremensku zonu. Ipak, zahtjev je pobudio interes u našem timu, a kolega predlaže izradu izvornih DNS paketa pomoću Python modula scrapy.
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())Ovaj fragment stvara DNS paket i šalje upit serveru metapodataka.
Korisnik pokreće kod, DNS odgovor se vraća, a aplikacija ga prima, što potvrđuje odsutnost problema na razini mreže.
Nakon još jednog "putovanja oko svijeta" zahtjev se vraća našem timu, i potpuno ga preuzimam, smatrajući da će korisniku biti lakše ako zahtjev prestane kružiti naokolo.
U međuvremenu, korisnik ljubazno pristaje pružiti snimku slike sustava. Ovo su vrlo dobre vijesti: mogućnost samostalnog testiranja sustava znatno ubrzava rješavanje problema, jer više ne trebam tražiti od korisnika da pokreće naredbe, šalje mi rezultate i analizira ih, sve mogu učiniti sam!
Kolege mi pomalo zavide. Za ručkom raspravljamo o zahtjevu, no nitko nema ideja o tome što se događa. Srećom, sam korisnik je već poduzeo mjere za ublažavanje posljedica i nema se gdje žuriti, tako da imamo vremena razraditi problem. A budući da imamo sliku, možemo provesti sve testove koji nas zanimaju. Odlično!
Vraćajući se korak unatrag
Jedno od najpopularnijih pitanja na intervjuima za posao sistemskog inženjera glasi: "Što se događa kada pingate ?» Вопрос шикарный, так как кандидату необходимо описать пусть от оболочки до пользовательского пространства, до ядра системы и далее к сети. Я улыбаюсь: иногда вопросы с интервью оказываются полезны и в реальной жизни…
Odlazim primijeniti ovo HR pitanje na trenutni problem. Grubo rečeno, kada pokušavate odrediti DNS ime, događa se sljedeće:
- Aplikacija poziva sistemsku biblioteku, na primjer libdns
- libdns provjerava konfiguraciju sustava kojem DNS serveru se treba obratiti (na dijagramu to je 169.254.169.254, server metapodataka)
- libdns koristi sistemske pozive za stvaranje UDP soketa (SOCK_DGRAM) i slanje UDP paketa s DNS upitom u obje strane
- Kroz sučelje sysctl može se konfigurirati UDP stog na razini jezgre
- Jezgra komunicira s hardverom za prijenos paketa putem mrežnog sučelja
- Hipervizor hvata i proslijeđuje paket serveru metapodataka kada dođe do kontakta
- Server metapodataka svojim čarobnjaštvom utvrđuje DNS ime i na isti način vraća odgovor

Podsjećam, koje smo hipoteze već razmotrili:
Hipoteza: Biblioteke su oštećene
- Test 1: pokrenuti strace u sustavu, provjeriti je li dig poziva ispravne sistemske pozive
- Rezultat: pozivaju se ispravni sistemi pozivi
- Test 2: putem srapy provjeriti možemo li određivati imena zaobilazeći sistemske biblioteke
- Rezultat: možemo
- Test 3: pokrenuti rpm –V na paketu libdns i md5sum datoteka biblioteke
- Rezultat: kod biblioteke je potpuno identičan kodu u radnom operativnom sustavu
- Test 4: montirati sliku korijenskog sustava korisnika na VM bez sličnog ponašanja, pokrenuti chroot, vidjeti radi li DNS
- Rezultat: DNS radi ispravno
Zaključak na temelju testova: problem nije u bibliotekama
Hipoteza: Prisutna je greška u DNS konfiguraciji
- Test 1: provjeriti tcpdump i promatrati ispravno li se šalju i primaju DNS paketi nakon pokretanja dig
- Rezultat: paketi se ispravno prenose
- Test 2: ponovo provjeriti na serveru
/etc/nsswitch.confi/etc/resolv.conf - Rezultat: sve je ispravno
Zaključak na temelju testova: problem nije u DNS konfiguraciji
Hipoteza: jezgra je oštećena
- Test: instalirati novu jezgru, provjeriti potpis, ponovno pokrenuti
- Rezultat: isto ponašanje
Zaključak na temelju testova: jezgra nije oštećena
Hipoteza: nepravilno ponašanje korisničke mreže (ili mrežnog sučelja hipervizora)
- Test 1: provjeriti postavke vatrozida
- Rezultat: vatrozid propušta DNS pakete kako na hostu, tako i na GCP-u
- Test 2: presresti promet i pratiti ispravnost prijenosa i povratka DNS upita
- Rezultat: tcpdump potvrđuje primitak povratnih paketa od strane hosta
Zaključak na temelju testova: problem nije u mreži
Hipoteza: server metapodataka ne radi
- Test 1: provjeriti logove servera metapodataka na anomalije
- Rezultat: u logovima nema anomalija
- Test 2: zaobići poslužitelj metapodataka preko
dig @8.8.8.8 - Rezultat: razrješavanje se prekida čak i bez korištenja poslužitelja metapodataka
Zaključak na temelju testova: problem nije u poslužitelju metapodataka
Zaključak: testirali smo sve podsustave osim postavki okruženja izvršenja!
Zalazeći u postavke okruženja izvršenja jezgre
Za postavljanje okruženja izvršenja jezgre možete iskoristiti opcije naredbenog retka (grub) ili sučelje sysctl. Zavirio sam u /etc/sysctl.conf i pomislite, otkrio sam nekoliko prilagođenih postavki. Imaginirajući da sam zgrabil nešto, odbacio sam sve non-network ili non-tcp postavke, ostajući s hrpom postavki net.core. Zatim sam se obratio onome gdje su VM smještene dozvole domaćina i počeo primjenjivati jednu za drugom postavke s pokvarenom VM, sve dok nisam došao do počinitelja:
net.core.rmem_default = 2147483647Evo ga, razbijač DNS konfiguracije! Pronašao sam oružje zločina. No, zašto se to događa? Još uvijek mi je trebao motiv.
Postavljanje osnovne veličine DNS paketa odvija se kroz net.core.rmem_default. Tipična vrijednost varira negdje između 200KiB, međutim, ako vaš poslužitelj prima mnogo DNS paketa, možete povećati veličinu bafera. Ako je bafer pun u trenutku kada stigne novi paket, primjerice jer ga aplikacija sporo obrađuje, počnete gubiti pakete. Naš klijent je ispravno povećao veličinu bafera jer se bojao gubitka podataka, s obzirom da je koristio aplikaciju za prikupljanje metrika putem DNS paketa. Vrijednost koju je postavio bila je maksimalno moguća: 231-1 (ako se postavi 231, jezgra će vratiti 'INVALID ARGUMENT').
Iznenada sam shvatio zašto nmap i scapy rade ispravno: koriste sirove sokete! Sirovi soketi se razlikuju od običnih: rade zaobići iptables i ne buferiraju se!
Ali zašto 'preveliki bafer' uzrokuje probleme? Očigledno ne funkcionira kako je zamišljeno.
U ovom trenutku mogao sam reproducirati problem na nekoliko jezgra i mnoštvu distribucija. Problem se već manifestirao na jezgru 3.x i sada se također manifestirao na jezgru 5.x.
Zaista, kada pokrenem
sysctl -w net.core.rmem_default=$((2**31-1))DNS prestaje raditi.
Počeo sam tražiti funkcionalne vrijednosti kroz jednostavni algoritam binarne pretrage i otkrio da sustav radi s 2147481343, no taj broj bio mi je besmislen skup cifara. Predložio sam klijentu da proba tu vrijednost, i on je odgovorio da je sustav proradio s google.com, ali je još uvijek izbacivao grešku s drugim domenama, pa sam nastavio svoje istraživanje.
Instalirao sam , alat koji sam trebao ranije iskoristiti: prikazuje gdje točno u jezgru dolazi paket. Krivac se pokazao kao funkcija udp_queue_rcv_skb. Preuzeo sam izvorne datoteke jezgre i dodao nekoliko da pratim gdje konkretno dolazi paket. Brzo sam otkrio potrebno uvjet if, i neko vrijeme sam samo buljio u to, jer je tada sve konačno došlo u cjelinu: 231-1, besmislen broj, neispravna domena… Riječ je o dijelu koda u __udp_enqueue_schedule_skb:
if (rmem > (size + sk->sk_rcvbuf))
goto uncharge_drop;Imajte na umu:
rmemima tip intsizeima tip u16 (bez potpisanog 16-bitnog int-a) i pohranjuje veličinu paketask->sk_rcvbufima tip int i pohranjuje veličinu buffera koja je po definiciji jednaka vrijednosti unet.core.rmem_default
Kada sk_rcvbuf približava se 231, zbrajanje veličine paketa može dovesti do . I budući da je to int, njegova vrijednost postaje negativna, tako da uvjet postaje istinit kada bi trebao biti lažan (više o tome možete saznati iz ).
Greška se ispravlja trivijalno: prebacivanjem na unsigned int. Primijenio sam ispravak i ponovno pokrenuo sustav, nakon čega je DNS ponovno proradio.
Okus pobjede
Poslao sam svoje nalaze klijentu i isporučio zakrpu jezgre. Zadovoljan sam: svaki komadić slagalice došao je na svoje mjesto, mogu točno objasniti zašto smo promatrali ono što smo promatrali, i što je najvažnije, uspjeli smo pronaći rješenje problema zahvaljujući zajedničkom radu!
Treba priznati da je slučaj bio rijedak, i srećom, od korisnika rijetko dobivamo toliko složene upite.
Izvor: habr.com
