Debugging latensi jaringan ing Kubernetes

Debugging latensi jaringan ing Kubernetes

Sawetara taun kepungkur Kubernetes wis rembugan ing blog GitHub resmi. Wiwit iku, wis dadi teknologi standar kanggo nyebarake layanan. Kubernetes saiki ngatur bagean penting saka layanan internal lan umum. Nalika kluster saya tambah akeh lan syarat kinerja dadi luwih ketat, kita wiwit ngerti manawa sawetara layanan ing Kubernetes ngalami latensi sing ora bisa diterangake kanthi beban aplikasi kasebut.

Ateges, aplikasi ngalami latensi jaringan sing katon acak nganti 100ms utawa luwih, nyebabake wektu entek utawa nyoba maneh. Layanan samesthine bisa nanggapi panjalukan luwih cepet tinimbang 100ms. Nanging iki ora mungkin yen sambungan kasebut mbutuhake wektu akeh. Kapisah, kita mirsani pitakon MySQL cepet banget sing kudune njupuk milliseconds, lan MySQL rampung ing milliseconds, nanging saka perspektif aplikasi sing njaluk, respon njupuk 100ms utawa luwih.

Iku langsung dadi cetha yen masalah mung dumadi nalika nyambung menyang simpul Kubernetes, sanajan telpon teka saka njaba Kubernetes. Cara paling gampang kanggo ngasilake masalah yaiku ing tes Vegeta, sing mlaku saka host internal apa wae, nguji layanan Kubernetes ing port tartamtu, lan kanthi sporadis ndhaptar latensi dhuwur. Ing artikel iki, kita bakal pirembagan bab carane kita bisa nlacak sabab saka masalah iki.

Ngilangi kerumitan sing ora perlu ing rantai sing nyebabake kegagalan

Kanthi ngasilake conto sing padha, kita pengin mbatesi fokus masalah lan mbusak lapisan kerumitan sing ora perlu. Kaping pisanan, ana akeh banget unsur ing aliran antarane Vegeta lan pods Kubernetes. Kanggo ngenali masalah jaringan sing luwih jero, sampeyan kudu ngilangi sawetara.

Debugging latensi jaringan ing Kubernetes

Klien (Vegeta) nggawe sambungan TCP karo sembarang simpul ing kluster. Kubernetes beroperasi minangka jaringan overlay (ing ndhuwur jaringan pusat data sing wis ana) sing nggunakake IPIP, yaiku, encapsulates paket IP jaringan overlay nang paket IP pusat data. Nalika nyambung menyang simpul pisanan, terjemahan alamat jaringan ditindakake Terjemahan Alamat Jaringan (NAT) stateful kanggo nerjemahake alamat IP lan port simpul Kubernetes menyang alamat IP lan port ing jaringan overlay (khusus, pod karo aplikasi). Kanggo paket sing mlebu, urutan tumindak sing mbalikke ditindakake. Iki minangka sistem sing kompleks kanthi akeh negara lan akeh unsur sing terus dianyari lan diganti nalika layanan disebar lan dipindhah.

Utilitas tcpdump ing tes Vegeta ana wektu tundha sajrone salaman TCP (antarane SYN lan SYN-ACK). Kanggo mbusak kerumitan sing ora perlu iki, sampeyan bisa nggunakake hping3 kanggo "ping" prasaja karo paket SYN. Kita mriksa yen ana wektu tundha ing paket respon, lan banjur ngreset sambungan. Kita bisa nyaring data mung kalebu paket sing luwih gedhe tinimbang 100ms lan entuk cara sing luwih gampang kanggo ngasilake masalah tinimbang tes lapisan jaringan 7 lengkap ing Vegeta. Iki minangka "ping" simpul Kubernetes nggunakake TCP SYN/SYN-ACK ing layanan "port simpul" (30927) kanthi interval 10ms, disaring kanthi respon sing paling alon:

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

Bisa langsung nggawe pengamatan pisanan. Yen dideleng saka nomer urut lan wektu, jelas yen iki dudu kemacetan sepisan. Wektu tundha asring nglumpukake lan pungkasane diproses.

Sabanjure, kita pengin ngerteni komponen apa wae sing bisa nyebabake kemacetan. Mungkin iki sawetara saka atusan aturan iptables ing NAT? Utawa ana masalah karo tunneling IPIP ing jaringan? Salah siji cara kanggo nyoba iki yaiku nguji saben langkah sistem kanthi ngilangi. Apa sing kedadeyan yen sampeyan mbusak logika NAT lan firewall, mung ninggalake bagean IPIP:

