Iš „Google“ tinklaraščio redaktoriaus: Ar kada nors susimąstėte, kaip „Google Cloud Technical Solutions“ (TSE) inžinieriai tvarko jūsų palaikymo užklausas? TSE techninės pagalbos inžinieriai yra atsakingi už vartotojų praneštų problemų šaltinių nustatymą ir ištaisymą. Kai kurios iš šių problemų yra gana paprastos, tačiau kartais tenka susidurti su bilietu, kuriam vienu metu reikia kelių inžinierių dėmesio. Šiame straipsnyje vienas iš TSE darbuotojų papasakos apie vieną labai keblią problemą iš savo pastarosios praktikos – . Šioje istorijoje pamatysime, kaip inžinieriams pavyko išspręsti situaciją ir kokių naujų dalykų išmoko taisydami klaidą. Tikimės, kad ši istorija ne tik informuos jus apie giliai įsišaknijusią klaidą, bet ir suteiks jums įžvalgos apie procesus, kurių reikia norint pateikti palaikymo bilietą „Google Cloud“.

Trikčių šalinimas yra ir mokslas, ir menas. Viskas prasideda nuo hipotezės apie nestandartinio sistemos elgesio priežastį sukūrimo, o po to patikrinamas jos stiprumas. Tačiau prieš formuluodami hipotezę, turime aiškiai apibrėžti ir tiksliai suformuluoti problemą. Jei klausimas skamba pernelyg neapibrėžtai, tuomet turėsite viską atidžiai išanalizuoti; Tai yra trikčių šalinimo „menas“.
Naudojant „Google Cloud“, tokie procesai tampa eksponentiškai sudėtingesni, nes „Google Cloud“ stengiasi užtikrinti savo vartotojų privatumą. Dėl šios priežasties TSE inžinieriai neturi prieigos redaguoti jūsų sistemų ir negali peržiūrėti konfigūracijų taip plačiai, kaip tai daro vartotojai. Todėl norėdami patikrinti bet kurią iš mūsų hipotezės, mes (inžinieriai) negalime greitai modifikuoti sistemos.
Kai kurie vartotojai tiki, kad viską sutvarkysime kaip mechaniką autoservise ir tiesiog atsiųsime virtualios mašinos ID, o iš tikrųjų procesas vyksta pokalbio formatu: renkame informaciją, formuojame ir patvirtiname (arba paneigiame) hipotezes, ir galiausiai sprendimo problemos yra pagrįstos bendravimu su klientu.
Aptariama problema
Šiandien turime istoriją su gera pabaiga. Viena iš sėkmingo siūlomos bylos išsprendimo priežasčių – labai detalus ir tikslus problemos aprašymas. Žemiau galite pamatyti pirmojo bilieto kopiją (redaguotą, kad paslėptumėte konfidencialią informaciją):

