Parandame vÔrgu viivitusi Kubernetes'es

Parandame vÔrgu viivitusi Kubernetes'es

KĂŒbernetesest on rÀÀgitud juba paar aastat tagasi ametlikus GitHubi blogis. Sellest ajast alates on see muutunud standardtehnoloogiaks teenuste juurutamiseks. NĂŒĂŒd haldab Kubernetese suur osa sisemistest ja avalikest teenustest. Kuna meie klastrid on suurenenud ja jĂ”udlusnĂ”uded on muutunud rangemaks, oleme hakanud mĂ€rkama, et teatud Kubernetese teenustes esinevad sporaadiliselt viivitused, mida ei saa seletada rakenduse enda koormusega. Essentsiaalselt esinevad rakendustes juhuslikud vĂ”rgu viivitused, mis ulatuvad 100 ms vĂ”i rohkem, mis toob kaasa ajautusi vĂ”i uuesti proovimise. Ootused olid, et teenused suudavad pĂ€ringutele palju kiiremini vastata kui 100 ms. Kuid see pole vĂ”imalik, kui ise ĂŒhendus vĂ”tab nii kaua aega. Eraldi oleme jĂ€lginud vĂ€ga kiireid MySQL pĂ€ringuid, mis pidid vĂ”tma millisekundeid, ja MySQL tĂ”epoolest tĂ€itis vastuse millisekunditega, kuid pĂ€ringu rakenduse seisukohalt kestis vastus 100 ms vĂ”i kauem.

Selgelt tuli vĂ€lja, et probleem ilmneb ainult Kubernetese sĂ”lmega ĂŒhendamisel, isegi kui kĂ”ne tuli Kubernetese vĂ€ljast. Probleemi on kĂ”ige lihtsam paljastada testis

, mis kÀivitatakse igalt sisemiselt hostilt, testib Kubernetese teenust kindlal pordil ja sporaadiliselt registreerib suurt viivitust. KÀesolevas artiklis kÀsitleme, kuidas Ônnestus meil selle probleemi pÔhjus jÀlile saada. VegetaEemaldame ebaolulise keerukuse rikke ahelast

Korrates sama nĂ€idet, soovisime kitsendada probleemi fookust ja eemaldada tarbetud keerukuse kihid. Alguses oli Kubernetese ja pod'ide vahelises voos liiga palju elemendid. SĂŒgava vĂ”rgu probleemi kindlakstegemiseks tuleb mĂ”ned neist vĂ€lja jĂ€tta.

Kliendi (Vegeta) TCP-ĂŒhenduse loomine igasuguse sĂ”lmiga klastris. Kubernetese töötab kui ĂŒlevĂ”tuv vĂ”rk (olemasoleva andmekeskuse vĂ”rgu kohal), mis kasutab

Parandame vÔrgu viivitusi Kubernetes'es

IPIP , mis kapseldab ĂŒlevĂ”tuvĂ”rgu IP-paketid andmekeskuse IP-pakettidesse. Kui esimesele sĂ”lmele ĂŒhendust luuakse, toimub vĂ”rguaadresside muutmineVĂ”rguaadresside tĂ”lkimine VĂ”rguaadresside tĂ”lge (NAT) olekseisuhteet Kubernetes-solmun IP-osoitteen ja portin muuntamiseksi IP-osoitteeksi ja portiksi ylikerroksessa (erityisesti sovelluspodille). Saapuneille pakkauksille suoritetaan kÀÀnteinen jĂ€rjestys. TĂ€mĂ€ on monimutkainen jĂ€rjestelmĂ€, jossa on suuri mÀÀrĂ€ tiloja ja elementtejĂ€, jotka pĂ€ivittyvĂ€t ja muuttuvat jatkuvasti palveluiden kĂ€yttöönoton ja siirron myötĂ€.

Utiliit tcpdump testissÀ Vegeta aiheuttaa viivettÀ TCP-kÀttelyssÀ (SYN ja SYN-ACK vÀlillÀ). TÀmÀn ylimÀÀrÀisen monimutkaisuuden poistamiseksi voidaan kÀyttÀÀ hping3 yksinkertaisille «ping» SYN-pakkauksille. Tarkistamme, onko vastauspakkauksessa viivettÀ, ja sitten suljemme yhteyden. Voimme suodattaa tiedot, sisÀltÀen vain yli 100 ms:n paketit, ja saada yksinkertaisemman tavan ongelman toistamiseen kuin tÀydellinen verkkotason 7 -testi Vegetassa. TÀssÀ ovat Kubernetes-solmun «pingit» kÀyttÀen TCP SYN/SYN-ACK palvelun «solmun portilla» (30927) 10 ms:n vÀlein, suodatettuna hitaimmista vasteista:

theojulienne@shell ~ $ sudo hping3 172.16.47.27 -S -p 30927 -i u10000 | egrep --line-buffered 'rtt=[0-9]{3}.'

len=46 ip=172.16.47.27 ttl=59 DF id=0 sport=30927 flags=SA seq=1485 win=29200 rtt=127.1 ms

