Rakonto pri mankantaj DNS-pakaĵoj de la teknika subteno de Google Cloud

De Google Blog Editor: Ĉu vi iam scivolis kiel inĝenieroj de Google Cloud Technical Solutions (TSE) pritraktas viajn subtenpetojn? TSE Technical Support Engineers respondecas pri identigado kaj korektado de uzant-raportitaj fontoj de problemoj. Iuj el ĉi tiuj problemoj estas sufiĉe simplaj, sed foje vi trovas bileton, kiu postulas la atenton de pluraj inĝenieroj samtempe. En ĉi tiu artikolo, unu el la dungitoj de TSE rakontos al ni pri unu tre malfacila problemo de sia lastatempa praktiko - kazo de mankantaj DNS-pakoj. En ĉi tiu rakonto, ni vidos kiel la inĝenieroj sukcesis solvi la situacion, kaj kiajn novajn aferojn ili lernis riparante la eraron. Ni esperas, ke ĉi tiu rakonto ne nur edukas vin pri profunda cimo, sed ankaŭ donas al vi sciojn pri la procezoj kiuj iras por registri subtenan bileton kun Google Cloud.

Rakonto pri mankantaj DNS-pakaĵoj de la teknika subteno de Google Cloud

Solvado de problemoj estas kaj scienco kaj arto. Ĉio komenciĝas per konstruado de hipotezo pri la kialo de la ne-norma konduto de la sistemo, post kiu ĝi estas testita pri forto. Tamen, antaŭ ol ni formuli hipotezon, ni devas klare difini kaj precize formuli la problemon. Se la demando sonas tro malklara, tiam vi devos ĉion analizi zorge; Ĉi tio estas la "arto" de solvo de problemoj.

Sub Google Cloud, tiaj procezoj fariĝas eksponente pli kompleksaj, ĉar Google Cloud provas sian eblon por garantii la privatecon de siaj uzantoj. Pro tio, TSE-inĝenieroj ne havas aliron por redakti viajn sistemojn, nek la kapablon rigardi agordojn tiel vaste kiel uzantoj. Tial, por testi iun el niaj hipotezoj, ni (inĝenieroj) ne povas rapide modifi la sistemon.

Iuj uzantoj kredas, ke ni riparos ĉion kiel mekanikistoj en aŭta servo, kaj simple sendos al ni la identigilon de virtuala maŝino, dum fakte la procezo okazas en konversacia formato: kolektado de informoj, formado kaj konfirmado (aŭ refutado) de hipotezoj, kaj, finfine, decidoproblemoj baziĝas sur komunikado kun la kliento.

Koncernita problemo

Hodiaŭ ni havas rakonton kun bona fino. Unu el la kialoj de la sukcesa solvado de la proponita kazo estas tre detala kaj preciza priskribo de la problemo. Malsupre vi povas vidi kopion de la unua bileto (redaktita por kaŝi konfidencajn informojn):
Rakonto pri mankantaj DNS-pakaĵoj de la teknika subteno de Google Cloud
Ĉi tiu mesaĝo enhavas multajn utilajn informojn por ni:

  • Specifa VM specifita
  • La problemo mem estas indikita - DNS ne funkcias
  • Ĝi estas indikita kie la problemo manifestiĝas - VM kaj ujo
  • La paŝoj kiujn la uzanto faris por identigi la problemon estas indikitaj.

La peto estis registrita kiel "P1: Kritika Efiko - Servo Neuzebla en produktado", kio signifas konstantan monitoradon de la situacio 24/7 laŭ la skemo "Sekvu la Sunon" (vi povas legi pli pri prioritatoj de uzantpetoj), kun ĝia translokigo de unu teknika subtena teamo al alia kun ĉiu horzonŝanĝo. Fakte, kiam la problemo atingis nian teamon en Zuriko, ĝi jam ĉirkaŭiris la terglobon. Ĝis tiu tempo, la uzanto prenis mildigajn rimedojn, sed timis ripetiĝon de la situacio en produktado, ĉar la radika kaŭzo ankoraŭ ne estis malkovrita.

Kiam la bileto atingis Zurikon, ni jam havis la jenajn informojn en la mano:

  • Enhavo /etc/hosts
  • Enhavo /etc/resolv.conf
  • konkludo iptables-save
  • Kunvenita de la teamo ngrep pcap dosiero

Kun ĉi tiuj datumoj, ni estis pretaj komenci la "enketon" kaj solvan fazon.