Šiame pranešime yra daug mums naudingos informacijos:
- Nurodyta konkreti VM
- Nurodoma pati problema - DNS neveikia
- Nurodoma, kur pasireiškia problema - VM ir konteineris
- Nurodomi veiksmai, kurių vartotojas ėmėsi, kad nustatytų problemą.
Prašymas buvo užregistruotas kaip „P1: Kritinis poveikis – paslauga nenaudojama gamyboje“, o tai reiškia nuolatinį situacijos stebėjimą 24/7 pagal schemą „Sekite saulę“ (daugiau galite paskaityti apie ), perkeliant ją iš vienos techninės pagalbos komandos į kitą kiekvieną kartą keičiant laiko juostą. Tiesą sakant, tuo metu, kai problema pasiekė mūsų komandą Ciuriche, ji jau buvo apskriejusi pasaulį. Iki to laiko vartotojas ėmėsi švelninimo priemonių, tačiau bijojo, kad situacija pasikartos gamyboje, nes pagrindinė priežastis dar nebuvo nustatyta.
Kai bilietas pasiekė Ciurichą, jau turėjome šią informaciją:
- Turinys
/etc/hosts - Turinys
/etc/resolv.conf - Produkcija
iptables-save - Surinkta komandos
ngreppcap failą
Turėdami šiuos duomenis, buvome pasirengę pradėti „tyrimo“ ir trikčių šalinimo etapą.
Pirmieji mūsų žingsniai
Pirmiausia patikrinome metaduomenų serverio žurnalus ir būseną bei įsitikinome, kad jis veikia tinkamai. Metaduomenų serveris reaguoja į IP adresą 169.254.169.254 ir, be kita ko, yra atsakingas už domenų vardų valdymą. Taip pat dar kartą patikrinome, ar ugniasienė tinkamai veikia su VM ir neblokuoja paketų.
Tai buvo kažkokia keista problema: nmap patikra paneigė mūsų pagrindinę hipotezę apie UDP paketų praradimą, todėl mintyse sugalvojome dar keletą variantų ir būdų, kaip juos patikrinti:
- Ar paketai metami pasirinktinai? => Patikrinkite iptables taisykles
- Ar ne per mažas? ? => Patikrinkite išvestį
ip a show - Ar problema taip pat turi įtakos tik UDP paketams arba TCP? => Varyk šalin
dig +tcp - Ar grąžinami dig sugeneruoti paketai? => Varyk šalin
tcpdump - Ar libdns veikia tinkamai? => Varyk šalin
stracepatikrinti paketų perdavimą abiem kryptimis
Čia mes nusprendžiame paskambinti vartotojui, kad pašalintume triktis tiesiogiai.
Pokalbio metu galime patikrinti keletą dalykų:
- Po kelių patikrinimų pašaliname iptables taisykles iš priežasčių sąrašo
- Tikriname tinklo sąsajas ir maršruto parinkimo lenteles ir dar kartą patikriname, ar MTU yra teisingas
- Mes tai atrandame
dig +tcp google.com(TCP) veikia taip, kaip turėtų, betdig google.com(UDP) neveikia - Nuvažiavęs
tcpdumptai vis dar veikiadig, nustatome, kad grąžinami UDP paketai - Nuvažiuojame
strace dig google.comir mes matome, kaip dig teisingai skambinasendmsg()иrecvms(), tačiau antrąjį nutraukia skirtasis laikas
Deja, ateina pamainos pabaiga ir mes esame priversti problemą eskaluoti į kitą laiko juostą. Tačiau užklausa sukėlė susidomėjimą mūsų komandoje, o kolega siūlo sukurti pradinį DNS paketą naudojant „skraidantį“ Python modulį.
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())Šis fragmentas sukuria DNS paketą ir siunčia užklausą metaduomenų serveriui.
Vartotojas paleidžia kodą, grąžinamas DNS atsakymas, o programa jį gauna, patvirtindama, kad tinklo lygiu nėra problemų.
Po dar vienos „kelionės aplink pasaulį“ užklausa grįžta į mūsų komandą, o aš ją visiškai perduodu sau, galvodama, kad vartotojui bus patogiau, jei užklausa nustos suktis iš vienos vietos į kitą.
Tuo tarpu vartotojas maloniai sutinka pateikti sistemos vaizdo momentinę nuotrauką. Tai labai gera žinia: galimybė pačiam išbandyti sistemą gerokai pagreitina gedimų šalinimą, nes man nebereikia prašyti vartotojo paleisti komandas, siųsti man rezultatus ir juos analizuoti, viską galiu padaryti pats!
Kolegos man pradeda po truputį pavydėti. Per pietus aptariame atsivertimą, bet niekas neįsivaizduoja, kas vyksta. Laimei, pats vartotojas jau ėmėsi priemonių pasekmes sušvelninti ir neskuba, todėl turime laiko išnarplioti problemą. Ir kadangi turime įvaizdį, galime atlikti bet kokius mus dominančius testus. Puiku!
Žengdamas žingsnį atgal
Vienas iš populiariausių interviu klausimų sistemų inžinieriams yra: „Kas atsitinka, kai pingate ? Klausimas puikus, nes kandidatas turi aprašyti viską nuo apvalkalo iki vartotojo erdvės, sistemos branduolio ir tinklo. Šypsausi: kartais interviu klausimai praverčia gyvenime...
Nusprendžiu šį HR klausimą pritaikyti esamai problemai. Grubiai tariant, kai bandote nustatyti DNS pavadinimą, nutinka taip:
- Programa iškviečia sistemos biblioteką, pvz., libdns
- libdns patikrina sistemos konfigūraciją, prie kurio DNS serverio turėtų susisiekti (schemoje tai yra 169.254.169.254, metaduomenų serveris)
- libdns naudoja sistemos iškvietimus, kad sukurtų UDP lizdą (SOKET_DGRAM) ir siųstų UDP paketus su DNS užklausa abiem kryptimis
- Per sysctl sąsają galite sukonfigūruoti UDP steką branduolio lygiu
- Branduolys sąveikauja su aparatine įranga ir perduoda paketus tinkle per tinklo sąsają
- Hipervizorius sugauna ir perduoda paketą metaduomenų serveriui, kai su juo susisiekia
- Metaduomenų serveris savo stebuklingai nustato DNS pavadinimą ir grąžina atsakymą naudodamas tą patį metodą