len=46 ip=172.16.47.27 ttl=59 DF id=0 sport=30927 flags=SA seq=1486 win=29200 rtt=117.0 ms

len=46 ip=172.16.47.27 ttl=59 DF id=0 sport=30927 flags=SA seq=1487 win=29200 rtt=106.2 ms

len=46 ip=172.16.47.27 ttl=59 DF id=0 sport=30927 flags=SA seq=1488 win=29200 rtt=104.1 ms

len=46 ip=172.16.47.27 ttl=59 DF id=0 sport=30927 flags=SA seq=5024 win=29200 rtt=109.2 ms

len=46 ip=172.16.47.27 ttl=59 DF id=0 sport=30927 flags=SA seq=5231 win=29200 rtt=109.2 ms

Voimme heti tehdÀ ensimmÀisen havainnon. JÀrjestysnumeroista ja aikarajoista on selvÀÀ, ettÀ nÀmÀ eivÀt ole kertaluonteisia tukoksia. Viive kertyy usein, ja lopulta se kÀsitellÀÀn.

Haluamme selvittÀÀ, mitkÀ komponentit voivat olla osallisina tukoksen syntymisessÀ. Onko se jokin sadoista iptables-sÀÀnnöistÀ NAT:ssÀ? Tai onko kyseessÀ IPIP-tunneloinnin ongelmat verkossa? Yksi tapa tarkistaa tÀmÀ on kÀydÀ lÀpi jÀrjestelmÀn jokainen vaihe poistamalla se. MitÀ tapahtuu, jos poistamme NAT:in ja palomuurin logiikan, jÀttÀen vain osan IPIP:stÀ:

Parandame vÔrgu viivitusi Kubernetes'es

Onneksi Linuxin avulla on helppo kÀyttÀÀ suoraan IP-ylikerrosta, jos kone kuuluu samaan verkkoon:

theojulienne@kube-node-client ~ $ sudo hping3 10.125.20.64 -S -i u10000 | egrep --line-buffered 'rtt=[0-9]{3}.'

len=40 ip=10.125.20.64 ttl=64 DF id=0 sport=0 flags=RA seq=7346 win=0 rtt=127.3 ms

len=40 ip=10.125.20.64 ttl=64 DF id=0 sport=0 flags=RA seq=7347 win=0 rtt=117.3 ms

len=40 ip=10.125.20.64 ttl=64 DF id=0 sport=0 flags=RA seq=7348 win=0 rtt=107.2 ms

Tulemuste pÔhjal on probleem ikka veel olemas! See vÀlistab iptables ja NAT. TÀhendab, probleem on TCP-s? Vaatame, kuidas tavaline ICMP-ping kÀib:

theojulienne@kube-node-client ~ $ sudo hping3 10.125.20.64 --icmp -i u10000 | egrep --line-buffered 'rtt=[0-9]{3}.'

len=28 ip=10.125.20.64 ttl=64 id=42594 icmp_seq=104 rtt=110.0 ms

len=28 ip=10.125.20.64 ttl=64 id=49448 icmp_seq=4022 rtt=141.3 ms

len=28 ip=10.125.20.64 ttl=64 id=49449 icmp_seq=4023 rtt=131.3 ms

len=28 ip=10.125.20.64 ttl=64 id=49450 icmp_seq=4024 rtt=121.2 ms

len=28 ip=10.125.20.64 ttl=64 id=49451 icmp_seq=4025 rtt=111.2 ms

len=28 ip=10.125.20.64 ttl=64 id=49452 icmp_seq=4026 rtt=101.1 ms

len=28 ip=10.125.20.64 ttl=64 id=50023 icmp_seq=4343 rtt=126.8 ms

len=28 ip=10.125.20.64 ttl=64 id=50024 icmp_seq=4344 rtt=116.8 ms

len=28 ip=10.125.20.64 ttl=64 id=50025 icmp_seq=4345 rtt=106.8 ms

len=28 ip=10.125.20.64 ttl=64 id=59727 icmp_seq=9836 rtt=106.1 ms

Tulemused nÀitavad, et probleem ei ole kadunud. VÔib-olla on tegemist IPIP tunneliga? Vaatame testi veel lihtsamaks:

Parandame vÔrgu viivitusi Kubernetes'es

Kas kÔik paketid saadetakse nende kahe hosti vahel?

theojulienne@kube-node-client ~ $ sudo hping3 172.16.47.27 --icmp -i u10000 | egrep --line-buffered 'rtt=[0-9]{3}.'

len=46 ip=172.16.47.27 ttl=61 id=41127 icmp_seq=12564 rtt=140.9 ms

len=46 ip=172.16.47.27 ttl=61 id=41128 icmp_seq=12565 rtt=130.9 ms

len=46 ip=172.16.47.27 ttl=61 id=41129 icmp_seq=12566 rtt=120.8 ms

len=46 ip=172.16.47.27 ttl=61 id=41130 icmp_seq=12567 rtt=110.8 ms

len=46 ip=172.16.47.27 ttl=61 id=41131 icmp_seq=12568 rtt=100.7 ms

len=46 ip=172.16.47.27 ttl=61 id=9062 icmp_seq=31443 rtt=134.2 ms