Niaj unuaj paŝoj

Antaŭ ĉio, ni kontrolis la protokolojn kaj staton de la metadatuma servilo kaj certigis, ke ĝi funkcias ĝuste. La metadatuma servilo respondas al la IP-adreso 169.254.169.254 kaj, interalie, respondecas pri kontrolo de domajnaj nomoj. Ni ankaŭ duoble kontrolis, ke la fajroŝirmilo funkcias ĝuste kun la VM kaj ne blokas pakaĵojn.

Estis ia stranga problemo: la nmap-kontrolo refutis nian ĉefan hipotezon pri la perdo de UDP-pakaĵoj, do ni mense elpensis plurajn pliajn eblojn kaj manierojn kontroli ilin:

  • Ĉu pakoj estas faligitaj selekteme? => Kontrolu regulojn de iptables
  • Ĉu ĝi ne estas tro malgranda? MTU? => Kontrolu eliron ip a show
  • Ĉu la problemo influas nur UDP-pakaĵojn aŭ TCP ankaŭ? => Veturi for dig +tcp
  • Ĉu dig generitaj pakoj estas resenditaj? => Veturi for tcpdump
  • Ĉu libdns funkcias ĝuste? => Veturi for strace kontroli la transdonon de pakoj en ambaŭ direktoj

Ĉi tie ni decidas voki la uzanton por solvi problemojn en vivo.

Dum la voko ni povas kontroli plurajn aferojn:

  • Post pluraj kontroloj ni ekskludas regulojn de iptables el la listo de kialoj
  • Ni kontrolas retajn interfacojn kaj vojtablojn, kaj duoble kontrolas, ke la MTU estas ĝusta
  • Ni malkovras tion dig +tcp google.com (TCP) funkcias kiel ĝi devus, sed dig google.com (UDP) ne funkcias
  • Forpelinte tcpdump ĝi ankoraŭ funkcias dig, ni trovas ke UDP-pakoj estas resenditaj
  • Ni veturas for strace dig google.com kaj ni vidas kiel dig ĝuste vokas sendmsg() и recvms(), tamen la dua estas interrompita de tempo-tempo

Bedaŭrinde, la fino de la deĵoro alvenas kaj ni estas devigitaj eskaladi la problemon al la sekva horzono. La peto tamen vekis intereson en nia teamo, kaj kolego sugestas krei la komencan DNS-pakaĵon per la scrapy Python-modulo.

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())

Ĉi tiu fragmento kreas DNS-pakaĵon kaj sendas la peton al la metadatuma servilo.

La uzanto kuras la kodon, la DNS-respondo estas resendita, kaj la aplikaĵo ricevas ĝin, konfirmante, ke ne ekzistas problemo ĉe la reto-nivelo.

Post alia "ĉirkaŭmonda vojaĝo", la peto revenas al nia teamo, kaj mi tute transdonas ĝin al mi, pensante, ke estos pli oportune por la uzanto, se la peto ĉesos rondiri de loko al loko.

Intertempe, la uzanto bonkore konsentas disponigi momentfoton de la sistema bildo. Ĉi tio estas tre bona novaĵo: la kapablo mem provi la sistemon multe pli rapidas la problemon, ĉar mi ne plu devas peti la uzanton ruli komandojn, sendi al mi la rezultojn kaj analizi ilin, mi povas fari ĉion mem!

Miaj kolegoj komencas iomete envii min. Dum tagmanĝo ni diskutas pri la konvertiĝo, sed neniu havas ideon, kio okazas. Feliĉe, la uzanto mem jam prenis mezurojn por mildigi la sekvojn kaj ne hastas, do ni havas tempon por dissekci la problemon. Kaj ĉar ni havas bildon, ni povas fari iujn ajn provojn, kiuj interesas nin. Bonege!

Farante paŝon malantaŭen

Unu el la plej popularaj intervjuaj demandoj por sistemaj inĝenieraj postenoj estas: "Kio okazas kiam vi pings www.google.com? La demando estas bonega, ĉar la kandidato bezonas priskribi ĉion de la ŝelo ĝis uzantspaco, ĝis la sistema kerno kaj poste ĝis la reto. Mi ridetas: foje intervjuaj demandoj montriĝas utilaj en la reala vivo...