Leiskite jums priminti, kokias hipotezes mes jau svarstėme:
Hipotezė: sugedusios bibliotekos
- 1 bandymas: paleiskite strace sistemoje, patikrinkite, ar dig iškviečia teisingus sistemos iškvietimus
- Rezultatas: iškviečiami teisingi sistemos skambučiai
- 2 bandymas: naudokite srapy, kad patikrintume, ar galime nustatyti pavadinimus, aplenkdami sistemos bibliotekas
- Rezultatas: galime
- 3 testas: paleiskite rpm –V libdns pakete ir md5sum bibliotekos failuose
- Rezultatas: bibliotekos kodas yra visiškai identiškas veikiančios operacinės sistemos kodui
- 4 bandymas: prijunkite vartotojo šakninės sistemos vaizdą prie VM be šio elgesio, paleiskite chroot, patikrinkite, ar veikia DNS
- Rezultatas: DNS veikia tinkamai
Išvada remiantis testais: problema ne bibliotekose
Hipotezė: DNS nustatymuose yra klaida
- 1 testas: patikrinkite tcpdump ir patikrinkite, ar DNS paketai siunčiami ir grąžinami tinkamai, paleidus dig
- Rezultatas: paketai perduodami teisingai
- 2 testas: dar kartą patikrinkite serverį
/etc/nsswitch.confи/etc/resolv.conf - Rezultatas: viskas teisinga
Išvada remiantis testais: problema ne DNS konfigūracijoje
Hipotezė: pažeista šerdis
- Testas: įdiekite naują branduolį, patikrinkite parašą, paleiskite iš naujo
- Rezultatas: panašus elgesys
Išvada remiantis testais: branduolys nepažeistas
Hipotezė: neteisingas vartotojo tinklo (arba hipervizoriaus tinklo sąsajos) elgesys
- 1 bandymas: patikrinkite ugniasienės nustatymus
- Rezultatas: ugniasienė perduoda DNS paketus ir pagrindiniame, ir GCP
- 2 testas: perimkite srautą ir stebėkite DNS užklausų perdavimo ir grąžinimo teisingumą
- Rezultatas: tcpdump patvirtina, kad pagrindinis kompiuteris gavo grįžtamuosius paketus
Išvada remiantis testais: problema ne tinkle
Hipotezė: metaduomenų serveris neveikia
- 1 bandymas: patikrinkite, ar metaduomenų serverio žurnaluose nėra anomalijų
- Rezultatas: žurnaluose anomalijų nėra
- 2 bandymas: apeiti metaduomenų serverį per
dig @8.8.8.8 - Rezultatas: skiriamoji geba sugenda net nenaudojant metaduomenų serverio
Išvada remiantis testais: problema ne metaduomenų serveryje
Esmė: išbandėme visas posistemes, išskyrus vykdymo laiko nustatymai!
Pasinerkite į branduolio vykdymo nustatymus
Norėdami sukonfigūruoti branduolio vykdymo aplinką, galite naudoti komandų eilutės parinktis (grub) arba sysctl sąsają. pažiūrėjau /etc/sysctl.conf ir tik pagalvokite, atradau kelis pasirinktinius nustatymus. Jausdamasis, kad būčiau už ko nors įsikibęs, atmečiau visus ne tinklo ar ne tcp nustatymus, likau kalnų nustatymais net.core. Tada nuėjau ten, kur VM buvo pagrindinio kompiuterio leidimai ir pradėjau taikyti nustatymus vieną po kito su sugedusia VM, kol radau kaltininką:
net.core.rmem_default = 2147483647Štai, DNS pažeidžianti konfigūracija! Radau žmogžudystės ginklą. Bet kodėl tai vyksta? Man vis tiek reikėjo motyvo.
Pagrindinis DNS paketų buferio dydis sukonfigūruojamas naudojant net.core.rmem_default. Įprasta vertė yra maždaug 200 KiB, tačiau jei jūsų serveris gauna daug DNS paketų, galbūt norėsite padidinti buferio dydį. Jei buferis yra pilnas, kai ateina naujas paketas, pavyzdžiui, dėl to, kad programa nepakankamai greitai jo apdoroja, pradėsite prarasti paketus. Mūsų klientas teisingai padidino buferio dydį, nes bijojo duomenų praradimo, nes naudojo programą metrikai rinkti per DNS paketus. Jo nustatyta vertė buvo didžiausia įmanoma: 231-1 (jei nustatyta į 231, branduolys pateiks „INVALID ARGUMENT“).
Staiga supratau, kodėl nmap ir scapy veikė tinkamai: jie naudojo neapdorotus lizdus! Neapdoroti lizdai skiriasi nuo įprastų lizdų: jie apeina iptables ir nėra buferiniai!
Bet kodėl „per didelis buferis“ sukelia problemų? Akivaizdu, kad tai neveikia taip, kaip numatyta.
Šiuo metu galėčiau atkurti problemą keliuose branduoliuose ir keliuose platinimuose. Problema jau atsirado 3.x branduolyje, o dabar ji atsirado ir 5.x branduolyje.
Tiesa, paleidus
sysctl -w net.core.rmem_default=$((2**31-1))DNS nustojo veikti.
Pradėjau ieškoti darbinių verčių naudodamas paprastą dvejetainį paieškos algoritmą ir radau, kad sistema veikė su 2147481343, tačiau šis skaičius man buvo beprasmis skaičių rinkinys. Pasiūliau klientui išbandyti šį numerį, o jis atsakė, kad sistema veikia su google.com, bet vis tiek davė klaidą su kitais domenais, todėl tęsiau tyrimą.
Aš įdiegiau , įrankis, kuris turėjo būti naudojamas anksčiau: jis tiksliai parodo, kurioje branduolio dalyje atsiduria paketas. Kaltininkas buvo funkcija udp_queue_rcv_skb. Atsisiunčiau branduolio šaltinius ir pridėjau kelis stebėti, kur tiksliai baigiasi paketas. Greitai radau tinkamą būklę if, ir kurį laiką tiesiog spoksojo į jį, nes būtent tada viskas galiausiai susidėjo į bendrą vaizdą: 231-1, beprasmis skaičius, neveikiantis domenas... Tai buvo kodo dalis __udp_enqueue_schedule_skb:
if (rmem > (size + sk->sk_rcvbuf))
goto uncharge_drop;Atkreipkite dėmesį:
rmemyra int tiposizeyra u16 tipo (nepasirašytas šešiolikos bitų int) ir saugo paketo dydįsk->sk_rcybufyra int tipo ir saugo buferio dydį, kuris pagal apibrėžimą yra lygus reikšmei innet.core.rmem_default
Kai sk_rcvbuf artėja prie 231, susumavus paketo dydį gali atsirasti . Ir kadangi tai yra int, jo reikšmė tampa neigiama, todėl sąlyga tampa teisinga, kai ji turėtų būti klaidinga (daugiau apie tai galite paskaityti adresu ).
Klaidą galima ištaisyti trivialiu būdu: liejant unsigned int. Pritaikiau taisymą ir iš naujo paleidau sistemą, o DNS vėl veikė.
Pergalės skonis
Savo išvadas persiunčiau klientui ir išsiunčiau branduolio pleistras. Džiaugiuosi: kiekviena dėlionės detalė dera viena prie kitos, galiu tiksliai paaiškinti, kodėl tai, ką pastebėjome, ir, svarbiausia, komandinio darbo dėka sugebėjome rasti problemos sprendimą!
Verta pripažinti, kad atvejis pasirodė retas, ir, laimei, retai sulaukiame tokių sudėtingų vartotojų užklausų.
Šaltinis: www.habr.com