len=46 ip=172.16.47.27 ttl=61 id=9063 icmp_seq=31444 rtt=124.2 ms

len=46 ip=172.16.47.27 ttl=61 id=9064 icmp_seq=31445 rtt=114.2 ms

len=46 ip=172.16.47.27 ttl=61 id=9065 icmp_seq=31446 rtt=104.2 ms

Oleme lihtsustanud olukorda kahe Kubernetes sĂ”lmpunktiga, mis saadavad ĂŒksteisele igasuguseid pakette, isegi ICMP pinge. Nad nĂ€evad ikka viivitust, kui sihtkohaks on 'halb' host (mĂ”ned halvemad kui teised).

NĂŒĂŒd viimane kĂŒsimus: miks viivitus tekib ainult kube-node serverites? Ja see juhtub, kui kube-node on saatja vĂ”i vastuvĂ”tja? Õnneks on seda ĂŒsna lihtne selgitada, saates paketti Kubernetesest vĂ€ljaspool hostist, kuid sama 'tuntud halva' vastuvĂ”tja juurde. Nagu nĂ€eme, probleem ei ole kadunud:

theojulienne@shell ~ $ sudo hping3 172.16.47.27 -p 9876 -S -i u10000 | egrep --line-buffered 'rtt=[0-9]{3}.'

len=46 ip=172.16.47.27 ttl=61 DF id=0 sport=9876 flags=RA seq=312 win=0 rtt=108.5 ms

len=46 ip=172.16.47.27 ttl=61 DF id=0 sport=9876 flags=RA seq=5903 win=0 rtt=119.4 ms

len=46 ip=172.16.47.27 ttl=61 DF id=0 sport=9876 flags=RA seq=6227 win=0 rtt=139.9 ms

len=46 ip=172.16.47.27 ttl=61 DF id=0 sport=9876 flags=RA seq=7929 win=0 rtt=131.2 ms

SeejÀrel teeme samu pÀringuid eelnevalt mainitud kube-node poolt vÀlisele hostile (mis vÀlistab algse hosti, kuna ping sisaldab nii RX kui TX komponenti):

theojulienne@kube-node-client ~ $ sudo hping3 172.16.33.44 -p 9876 -S -i u10000 | egrep --line-buffered 'rtt=[0-9]{3}.'
^C
--- 172.16.33.44 hping statistika ---
22352 paketti saadetud, 22350 paketti vastu vÔetud, 1% paketi kadu
ĂŒmbermineku minimaalne/keskmine/maksimaalne = 0.2/7.6/1010.6 ms

Pakettide hilinemise analĂŒĂŒsimisel saime mĂ”ningast tĂ€iendavat teavet. EelkĂ”ige, et saatja (allpool) nĂ€eb seda aegumist, samas kui saaja (ĂŒles) ei nĂ€e - vt veerg Delta (sekundites):

Parandame vÔrgu viivitusi Kubernetes'es

Lisaks, kui vaadata TCP ja ICMP pakettide jÀrjekorra erinevust (jÀrjekorranumbrite jÀrgi) saaja poolel, siis ICMP paketid jÔuavad alati samas jÀrjekorras, nagu need saadeti, aga erineva ajastusega. Samal ajal vahelduvad TCP paketid mÔnikord, ja osa neist jÀÀb pidama. EelkÔige, kui uurida SYN pakettide porte, siis saatja poolel need on jÀrjestatud, saaja poolel aga mitte.

On peen erinevus selles, kuidas kaasaegsed serverite vĂ”rkkardid (nagu meie andmekeskuses) kĂ€sitlevad pakkette, mis sisaldavad TCP-d vĂ”i ICMP-d. Kui paketid saabuvad, siis vĂ”rgukaart 'hĂ€sheerib neid ĂŒhenduse lĂ”ikes', st pĂŒĂŒab jagada ĂŒhendused jĂ€rjekordadesse ning saata iga jĂ€rjekord eraldi protsessori tuumale. TCP puhul sisaldab see hĂ€sheerimine nii allika kui siht-IP-aadressi ja porti. TeisisĂ”nu, iga ĂŒhendus hĂ€sheeritakse (vĂ”imalikult) eri viisil. ICMP puhul hĂ€sheeritakse ainult IP-aadresse, kuna porte pole. Veel ĂŒks uus tĂ€helepanek: selle perioodi jooksul nĂ€eme ICMP viivitusi kĂ”ikides suhtluses kahe hosti vahel, kuid TCP-l ei ole. See annab meile mĂ€rku, et pĂ”hjus on tĂ”enĂ€oliselt seotud RX jĂ€rjekordade hĂ€sheerimisega: peaaegu kindlasti tekib ummik pakettide RX töötlemisel, mitte vastuste saatmisel.

See vĂ€listab vĂ”imalikest pĂ”hjustest pakettide saatmise. NĂŒĂŒd teame, et pakettide töötlemise probleem on osaliselt seotud mĂ”nede kube-node serveritega.

Selgitame vÀlja pakettide töötlemise Linuxi tuumas