Debugging latensi jaringan ing Kubernetes

Untunge, Linux nggampangake ngakses lapisan overlay IP kanthi langsung yen mesin ana ing jaringan sing padha:

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

Dideleng saka asil, masalah isih tetep! Iki ora kalebu iptables lan NAT. Dadi masalah TCP? Ayo ndeleng kepiye ping ICMP biasa:

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

Asil nuduhake yen masalah durung ilang. Mungkin iki trowongan IPIP? Ayo dadi luwih gampang tes:

Debugging latensi jaringan ing Kubernetes

Apa kabeh paket dikirim antarane loro host iki?

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

Kita wis simplified kahanan kanggo loro kelenjar Kubernetes ngirim saben liyane paket sembarang, malah ping ICMP. Dheweke isih ndeleng latensi yen host target "ala" (sawetara luwih elek tinimbang liyane).

Saiki pitakonan pungkasan: kenapa wektu tundha mung ana ing server kube-node? Lan kedadeyan nalika kube-node minangka pangirim utawa panrima? Begjanipun, iki uga cukup gampang kanggo tokoh metu dening ngirim paket saka host njaba Kubernetes, nanging karo padha "dikenal ala" panampa. Nalika sampeyan bisa ndeleng, masalah ora ilang:

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

Kita banjur bakal mbukak panjalukan sing padha saka sumber kube-node sadurunge menyang host eksternal (sing ora kalebu host sumber amarga ping kalebu komponen RX lan 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

Kanthi mriksa panangkepan paket latensi, kita entuk sawetara informasi tambahan. Khusus, sing pangirim (ngisor) ndeleng wektu entek iki, nanging panampa (ndhuwur) ora - ndeleng kolom Delta (ing detik):

Debugging latensi jaringan ing Kubernetes

Kajaba iku, yen katon ing prabédan ing urutan TCP lan ICMP paket (kanthi nomer urutan) ing sisih panampa, paket ICMP tansah teka ing urutan padha dikirim, nanging karo wektu beda. Ing wektu sing padha, paket TCP kadhangkala interleave, lan sawetara sing macet. Ing tartamtu, yen nliti bandar paket SYN, padha supaya ing sisih pangirim, nanging ora ing panrima.

Ana prabédan subtle ing carane kertu jaringan server modern (kaya ing pusat data kita) ngolah paket sing ngemot TCP utawa ICMP. Nalika paket teka, adaptor jaringan "hashes saben sambungan", iku nyoba kanggo break sambungan menyang antrian lan ngirim saben antrian kanggo inti prosesor kapisah. Kanggo TCP, hash iki kalebu alamat lan port IP sumber lan tujuan. Ing tembung liyane, saben sambungan hash (potensial) beda. Kanggo ICMP, mung alamat IP sing di-hash, amarga ora ana port.

Pengamatan anyar liyane: sajrone wektu iki, kita ndeleng tundha ICMP ing kabeh komunikasi antarane rong host, nanging TCP ora. Iki ngandhani yen sababe ana hubungane karo hashing antrian RX: kemacetan meh mesthi ana ing pangolahan paket RX, ora ing ngirim tanggapan.

Iki ngilangake ngirim paket saka dhaptar bisa nimbulaké. Saiki kita ngerti manawa masalah pangolahan paket ana ing sisih nampa ing sawetara server kube-node.

Ngerteni pangolahan paket ing kernel Linux

Kanggo ngerti sebabe masalah kedadeyan ing panrima ing sawetara server kube-node, ayo goleki carane kernel Linux ngolah paket.

Bali menyang implementasine tradisional paling prasaja, kertu jaringan nampa paket lan ngirim ngganggu kernel Linux sing ana paket sing kudu diproses. Kernel mungkasi karya liyane, ngalih konteks menyang handler interrupt, ngolah paket, banjur bali menyang tugas saiki.

Debugging latensi jaringan ing Kubernetes

Ngalih konteks iki alon: latensi bisa uga ora katon ing kertu jaringan 10Mbps ing taun 90-an, nanging ing kertu 10G modern kanthi throughput maksimal 15 yuta paket per detik, saben inti saka server wolung inti cilik bisa diganggu jutaan. kaping per detik.

Supaya ora terus-terusan nangani interupsi, akeh taun kepungkur Linux ditambahake NAPI: Network API sing kabeh driver modern digunakake kanggo nambah kinerja ing kacepetan dhuwur. Ing kacepetan kurang kernel isih nampa interrupts saka kertu jaringan ing cara lawas. Sawise cukup paket teka sing ngluwihi ambang, kernel disables interrupts lan malah wiwit polling adaptor jaringan lan njupuk paket ing chunks. Pangolahan ditindakake ing softirq, yaiku, ing konteks interrupts piranti lunak sawise telpon sistem lan interrupts hardware, nalika kernel (minangka gantos kanggo papan pangguna) wis mlaku.

Debugging latensi jaringan ing Kubernetes

Iki luwih cepet, nanging nyebabake masalah sing beda. Yen ana akeh banget paket, banjur kabeh wektu ngginakaken Processing paket saka kertu jaringan, lan pangolahan papan pangguna ora duwe wektu kanggo bener kosongaké antrian iki (maca saka sambungan TCP, etc.). Pungkasane antrian diisi lan kita miwiti nyelehake paket. Ing upaya kanggo golek imbangan, kernel nyetel budget kanggo jumlah maksimum paket diproses ing konteks softirq. Sawise budget iki ngluwihi, thread kapisah awakened ksoftirqd (sampeyan bakal weruh salah siji saka wong-wong mau ing ps saben inti) sing nangani softirqs iki njaba syscall normal / path interrupt. Utas iki dijadwalake nggunakake panjadwal proses standar, sing nyoba ngalokasi sumber daya kanthi adil.

Debugging latensi jaringan ing Kubernetes

Sawise sinau carane kernel ngolah paket, sampeyan bisa ndeleng manawa ana kemungkinan kemacetan. Yen telpon softirq ditampa kurang asring, paket kudu ngenteni sawetara wektu kanggo diproses ing antrian RX ing kertu jaringan. Iki bisa uga amarga sawetara tugas mblokir inti prosesor, utawa liya sing nyegah inti saka mlaku softirq.

Narrowing Processing mudhun kanggo inti utawa cara

Softirq telat mung guess kanggo saiki. Nanging masuk akal, lan kita ngerti yen kita ndeleng sing meh padha. Dadi langkah sabanjure kanggo konfirmasi teori iki. Lan yen wis dikonfirmasi, banjur golek alesan kanggo telat.

Ayo bali menyang paket alon:

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

Kaya sing wis dirembug sadurunge, paket ICMP iki digayuh dadi antrian RX NIC siji lan diproses dening inti CPU siji. Yen kita pengin ngerti carane Linux dianggo, iku migunani kanggo ngerti ngendi (inti CPU kang) lan carane (softirq, ksoftirqd) paket iki diproses kanggo trek proses.

Saiki wektune nggunakake alat sing ngidini sampeyan ngawasi kernel Linux ing wektu nyata. Kene kita digunakake Bcc. Piranti alat iki ngidini sampeyan nulis program C cilik sing nduwe fungsi sing sewenang-wenang ing kernel lan nahan acara kasebut dadi program Python ruang pangguna sing bisa ngolah lan ngasilake asil kasebut. Hooking fungsi kasepakatan ing kernel punika bisnis angel, nanging sarana dirancang kanggo keamanan maksimum lan dirancang kanggo trek mudhun persis jenis masalah produksi sing ora gampang maleh ing test utawa lingkungan pembangunan.

Rencana ing kene gampang: kita ngerti manawa kernel ngolah ping ICMP iki, mula kita bakal nglebokake fungsi kernel. icmp_echo, sing nampa paket panjalukan gema ICMP sing mlebu lan miwiti ngirim respon gema ICMP. Kita bisa ngenali paket kanthi nambah nomer icmp_seq, kang nuduhake hping3 ing ndhuwur.

Kode skrip bcc katon rumit, nanging ora medeni minangka misale jek. Fungsi icmp_echo ngirim struct sk_buff *skb: Iki paket karo " request gema ". Kita bisa nglacak, narik metu urutane echo.sequence (sing mbandhingake karo icmp_seq dening hping3 выше), lan ngirim menyang ruang panganggo. Iku uga trep kanggo njupuk jeneng proses saiki / id. Ing ngisor iki minangka asil sing bisa dideleng langsung nalika kernel ngolah paket:

TGID PID PROSES NAMA ICMP_SEQ
0 0 swapper / 11
770 0 swapper / 0
11 771 swapper / 0
0 11 swapper / 772
0 0 swapper / 11
773 0 prometheus 0
11 774 swapper / 20041
20086 775 swapper / 0
0 11 swapper / 776
0 0 spokes-laporan-s 11

Sampeyan kudu nyatet kene sing ing konteks softirq pangolahan sing digawe sistem telpon bakal katon minangka "proses" nalika ing kasunyatan iku kernel sing aman ngolah paket ing konteks kernel.

Kanthi alat iki kita bisa digandhengake proses tartamtu karo paket tartamtu sing nuduhake wektu tundha saka hping3. Ayo dadi prasaja grep ing panangkepan iki kanggo nilai tartamtu icmp_seq. Paket sing cocog karo nilai icmp_seq ing ndhuwur diwenehi tandha bebarengan karo RTT sing diamati ing ndhuwur (ing kurung minangka nilai RTT sing dikarepake kanggo paket sing disaring amarga nilai RTT kurang saka 50ms):

TGID PID PROSES 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)