Mi decidas apliki ĉi tiun HR-demandon al aktuala problemo. Proksimume, kiam vi provas determini DNS-nomon, jen okazas:

  1. La aplikaĵo vokas sistembibliotekon kiel libdns
  2. libdns kontrolas la sisteman agordon al kiu DNS-servilo ĝi kontaktu (en la diagramo tio estas 169.254.169.254, metadatuma servilo)
  3. libdns uzas sistemajn vokojn por krei UDP-ingon (SOKET_DGRAM) kaj sendi UDP-pakaĵojn kun DNS-demando en ambaŭ direktoj.
  4. Per la sysctl-interfaco vi povas agordi la UDP-stakon ĉe la kernnivelo
  5. La kerno interagas kun la aparataro por elsendi pakaĵetojn tra la reto per la retinterfaco
  6. La hiperviziero kaptas kaj transdonas la pakaĵeton al la metadatuma servilo post kontakto kun ĝi
  7. La metadatuma servilo, per sia magio, determinas la DNS-nomon kaj resendas respondon uzante la saman metodon

Rakonto pri mankantaj DNS-pakaĵoj de la teknika subteno de Google Cloud
Mi memorigu al vi, kiajn hipotezojn ni jam pripensis:

Hipotezo: Rompitaj bibliotekoj

  • Testo 1: rulu Strace en la sistemo, kontrolu, ke dig vokas la ĝustajn sistemvokojn
  • Rezulto: Ĝustaj sistemvokoj estas vokataj
  • Testo 2: uzante srapy por kontroli ĉu ni povas determini nomojn preterirante sistemajn bibliotekojn
  • Rezulto: ni povas
  • Testo 3: rulu rpm –V sur la libdns-pakaĵo kaj md5sum-bibliotekaj dosieroj
  • Rezulto: la bibliotekkodo estas tute identa al la kodo en la funkcianta operaciumo
  • Testo 4: muntu la radiksisteman bildon de la uzanto sur VM sen ĉi tiu konduto, rulu chroot, vidu ĉu DNS funkcias
  • Rezulto: DNS funkcias ĝuste

Konkludo bazita sur testoj: la problemo ne estas en la bibliotekoj

Hipotezo: Estas eraro en la DNS-agordoj

  • Testo 1: kontrolu tcpdump kaj vidu ĉu DNS-pakoj estas senditaj kaj resenditaj ĝuste post rulado dig
  • Rezulto: pakoj estas transdonitaj ĝuste
  • Testo 2: duobla kontrolo sur la servilo /etc/nsswitch.conf и /etc/resolv.conf
  • Rezulto: ĉio estas ĝusta

Konkludo bazita sur testoj: la problemo ne estas kun la DNS-agordo

Hipotezo: kerno difektita

  • Testo: instalu novan kernon, kontrolu subskribon, rekomencu
  • Rezulto: simila konduto

Konkludo bazita sur testoj: la kerno ne estas difektita

Hipotezo: malĝusta konduto de la uzantreto (aŭ hipervizila retinterfaco)

  • Testo 1: Kontrolu viajn fajroŝirmilojn
  • Rezulto: la fajroŝirmilo pasas DNS-pakojn sur kaj la gastiganto kaj GCP
  • Testo 2: kapti trafikon kaj kontroli la ĝustecon de la transdono kaj reveno de DNS-petoj
  • Rezulto: tcpdump konfirmas, ke la gastiganto ricevis revenpakaĵojn

Konkludo bazita sur testoj: la problemo ne estas en la reto

Hipotezo: la metadatuma servilo ne funkcias

  • Testo 1: kontrolu la protokolojn de la metadatumoj pri anomalioj
  • Rezulto: ne estas anomalioj en la protokoloj
  • Testo 2: Preterpasu la metadatuman servilon per dig @8.8.8.8
  • Rezulto: Rezolucio estas rompita eĉ sen uzi metadatuman servilon

Konkludo bazita sur testoj: la problemo ne estas kun la metadatuma servilo

Funda linio: ni testis ĉiujn subsistemojn krom rultempaj agordoj!

Plonĝado en Kernel Runtime Settings

Por agordi la kernan ekzekutmedion, vi povas uzi komandliniajn opciojn (grub) aŭ la sysctl-interfacon. Mi enrigardis /etc/sysctl.conf kaj nur pensu, mi malkovris plurajn kutimajn agordojn. Sentante, kvazaŭ mi kaptis ion, mi forĵetis ĉiujn ne-retajn aŭ ne-tcp-agordojn, restante kun la montaj agordoj. net.core. Tiam mi iris al kie la gastigaj permesoj estis en la VM kaj komencis apliki la agordojn unu post la alia, unu post la alia, kun la rompita VM, ĝis mi trovis la kulpulon:

net.core.rmem_default = 2147483647

Jen ĝi estas, DNS-rompanta agordo! Mi trovis la murdan armilon. Sed kial tio ĉi okazas? Mi ankoraŭ bezonis motivon.

La baza DNS-pakaĵbufrgrandeco estas agordita per net.core.rmem_default. Tipa valoro estas ie ĉirkaŭ 200KiB, sed se via servilo ricevas multajn DNS-pakojn, vi eble volas pliigi la bufran grandecon. Se la bufro estas plena kiam nova pakaĵo alvenas, ekzemple ĉar la aplikaĵo ne sufiĉe rapide prilaboras ĝin, tiam vi komencos perdi pakaĵojn. Nia kliento ĝuste pliigis la bufran grandecon ĉar li timis perdon de datumoj, ĉar li uzis aplikaĵon por kolekti metrikojn per DNS-pakoj. La valoro kiun li starigis estis la maksimuma ebla: 231-1 (se agordita al 231, la kerno resendos "NEVALIDA ARGUMENTO").

Subite mi komprenis, kial nmap kaj scapy funkcias ĝuste: ili uzis krudajn ingojn! Krudaj ingoj diferencas de regulaj ingoj: ili preterpasas iptablelojn, kaj ili ne estas bufrigitaj!

Sed kial "bufro tro granda" kaŭzas problemojn? Ĝi klare ne funkcias kiel celite.

Je ĉi tiu punkto mi povus reprodukti la problemon sur pluraj kernoj kaj pluraj distribuoj. La problemo jam aperis sur la kerno 3.x kaj nun ĝi aperis ankaŭ sur la kerno 5.x.

Efektive, ĉe ekfunkciigo

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

DNS ĉesis funkcii.

Mi komencis serĉi laborvalorojn per simpla binara serĉa algoritmo kaj trovis, ke la sistemo funkciis kun 2147481343, sed ĉi tiu nombro estis sensignifa aro de nombroj por mi. Mi sugestis, ke la kliento provu ĉi tiun numeron, kaj li respondis, ke la sistemo funkcias kun google.com, sed tamen donis eraron kun aliaj domajnoj, do mi daŭrigis mian esploron.

Mi instalis dropwatch, ilo kiu devus esti uzata pli frue: ĝi montras precize kie en la kerno pako finas. La kulpulo estis la funkcio udp_queue_rcv_skb. Mi elŝutis la kernfontojn kaj aldonis kelkajn funkcioj printk por spuri kie precize la pako finas. Mi rapide trovis la ĝustan kondiĉon if, kaj simple rigardis ĝin dum kelka tempo, ĉar ĝuste tiam ĉio finfine kuniĝis en tutan bildon: 231-1, sensignifa nombro, nefunkcianta domajno... Ĝi estis kodo en __udp_enqueue_schedule_skb:

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

Bonvolu noti:

  • rmem estas de tipo int
  • size estas de tipo u16 (sensigna dekses-bita int) kaj stokas la pakaĵetgrandecon
  • sk->sk_rcybuf estas de tipo int kaj stokas la bufrograndecon kiu, laŭdifine, estas egala al la valoro en net.core.rmem_default

Kiam sk_rcvbuf alproksimiĝas al 231, sumigi la pakaĵetgrandecon povas rezultigi entjera superfluo. Kaj ĉar ĝi estas int, ĝia valoro fariĝas negativa, do la kondiĉo fariĝas vera kiam ĝi devus esti falsa (vi povas legi pli pri tio ĉe ligilo).

La eraro povas esti korektita en bagatela maniero: per gisado unsigned int. Mi aplikis la riparadon kaj rekomencis la sistemon kaj DNS denove funkciis.

Gusto de venko

Mi plusendis miajn trovojn al la kliento kaj sendis LKML kerno diakilo. Mi ĝojas: ĉiu peco de la enigmo kongruas, mi povas klarigi precize kial ni observis tion, kion ni observis, kaj plej grave, ni povis trovi solvon al la problemo danke al nia teamlaboro!

Indas rekoni, ke la kazo montriĝis malofta, kaj feliĉe ni malofte ricevas tiajn kompleksajn petojn de uzantoj.

Rakonto pri mankantaj DNS-pakaĵoj de la teknika subteno de Google Cloud


fonto: www.habr.com

Aldoni komenton