Kuna mÔistame, miks probleem tekkib saaja poolel mÔnedel kube-node serveritel, vaatame, kuidas Linuxi tuum töötleb pakette.

Naastes kÔige lihtsamasse traditsioonilisse rakendusse, vÔrgukaart saab paketi ja saadab

katkestuse Linuxi tuumale, et teatada, et on pakett, mida peab töötlema. Tuum peatab muu töö, vahetab konteksti katkestuse kĂ€sitlejale, töötleb paketti ja seejĂ€rel naaseb praegustele ĂŒlesannetele. Linuxi kernelile, et saabunud on pakett, mida tuleb töödelda. Kernel peatab muud toimingud, lĂŒlitab konteksti katkestusekĂ€sitlejale, töötleb paketi ja naaseb seejĂ€rel kĂ€imasolevate ĂŒlesannete juurde.

Parandame vÔrgu viivitusi Kubernetes'es

Kontexti vahetamine toimub aeglaselt: kuigi 10-megabitiste vÔrgukaartide puhul 90-ndatel vÔis viivitus jÀÀda mÀrkamatuks, siis tÀnapÀevastes 10G kaartides, mille maksimaalne lÀbilaskevÔime on 15 miljonit paketti sekundis, vÔivad iga tuuma vÀikese kaheksatuumalise serveri katkestused toimuda miljoneid kordi sekundis.

Kuna katkestuste pideva töötlemisega tegelemine pole praktiline, lisati Linuxisse juba mitu aastat tagasi NAPI: vĂ”rgurakendusprogrammide liides, mida kasutavad kĂ”ik kaasaegsed draiverid, et suurendada jĂ”udlust kĂ”rgetel kiirusel. Madalatel kiirusel vĂ”tab tuum ikka veel katkestusi vĂ”rgu kaardilt vana meetodi jĂ€rgi. Kui piisav kogus pakette, mis ĂŒletab kĂŒnnise, saabub, keelab tuum katkestused ja asub selle asemel vĂ”rgukaarti kĂŒsitlema ning pakette partii kaupa koguma. Töötlemine toimub softirq kontekstis, see tĂ€hendab programmi katkestuste kontekstis sĂŒsteemikĂ”nede ja riistvarakatkestuste jĂ€rel, kui tuum (erinevalt kasutajaruumi) on juba kĂ€ivitatud.

Parandame vÔrgu viivitusi Kubernetes'es

See on palju kiirem, kuid tekitab teisi probleeme. Kui pakette on liiga palju, kulub kogu aeg vĂ”rgu kaardilt pakettide töötlemiseks ja kasutajaruumi protsessid ei jĂ”ua neid jĂ€rjekordadest reaalselt tĂŒhjendada (nĂ€iteks lugedes TCP-ĂŒhendustest jne). LĂ”puks tĂ€ituvad jĂ€rjekorrad ja hakkame pakette tagasi viskama. Tasakaalu leidmiseks seab tuum maksimaalse pakettide arvu, mis töötlemise kontekstis softirq-s saab töödeldud. Kui see eelarve ĂŒletatakse, kĂ€ivitatakse eraldi thread ksoftirqd (nĂ€ete ĂŒhte neist igas ps tuumas), mis kĂ€sitleb neid softirq-sid tavapĂ€rase syscall/ katkestuste teest vĂ€ljaspool. See teema plaanitakse standardse protsesside ajakava abil, mis pĂŒĂŒab hoolikalt jagada ressursse.

Parandame vÔrgu viivitusi Kubernetes'es

Uurides, kuidas tuum pakette töötleb, vĂ”ib mĂ€rgata, et siin on teatav tĂ”enĂ€osus ummikute tekkimiseks. Kui softirq-kĂ”nesid tuleb harvemini, peavad paketid mĂ”nda aega ootama vĂ”rgu kaardil RX jĂ€rjekorras töötlemist. VĂ”ib-olla juhtub see mingist ĂŒlesandest, mis blokeerib protsessorituuma, vĂ”i midagi muud takistab tuumast softirq kĂ€ivitamist.

Piirame töötlemise tuuma vÔi meetodini.

Softirq viivitused on praegu vaid oletus. Kuid see on mÔistlik ja me teame, et meil on jÀlgida midagi vÀga sarnast. Seega on jÀrgmine samm selle teooria kinnitamine. Ja kui see kinnitub, leida viivituste pÔhjus.

Naaseme meie aeglaste pakettide juurde:

len=46 ip=172.16.53.32 ttl=61 id=29573 icmp_seq=1953 rtt=99.3 ms

len=46 ip=172.16.53.32 ttl=61 id=29574 icmp_seq=1954 rtt=89.3 ms

len=46 ip=172.16.53.32 ttl=61 id=29575 icmp_seq=1955 rtt=79.2 ms

len=46 ip=172.16.53.32 ttl=61 id=29576 icmp_seq=1956 rtt=69.1 ms

len=46 ip=172.16.53.32 ttl=61 id=29577 icmp_seq=1957 rtt=59.1 ms

len=46 ip=172.16.53.32 ttl=61 id=29790 icmp_seq=2070 rtt=75.7 ms