Asil ngandhani sawetara perkara. Kaping pisanan, kabeh paket kasebut diproses kanthi konteks ksoftirqd/11. Iki tegese kanggo pasangan tartamtu saka mesin iki, paket ICMP wis hashed kanggo inti 11 ing mburi nampa. Kita uga weruh manawa ana macet, ana paket sing diproses ing konteks panggilan sistem cadvisor... Banjur ksoftirqd njupuk alih tugas lan ngolah antrian akumulasi: persis nomer paket sing wis nambah sawise cadvisor.

Kasunyatan sing langsung sadurunge tansah bisa cadvisor, nuduhake keterlibatane ing masalah kasebut. Ironis, tujuane cadvisor - "nganalisa panggunaan sumber daya lan karakteristik kinerja saka wadhah mlaku" tinimbang nyebabake masalah kinerja iki.

Kaya karo aspek wadhah liyane, kabeh iki minangka alat sing canggih lan bisa uga bakal nemu masalah kinerja ing sawetara kahanan sing ora dikarepake.

Apa sing ditindakake cadvisor sing nyuda antrian paket?

Saiki kita duwe pangerten sing apik babagan kedadeyan kacilakan, proses apa sing nyebabake, lan CPU apa. Kita weruh yen amarga pamblokiran hard, kernel Linux ora duwe wektu kanggo gawe jadwal ksoftirqd. Lan kita weruh yen paket diproses ing konteks cadvisor. Iku logis kanggo nganggep sing cadvisor ngluncurake syscall alon, sawise kabeh paket sing diklumpukake ing wektu kasebut diproses:

Debugging latensi jaringan ing Kubernetes

Iki minangka teori, nanging kepiye carane nyoba? Apa sing bisa ditindakake yaiku nglacak inti CPU sajrone proses iki, golek titik ing ngendi jumlah paket ngluwihi anggaran lan diarani ksoftirqd, banjur katon luwih cepet maneh kanggo ndeleng apa persis sing mlaku ing inti CPU sadurunge titik kasebut. . Iku kaya x-raying CPU saben sawetara milliseconds. Bakal katon kaya iki:

Debugging latensi jaringan ing Kubernetes

Kanthi gampang, kabeh iki bisa ditindakake kanthi alat sing wis ana. Tuladhane, rekaman perf mriksa inti CPU tartamtu ing frekuensi tartamtu lan bisa generate jadwal telpon kanggo sistem mlaku, kalebu loro papan pangguna lan kernel Linux. Sampeyan bisa njupuk rekaman iki lan ngolah kanthi nggunakake garpu cilik program kasebut FlameGraph saka Brendan Gregg, kang ngreksa urutan tilak tumpukan. Kita bisa nyimpen jejak tumpukan siji-baris saben 1 ms, banjur nyorot lan nyimpen sampel 100 milidetik sadurunge jejak kasebut tekan. 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

Mangkene asile:

(сотни следов, которые выглядят похожими)

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

Ana akeh perkara ing kene, nanging sing paling penting yaiku kita nemokake pola "cadvisor sadurunge ksoftirqd" sing kita deleng sadurunge ing tracer ICMP. Iki artine apa?

Saben baris minangka tilak CPU ing wektu tartamtu. Saben panggilan mudhun tumpukan ing baris dipisahake dening titik koma. Ing tengah garis kita ndeleng syscall diarani: read(): .... ;do_syscall_64;sys_read; .... Dadi cadvisor mbuwang akeh wektu ing telpon sistem read()related kanggo fungsi mem_cgroup_* (ndhuwur tumpukan telpon / mburi baris).

Ora trep kanggo ndeleng ing tilak telpon apa persis sing diwaca, supaya mbukak strace lan ayo ndeleng apa sing ditindakake cadvisor lan golek panggilan sistem luwih saka 100ms:

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>

