ProHoster > Blogi > Haldamine > Lugu puuduvatest DNS-pakettidest Google Cloudi tehnilise toe kaudu
Lugu puuduvatest DNS-pakettidest Google Cloudi tehnilise toe kaudu
Google'i ajaveebi redaktorist: Kas olete kunagi mõelnud, kuidas Google'i pilve tehniliste lahenduste (TSE) insenerid teie tugitaotlusi käsitlevad? TSE tehnilise toe insenerid vastutavad kasutajate teatatud probleemide allikate tuvastamise ja parandamise eest. Mõned neist probleemidest on üsna lihtsad, kuid mõnikord tuleb ette pilet, mis nõuab korraga mitme inseneri tähelepanu. Selles artiklis räägib üks TSE töötajatest meile ühest väga keerulisest probleemist, mis on tema hiljutisest praktikast pärit - puuduvate DNS-pakettide korral. Selles loos näeme, kuidas inseneridel õnnestus olukord lahendada ja mida uut nad vea parandamisel teada said. Loodame, et see lugu ei teavita teid mitte ainult sügavalt juurdunud veast, vaid annab teile ka ülevaate protsessidest, mis kuluvad Google Cloudi tugipileti esitamiseks.
Veaotsing on nii teadus kui ka kunst. Kõik algab süsteemi ebastandardse käitumise põhjuse kohta hüpoteesi püstitamisest, misjärel testitakse selle tugevust. Enne hüpoteesi sõnastamist peame aga probleemi selgelt määratlema ja täpselt sõnastama. Kui küsimus tundub liiga ebamäärane, peate kõike hoolikalt analüüsima; See on tõrkeotsingu "kunst".
Google Cloudi all muutuvad sellised protsessid eksponentsiaalselt keerukamaks, kuna Google Cloud annab endast parima, et tagada oma kasutajate privaatsus. Seetõttu pole TSE inseneridel juurdepääsu teie süsteemide redigeerimiseks ega ka võimalust vaadata konfiguratsioone nii laialt kui kasutajatel. Seetõttu ei saa me (insenerid) oma hüpoteesi testimiseks süsteemi kiiresti muuta.
Mõned kasutajad usuvad, et teeme kõik asjad korda nagu mehaanika autoteeninduses ja saadame meile lihtsalt virtuaalmasina ID, samas kui tegelikult toimub protsess vestlusvormingus: info kogumine, hüpoteeside moodustamine ja kinnitamine (või ümberlükkamine), ja lõpuks põhinevad otsustusprobleemid kliendiga suhtlemisel.
Probleem kõne all
Täna on meil hea lõpuga lugu. Kavandatava juhtumi eduka lahendamise üheks põhjuseks on probleemi väga detailne ja täpne kirjeldus. Allpool näete esimese pileti koopiat (konfidentsiaalse teabe peitmiseks muudetud):
See sõnum sisaldab meile palju kasulikku teavet:
Määratud konkreetne VM
Probleem ise on näidatud - DNS ei tööta
Näidatakse, kus probleem avaldub - VM ja konteiner
Näidatud on toimingud, mida kasutaja probleemi tuvastamiseks astus.
Taotlus registreeriti kui “P1: Critical Impact – Service Unusable in production”, mis tähendab pidevat 24/7 olukorra jälgimist skeemi “Follow the Sun” järgi (saate lugeda lähemalt kasutajapäringute prioriteedid) koos selle üleminekuga ühelt tehnilise toe meeskonnalt teisele iga ajavööndivahetusega. Tegelikult oli probleem meie meeskonnani Zürichis jõudnud juba ümber maakera. Selleks ajaks oli kasutaja võtnud leevendusmeetmeid, kuid kartis tootmises olukorra kordumist, kuna algpõhjust polnud veel avastatud.
Kui pilet Zürichisse jõudis, oli meil juba käes järgmine info:
Sisu /etc/hosts
Sisu /etc/resolv.conf
Väljund iptables-save
Meeskonna poolt kokku pandud ngrep pcap fail
Nende andmetega olime valmis alustama "juurdluse" ja tõrkeotsingu etappi.
Meie esimesed sammud
Kõigepealt kontrollisime metaandmete serveri logisid ja olekut ning veendusime, et see töötab õigesti. Metaandmete server vastab IP-aadressile 169.254.169.254 ja muuhulgas vastutab domeeninimede kontrollimise eest. Samuti kontrollisime üle, kas tulemüür töötab VM-iga õigesti ega blokeeri pakette.
See oli mingi kummaline probleem: nmap-kontroll lükkas ümber meie peamise hüpoteesi UDP-pakettide kadumise kohta, nii et mõtlesime välja veel mitu võimalust ja viisi nende kontrollimiseks:
Kas paketid kukutatakse valikuliselt? => Kontrollige iptablesi reegleid
Kas pole liiga väike? MTU? => Kontrolli väljundit ip a show
Kas probleem puudutab ka ainult UDP-pakette või TCP-d? => Sõida minema dig +tcp
Kas dig genereeritud paketid tagastatakse? => Sõida minema tcpdump
Kas libdns töötab õigesti? => Sõida minema strace et kontrollida pakettide edastamist mõlemas suunas
Siin otsustame helistada kasutajale probleemide tõrkeotsinguks.
Kõne ajal saame kontrollida mitmeid asju:
Pärast mitut kontrolli jätame põhjuste loendist välja iptablesi reeglid
Kontrollime võrguliideseid ja marsruutimistabeleid ning veelkord, et MTU oleks õige
Me avastame selle dig +tcp google.com (TCP) töötab nii nagu peab, kuid dig google.com (UDP) ei tööta
Olles ära sõitnud tcpdump see ikka töötab dig, leiame, et UDP-pakette tagastatakse
Sõidame minema strace dig google.com ja näeme, kuidas dig õigesti kutsub sendmsg() и recvms(), kuid teine katkestatakse ajalõpuga
Kahjuks saabub vahetuse lõpp ja oleme sunnitud probleemi järgmisse ajavööndisse eskaleerima. Taotlus aga äratas meie meeskonnas huvi ning kolleeg soovitab luua algse DNS-i paketi, kasutades kraapivat Pythoni moodulit.
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())
See fragment loob DNS-paketi ja saadab päringu metaandmete serverisse.
Kasutaja käivitab koodi, DNS-i vastus tagastatakse ja rakendus võtab selle vastu, kinnitades, et võrgu tasemel pole probleemi.
Pärast järjekordset “ümbermaailmareisi” naaseb taotlus meie meeskonnale ja ma kannan selle täielikult enda peale, arvates, et kasutajale on mugavam, kui päring lakkab ühest kohast tiirlemas.
Seni on kasutaja lahkelt nõus andma süsteemipildist hetktõmmise. See on väga hea uudis: võimalus süsteemi ise testida muudab tõrkeotsingu palju kiiremaks, sest ma ei pea enam paluma kasutajal käske käivitada, tulemusi mulle saata ja analüüsida, saan kõike ise teha!
Kolleegid hakkavad mind veidi kadestama. Lõuna ajal arutame pöördumist, kuid kellelgi pole aimugi, mis toimub. Õnneks on kasutaja ise tagajärgede leevendamiseks juba meetmeid võtnud ega kiirusta, seega on meil aega probleemi lahkamiseks. Ja kuna meil on pilt, saame läbi viia mis tahes teste, mis meid huvitavad. Suurepärane!
Astudes sammu tagasi
Üks populaarsemaid intervjuuküsimusi süsteemiinseneride ametikohtadel on: „Mis juhtub, kui pingida www.google.com? Küsimus on suurepärane, kuna kandidaat peab kirjeldama kõike alates kestast kuni kasutajaruumi, süsteemituuma ja seejärel võrguni. Naeratan: mõnikord osutuvad intervjuuküsimused ka päriselus kasulikuks...
Otsustan rakendada seda HR-küsimust praegusele probleemile. Jämedalt öeldes, kui proovite DNS-nime määrata, juhtub järgmine:
Rakendus kutsub välja süsteemiteegi, näiteks libdns
libdns kontrollib süsteemi konfiguratsiooni, millise DNS-serveriga ta peaks ühendust võtma (diagrammil on see 169.254.169.254, metaandmete server)
libdns kasutab süsteemikutseid, et luua UDP-pesa (SOKET_DGRAM) ja saata UDP-pakette koos DNS-päringuga mõlemas suunas
Sysctl liidese kaudu saate konfigureerida UDP pinu kerneli tasemel
Kernel suhtleb riistvaraga, et edastada pakette võrgu kaudu võrguliidese kaudu
Hüpervisor püüab kinni ja edastab paketi metaandmeserverisse, kui sellega kokku puutub
Metaandmete server määrab oma võluväel DNS-i nime ja tagastab vastuse sama meetodit kasutades
Lubage mul teile meelde tuletada, milliseid hüpoteese oleme juba kaalunud:
Hüpotees: Katkised raamatukogud
Test 1: käivitage süsteemis strace, kontrollige, kas dig kutsub õigeid süsteemikutseid
Tulemus: helistatakse õigetele süsteemikõnedele
Test 2: srapy abil kontrollige, kas suudame nimesid määrata süsteemiteeke mööda minnes
Tulemus: saame
Test 3: käivitage paketis libdns ja md5sum teegifailides rpm –V
Tulemus: teegi kood on täiesti identne töötava operatsioonisüsteemi koodiga
Test 4: paigaldage kasutaja juursüsteemi kujutis virtuaalsesse masinasse ilma selle käitumiseta, käivitage chroot ja vaadake, kas DNS töötab
Tulemus: DNS töötab õigesti
Testide põhjal tehtud järeldus: probleem ei ole raamatukogudes
Hüpotees: DNS-i sätetes on viga
Test 1: kontrollige tcpdump ja vaadake, kas DNS-paketid saadetakse ja tagastatakse pärast digi käivitamist õigesti
Tulemus: paketid edastatakse õigesti
Test 2: kontrollige serverit uuesti /etc/nsswitch.conf и /etc/resolv.conf
Tulemus: kõik on õige
Testide põhjal tehtud järeldus: probleem ei ole DNS-i konfiguratsioonis
Hüpotees: südamik kahjustatud
Test: installige uus kernel, kontrollige allkirja, taaskäivitage
Tulemus: sarnane käitumine
Testide põhjal tehtud järeldus: tuum ei ole kahjustatud
Hüpotees: kasutajavõrgu (või hüperviisori võrguliidese) vale käitumine
Test 1: kontrollige tulemüüri sätteid
Tulemus: tulemüür edastab DNS-paketid nii hostis kui ka GCP-s
Test 2: peatage liiklus ja jälgige DNS-i päringute edastamise ja tagastamise õigsust
Tulemus: tcpdump kinnitab, et host on vastu võtnud tagastuspaketid
Testide põhjal tehtud järeldus: probleem pole võrgus
Hüpotees: metaandmete server ei tööta
Test 1: kontrollige metaandmeserveri logisid kõrvalekallete suhtes
Tulemus: logides pole anomaaliaid
Test 2: mööduge metaandmete serverist selle kaudu dig @8.8.8.8
Tulemus: eraldusvõime on katki isegi ilma metaandmete serverita
Testide põhjal tehtud järeldus: probleem ei ole metaandmete serveris
Tulemus: testisime kõiki alamsüsteeme v.a käitusaja seaded!
Kerneli käitusaja sätetesse sukeldumine
Kerneli täitmiskeskkonna konfigureerimiseks võite kasutada käsurea suvandeid (grub) või sysctl liidest. Vaatasin sisse /etc/sysctl.conf ja mõelge vaid, avastasin mitu kohandatud seadet. Tundes, nagu oleksin millestki kinni haaranud, loobusin kõik võrguvälised või mitte-tcp-sätted, jäädes mäeseadetele net.core. Seejärel läksin sinna, kus VM-is olid hostiõigused ja hakkasin katkise VM-iga ükshaaval sätteid rakendama, kuni leidsin süüdlase:
net.core.rmem_default = 2147483647
Siin see on, DNS-i murdev konfiguratsioon! Leidsin mõrvarelva. Aga miks see juhtub? Mul oli ikka vaja motiivi.
Põhiline DNS-paketi puhvri suurus on konfigureeritud kaudu net.core.rmem_default. Tüüpiline väärtus on kuskil 200KiB, kuid kui teie server saab palju DNS-pakette, võiksite puhvri suurust suurendada. Kui puhver on uue paketi saabudes täis, näiteks seetõttu, et rakendus ei töötle seda piisavalt kiiresti, siis hakkate pakette kaotama. Meie klient suurendas puhvri suurust õigesti, kuna kartis andmete kadumist, kuna kasutas DNS-pakettide kaudu mõõdikute kogumise rakendust. Tema seatud väärtus oli maksimaalne võimalik: 231-1 (kui see on seatud väärtusele 231, tagastab kernel "INVALID ARGUMENT").
Järsku mõistsin, miks nmap ja scapy õigesti töötasid: nad kasutasid töötlemata pistikupesasid! Toorpesad erinevad tavalistest pesadest: need mööduvad iptable-test ja neid ei puhverdata!
Aga miks "puhver liiga suur" probleeme tekitab? Ilmselgelt see ei tööta nii, nagu ette nähtud.
Siinkohal võin probleemi korrata mitmes tuumas ja mitmes distributsioonis. Probleem ilmnes juba 3.x tuumal ja nüüd ilmnes ka 5.x tuumal.
Tõepoolest, käivitamisel
sysctl -w net.core.rmem_default=$((2**31-1))
DNS lakkas töötamast.
Hakkasin lihtsa binaarotsingu algoritmi abil tööväärtusi otsima ja leidsin, et süsteem töötas numbriga 2147481343, kuid see number oli minu jaoks mõttetu arvude komplekt. Soovitasin kliendil seda numbrit proovida ja ta vastas, et süsteem töötas google.com-iga, kuid andis siiski vea teiste domeenide puhul, nii et jätkasin uurimist.
Olen installinud tilkkell, tööriist, mida oleks pidanud varem kasutama: see näitab täpselt, kuhu tuumas pakett jõuab. Süüdlane oli funktsioon udp_queue_rcv_skb. Laadisin alla kerneli allikad ja lisasin mõned funktsioonidprintk et jälgida, kuhu pakett täpselt jõuab. Leidsin kiiresti õige seisukorra if, ja lihtsalt jõllitasin seda mõnda aega, sest just siis sai kõik lõpuks tervikpildiks kokku: 231-1, mõttetu number, mittetöötav domeen... See oli koodijupp aastal __udp_enqueue_schedule_skb:
if (rmem > (size + sk->sk_rcvbuf))
goto uncharge_drop;
Pange tähele:
rmem on tüüpi int
size on tüüpi u16 (allkirjata kuueteistkümnebitine int) ja salvestab paketi suuruse
sk->sk_rcybuf on tüüpi int ja salvestab puhvri suuruse, mis definitsiooni järgi on võrdne väärtusega in net.core.rmem_default
Millal sk_rcvbuf läheneb 231-le, võib tulemuseks olla paketi suuruse summeerimine täisarvu ülevool. Ja kuna see on int, muutub selle väärtus negatiivseks, nii et tingimus muutub tõeseks, kui see peaks olema väär (selle kohta saate rohkem lugeda aadressilt link).
Viga saab parandada triviaalsel viisil: valades unsigned int. Rakendasin paranduse ja taaskäivitasin süsteemi ning DNS töötas uuesti.
Võidu maitse
Edastasin oma leiud kliendile ja saatsin LKML kerneli plaaster. Mul on hea meel: iga pusletükk sobib kokku, oskan täpselt seletada, miks me vaatletut jälgisime ja mis kõige tähtsam, saime tänu meeskonnatööle probleemile lahenduse leida!
Tasub tõdeda, et juhtum osutus harvaks ja õnneks saame kasutajatelt nii keerulisi taotlusi harva.