len=46 ip=172.16.53.32 ttl=61 id=29791 icmp_seq=2071 rtt=65.6 ms

len=46 ip=172.16.53.32 ttl=61 id=29792 icmp_seq=2072 rtt=55.5 ms

Nagu varem arutatud, on need ICMP paketid hakatud ĂŒhe NIC RX jĂ€rjekorda ja töödeldud ĂŒhe CPU tuuma poolt. Kui me tahame mĂ”ista Linuxi toimimist, on kasulik teada, kus (millisel CPU tuumal) ja kuidas (softirq, ksoftirqd) neid pakette töödeldakse, et jĂ€lgida protsessi.

NĂŒĂŒd on aeg kasutada tööriistu, mis vĂ”imaldavad reaalajas jĂ€lgida Linuxi tuuma tööd. Siin kasutasime bcc. See tööriistade komplekt vĂ”imaldab kirjutada vĂ€ikeseid C programme, mis tabavad juhuslikke funktsioone tuumas ja puhvrivad sĂŒndmusi kasutaja ruumi Python programmile, mis suudab neid töödelda ja tagastada teile tulemuse. Juhuslikud funktsioonide tahvlid tuumas on keeruline teema, kuid utiliit on kavandatud maksimaalse turvalisuse tagamiseks ja mĂ”eldud jĂ€lgima just selliseid tootmisprotsesside probleeme, mida on keeruline kopeerida testimis- vĂ”i arenduskeskkonnas.

Plaan on lihtne: me teame, et tuum töötleb neid ICMP pingeid, seega paneme taha juure funktsiooni icmp_echo, mis vastuvÔtab sissetuleva ICMP-paketi "echo request" ja algatab ICMP-vastuse "echo response" saatmise. Me saame paketti tuvastada icmp_seq arvu suurenemise jÀrgi, mis nÀitab hping3 kÔrgem.

Kood bcc tundub keeruline, kuid see pole nii hirmus, kui nĂ€ib. Funktsioon icmp_echo edastab struct sk_buff *skb: see on "echo request" pakk. Me saame selle jĂ€lgida, eemaldada jĂ€rjestuse echo.sequence (mis vastab icmp_seq hping3-st ĂŒle), ja saata selle kasutaja ruumi. Samuti on mugav jÀÀdvustada praegune protsessi nimi/identifikaator. Allpool on nĂ€idatud tulemused, mida nĂ€eme pakettide töötlemise ajal tuuma poolt:

TGID    PID     PROCESS NAME    ICMP_SEQ
0       0       swapper/11      770
0       0       swapper/11      771
0       0       swapper/11      772
0       0       swapper/11      773
0       0       swapper/11      774
20041   20086   prometheus      775
0       0       swapper/11      776
0       0       swapper/11      777
0       0       swapper/11      778
4512    4542   spokes-report-s  779

Siin tuleb mĂ€rkida, et kontekstis softirq protsessid, mis tegid sĂŒsteemikĂ”nesid, kuvatakse kui „protsessid“, kuigi tegelikult töödeldakse pakette ohutult tuuma kontekstis.

Selle tööriistaga saame seostada konkreetseid protsesse konkreetsete paketidega, mis nĂ€itavad viivitust hping3. Teeme lihtsa grep sellel salvestusel teatud vÀÀrtuste jaoks icmp_seq. Paketid, mis vastavad ĂŒlalmainitud icmp_seq vÀÀrtustele, on mĂ€rgitud koos nende RTT-ga, mida me ĂŒlal nĂ€gime (sulgudes on oodatud RTT vÀÀrtused pakettide puhul, mille filtreerisime vĂ€lja vÀÀrtuste alla 50 ms tĂ”ttu):

TGID    PID     PROCESS NAME    ICMP_SEQ ** RTT
--
10137   10436   cadvisor        1951
10137   10436   cadvisor        1952
76      76      ksoftirqd/11    1953 ** 99ms
76      76      ksoftirqd/11    1954 ** 89ms
76      76      ksoftirqd/11    1955 ** 79ms
76      76      ksoftirqd/11    1956 ** 69ms
76      76      ksoftirqd/11    1957 ** 59ms
76      76      ksoftirqd/11    1958 ** (49ms)
76      76      ksoftirqd/11    1959 ** (39ms)
76      76      ksoftirqd/11    1960 ** (29ms)
76      76      ksoftirqd/11    1961 ** (19ms)
76      76      ksoftirqd/11    1962 ** (9ms)
--
10137   10436   cadvisor        2068
10137   10436   cadvisor        2069
76      76      ksoftirqd/11    2070 ** 75ms
76      76      ksoftirqd/11    2071 ** 65ms
76      76      ksoftirqd/11    2072 ** 55ms
76      76      ksoftirqd/11    2073 ** (45ms)
76      76      ksoftirqd/11    2074 ** (35ms)
76      76      ksoftirqd/11    2075 ** (25ms)
76      76      ksoftirqd/11    2076 ** (15ms)
76      76      ksoftirqd/11    2077 ** (5ms)