Kaya sing dikarepake, kita ndeleng telpon alon ing kene read(). Saka isi operasi maca lan konteks mem_cgroup iku cetha sing tantangan iki read() deleng file memory.stat, sing nuduhake panggunaan memori lan watesan cgroup (teknologi isolasi sumber daya Docker). Alat cadvisor takon file iki kanggo njupuk informasi panggunaan sumber daya kanggo wadhah. Ayo priksa manawa kernel utawa cadvisor nindakake perkara sing ora dikarepake:

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 ~ $

Saiki kita bisa ngasilake bug lan ngerti manawa kernel Linux ngadhepi patologi.

Apa operasi maca alon banget?

Ing tahap iki, luwih gampang golek pesen saka pangguna liyane babagan masalah sing padha. Dadi metu, ing tracker cadvisor bug iki kacarita minangka masalah panggunaan CPU sing berlebihan, mung ora ana sing weruh manawa latensi kasebut uga dibayangke kanthi acak ing tumpukan jaringan. Iku pancene ngeweruhi sing cadvisor akeh wektu CPU saka samesthine, nanging iki ora diwenehi akeh wigati, amarga server kita duwe akeh sumber daya CPU, supaya masalah iki ora kasebut kanthi teliti, sinau.

Masalahe yaiku cgroups nganggep panggunaan memori ing ruang jeneng (wadhah). Nalika kabeh pangolahan ing cgroup iki metu, Docker ngeculake cgroup memori. Nanging, "memori" ora mung memori proses. Senajan memori proses dhewe wis ora digunakake maneh, katon yen kernel isih nemtokake isi cached, kayata dentries lan inode (direktori lan file metadata), kang cached ing cgroup memori. Saka katrangan masalah:

zombie cgroups: cgroups sing ora ana pangolahan lan wis dibusak, nanging isih duwe memori diparengake (ing cilik, saka cache dentry, nanging uga bisa diparengake saka cache kaca utawa tmpfs).

Priksa kernel kabeh kaca ing cache nalika mbebasake cgroup bisa dadi alon banget, mula proses kesed dipilih: ngenteni nganti kaca-kaca iki dijaluk maneh, banjur pungkasane mbusak cgroup nalika memori pancen dibutuhake. Nganti titik iki, cgroup isih dianggep nalika ngumpulake statistik.

Saka sudut pandang kinerja, dheweke ngorbanake memori kanggo kinerja: nyepetake pembersihan awal kanthi ninggalake sawetara memori cache. Iki apik. Nalika kernel nggunakake pungkasan saka memori cached, cgroup pungkasanipun ngankat, supaya ora bisa disebut "bocor". Sayange, implementasine tartamtu saka mekanisme panelusuran memory.stat ing versi kernel iki (4.9), digabungake karo jumlah gedhe saka memori ing server kita, tegese iku njupuk luwih maneh kanggo mulihake data cache paling anyar lan mbusak nir cgroup.

Pranyata sawetara kelenjar kita duwe akeh zombie cgroup sing maca lan latensi ngluwihi sedetik.

Solusi kanggo masalah cadvisor yaiku kanthi cepet mbebasake dentries / inodes cache ing saindhenging sistem, sing langsung ngilangi latensi maca uga latensi jaringan ing host, amarga ngresiki cache nguripake kaca zombie cgroup sing di-cache lan uga dibebasake. Iki ora solusi, nanging nandheske sabab saka masalah.

Ternyata ing versi kernel anyar (4.19+) kinerja telpon wis apik memory.stat, dadi ngalih menyang kernel iki ndandani masalah. Ing wektu sing padha, kita duwe alat kanggo ndeteksi simpul masalah ing kluster Kubernetes, nguras kanthi apik lan urip maneh. Kita nyisir kabeh kluster, nemokake simpul kanthi latensi sing cukup dhuwur lan reboot. Iki menehi wektu kanggo nganyari OS ing server sing isih ana.

Kanggo ngringkes

Amarga bug iki mandheg pangolahan antrian RX NIC nganti atusan milidetik, iki uga nyebabake latensi dhuwur ing sambungan cendhak lan latensi sambungan tengah, kayata antarane panjalukan MySQL lan paket respon.

Ngerteni lan njaga kinerja sistem sing paling dhasar, kayata Kubernetes, iku penting kanggo linuwih lan kacepetan kabeh layanan adhedhasar iku. Saben sistem sing sampeyan lakoni entuk manfaat saka peningkatan kinerja Kubernetes.

Source: www.habr.com

Add a comment