Un paru d'anni fà Kubernetes
Essenzialmente, l'applicazioni sperimentanu una latenza aleatoria di a rete di finu à 100 ms o più, chì si traduce in timeouts o tentativi. I servizii eranu previsti per pudè risponde à e dumande assai più veloce di 100 ms. Ma questu hè impussibile se a cunnessione stessu pigghia tantu tempu. Separatamente, avemu osservatu e dumande di MySQL assai veloci chì duveranu piglià millisecondi, è MySQL hà cumpletu in millisecondi, ma da a perspettiva di l'applicazione richiesta, a risposta hà pigliatu 100 ms o più.
Immediatamente hè diventatu chjaru chì u prublema hè accadutu solu quandu si cunnetta à un node Kubernetes, ancu s'è a chjamata hè vinuta da fora di Kubernetes. A manera più faciule di ripruduce u prublema hè in una prova
Eliminazione di cumplessità inutile in a catena chì porta à u fallimentu
Riproducendu u listessu esempiu, avemu vulsutu ristrettu u focu di u prublema è caccià strati innecessarii di cumplessità. Inizialmente, ci era troppu elementi in u flussu trà Vegeta è i podi Kubernetes. Per identificà un prublema di rete più profonda, avete bisognu di escludiri alcuni di elli.
U cliente (Vegeta) crea una cunnessione TCP cù qualsiasi node in u cluster. Kubernetes opera cum'è una reta overlay (in cima à a reta di u centru di dati esistenti) chì usa
Utilità tcpdump
in a prova di Vegeta ci hè un ritardu durante a stretta di mano TCP (trà SYN è SYN-ACK). Per sguassà sta cumplessità inutile, pudete aduprà hping3
per semplici "pings" cù pacchetti SYN. Avemu verificatu s'ellu ci hè un ritardu in u pacchettu di risposta, è poi resettate a cunnessione. Pudemu filtrà e dati per include solu pacchetti più grande di 100 ms è uttene un modu più faciule per riproduce u prublema cà a prova di a reta di a reta 7 di Vegeta. Eccu i "pings" di u nodu Kubernetes chì utilizanu TCP SYN/SYN-ACK nantu à u "portu di u nodu" di u serviziu (30927) à intervalli di 10 ms, filtrati da e risposte più lente:
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
Pudete subitu fà a prima osservazione. A ghjudicà da i numeri di sequenza è i timings, hè chjaru chì ùn sò micca congestioni una volta. U ritardu spessu s'accumula è hè eventualmente processatu.
Dopu, vulemu sapè quale cumpunenti pò esse implicati in l'occurrence di congestioni. Forse queste sò alcune di e centinaie di reguli iptables in NAT? O ci sò prublemi cù u tunneling IPIP in a reta? Una manera di verificà questu hè di pruvà ogni passu di u sistema eliminendu. Chì succede si sguassate a logica NAT è firewall, lascendu solu a parte IPIP:
Fortunatamente, Linux facilita l'accessu à a capa di sovrapposizione IP direttamente se a macchina hè nantu à a stessa reta:
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
A ghjudicà da i risultati, u prublema ferma sempre ! Questu esclude iptables è NAT. Allora u prublema hè TCP? Videmu cumu si passa un ping ICMP regulare:
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
I risultati mostranu chì u prublema ùn hè micca andatu. Forse questu hè un tunnel IPIP? Semplicemu ancu a prova:
Sò tutti i pacchetti mandati trà sti dui ospiti?
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
Avemu simplificatu a situazione à dui nodi Kubernetes chì si mandanu ogni pacchettu, ancu un ping ICMP. Anu sempre vede a latenza se l'ospitu di destinazione hè "cattivu" (alcuni peggiu cà l'altri).
Avà l'ultima quistione: perchè u ritardu hè solu in i servitori kube-node? È succede quandu kube-node hè u mittente o u receptore? Per furtuna, questu hè ancu abbastanza faciule da capisce mandendu un pacchettu da un òspite fora di Kubernetes, ma cù u stessu destinatariu "cunnisciutu cattivu". Comu pudete vede, u prublema ùn hè micca sparitu:
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
Eseguiremu allora e stesse richieste da a fonte precedente kube-node à l'ospite esternu (chì esclude l'ospite di fonte postu chì u ping include sia un cumpunente RX sia TX):
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
Esaminendu e catture di pacchetti di latenza, avemu ottenutu alcune informazioni supplementari. In particulare, chì u mittente (in fondu) vede stu timeout, ma u destinatariu (in cima) ùn vede micca a colonna Delta (in seconde):
Inoltre, se fighjate a diffarenza in l'ordine di i pacchetti TCP è ICMP (per numeri di sequenza) da u latu di u destinatariu, i pacchetti ICMP sempre ghjunghjenu in a listessa sequenza in quale sò stati mandati, ma cù un timing differente. À u listessu tempu, i pacchetti TCP si intreccianu qualchì volta, è alcuni di elli si bloccanu. In particulare, se esaminate i porti di i pacchetti SYN, sò in ordine da u latu di u mittente, ma micca da u latu di u receptore.
Ci hè una sfarenza sottile in cumu
Un'altra nova osservazione: durante stu periodu vedemu ritardi ICMP in tutte e cumunicazioni trà dui ospiti, ma TCP ùn hè micca. Questu ci dice chì a causa hè prubabilmente ligata à l'hashing di fila RX: a congestione hè quasi certamente in u processu di pacchetti RX, micca in l'inviu di risposte.
Questu elimina l'inviu di pacchetti da a lista di e pussibuli cause. Avà sapemu chì u prublema di trasfurmazioni di pacchetti hè nantu à u latu di riceve in certi servitori kube-node.
Capisce u processu di pacchetti in u kernel Linux
Per capisce perchè u prublema si trova à u ricevitore in certi servitori kube-node, fighjemu cumu u kernel Linux processa i pacchetti.
Riturnendu à l'implementazione tradiziunale più simplice, a carta di rete riceve u pacchettu è manda
Questa cunversione di u cuntestu hè lenta: a latenza puderia micca esse notevule nantu à e carte di rete 10Mbps in l'anni '90, ma nantu à e carte 10G muderne cù un rendimentu massimu di 15 milioni di pacchetti per seconda, ogni core di un picculu servitore di ottu core pò esse interrotta milioni. di volte per seconda.
Per ùn trattà constantemente interruzioni, parechji anni fà Linux hà aghjustatu
Questu hè assai più veloce, ma causa un prublema diversu. Se ci sò troppu pacchetti, allora tuttu u tempu hè passatu à trasfurmà i pacchetti da a carta di rete, è i prucessi di u spaziu di l'utilizatori ùn anu micca u tempu di sviutata sti file (leghjendu da e cunnessione TCP, etc.). Eventualmente e file si riempianu è cuminciamu à abbandunà i pacchetti. In un tentativu di truvà un equilibriu, u kernel stabilisce un budgetu per u numeru massimu di pacchetti processati in u cuntestu softirq. Una volta stu budgetu hè superatu, un filu separatu hè svegliatu ksoftirqd
(ne vedete unu in ps
per core) chì gestisce questi softirq fora di u percorsu normale di syscall/interrupt. Stu filu hè pianificatu utilizendu u pianificatore di prucessu standard, chì prova di assignà risorse in modu ghjustu.
Dopu avè studiatu cumu u kernel processa i pacchetti, pudete vede chì ci hè una certa probabilità di congestione. Se e chiamate softirq sò ricevute menu freti, i pacchetti duveranu aspittà per qualchì tempu per esse processati in a fila RX nantu à a carta di rete. Questu pò esse dovutu à qualchì compitu chì blocca u core di u processatore, o qualcosa altru impedisce à u core di eseguisce softirq.
Ristrettu u prucessu finu à u core o u metudu
I ritardi di Softirq sò solu una supposizione per ora. Ma hè sensu, è sapemu chì vedemu qualcosa assai simili. Allora u prossimu passu hè di cunfirmà sta teoria. È s'ellu hè cunfirmatu, allora truvà u mutivu di i ritardi.
Riturnemu à i nostri pacchetti lenti:
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
Cum'è discutitu prima, questi pacchetti ICMP sò sbulicati in una sola fila RX NIC è processati da un unicu core CPU. Se vulemu capisce cumu funziona Linux, hè utile sapè induve (in quale core CPU) è cumu (softirq, ksoftirqd) sti pacchetti sò processati per seguità u prucessu.
Avà hè u tempu d'utilizà strumenti chì permettenu di monitorà u kernel Linux in tempu reale. Quì avemu usatu
U pianu quì hè simplice: sapemu chì u kernel processa questi ping ICMP, cusì metteremu un ganciu nantu à a funzione kernel. hping3
più altu.
codice icmp_echo
trasmette struct sk_buff *skb
: Questu hè un pacchettu cù una "echo request". Pudemu seguità, tira fora a sequenza echo.sequence
(chì si compara cù icmp_seq
da hping3 выше
), è mandà lu à u spaziu utilizatori. Hè ancu cunvenutu per catturà u nome / id di prucessu attuale. Quì sottu sò i risultati chì vedemu direttamente mentre u kernel processa i pacchetti:
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 775 swapper/0 0 11 776 swapper/0 0 11 777 swapper/0 0 11 778 4512 4542 779 swapper/XNUMX XNUMX XNUMX XNUMX raggi-rapportu-s XNUMX
Si deve esse nutatu quì chì in u cuntestu softirq
I prucessi chì anu fattu e chjama di u sistema appariscenu cum'è "processi" quandu in fattu hè u kernel chì processa in modu sicuru i pacchetti in u cuntestu di u kernel.
Cù stu strumentu pudemu associà prucessi specifichi cù pacchetti specifichi chì mostranu un ritardu di hping3
. Facemu sèmplice grep
nantu à sta cattura per certi valori icmp_seq
. I pacchetti chì currispondenu à i valori icmp_seq sopra sò stati nutati cù u so RTT chì avemu osservatu sopra (in parentesi sò i valori RTT previsti per i pacchetti chì avemu filtratu per via di i valori RTT menu di 50 ms):
TGID PID PROCESS NAME ICMP_SEQ ** RTT -- 10137 10436 cadvisor 1951 10137 10436 cadvisor 1952 76 76 ksoftirqd/11 1953 ** 99ms 76 76 ksoftirqir 11 1954 ksoftirqd/89 76 d /76 11 ** 1955ms 79 76 ksoftirqd/76 11 ** 1956ms 69 76 ksoftirqd/76 11 ** 1957ms 59 76 ksoftirqd/76 11 ** (1958ms) 49 76 ksoftirqd/76 11 ** (1959ms) 39ms) 76/76 ksoftirqd ** 11 ksoftirq d / 1960 29 ** (76ms) 76 11 ksoftirqd/1961 19 ** (76ms) -- 76 11 cadvisor 1962 9 10137 cadvisor 10436 2068 10137 ksoftirqd/10436 **2069 ** 76 76 11 ** 2070 ms 75 76 ksoftirqd/ 76 11 ** 2071ms 65 76 ksoftirqd/76 11 ** (2072ms) 55 76 ksoftirqd/76 11 ** (2073ms) 45 76 ksoftirqd/76 11/2074 **35 76 **softirqd/76 11 ** (2075ms) 25 ms ) 76 76 ksoftirqd/11 2076 ** (15 ms)
I risultati ci dicenu parechje cose. Prima, tutti sti pacchetti sò trattati da u cuntestu ksoftirqd/11
. Questu significa chì per questu paru particulari di machini, i pacchetti ICMP sò stati hashed à core 11 à l'estremità di riceve. Avemu vistu ancu chì ogni volta chì ci hè una cunfittura, ci sò pacchetti chì sò processati in u cuntestu di a chjama di u sistema. cadvisor
. Dopu ksoftirqd
ripiglià u compitu è processa a fila accumulata: esattamente u numeru di pacchetti chì anu accumulatu dopu cadvisor
.
U fattu chì immediatamenti prima sempre travaglia cadvisor
, implica a so implicazione in u prublema. Irnicamenti, u scopu
Cum'è cù l'altri aspetti di i cuntenituri, sò tutti strumenti assai avanzati è ponu esse espertu di prublemi di rendiment in certi circustanze impreviste.
Chì face cadvisor chì rallenta a fila di pacchetti?
Avemu avà una bella cunniscenza di cumu si faci u crash, chì prucessu hè causatu, è nantu à quale CPU. Avemu vistu chì per via di u bloccu duru, u kernel Linux ùn hà micca tempu di pianificà ksoftirqd
. È vedemu chì i pacchetti sò processati in u cuntestu cadvisor
. Hè logicu per suppone chì cadvisor
lancia un syscall lento, dopu chì tutti i pacchetti accumulati in quellu tempu sò processati:
Questa hè una teoria, ma cumu pruvà? Ciò chì pudemu fà hè traccia u core di CPU in tuttu stu prucessu, truvate u puntu induve u numeru di pacchetti supera u budgetu è ksoftirqd hè chjamatu, è dopu guardà un pocu più in daretu per vede ciò chì esattamente era in esecuzione nantu à u core CPU appena prima di quellu puntu. . Hè cum'è una radiografia di u CPU ogni pochi millisecondi. Serà qualcosa cusì:
Convenientemente, tuttu questu pò esse fattu cù l'arnesi esistenti. Per esempiu, 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
Eccu i risultati:
(сотни следов, которые выглядят похожими)
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
Ci hè parechje cose quì, ma u principale hè chì truvamu u mudellu "cadvisor before ksoftirqd" chì avemu vistu prima in u tracciatore ICMP. Cosa significa?
Ogni linea hè una traccia di CPU in un certu puntu in u tempu. Ogni chjama à a pila nantu à una linea hè siparata da un puntu e virgola. À mezu à e linii vedemu u syscall chjamatu: read(): .... ;do_syscall_64;sys_read; ...
. Allora cadvisor passa assai tempu nantu à a chjama di u sistema read()
in relazione cù e funzioni mem_cgroup_*
(top of call stack/end of line).
Hè sconveniente per vede in una traccia di chjama ciò chì esattamente hè lettu, allora corremu strace
è vedemu ciò chì face cadvisor è truvate e chjama di u sistema più longu di 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>
Cum'è puderebbe aspittà, vedemu chjamate lente quì read()
. Da u cuntenutu di l'operazioni di lettura è u cuntestu mem_cgroup
hè chjaru chì sti sfide read()
riferite à u schedariu memory.stat
, chì mostra l'usu di memoria è i limiti di cgroup (a tecnulugia di isolamentu di risorse di Docker). L'uttellu di cadvisor interruga stu schedariu per ottene infurmazione di l'usu di risorse per i cuntenituri. Cuntrollamu s'ellu hè u kernel o cadvisor chì face qualcosa inesperu:
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 ~ $
Avà pudemu ripruduce u bug è capisce chì u kernel Linux face una patologia.
Perchè l'operazione di lettura hè cusì lenta?
À questu stadiu, hè assai più faciule per truvà missaghji da altri utilizatori nantu à prublemi simili. Cum'è hè risultatu, in u cadvisor tracker stu bug hè statu signalatu cum'è
U prublema hè chì i cgroups piglianu in contu l'usu di memoria in u spaziu di nomi (container). Quandu tutti i prucessi in questu cgroup esce, Docker libera u cgroup di memoria. Tuttavia, "memoria" ùn hè micca solu memoria di prucessu. Ancu s'è a memoria di u prucessu stessu ùn hè più utilizata, pare chì u kernel assigna ancu cuntenuti in cache, cum'è dentries è inodes (metadata di repertoriu è file), chì sò in cache in u cgroup di memoria. Da a descrizzione di u prublema:
cgroups zombie: cgroups chì ùn anu micca prucessi è sò stati sguassati, ma anu sempre memoria attribuita (in u mo casu, da a cache di dentry, ma pò ancu esse attribuita da a cache di pagina o tmpfs).
A verificazione di u kernel di tutte e pagine in u cache quandu liberate un cgroup pò esse assai lenta, cusì u prucessu lazy hè sceltu: aspettate finu à chì queste pagine sò richieste di novu, è infine sguassate u cgroup quandu a memoria hè veramente necessariu. Finu à questu puntu, cgroup hè sempre cunsideratu quandu cullighjate statistiche.
Da u puntu di vista di u rendiment, anu sacrificatu a memoria per u rendiment: accelerà a pulizia iniziale lascendu una certa memoria cache. Questu hè bè. Quandu u kernel usa l'ultimu di a memoria in cache, u cgroup hè eventualmente sbulicatu, perchè ùn pò micca esse chjamatu "fuga". Sfurtunatamente, l'implementazione specifica di u mecanismu di ricerca memory.stat
in questa versione di kernel (4.9), cumminata cù l'immensa quantità di memoria in i nostri servitori, significa chì ci vole assai più tempu per restaurà l'ultime dati in cache è sguassate i zombies cgroup.
Risulta chì alcuni di i nostri nodi avianu tanti zombies cgroup chì a lettura è a latenza superavanu un secondu.
A soluzione per u prublema di cadvisor hè di liberà immediatamente i cache di dentries / inodi in tuttu u sistema, chì elimina immediatamente a latenza di lettura è a latenza di a rete in l'ospitu, postu chì sguassate a cache accende e pagine di cgroup zombie in cache è li libera ancu. Questa ùn hè micca una suluzione, ma cunfirma a causa di u prublema.
Hè risultatu chì in e versioni di kernel più recenti (4.19+) u rendimentu di a chjama hè stata migliurata memory.stat
, cusì cambiendu à stu kernel hà risoltu u prublema. À u listessu tempu, avemu avutu strumenti per detectà i nodi problematici in clusters Kubernetes, sguassate cù grazia è riavviate. Avemu pettinatu tutti i clusters, truvamu nodi cù una latenza abbastanza alta è li riavviamu. Questu ci hà datu u tempu per aghjurnà u SO nantu à i servitori rimanenti.
Per sintetizà
Perchè stu bug hà firmatu l'elaborazione di a fila di RX NIC per centinaie di millisecondi, hà causatu simultaneamente una alta latenza in cunnessione curta è una latenza di cunnessione media, cum'è trà e dumande MySQL è i pacchetti di risposta.
Capisce è mantene a prestazione di i sistemi più fundamentali, cum'è Kubernetes, hè critica per l'affidabilità è a rapidità di tutti i servizii basati nantu à elli. Ogni sistema chì eseguite beneficia di i miglioramenti di u rendiment di Kubernetes.
Source: www.habr.com