Tulemused rÀÀgivad meile mitmest asjast. Esiteks, kĂ”ik need paketid töödeldakse kontekstis ksoftirqd/11. See tĂ€hendab, et selle konkreetse masinate paari jaoks hakatakse ICMP-pakette hashima tuuma 11 vastuvĂ”tva poolele. Me nĂ€eme ka, et iga ummistuse ajal on olemas pakette, mida töödeldakse sĂŒsteemikĂ”ne kontekstis cadvisor. Siis ksoftirqd vĂ”tab ĂŒlesande enda kanda ja töötleb akumuleeritud jĂ€rjekorra: see on sama palju pakette, mis on kogunenud pĂ€rast cadvisor.

See, et vahetult enne seda töötab alati cadvisor, viitab tema osalusele probleemis. Irooniliselt on tema eesmĂ€rk cadvisor — „analĂŒĂŒsida ressursside kasutamist ja kĂ€ivitatud konteinerite jĂ”udluse omadusi“, mitte tekitada seda jĂ”udlusprobleemi.

Nagu teiste konteinerite töö aspektidega, on see kÔik ÀÀrmiselt keeruline tööriist, millelt vÔib oodata jÔudlusprobleeme teatud ettenÀgematutes oludes.

Mida teeb cadvisor, mis aeglustab paketijÀrjekorda?

NĂŒĂŒd on meil ĂŒsna hea arusaam, kuidas tĂ”rked toimuvad, milline protsess need pĂ”hjustab ja millisel CPU-l need esinevad. NĂ€eme, et Linuxi tuuma tĂ”ttu ei suuda range lukustamine Ă”igel ajal planeerida. ksoftirqd. Ja me nĂ€eme, et pakette töödeldakse kontekstis. cadvisor. On loogiline eeldada, et cadvisor kĂ€ivitab aeglase syscall'i, mille jĂ€rel töödeldakse kĂ”ik selle aja jooksul kuhjunud paketid:

Parandame vÔrgu viivitusi Kubernetes'es

See on teooria, aga kuidas seda kontrollida? Mis me saavad teha, on jĂ€lgida CPU tuuma tööd kogu selle protsessi vĂ€ltel, leida punkt, kus pakettide hulga ĂŒletamine toimub ja ksoftirqd kĂ€ivitatakse, ning seejĂ€rel vaadata veidi varem — mis tĂ€pselt tuuma CPU-l selles hetkes töötas. See on nagu röntgenpilt CPU-st iga paar millisekundi jĂ€rel. See nĂ€eb vĂ€lja umbes nii:

Parandame vÔrgu viivitusi Kubernetes'es

Kena on see, et kogu seda saab teha olemasolevate tööriistadega. NĂ€iteks perf record kontrollib mÀÀratud aegade jĂ€rel antud CPU tuuma ja suudab genereerida töötava sĂŒsteemi kutsete graafiku, sealhulgas nii kasutajaruumi kui ka Linuxi tuuma. Saame vĂ”tta selle salvestuse ja töödelda seda vĂ€ikese forki abil programmist FlameGraph Brendan Greggilt, mis sĂ€ilitab virnastamise jĂ€rjekorra. Saame salvestada ĂŒhekordsed virnastamisjĂ€ljed iga 1 ms jĂ€rel ja seejĂ€rel eraldada ja salvestada nĂ€idise 100 millisekundi enne, kui jĂ€lgimus salvestatakse. ksoftirqd:

# record 999 times a second, or every 1ms with some offset so not to align exactly with timers
sudo perf record -C 11 -g -F 999
# take that recording and make a simpler stack trace.
sudo perf script 2>/dev/null | ./FlameGraph/stackcollapse-perf-ordered.pl | grep ksoftir -B 100

Siin on tulemused:

(sajaid jÀlgi, mis nÀevad vÀlja sarnased)

