Duela urte pare bat Kubernetes
Funtsean, aplikazioek ausazko sareko latentzia izaten dute 100 ms edo gehiagoko latentzia, eta ondorioz denbora-muga edo berriro saiakerak izaten dira. Zerbitzuek eskaerei 100 ms baino askoz azkarrago erantzuteko gai izango zirela espero zen. Baina hori ezinezkoa da konexioak berak hainbeste denbora hartzen badu. Bereiz, milisegundo hartu behar zuten MySQL kontsulta oso azkarrak ikusi genituen, eta MySQLk milisegundotan osatu zuen, baina eskaera egiten duen aplikazioaren ikuspegitik, erantzunak 100 ms edo gehiago behar zituen.
Berehala argi geratu zen arazoa Kubernetes nodo batera konektatzean bakarrik gertatzen zela, nahiz eta deia Kubernetes kanpotik etorri. Arazoa erreproduzitzeko modurik errazena proba batean da
Porrota eragiten duen katean beharrezkoa ez den konplexutasuna ezabatzea
Adibide bera erreproduzituz, arazoaren fokua murriztu eta beharrezkoak ez diren konplexutasun geruzak kendu nahi izan ditugu. Hasieran, elementu gehiegi zeuden Vegeta eta Kubernetes lekaren arteko fluxuan. Sare-arazo sakonagoa identifikatzeko, horietako batzuk baztertu behar dituzu.
Bezeroak (Vegeta) TCP konexio bat sortzen du klusterreko edozein nodorekin. Kubernetes-ek erabiltzen duen gainjartze-sare gisa funtzionatzen du (lehendik dagoen datu-zentroen sarearen gainean).
Erabilgarritasuna tcpdump
Vegeta proban atzerapen bat dago TCP esku-ematean (SYN eta SYN-ACK artean). Alferrikako konplexutasun hori kentzeko, erabil dezakezu hping3
SYN paketeekin "ping" soiletarako. Erantzun paketean atzerapenik dagoen egiaztatzen dugu, eta gero konexioa berrezarri. Datuak iragazi ditzakegu 100 ms baino handiagoak diren paketeak soilik sartzeko eta Vegetaren sare-geruza osoa 7 proba baino arazoa erreproduzitzeko modu errazagoa lortzeko. Hona hemen Kubernetes nodoaren "ping-ak" TCP SYN/SYN-ACK erabiliz zerbitzuko "nodo ataka" (30927) 10 ms-ko tarteetan, erantzun motelenek iragazita:
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
Lehen behaketa berehala egin dezake. Sekuentzia-zenbakiak eta denborak ikusita, argi dago ez direla behin-behineko pilaketak. Atzerapena askotan metatzen da eta azkenean prozesatu egiten da.
Jarraian, pilaketak agertzean zein osagai izan daitezkeen jakin nahi dugu. Agian hauek dira NATeko iptables-en ehunka arauetako batzuk? Edo arazorik al dago sarean IPIP tunelarekin? Hau egiaztatzeko modu bat sistemaren urrats bakoitza probatzea da, ezabatuz. Zer gertatzen da NAT eta suebaki logika kentzen badituzu, IPIP zatia bakarrik utziz:
Zorionez, Linuxek IP gainjarri geruza zuzenean sartzea errazten du makina sare berean badago:
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
Emaitzak ikusita, arazoak jarraitzen du oraindik! Honek iptables eta NAT baztertzen ditu. Beraz, arazoa TCP al da? Ikus dezagun ICMP ping arrunta nola doan:
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
Emaitzek erakusten dute arazoa ez dela desagertu. Agian hau IPIP tunel bat da? Sinplifikatu dezagun proba gehiago:
Bi ostalari hauen artean bidaltzen al dira pakete guztiak?
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
Egoera sinplifikatu dugu Kuberneteseko bi nodotara, edozein pakete elkarri bidaliz, baita ICMP ping bat ere. Oraindik latentzia ikusten dute xede-ostalaria "txarra" bada (batzuk besteak baino okerragoak).
Orain azken galdera: zergatik gertatzen da atzerapena kube-node zerbitzarietan soilik? Eta gertatzen al da kube-node igorlea edo hartzailea denean? Zorionez, hori ere nahiko erraza da Kubernetes-etik kanpoko ostalari batetik pakete bat bidaliz, baina hartzaile "txar ezaguna" berarekin. Ikus dezakezunez, arazoa ez da desagertu:
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
Ondoren, aurreko kube-node iturburutik kanpoko ostalarira eskaera berdinak exekutatuko ditugu (iturburuko ostalaria baztertzen duena, ping-ak RX eta TX osagaiak barne hartzen dituelako):
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
Latentzia-paketeen harrapaketa aztertuta, informazio gehigarri bat lortu dugu. Zehazki, igorleak (behean) denbora-muga hori ikusten duela, baina hartzaileak (goian) ez duela - Delta zutabea ikusten du (segundotan):
Horrez gain, hartzailearen aldean TCP eta ICMP paketeen ordenaren (sekuentzia-zenbakien arabera) desberdintasuna ikusten baduzu, ICMP paketeak beti bidali ziren sekuentzia berean iristen dira, baina denbora ezberdinarekin. Aldi berean, TCP paketeak tartekatzen dira batzuetan, eta horietako batzuk trabatu egiten dira. Bereziki, SYN paketeen atakak aztertzen badituzu, ordenatuta daude igorlearen aldean, baina ez hartzailearen aldean.
Ezberdintasun sotil bat dago nola
Beste behaketa berri bat: aldi honetan ICMP atzerapenak ikusten ditugu bi ostalarien arteko komunikazio guztietan, baina TCPk ez. Honek esaten digu kausa RX ilararen hashingarekin erlazionatuta dagoela: pilaketak RX paketeen prozesamenduan dago ia ziur, ez erantzunak bidaltzean.
Honek kausa posibleen zerrendatik paketeak bidaltzea ezabatzen du. Orain badakigu paketeen prozesatzeko arazoa kube-node zerbitzari batzuetan jasotzeko aldean dagoela.
Linux nukleoan paketeen prozesamendua ulertzea
Kube-node zerbitzari batzuetako hargailuan arazoa zergatik gertatzen den ulertzeko, ikus dezagun nola prozesatzen dituen Linux nukleoak paketeak.
Inplementazio tradizional errazenera itzuliz, sare-txartelak paketea jasotzen du eta bidaltzen du
Testuinguru aldaketa hau motela da: baliteke latentzia ez izatea 10eko hamarkadan 90 Mbps sareko txarteletan nabaritzea, baina segundoko 10 milioi pakete gehienez 15 milioi pakete duten XNUMXG txartel modernoetan, zortzi nukleoko zerbitzari txiki baten nukleo bakoitza milioika eten daiteke. segundoko aldiz.
Etenaldiak etengabe kudeatzeko, duela urte asko Linux gehitu zuen
Hau askoz azkarragoa da, baina beste arazo bat eragiten du. Pakete gehiegi badira, denbora guztia sare-txarteletik paketeak prozesatzen igarotzen da, eta erabiltzaile-espazio-prozesuek ez dute ilara horiek benetan husteko denborarik (TCP konexioetatik irakurtzen, etab.). Azkenean ilarak betetzen dira eta paketeak jaisten hasten gara. Oreka aurkitu nahian, nukleoak aurrekontua ezartzen du softirq testuinguruan prozesatutako pakete kopuru maximorako. Aurrekontu hori gaindituta, aparteko hari bat pizten da ksoftirqd
(Horietako bat ikusiko duzu ps
nukleo bakoitzeko) softirq hauek kudeatzen dituen syscall/eten bide arruntetik kanpo. Hari hau prozesuen programatzaile estandarra erabiliz programatzen da, baliabideak modu egokian esleitzen saiatzen dena.
Nukleoak paketeak nola prozesatzen dituen aztertuta, pilaketak izateko probabilitate jakin bat dagoela ikus dezakezu. Softirq deiak maizago jasotzen badira, paketeak denbora pixka bat itxaron beharko dute sare-txarteleko RX ilaran prozesatzeko. Baliteke prozesadorearen nukleoa blokeatzen duen atazaren batek edo beste zerbaitek nukleoak softirq exekutatzeko eragozten duelako.
Prozesamendua muinera edo metodora murriztea
Softirq-en atzerapenak asmakizun bat besterik ez dira oraingoz. Baina zentzuzkoa da, eta badakigu oso antzeko zerbait ikusten ari garela. Beraz, hurrengo urratsa teoria hau berrestea da. Eta baieztatzen bada, aurkitu atzerapenen arrazoia.
Itzuli gaitezen gure pakete geldoetara:
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
Lehenago esan bezala, ICMP pakete hauek RX NIC ilara bakarrean sartzen dira eta CPU nukleo bakar batek prozesatzen ditu. Linux-ek nola funtzionatzen duen ulertu nahi badugu, pakete hauek non (zein CPU nukleotan) eta nola (softirq, ksoftirqd) prozesatzen diren jakitea komeni da prozesuaren jarraipena egiteko.
Orain denbora errealean Linux nukleoa kontrolatzeko aukera ematen duten tresnak erabiltzeko garaia da. Hemen erabili dugu
Hemen plana erraza da: badakigu nukleoak ICMP ping hauek prozesatzen dituela, beraz, nukleoaren funtzioari amu bat jarriko diogu. hping3
handiagorik.
Code icmp_echo
transmititzen du struct sk_buff *skb
: "oihartzun eskaera" duen pakete bat da. Jarraitu dezakegu, sekuentzia atera echo.sequence
(ekin alderatzen duena icmp_seq
hping3-ren eskutik Π²ΡΡΠ΅
), eta bidali erabiltzailearen espaziora. Erosoa da uneko prozesuaren izena/id harrapatzea ere. Hona hemen nukleoak paketeak prozesatzen dituen bitartean zuzenean ikusten ditugun emaitzak:
TGID PID PROZESUA IZENA 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 swapper/775 0 0 11 swapper/776 0 0 11 swapper 777 0 0 11 trukatu/778 4512 4542 779 erradio-txostena XNUMX
Kontuan izan behar da hemen testuinguruan softirq
sistema-deiak egin zituzten prozesuak "prozesu" gisa agertuko dira, kernelaren testuinguruan paketeak segurtasunez prozesatzen dituen nukleoa denean.
Tresna honekin prozesu zehatzak atzerapena erakusten duten pakete zehatzekin lotu ditzakegu hping3
. Egin dezagun erraza grep
balio jakin batzuen harrapaketa honen gainean icmp_seq
. Goiko icmp_seq balioekin bat datozen paketeak goian ikusi ditugun RTTrekin batera adierazi dira (parentesi artean 50 ms baino gutxiagoko RTT balioengatik iragazi ditugun paketeetarako espero diren RTT balioak daude):
TGID PID PROZESUA IZENA ICMP_SEQ ** RTT -- 10137 10436 cadvisor 1951 10137 10436 cadvisor 1952 76 76 ksoftirqd/11 1953 ** 99ms 76 76 ksoftir 11 1954 ksoftir 89 76 ksoftirqd/76 11 ir qd/1955 79 ** 76ms 76 11 ksoftirqd/ 1956 69 ** 76ms 76 11 ksoftirqd/1957 59 ** 76ms 76 11 ksoftirqd/1958 49 ** (76ms) 76 11 ksoftirqd/1959 39 ** (76ms 76 11 ksoftirqd/1960 29 ** (76ms) 76 11 ksoftirqd/1961 19 ** (76ms 76/11) **1962qd 9 10137 ksoft irqd/ 10436 2068 ** (10137ms) 10436 2069 ksoftirqd/76 76 ** (11ms) -- 2070 75 cadvisor 76 76 11 cadvisor 2071 65 76 ksoftir 76/11 ksoftir 2072 55 ksoftir irqd/76 76 ** 11ms 2073 45 ksoftirqd/ 76 76 ** 11ms 2074 35 ksoftirqd/76 76 ** (11ms) 2075 25 ksoftirqd/76 76 ** (11ms) 2076 15 ksoftirqd/76 76/11 **2077 5 ksoftirqd/XNUMX XNUMX ** (XNUMX ms) ** (XNUMX ms ) XNUMX XNUMX ksoftirqd/XNUMX XNUMX ** (XNUMX ms)
Emaitzek hainbat gauza esaten dizkigute. Lehenik eta behin, pakete horiek guztiak testuinguruaren arabera prozesatzen dira ksoftirqd/11
. Horrek esan nahi du makina pare zehatz honetarako, ICMP paketeak 11 nukleoan haztatu zirela hartzailearen amaieran. Era berean, ikusten dugu jam bat dagoen bakoitzean sistema-deiaren testuinguruan prozesatzen diren paketeak daudela. cadvisor
. Ondoren ksoftirqd
zeregina hartzen du eta metatutako ilara prozesatzen du: zehatz-mehatz pilatutako pakete kopurua ondoren cadvisor
.
Izan ere, berehala aurretik beti funtzionatzen duela cadvisor
, bere arazoan parte hartzea dakar. Ironikoki, helburua
Edukiontzien beste alderdi batzuekin gertatzen den bezala, tresna oso aurreratuak dira eta errendimendu arazoak izango dituztela espero daiteke ezusteko egoera batzuetan.
Zer egiten du cadvisor-ek pakete-ilara moteltzen duenik?
Orain nahiko ondo ulertzen dugu kraskadura nola gertatzen den, zer prozesu eragiten duen eta zein CPUtan. Blokeo gogorra dela eta, Linux nukleoak ez duela programatzeko denborarik ikusten dugu ksoftirqd
. Eta paketeak testuinguruan prozesatzen direla ikusten dugu cadvisor
. Logikoa da hori suposatzea cadvisor
syscall motela abiarazten du, eta, ondoren, une horretan pilatutako pakete guztiak prozesatzen dira:
Hau teoria bat da, baina nola probatu? Egin dezakeguna da prozesu honetan zehar PUZaren nukleoa trazatzea, pakete kopurua aurrekontua gainditzen duen eta ksoftirqd deitzen den puntua aurkitzea eta, gero, atzera pixka bat atzera begiratu, puntu hori baino lehen PUZaren nukleoan zer exekutatzen ari zen ikusteko. . PUZa milisegundo batzuetan X izpiak egitea bezalakoa da. Honelako itxura izango du:
Eroso, hori guztia lehendik dauden tresnekin egin daiteke. Adibidez, 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
Hona hemen emaitzak:
(ΡΠΎΡΠ½ΠΈ ΡΠ»Π΅Π΄ΠΎΠ², ΠΊΠΎΡΠΎΡΡΠ΅ Π²ΡΠ³Π»ΡΠ΄ΡΡ ΠΏΠΎΡ
ΠΎΠΆΠΈΠΌΠΈ)
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
Hemen gauza asko daude, baina gauza nagusia da "cadvisor aurretik ksoftirqd" eredua aurkitzen dugula lehenago ICMP trazatzailean. Zer esan nahi du?
Lerro bakoitza PUZaren arrastoa da une jakin batean. Lerro bateko pilatik beherako dei bakoitza puntu eta komaz bereizten da. Lerroen erdian syscall izenekoa ikusten dugu: read(): .... ;do_syscall_64;sys_read; ...
. Beraz, cadvisor-ek denbora asko ematen du sistema-deian read()
funtzioekin lotutakoak mem_cgroup_*
(deien pilaren goiko/lerroaren amaiera).
Deserosoa da dei-arlo batean zer irakurtzen den zehazki ikustea, beraz, korrika egin dezagun strace
eta ikus ditzagun cadvisor-ek zer egiten duen eta aurki ditzagun 100 ms baino luzeagoak diren sistema-deiak:
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>
Espero zenuten bezala, dei motelak ikusten ditugu hemen read()
. Irakurketa eragiketen edukietatik eta testuingurutik mem_cgroup
argi dago erronka horiek read()
fitxategira jo memory.stat
, memoriaren erabilera eta cgroup mugak erakusten dituena (Dockerren baliabideak isolatzeko teknologia). Cadvisor tresnak fitxategi hau kontsultatzen du edukiontzietarako baliabideen erabilerari buruzko informazioa lortzeko. Egiaztatu dezagun nukleoa edo cadvisor den ustekabeko zerbait egiten ari den:
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 ~ $
Orain akatsa erreproduzitu dezakegu eta Linux nukleoa patologia baten aurrean dagoela uler dezakegu.
Zergatik da hain motela irakurtzeko eragiketa?
Fase honetan, askoz errazagoa da antzeko arazoei buruzko beste erabiltzaileen mezuak aurkitzea. Gertatu zenez, cadvisor tracker-en akats hau honela jakinarazi zen
Arazoa da cgroups-ek izen-eremuaren (edukiontzi) barruan dagoen memoriaren erabilera kontuan hartzen duela. Cgroup honetako prozesu guztiak irteten direnean, Docker-ek memoria cgroup askatzen du. Hala ere, "memoria" ez da prozesu memoria soilik. Prozesu-memoria bera jada erabiltzen ez den arren, badirudi nukleoak oraindik ere cache-ko edukiak esleitzen dituela, hala nola dentries eta inodeak (direktorio eta fitxategi metadatuak), memoriaren cgroup-ean gordetzen direnak. Arazoaren deskribapenetik:
zonbi cgroups: prozesurik ez duten eta ezabatu diren cgroups, baina oraindik memoria esleituta daukatenak (nire kasuan, dentry cachetik, baina orrialdeko cachetik edo tmpfs-tik ere esleitu daiteke).
Cgroup bat askatzean nukleoaren cacheko orrialde guztien egiaztapena oso motela izan daiteke, beraz, prozesu alferra aukeratzen da: itxaron orrialde hauek berriro eskatu arte, eta, azkenik, garbitu cgroup memoria benetan behar denean. Une honetara arte, cgroup oraindik ere kontuan hartzen da estatistikak biltzeko orduan.
Errendimenduaren ikuspuntutik, memoria sakrifikatu zuten errendimendurako: hasierako garbiketa bizkortu, cacheko memoriaren bat atzean utzita. Hau ondo dago. Nukleoak cache-ko memoriaren azkena erabiltzen duenean, azkenean cgroup garbitzen da, beraz, ezin zaio "filtrazio" deitu. Zoritxarrez, bilaketa-mekanismoaren ezarpen zehatza memory.stat
nukleoaren bertsio honetan (4.9), gure zerbitzarietako memoria kopuru handiarekin konbinatuta, askoz ere denbora gehiago behar da cacheko azken datuak berreskuratzeko eta cgroup zonbiak garbitzeko.
Ematen du gure nodo batzuek hainbeste cgroup zonbi zituztela irakurketa eta latentzia segundo bat gainditzen zutela.
Cadvisor arazoaren konponbidea sistema osoan dentries/inodoen cacheak berehala askatzea da, eta horrek berehala ezabatzen du irakurketa latentzia eta sarearen latentzia ostalarian, cachea garbitzeak cacheko zonbi cgroup orrialdeak pizten ditu eta haiek ere askatzen baititu. Hau ez da irtenbide bat, baina arazoaren kausa baieztatzen du.
Kernel bertsio berriagoetan (4.19+) deien errendimendua hobetu zen memory.stat
, beraz, nukleo honetara aldatzeak arazoa konpondu du. Aldi berean, Kubernetes klusterretan nodo problematikoak detektatzeko tresnak genituen, dotorez hustu eta berrabiarazi. Kluster guztiak orraztu, nahikoa latentzia handiko nodoak aurkitu eta berrabiarazi genituen. Horrek denbora eman zigun gainerako zerbitzarietan OS eguneratzeko.
Laburbilduz
Akats honek RX NIC ilararen prozesamendua ehunka milisegundotan geldiarazi zuenez, aldi berean latentzia handia eragin zuen konexio laburretan eta konexio erdiko latentzia, esate baterako, MySQL eskaeren eta erantzun-paketeen artean.
Sistema oinarrizkoenen errendimendua ulertzea eta mantentzea, hala nola Kubernetes, funtsezkoa da horietan oinarritutako zerbitzu guztien fidagarritasuna eta abiadura lortzeko. Exekutatzen dituzun sistema bakoitzak Kubernetesen errendimenduaren hobekuntzak lortzen ditu.
Iturria: www.habr.com