Pirms pÄris gadiem Kubernetes
BÅ«tÄ«bÄ lietojumprogrammas saskaras ar Ŕķietami nejauÅ”u tÄ«kla latentumu lÄ«dz 100 ms vai vairÄk, kÄ rezultÄtÄ rodas noildze vai atkÄrtojumi. Paredzams, ka pakalpojumi spÄs atbildÄt uz pieprasÄ«jumiem daudz ÄtrÄk nekÄ 100 ms. Bet tas nav iespÄjams, ja pats savienojums aizÅem tik daudz laika. AtseviŔķi mÄs novÄrojÄm ļoti Ätrus MySQL vaicÄjumus, kam vajadzÄja aizÅemt milisekundes, un MySQL pabeidza milisekundÄs, taÄu no pieprasÄ«juma iesniedzÄjas lietojumprogrammas viedokļa atbilde aizÅÄma 100 ms vai vairÄk.
Uzreiz kļuva skaidrs, ka problÄma radÄs tikai savienojoties ar Kubernetes mezglu, pat ja zvans nÄca no Ärpuses Kubernetes. VienkÄrÅ”Äkais veids, kÄ atkÄrtot problÄmu, ir tests
NevajadzÄ«gas sarežģītÄ«bas novÄrÅ”ana Ä·ÄdÄ, kas noved pie neveiksmes
AtkÄrtojot to paÅ”u piemÄru, mÄs vÄlÄjÄmies saÅ”aurinÄt problÄmas fokusu un noÅemt nevajadzÄ«gus sarežģītÄ«bas slÄÅus. SÄkotnÄji plÅ«smÄ starp VeÄ£etu un Kubernetes pÄkstÄ«m bija pÄrÄk daudz elementu. Lai noteiktu dziļÄku tÄ«kla problÄmu, dažas no tÄm ir jÄizslÄdz.
Klients (Vegeta) izveido TCP savienojumu ar jebkuru klastera mezglu. Kubernetes darbojas kÄ pÄrklÄjuma tÄ«kls (papildus esoÅ”ajam datu centra tÄ«klam), kas izmanto
Lietderība tcpdump
Vegeta testÄ ir aizkave TCP rokasspiediena laikÄ (starp SYN un SYN-ACK). Lai noÅemtu Å”o nevajadzÄ«go sarežģītÄ«bu, varat izmantot hping3
vienkÄrÅ”iem āpingiemā ar SYN paketÄm. MÄs pÄrbaudÄm, vai atbildes paketÄ ir aizkave, un pÄc tam atiestatÄm savienojumu. MÄs varam filtrÄt datus, lai iekļautu tikai paketes, kas ir lielÄkas par 100 ms, un iegÅ«t vienkÄrÅ”Äku veidu, kÄ reproducÄt problÄmu nekÄ pilna tÄ«kla 7. slÄÅa pÄrbaude pakalpojumÄ Vegeta. Å eit ir Kubernetes mezgla āpingsā, izmantojot TCP SYN/SYN-ACK pakalpojuma ānode portÄā (30927) ar 10 ms intervÄlu, filtrÄjot pÄc lÄnÄkÄs atbildes:
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
Var uzreiz veikt pirmo novÄrojumu. Spriežot pÄc kÄrtas numuriem un laikiem, ir skaidrs, ka tie nav vienreizÄji sastrÄgumi. KavÄÅ”anÄs bieži uzkrÄjas un galu galÄ tiek apstrÄdÄta.
TÄlÄk mÄs vÄlamies noskaidrot, kuras sastÄvdaļas var bÅ«t saistÄ«tas ar sastrÄgumu raÅ”anos. VarbÅ«t Å”ie ir daži no simtiem NAT iptables noteikumu? Vai arÄ« ir problÄmas ar IPIP tunelÄÅ”anu tÄ«klÄ? Viens no veidiem, kÄ to pÄrbaudÄ«t, ir pÄrbaudÄ«t katru sistÄmas posmu, to novÄrÅ”ot. Kas notiek, ja noÅemat NAT un ugunsmÅ«ra loÄ£iku, atstÄjot tikai IPIP daļu:
Par laimi, Linux ļauj viegli piekļūt tieÅ”i IP pÄrklÄjuma slÄnim, ja iekÄrta atrodas tajÄ paÅ”Ä tÄ«klÄ:
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
Spriežot pÄc rezultÄtiem, problÄma joprojÄm pastÄv! Tas izslÄdz iptables un NAT. TÄtad problÄma ir TCP? ApskatÄ«sim, kÄ notiek parastais ICMP ping:
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
RezultÄti liecina, ka problÄma nav pazudusi. VarbÅ«t tas ir IPIP tunelis? VienkÄrÅ”osim testu vÄl vairÄk:
Vai visas paketes tiek nosūtītas starp Ŕiem diviem saimniekiem?
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
MÄs esam vienkÄrÅ”ojuÅ”i situÄciju lÄ«dz diviem Kubernetes mezgliem, kas viens otram nosÅ«ta jebkuru paketi, pat ICMP ping. ViÅi joprojÄm redz latentumu, ja mÄrÄ·a resursdators ir "slikts" (daži sliktÄki par citiem).
Tagad pÄdÄjais jautÄjums: kÄpÄc aizkave notiek tikai kube-node serveros? Un vai tas notiek, ja kube-node ir sÅ«tÄ«tÄjs vai saÅÄmÄjs? Par laimi, to ir arÄ« diezgan viegli noskaidrot, nosÅ«tot paketi no resursdatora Ärpus Kubernetes, bet ar to paÅ”u āzinÄmo sliktuā adresÄtu. KÄ redzat, problÄma nav pazudusi:
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
PÄc tam mÄs izpildÄ«sim tos paÅ”us pieprasÄ«jumus no iepriekÅ”ÄjÄ avota kube-node ÄrÄjam resursdatoram (kas izslÄdz avota resursdatoru, jo ping ietver gan RX, gan TX komponentu):
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 statistic ---
22352 packets transmitted, 22350 packets received, 1% packet loss
round-trip min/avg/max = 0.2/7.6/1010.6 ms
PÄrbaudot latentuma pakeÅ”u uztverÅ”anu, mÄs ieguvÄm papildu informÄciju. KonkrÄti, ja sÅ«tÄ«tÄjs (apakÅ”Ä) redz Å”o taimautu, bet adresÄts (augÅ”Äjais) neredz - skatiet kolonnu Delta (sekundÄs):
TurklÄt, ja paskatÄs uz atŔķirÄ«bu TCP un ICMP pakeÅ”u secÄ«bÄ (pÄc kÄrtas numuriem) saÅÄmÄja pusÄ, ICMP paketes vienmÄr nonÄk tajÄ paÅ”Ä secÄ«bÄ, kÄdÄ tÄs tika nosÅ«tÄ«tas, bet ar atŔķirÄ«gu laiku. TajÄ paÅ”Ä laikÄ TCP paketes dažkÄrt pÄriet, un dažas no tÄm iestrÄgst. Jo Ä«paÅ”i, ja pÄrbaudÄt SYN pakeÅ”u portus, tie ir kÄrtÄ«bÄ sÅ«tÄ«tÄja pusÄ, bet ne saÅÄmÄja pusÄ.
Ir neliela atŔķirÄ«ba, kÄ
VÄl viens jauns novÄrojums: Å”ajÄ periodÄ mÄs redzam ICMP aizkavi visos sakaros starp diviem resursdatoriem, bet TCP ne. Tas norÄda, ka iemesls, visticamÄk, ir saistÄ«ts ar RX rindas jaukÅ”anu: pÄrslodze gandrÄ«z noteikti ir saistÄ«ta ar RX pakeÅ”u apstrÄdi, nevis atbilžu nosÅ«tÄ«Å”anu.
Tas izslÄdz pakeÅ”u sÅ«tÄ«Å”anu no iespÄjamo iemeslu saraksta. Tagad mÄs zinÄm, ka pakeÅ”u apstrÄdes problÄma dažos Kube-node serveros ir uztverÅ”anas pusÄ.
Izpratne par pakeÅ”u apstrÄdi Linux kodolÄ
Lai saprastu, kÄpÄc problÄma rodas dažu kube mezglu serveru uztvÄrÄjÄ, apskatÄ«sim, kÄ Linux kodols apstrÄdÄ paketes.
Atgriežoties pie vienkÄrÅ”ÄkÄs tradicionÄlÄs ievieÅ”anas, tÄ«kla karte saÅem paketi un nosÅ«ta
Å Ä« konteksta pÄrslÄgÅ”ana ir lÄna: latentums, iespÄjams, nebija pamanÄms 10 Mbps tÄ«kla kartÄs 90. gados, taÄu mÅ«sdienu 10 G kartÄs ar maksimÄlo caurlaidspÄju 15 miljoni pakeÅ”u sekundÄ katrs neliela astoÅu kodolu servera kodols var tikt pÄrtraukts miljoniem. reizes sekundÄ.
Lai nepÄrtraukti netiktu apstrÄdÄti pÄrtraukumi, pirms daudziem gadiem pievienoja Linux
Tas ir daudz ÄtrÄk, taÄu rada citu problÄmu. Ja pakeÅ”u ir par daudz, tad viss laiks tiek tÄrÄts pakeÅ”u apstrÄdei no tÄ«kla kartes, un lietotÄja telpas procesiem nav laika Ŕīs rindas reÄli iztukÅ”ot (nolasot no TCP savienojumiem utt.). Galu galÄ rindas piepildÄs, un mÄs sÄkam mest paciÅas. MÄÄ£inot atrast lÄ«dzsvaru, kodols nosaka budžetu maksimÄlajam softirq kontekstÄ apstrÄdÄto pakeÅ”u skaitam. Kad Å”is budžets ir pÄrsniegts, tiek pamodinÄts atseviŔķs pavediens ksoftirqd
(jÅ«s redzÄsit vienu no tiem ps
vienam kodolam), kas apstrÄdÄ Å”os softirq Ärpus parastÄ syscall/pÄrtraukÅ”anas ceļa. Å is pavediens ir ieplÄnots, izmantojot standarta procesu plÄnotÄju, kas mÄÄ£ina taisnÄ«gi pieŔķirt resursus.
IzpÄtÄ«jis, kÄ kodols apstrÄdÄ paketes, jÅ«s varat redzÄt, ka pastÄv zinÄma pÄrslodzes iespÄjamÄ«ba. Ja softirq zvani tiek saÅemti retÄk, paketÄm bÅ«s kÄdu laiku jÄgaida, lai tÄs tiktu apstrÄdÄtas tÄ«kla kartes RX rindÄ. Tas var bÅ«t saistÄ«ts ar kÄdu uzdevumu, kas bloÄ·Ä procesora kodolu, vai kaut kas cits neļauj kodolam darboties softirq.
ApstrÄdes saÅ”aurinÄÅ”ana lÄ«dz kodolam vai metodei
Softirq kavÄÅ”anÄs pagaidÄm ir tikai minÄjums. Bet tam ir jÄga, un mÄs zinÄm, ka redzam kaut ko ļoti lÄ«dzÄ«gu. TÄtad nÄkamais solis ir apstiprinÄt Å”o teoriju. Un, ja tas apstiprinÄs, tad atrodiet kavÄÅ”anÄs iemeslu.
AtgriezÄ«simies pie mÅ«su lÄnajÄm paketÄm:
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
KÄ minÄts iepriekÅ”, Ŕīs ICMP paketes tiek sajauktas vienÄ RX NIC rindÄ un apstrÄdÄtas ar vienu CPU kodolu. Ja vÄlamies saprast, kÄ darbojas Linux, ir noderÄ«gi zinÄt, kur (kurÄ CPU kodolÄ) un kÄ (softirq, ksoftirqd) Ŕīs pakotnes tiek apstrÄdÄtas, lai izsekotu procesam.
Tagad ir pienÄcis laiks izmantot rÄ«kus, kas ļauj pÄrraudzÄ«t Linux kodolu reÄllaikÄ. Å eit mÄs izmantojÄm
PlÄns Å”eit ir vienkÄrÅ”s: mÄs zinÄm, ka kodols apstrÄdÄ Å”os ICMP ping, tÄpÄc mÄs izmantosim kodola funkciju. hping3
iepriekÅ”.
Kods icmp_echo
nodod struct sk_buff *skb
: Å Ä« ir pakete ar "atbalss pieprasÄ«jumu". MÄs varam to izsekot, izvilkt secÄ«bu echo.sequence
(kas salīdzina ar icmp_seq
ar hping3 Š²ŃŃŠµ
) un nosÅ«tiet to uz lietotÄja vietu. Ir arÄ« Ärti tvert paÅ”reizÄjÄ procesa nosaukumu/id. TÄlÄk ir norÄdÄ«ti rezultÄti, kurus mÄs redzam tieÅ”i, kodolam apstrÄdÄjot paketes:
TGID PID PROCESA NOSAUKUMS ICMP_SEQ 0 0 mijmaiÅa/11 770 0 0 mijmaiÅa/11 771 0 0 mijmaiÅa/11 772 0 0 mijmaiÅa/11 773 0 0 mijmaiÅa/11 774 20041 20086 Prometejs 775 0 0 mijmaiÅa/11 776 0 0 mijmaiÅa/11 777 0 0 mijmaiÅa/11 778 4512 4542 spieÄ·i-ziÅojumi-s 779
Te gan jÄatzÄ«mÄ, ka kontekstÄ softirq
procesi, kas veica sistÄmas izsaukumus, parÄdÄ«sies kÄ "procesi", lai gan patiesÄ«bÄ kodols ir tas, kas droÅ”i apstrÄdÄ paketes kodola kontekstÄ.
Izmantojot Å”o rÄ«ku, mÄs varam saistÄ«t konkrÄtus procesus ar konkrÄtÄm pakotnÄm, kas parÄda aizkavi hping3
. PadarÄ«sim to vienkÄrÅ”u grep
par Å”o uztverÅ”anu noteiktÄm vÄrtÄ«bÄm icmp_seq
. Paketes, kas atbilst iepriekÅ” minÄtajÄm icmp_seq vÄrtÄ«bÄm, tika atzÄ«mÄtas kopÄ ar to RTT, ko novÄrojÄm iepriekÅ” (iekavÄs ir norÄdÄ«tas paredzamÄs RTT vÄrtÄ«bas paketÄm, kuras izfiltrÄjÄm, jo āāRTT vÄrtÄ«bas bija mazÄkas par 50 ms):
TGID PID PROCESA NOSAUKUMS ICMP_SEQ ** RTT -- 10137 10436 cadvisor 1951.g 10137 10436 cadvisor 1952.g 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** (49 ms) 76 76 ksoftirqd/11, 1959 ** (39 ms) 76 76 ksoftirqd/11 1960 ** (29 ms) 76 76 ksoftirqd/11, 1961 ** (19 ms) 76 76 ksoftirqd/11, 1962 ** (9 ms) -- 10137 10436 cadvisor 2068 10137 10436 cadvisor 2069 76 76 ksoftirqd/11 2070 ** 75 ms 76 76 ksoftirqd/11 2071 ** 65 ms 76 76 ksoftirqd/11 2072 ** 55 ms 76 76 ksoftirqd/11 2073** (45 ms) 76 76 ksoftirqd/11 2074** (35 ms) 76 76 ksoftirqd/11 2075 ** (25 ms) 76 76 ksoftirqd/11 2076 ** (15 ms) 76 76 ksoftirqd/11 2077** (5 ms)
RezultÄti mums saka vairÄkas lietas. PirmkÄrt, visas Ŕīs pakotnes apstrÄdÄ konteksts ksoftirqd/11
. Tas nozÄ«mÄ, ka Å”im konkrÄtajam maŔīnu pÄrim ICMP paketes tika sajauktas lÄ«dz 11. kodolam saÅemÅ”anas galÄ. MÄs arÄ« redzam, ka ikreiz, kad ir iestrÄgums, ir paketes, kas tiek apstrÄdÄtas sistÄmas izsaukuma kontekstÄ cadvisor
. PÄc tam ksoftirqd
pÄrÅem uzdevumu un apstrÄdÄ uzkrÄto rindu: tieÅ”i tik pakeÅ”u skaitu, kas ir sakrÄjuÅ”Äs pÄc cadvisor
.
Tas, ka tieÅ”i pirms tam vienmÄr strÄdÄ cadvisor
, nozÄ«mÄ viÅa iesaistÄ«Å”anos problÄmas risinÄÅ”anÄ. Ironiski, mÄrÄ·is
TÄpat kÄ ar citiem konteineru aspektiem, Å”ie visi ir ļoti uzlaboti rÄ«ki, un var rasties darbÄ«bas problÄmas dažos neparedzÄtos apstÄkļos.
Ko dara cadvisor, kas palÄnina pakeÅ”u rindu?
Tagad mums ir diezgan laba izpratne par to, kÄ notiek avÄrija, kÄds process to izraisa un kurÄ CPU. MÄs redzam, ka cietÄs bloÄ·ÄÅ”anas dÄļ Linux kodolam nav laika ieplÄnot ksoftirqd
. Un mÄs redzam, ka paketes tiek apstrÄdÄtas kontekstÄ cadvisor
. Ir loÄ£iski to pieÅemt cadvisor
palaiž lÄnu syscall, pÄc kuras tiek apstrÄdÄtas visas tajÄ laikÄ uzkrÄtÄs paketes:
TÄ ir teorija, bet kÄ to pÄrbaudÄ«t? MÄs varam izsekot CPU kodolam Å”ajÄ procesÄ, atrast vietu, kur pakeÅ”u skaits pÄrsniedz budžetu un tiek izsaukts ksoftirqd, un pÄc tam paskatÄ«ties nedaudz tÄlÄk, lai redzÄtu, kas tieÅ”i pirms Ŕī punkta darbojÄs CPU kodolÄ. . Tas ir tÄpat kÄ ik pÄc dažÄm milisekundÄm veikt CPU rentgenu. Tas izskatÄ«sies apmÄram Å”Ädi:
Ärti to visu var izdarÄ«t ar esoÅ”ajiem instrumentiem. PiemÄram, 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
LÅ«k, rezultÄti:
(ŃŠ¾ŃŠ½Šø ŃŠ»ŠµŠ“Š¾Š², ŠŗŠ¾ŃŠ¾ŃŃŠµ Š²ŃŠ³Š»ŃŠ“ŃŃ ŠæŠ¾Ń
Š¾Š¶ŠøŠ¼Šø)
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];[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 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
Å eit ir daudz lietu, taÄu galvenais ir tas, ka mÄs atrodam modeli ācadvisor before ksoftirqdā, ko redzÄjÄm iepriekÅ” ICMP izsekotÄjs. Ko tas nozÄ«mÄ?
Katra lÄ«nija ir CPU izsekoÅ”ana noteiktÄ laika brÄ«dÄ«. Katrs lÄ«nijas izsaukums tiek atdalÄ«ts ar semikolu. LÄ«niju vidÅ« mÄs redzam, ka tiek izsaukts syscall: read(): .... ;do_syscall_64;sys_read; ...
. TÄtad cadvisor pavada daudz laika sistÄmas zvanam read()
kas saistÄ«ti ar funkcijÄm mem_cgroup_*
(zvanu kaudzes augŔdaļa/līnijas beigas).
Ir neÄrti zvana trasÄ redzÄt, kas tieÅ”i tiek nolasÄ«ts, tÄpÄc palaidÄ«sim strace
un paskatÄ«simies, ko dara cadvisor, un atradÄ«sim sistÄmas zvanus, kas garÄki par 100 ms:
theojulienne@kube-node-bad ~ $ sudo strace -p 10137 -T -ff 2>&1 | egrep '<0.[1-9]'
[pid 10436] <... futex resumed> ) = 0 <0.156784>
[pid 10432] <... futex resumed> ) = 0 <0.258285>
[pid 10137] <... futex resumed> ) = 0 <0.678382>
[pid 10384] <... futex resumed> ) = 0 <0.762328>
[pid 10436] <... read resumed> "cache 154234880nrss 507904nrss_h"..., 4096) = 658 <0.179438>
[pid 10384] <... futex resumed> ) = 0 <0.104614>
[pid 10436] <... futex resumed> ) = 0 <0.175936>
[pid 10436] <... read resumed> "cache 0nrss 0nrss_huge 0nmapped_"..., 4096) = 577 <0.228091>
[pid 10427] <... read resumed> "cache 0nrss 0nrss_huge 0nmapped_"..., 4096) = 577 <0.207334>
[pid 10411] <... epoll_ctl resumed> ) = 0 <0.118113>
[pid 10382] <... pselect6 resumed> ) = 0 (Timeout) <0.117717>
[pid 10436] <... read resumed> "cache 154234880nrss 507904nrss_h"..., 4096) = 660 <0.159891>
[pid 10417] <... futex resumed> ) = 0 <0.917495>
[pid 10436] <... futex resumed> ) = 0 <0.208172>
[pid 10417] <... futex resumed> ) = 0 <0.190763>
[pid 10417] <... read resumed> "cache 0nrss 0nrss_huge 0nmapped_"..., 4096) = 576 <0.154442>
KÄ jÅ«s varÄtu gaidÄ«t, mÄs redzam lÄnus zvanus read()
. No lasīŔanas darbību satura un konteksta mem_cgroup
ir skaidrs, ka Å”ie izaicinÄjumi read()
atsaukties uz failu memory.stat
, kas parÄda atmiÅas lietojumu un cgroup ierobežojumus (Docker resursu izolÄcijas tehnoloÄ£ija). Cadvisor rÄ«ks vaicÄ Å”o failu, lai iegÅ«tu informÄciju par konteineru resursu lietojumu. PÄrbaudÄ«sim, vai kodols vai cadvisor nedara kaut ko neparedzÄtu:
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 ~ $
Tagad mÄs varam atveidot kļūdu un saprast, ka Linux kodols saskaras ar patoloÄ£iju.
KÄpÄc lasÄ«Å”anas darbÄ«ba ir tik lÄna?
Å ajÄ posmÄ ir daudz vieglÄk atrast ziÅojumus no citiem lietotÄjiem par lÄ«dzÄ«gÄm problÄmÄm. KÄ izrÄdÄ«jÄs, cadvisor tracker par Å”o kļūdu tika ziÅots kÄ
ProblÄma ir tÄ, ka cgroups Åem vÄrÄ atmiÅas izmantoÅ”anu nosaukumvietÄ (konteinerÄ). Kad visi procesi Å”ajÄ cgrupÄ iziet, Docker atbrÄ«vo atmiÅas cgrupu. TomÄr "atmiÅa" nav tikai procesa atmiÅa. Lai gan pati procesa atmiÅa vairs netiek izmantota, Ŕķiet, ka kodols joprojÄm pieŔķir keÅ”atmiÅÄ saglabÄto saturu, piemÄram, dentries un inodes (direktoriju un failu metadatus), kas tiek saglabÄti atmiÅas cgrupÄ. No problÄmas apraksta:
zombie cgroups: cgroups, kurÄm nav procesu un ir izdzÄstas, bet joprojÄm ir atvÄlÄta atmiÅa (manÄ gadÄ«jumÄ no dentry cache, bet to var arÄ« pieŔķirt no lapas keÅ”atmiÅas vai tmpfs).
Kodola visu keÅ”atmiÅÄ esoÅ”o lapu pÄrbaude, atbrÄ«vojot cgrupu, var bÅ«t ļoti lÄna, tÄpÄc tiek izvÄlÄts slinks process: pagaidiet, lÄ«dz Ŕīs lapas atkal tiek pieprasÄ«tas, un tad beidzot notÄ«riet cgrupu, kad patieÅ”Äm ir nepiecieÅ”ama atmiÅa. LÄ«dz Å”im brÄ«dim, apkopojot statistiku, joprojÄm tiek Åemta vÄrÄ cgroup.
No veiktspÄjas viedokļa viÅi upurÄja atmiÅu veiktspÄjai: paÄtrina sÄkotnÄjo tÄ«rÄ«Å”anu, atstÄjot daļu keÅ”atmiÅas. Tas ir labi. Kad kodols izmanto pÄdÄjo keÅ”atmiÅÄ saglabÄto atmiÅu, cgrupa galu galÄ tiek notÄ«rÄ«ta, tÄpÄc to nevar saukt par "noplÅ«di". DiemžÄl konkrÄta meklÄÅ”anas mehÄnisma Ä«stenoÅ”ana memory.stat
Å”ajÄ kodola versijÄ (4.9) kopÄ ar milzÄ«go atmiÅas apjomu mÅ«su serveros nozÄ«mÄ, ka ir nepiecieÅ”ams daudz ilgÄks laiks, lai atjaunotu jaunÄkos keÅ”atmiÅÄ saglabÄtos datus un notÄ«rÄ«tu cgroup zombijus.
IzrÄdÄs, ka dažos mÅ«su mezglos bija tik daudz cgroup zombiju, ka lasÄ«Å”anas un latentuma ilgums pÄrsniedza sekundi.
Cadvisor problÄmas risinÄjums ir nekavÄjoties atbrÄ«vot dentries/inodes keÅ”atmiÅas visÄ sistÄmÄ, kas nekavÄjoties novÄrÅ” lasÄ«Å”anas latentumu, kÄ arÄ« tÄ«kla latentumu resursdatorÄ, jo, notÄ«rot keÅ”atmiÅu, tiek ieslÄgtas keÅ”atmiÅÄ saglabÄtÄs cgroup zombiju lapas, un tÄs arÄ« tiek atbrÄ«votas. Tas nav risinÄjums, bet apstiprina problÄmas cÄloni.
IzrÄdÄ«jÄs, ka jaunÄkÄs kodola versijÄs (4.19+) zvanu veiktspÄja tika uzlabota memory.stat
, tÄpÄc, pÄrejot uz Å”o kodolu, problÄma tika novÄrsta. TajÄ paÅ”Ä laikÄ mums bija rÄ«ki, lai atklÄtu problemÄtiskos mezglus Kubernetes klasteros, graciozi tos iztukÅ”otu un atsÄknÄtu. MÄs izÄ·emmÄjÄm visas kopas, atradÄm mezglus ar pietiekami augstu latentumu un pÄrstartÄjÄm tos. Tas deva mums laiku atjauninÄt OS atlikuÅ”ajos serveros.
SummÄjot
TÄ kÄ Å”Ä« kļūda apturÄja RX NIC rindas apstrÄdi uz simtiem milisekundÄm, tÄ vienlaikus izraisÄ«ja gan lielu latentumu Ä«siem savienojumiem, gan vidÄja savienojuma latentumu, piemÄram, starp MySQL pieprasÄ«jumiem un atbildes paketÄm.
VissvarÄ«gÄko sistÄmu, piemÄram, Kubernetes, veiktspÄjas izpratne un uzturÄÅ”ana ir ļoti svarÄ«ga visu uz tÄm balstÄ«to pakalpojumu uzticamÄ«bai un Ätrumam. Katra jÅ«su darbinÄtÄ sistÄma gÅ«st labumu no Kubernetes veiktspÄjas uzlabojumiem.
Avots: www.habr.com