cadvisor;[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];entry_SYSCALL_64_after_swapgs;do_syscall_64;sys_read;vfs_read;seq_read;memcg_stat_show;mem_cgroup_nr_lru_pages;mem_cgroup_node_nr_lru_pages cadvisor;[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];entry_SYSCALL_64_after_swapgs;do_syscall_64;sys_read;vfs_read;seq_read;memcg_stat_show;mem_cgroup_nr_lru_pages;mem_cgroup_node_nr_lru_pages cadvisor;[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];entry_SYSCALL_64_after_swapgs;do_syscall_64;sys_read;vfs_read;seq_read;memcg_stat_show;mem_cgroup_iter cadvisor;[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];entry_SYSCALL_64_after_swapgs;do_syscall_64;sys_read;vfs_read;seq_read;memcg_stat_show;mem_cgroup_nr_lru_pages;mem_cgroup_node_nr_lru_pages cadvisor;[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadvisor];[cadadvisor];[cadvisor];entry_SYSCALL_64_after_swapgs;do_syscall_64;sys_read;vfs_read;seq_read;memcg_stat_show;mem_cgroup_nr_lru_pages;mem_cgroup_node_nr_lru_pages ksoftirqd/11;ret_from_fork;kthread;kthread;smpboot_thread_fn;smpboot_thread_fn;run_ksoftirqd;__do_softirq;net_rx_action;ixgbe_poll;ixgbe_clean_rx_irq;napi_gro_receive;netif_receive_skb_internal;inet_gro_receive;bond_handle_frame;__netif_receive_skb_core;ip_rcv_finish;ip_rcv;ip_forward_finish;ip_forward;ip_finish_output;nf_iterate;ip_output;ip_finish_output2;__dev_queue_xmit;dev_hard_start_xmit;ipip_tunnel_xmit;ip_tunnel_xmit;iptunnel_xmit;ip_local_out;dst_output;__ip_local_out;nf_hook_slow;nf_iterate;nf_conntrack_in;generic_packet;ipt_do_table;set_match_v4;ip_set_test;hash_net4_kadt;ixgbe_xmit_frame_ring;swiotlb_dma_mapping_error;hash_net4_test ksoftirqd/11;ret_from_fork;kthread;kthread;smpboot_thread_fn;smpboot_thread_fn;run_ksoftirqd;__do_softirq;net_rx_action;gro_cell_poll;napi_gro_receive;netif_receive_skb_internal;inet_gro_receive;__netif_receive_skb_core;ip_rcv_finish;ip_rcv;ip_forward_finish;ip_forward;ip_finish_output;nf_iterate;ip_output;ip_finish_output2;__dev_queue_xmit;dev_hard_start_xmit;dev_queue_xmit_nit;packet_rcv;tpacket_rcv;sch_direct_xmit;validate_xmit_skb_list;validate_xmit_skb;netif_skb_features;ixgbe_xmit_frame_ring;swiotlb_dma_mapping_error;__dev_queue_xmit;dev_hard_start_xmit;__bpf_prog_run;__bpf_prog_run

Siin on palju, kuid peamine, et leidsime mustri „cadvisor enne ksoftirqd“, mida oleme varem nĂ€inud ICMP jĂ€lgijas. Mis see tĂ€hendab?

Iga rida on CPU jĂ€lgimine kindlal ajahetkel. Iga allavoolu kutse reas on eraldatud semikooloniga. Ridade keskel nĂ€eme kutset: read(): .... ;do_syscall_64;sys_read; .... Nii et cadvisor veedab palju aega sĂŒsteemi kutsele read(), mis on seotud funktsioonidega mem_cgroup_* (kutsu ĂŒles vĂ€ljund/reana lĂ”pus).

KutsumisjĂ€lgides on ebamugav vaadata, mida tĂ€pselt loetakse, seega kĂ€ivitame strace ja vaatame, mida cadvisor teeb, ja leiame rohkem kui 100 ms kestvaid sĂŒsteemi kutseid:

theojulienne@kube-node-bad ~ $ sudo strace -p 10137 -T -ff 2>&1 | egrep '<0.[1-9]'
[pid 10436] ) = 0
[pid 10432] ) = 0
[pid 10137] ) = 0
[pid 10384] ) = 0
[pid 10436] "cache 154234880nrss 507904nrss_h"..., 4096) = 658
[pid 10384] ) = 0
[pid 10436] ) = 0
[pid 10436] "cache 0nrss 0nrss_huge 0nmapped_"..., 4096) = 577
[pid 10427] "cache 0nrss 0nrss_huge 0nmapped_"..., 4096) = 577
[pid 10411] ) = 0
[pid 10382] ) = 0 (Timeout)
[pid 10436] "cache 154234880nrss 507904nrss_h"..., 4096) = 660
[pid 10417] ) = 0
[pid 10436] ) = 0
[pid 10417] ) = 0
[pid 10417] "cache 0nrss 0nrss_huge 0nmapped_"..., 4096) = 576

Nagu oodata vĂ”is, nĂ€eme siin aeglaseid kutseid. read(). Lugemisoperatsioonide ja konteksti sisu mem_cgroup on selge, et need kutsed read() on seotud failiga memory.stat, mis nĂ€itab mĂ€lukasutust ja cgroupide piirmÀÀrasid (Dockeris ressursside isolatsiooni tehnoloogia). Cadvisor tööriist kĂŒsib seda faili, et saada teavet konteinerite ressursside kasutamise kohta. Kontrollime, kas see on tuuma pĂ”hjus vĂ”i teeb cadvisor midagi ootamatut:

theojulienne@kube-node-bad ~ $ time cat /sys/fs/cgroup/memory/memory.stat >/dev/null

real 0m0.153s
user 0m0.000s
sys 0m0.152s
theojulienne@kube-node-bad ~ $

NĂŒĂŒd saame vea taasluua ja mĂ”istame, et Linuxi tuum seisab silmitsi patoloogiaga.

Miks on lugemise operatsioon nii aeglane?

Selles etapis on oluliselt lihtsam leida teiste kasutajate sĂ”numeid sarnaste probleemide kohta. Selgus, et cadvisor tracker'is on selle vea kohta teatatud kui CPU ĂŒlemÀÀrase kasutamise probleemist, kuid keegi ei pannud tĂ€hele, et viivitus peegeldub ka juhuslikult vĂ”rgu stĂ€kis. TĂ”epoolest on mĂ€rgata, et cadvisor kasutab rohkem protsessori aega, kui oodatud, kuid sellele ei pööratud erilist tĂ€helepanu, kuna meie serveritel on palju protsessorivĂ”imsust, seega ei uuritud probleemi pĂ”hjalikult.

Probleem seisneb selles, et kontrollrĂŒhmad (cgroups) arvestavad mĂ€lukasutust nimespetsiifilises (konteineris). Kui kĂ”ik protsessid selles cgroupis lĂ”petavad, vabastab Docker mĂ€lukontrollrĂŒhma. Kuid "mĂ€lu" ei ole lihtsalt protsessi mĂ€lu. Kuigi protsesside mĂ€lu ei ole enam kasutuses, selgub, et tuum mÀÀrab veel vahemĂ€lu sisu, nagu dentrid ja inode'id (kataloogide ja failide metaandmed), mis on vahemĂ€lu memory cgroupis. Probleemi kirjeldusest:

cgroups-zombid: kontrollerĂŒhmad, mis ei sisalda protsesse ja on eemaldatud, kuid millele on endiselt eraldatud mĂ€lu (minu juhul dentry vahemĂ€lust, kuid see vĂ”ib samuti tulla lehe vahemĂ€lust vĂ”i tmpfs-lt).

Tuuma kontrollimine kĂ”igi lehtede puhul vahemĂ€lus cgroupi vabastamisel vĂ”ib olla vĂ€ga aeglane, seetĂ”ttu valitakse laisk protsess: oodata, kuni need lehed uuesti kĂŒsitakse, ja alles siis, kui mĂ€lu on tĂ”eliselt vajalik, lĂ”puks cgroup puhastada. Enne seda hetke arvestatakse cgroupi ikka veel statistika kogumisel.

Tulemuslikkuse osas ohverdasid nad mĂ€lu tĂ”hususe nimel: esialgne tĂŒhjendus kiirenes vĂ€hese vahepealse mĂ€lu arvelt. See on normaalne. Kui sĂŒdamik kasutab viimast osa vahepealsest mĂ€lust, tĂŒhjendatakse cgroup lĂ”puks, seega ei saa seda pidada "lekkele". Kahjuks toob selle tuuma (4.9) otsingumehhanismi konkreetne teostus koos tohutu mĂ€luhulgaga meie serverites kaasa selle, et viimaste vahepealsete andmete taastamiseks ja cgroup-zombi puhastamiseks kulub palju rohkem aega. memory.stat Selgub, et mĂ”nel meie sĂ”lmel oli nii palju cgroup-zombies, et lugemine ja latentsus ĂŒletasid sekundi.

Cadvisor'i probleemi ĂŒmbersĂ”iduks on koheselt vabastada dentries/inodes mĂ€lu kogu sĂŒsteemis, mis eemaldab viivituse lugemisel ja samuti vĂ”rgu latentsuse hostis, kuna vahepealse mĂ€lu eemaldamine hĂ”lmab ka cgroup-zombi vahepealseid lehti, mis vabastatakse samuti. See ei ole lahendus, kuid kinnitab probleemi pĂ”hjust.

Tuli vĂ€lja, et uuemates tuuma versioonides (4.19+) on vĂ€ljundite tĂ”husus parem, seega ĂŒleminek sellele tuumale eemaldas probleemi. Samuti oli meil vahendid probleemsete sĂ”lmede tuvastamiseks Kubernetes'i klastrites, nende elegantseks vĂ€ljavĂ”tmiseks ja taaskĂ€ivitamiseks. KĂ€isime kĂ”ik klastrid lĂ€bi, leidsime sĂ”lmed, mille latentsus oli piisavalt kĂ”rge, ja taaskĂ€ivitasime nad. See andis meile aega operatsioonisĂŒsteemi uuendamiseks teistel serveritel.

Kuna see tĂ”rge peatas NIC RX jĂ€rjekordade töötlemise saatmiseks sadu millisekundeid, pĂ”hjustas see samal ajal suurt latentsust lĂŒhikestes ĂŒhendustes ja latentsust ĂŒhenduse keskel, nĂ€iteks MySQL pĂ€ringute ja vastuspakettide vahel. memory.statKubernetes'i kĂ”ige pĂ”hivĂ”rkude tĂ”hususe mĂ”istmine ja toetamine on kriitilise tĂ€htsusega kĂ”ikide nende pĂ”hjal toimivate teenuste usaldusvÀÀrsuse ja kiirus. Kubernetes'i tĂ”hususe parendamised toovad kasu kĂ”igile kĂ€ivitatavatele sĂŒsteemidele.

KokkuvÔtteks

đŸ„‡Silmusme parandamine Kubernetes'is | ProHoster

đŸ„‡ Veaotsing vĂ”rgu viivitustes Kubernetesis | ProHoster

Allikas: habr.com

Osta usaldusvÀÀrne veebimajutus DDoS-kaitsega veebisaitidele, VPS VDS serverid đŸ”„ Osta usaldusvÀÀrne veebimajutus DDoS-kaitsega veebisaitidele, VPS VDS serverid - ProHoster