Debugging Netzwierk latency a Kubernetes

Debugging Netzwierk latency a Kubernetes

Virun e puer Joer Kubernetes schonn diskutéiert op den offiziellen GitHub Blog. Zënterhier ass et d'Standardtechnologie ginn fir Servicer z'installéieren. Kubernetes geréiert elo e groussen Deel vun internen an ëffentleche Servicer. Wéi eis Cluster gewuess sinn an d'Leeschtungsfuerderunge méi streng ginn, hu mir ugefaang ze bemierken datt verschidde Servicer op Kubernetes sporadesch latency erliewen, déi net duerch d'Laascht vun der Applikatioun selwer erkläert kënne ginn.

Wesentlech erliewen Uwendungen anscheinend zoufälleg Netzwierklatenz vu bis zu 100ms oder méi, wat zu Timeouts oder Neiverspriechen resultéiert. D'Servicer goufen erwaart datt se vill méi séier wéi 100ms op Ufroe reagéiere kënnen. Awer dëst ass onméiglech wann d'Verbindung selwer esou vill Zäit hëlt. Separat hu mir ganz séier MySQL Ufroen observéiert déi Millisekonnen sollten daueren, a MySQL huet a Millisekonnen fäerdeg gemaach, awer aus der Perspektiv vun der Ufro Uwendung huet d'Äntwert 100ms oder méi gedauert.

Et gouf direkt kloer datt de Problem nëmme geschitt ass wann Dir mat engem Kubernetes Node verbënnt, och wann den Uruff vu baussen Kubernetes koum. Deen einfachste Wee fir de Problem ze reproduzéieren ass an engem Test Vegeta, deen aus all internen Host leeft, testt de Kubernetes Service op engem spezifeschen Hafen a registréiert sporadesch héich latency. An dësem Artikel wäerte mir kucken wéi mir d'Ursaach vun dësem Problem konnten verfollegen.

Eliminatioun vun onnéideg Komplexitéit an der Kette féiert zu Echec

Andeems mir datselwecht Beispill reproduzéieren, wollte mir de Fokus vum Problem schmuel an onnéideg Schichten vu Komplexitéit ewechhuelen. Am Ufank waren et ze vill Elementer am Floss tëscht Vegeta an de Kubernetes Pods. Fir e méi déif Netzwierkproblem z'identifizéieren, musst Dir e puer vun hinnen ausschléissen.

Debugging Netzwierk latency a Kubernetes

De Client (Vegeta) erstellt eng TCP Verbindung mat all Node am Cluster. Kubernetes fonctionnéiert als Iwwerlagernetz (op Top vum existente Datenzenternetz) dat benotzt IPIP, dat heescht, et encapsuléiert d'IP-Pakete vum Overlay-Netz an den IP-Pakete vum Rechenzentrum. Wann Dir un den éischte Node verbënnt, gëtt d'Netzadresseiwwersetzung duerchgefouert Network Adress Iwwersetzung (NAT) statesch fir d'IP Adress an den Hafen vum Kubernetes Node op d'IP Adress an den Hafen am Overlay Netzwierk ze iwwersetzen (speziell de Pod mat der Applikatioun). Fir erakommen Pakete gëtt déi ëmgedréint Sequenz vun Aktiounen ausgefouert. Et ass e komplexe System mat vill Staat a vill Elementer déi dauernd aktualiséiert a geännert ginn wéi d'Servicer ofgebaut a geréckelt ginn.

Utility tcpdump am Vegeta Test gëtt et eng Verzögerung während dem TCP Handshake (tëscht SYN an SYN-ACK). Fir dës onnéideg Komplexitéit ze läschen, kënnt Dir benotzen hping3 fir einfach "Pings" mat SYN Pakete. Mir kontrolléieren ob et eng Verspéidung am Äntwertpaket ass, an dann d'Verbindung zrécksetzen. Mir kënnen d'Donnéeën filteren fir nëmme Pakete méi grouss wéi 100ms ze enthalen an e méi einfache Wee fir de Problem ze reproduzéieren wéi de komplette Netzwierk Layer 7 Test zu Vegeta. Hei sinn de Kubernetes Node "pings" mat TCP SYN / SYN-ACK am Service "Node port" (30927) mat 10ms Intervalle, gefiltert duerch luesst Äntwerten:

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

Kann direkt déi éischt Observatioun maachen. No de Sequenznummeren an Timing ze beurteelen, ass et kloer datt dëst keng eemoleg Stau sinn. D'Verzögerung accumuléiert dacks a gëtt schlussendlech veraarbecht.

Als nächst wëlle mir erausfannen, wéi eng Komponenten am Optriede vu Stau involvéiert sinn. Vläicht sinn dës e puer vun den honnerte vun iptables Regelen am NAT? Oder ginn et Probleemer mat IPIP Tunneling am Netz? Ee Wee fir dëst ze testen ass all Schrëtt vum System ze testen andeems se se eliminéiert. Wat geschitt wann Dir NAT a Firewall Logik läscht, nëmmen den IPIP Deel léisst:

Debugging Netzwierk latency a Kubernetes

Glécklecherweis mécht Linux et einfach Zougang zu der IP-Iwwerlagerschicht direkt wann d'Maschinn am selwechte Netz ass:

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

No de Resultater beurteelen, bleift de Problem nach ëmmer! Dëst ausgeschloss iptables an NAT. Also ass de Problem TCP? Loosst eis kucken wéi e reegelméissegen ICMP Ping geet:

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

D'Resultater weisen datt de Problem net fort ass. Vläicht ass dëst en IPIP Tunnel? Loosst eis den Test weider vereinfachen:

Debugging Netzwierk latency a Kubernetes

Sinn all Päck tëscht dësen zwee Hosten geschéckt?

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

Mir hunn d'Situatioun op zwee Kubernetes Noden vereinfacht, déi géigesäiteg all Paket schécken, och en ICMP Ping. Si gesinn nach ëmmer Latenz wann den Zilhost "schlecht" ass (e puer méi schlëmm wéi anerer).

Elo déi lescht Fro: Firwat geschitt d'Verzögerung nëmmen op Kube-Node Serveren? A geschitt et wann de Kube-Node de Sender oder den Empfänger ass? Glécklecherweis ass dëst och ganz einfach erauszefannen andeems Dir e Paket vun engem Host ausserhalb vu Kubernetes schéckt, awer mam selwechte "bekannte schlechten" Empfänger. Wéi Dir gesitt, ass de Problem net verschwonnen:

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

Mir lafen dann déiselwecht Ufroe vum fréiere Quell Kube-Node op den externen Host (wat de Quellhost ausgeschloss ass, well de Ping souwuel e RX wéi och TX Komponent enthält):

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

Duerch d'Untersuchung vun latency Packet Captures hu mir e puer zousätzlech Informatioun kritt. Speziell, datt de Sender (ënnen) dësen Timeout gesäit, awer den Empfänger (uewen) net - kuckt d'Delta Kolonn (a Sekonnen):

Debugging Netzwierk latency a Kubernetes

Zousätzlech, wann Dir den Ënnerscheed an der Uerdnung vun TCP- an ICMP-Päckchen kuckt (duerch Sequenznummeren) op der Empfängersäit, kommen ICMP-Päckchen ëmmer an der selwechter Sequenz an där se geschéckt goufen, awer mat engem aneren Timing. Zur selwechter Zäit interleave TCP Pakete heiansdo, an e puer vun hinnen hänke fest. Besonnesch, wann Dir d'Ports vu SYN Pakete ënnersicht, sinn se op der Säit vum Sender an der Rei, awer net op der Säit vum Empfänger.

Et gëtt e subtilen Ënnerscheed am wéi Reseau Kaarte modern Serveren (wéi déi an eisem Rechenzentrum) veraarbecht Pakete mat TCP oder ICMP. Wann e Paket ukomm ass, "hasht den Netzadapter et pro Verbindung", dat heescht, et probéiert d'Verbindungen an d'Schlaangen ze briechen an all Schlaang an e separaten Prozessorkär ze schécken. Fir TCP enthält dësen Hash souwuel d'Quell an d'Destinatioun IP Adress an den Hafen. An anere Wierder, all Verbindung ass hashed (potentiel) anescht. Fir ICMP ginn nëmmen IP Adressen hashed, well et keng Ports gëtt.

Eng aner nei Observatioun: während dëser Period gesi mir ICMP Verspéidungen op all Kommunikatioun tëscht zwee Hosten, awer TCP net. Dëst seet eis datt d'Ursaach méiglecherweis mam RX Queue hashing verbonnen ass: de Stau ass bal sécher an der Veraarbechtung vu RX Paketen, net an der Sendung vun Äntwerten.

Dëst eliminéiert d'Sendung vu Pakete vun der Lëscht vu méiglechen Ursaachen. Mir wëssen elo datt de Paketveraarbechtungsproblem op der Empfangssäit op e puer Kube-Node Server ass.

Paketveraarbechtung am Linux Kernel verstoen

Fir ze verstoen firwat de Problem am Empfänger op e puer Kube-Node Serveren geschitt, kucke mer wéi de Linux Kernel Pakete veraarbecht.

Zréck op déi einfachst traditionell Ëmsetzung, kritt d'Netzkaart de Paket a schéckt ënnerbrach de Linux Kernel datt et e Package gëtt dee muss veraarbecht ginn. De Kernel stoppt aner Aarbecht, wiesselt de Kontext op den Ënnerbriechungshandler, veraarbecht de Paket, an geet dann zréck op déi aktuell Aufgaben.

Debugging Netzwierk latency a Kubernetes

Dëse Kontextwiessel ass lues: Latenz wier vläicht net bemierkbar op 10Mbps Netzwierkkaarten an den 90er, awer op modernen 10G Kaarte mat engem maximalen Duerchgang vu 15 Millioune Pakete pro Sekonn, kann all Kär vun engem klengen Aacht-Kär Server Millioune ënnerbrach ginn vun Mol pro Sekonn.

Fir net stänneg Ënnerbriechungen ze handhaben, huet viru ville Joer Linux derbäigesat NAPI: Network API déi all modern Chauffeuren benotze fir d'Performance bei héijer Geschwindegkeet ze verbesseren. Bei nidderegen Geschwindegkeete kritt de Kernel nach ëmmer Ënnerbriechungen vun der Netzwierkkaart op déi al Manéier. Wann genuch Pakete kommen, déi d'Schwell iwwerschreiden, deaktivéiert de Kärel Ënnerbriechungen an amplaz fänkt un den Netzwierkadapter ze pollen an Päckchen a Stécker opzehuelen. D'Veraarbechtung gëtt a Softirq gemaach, dat heescht, an Kontext vun Software Ënnerbriechungen no System Appellen an Hardware Ënnerbriechungen, wann de Kärel (am Géigesaz zu Benotzer Raum) scho leeft.

Debugging Netzwierk latency a Kubernetes

Dëst ass vill méi séier, awer verursaacht en anere Problem. Wann et ze vill Pakete sinn, da gëtt all d'Zäit verbraucht fir Pakete vun der Netzwierkkaart ze veraarbecht, an d'Benotzerraumprozesser hunn keng Zäit fir dës Schlaangen tatsächlech eidel ze maachen (liesen vun TCP Verbindungen, etc.). Schlussendlech füllen d'Schlaangen op a mir fänken un Päckchen ze falen. An engem Versuch e Gläichgewiicht ze fannen, setzt de Kernel e Budget fir déi maximal Unzuel u Päck, déi am softirq Kontext veraarbecht ginn. Wann dëse Budget iwwerschratt ass, gëtt e separate Fuedem erwächt ksoftirqd (Dir gesitt ee vun hinnen an ps pro Kär) déi dës Softirqs ausserhalb vum normale Syscall / Ënnerbriechungswee handhabt. Dëse Fuedem ass geplangt mat dem Standardprozess Scheduler, dee probéiert Ressourcen gerecht ze verdeelen.

Debugging Netzwierk latency a Kubernetes

Nodeems Dir studéiert hutt wéi de Kernel Pakete veraarbecht, kënnt Dir gesinn datt et eng gewësse Wahrscheinlechkeet vu Stau ass. Wann softirq Uriff manner dacks opgeholl ginn, musse Pakete fir eng Zäit waarden fir an der RX-Schlaang op der Netzwierkkaart veraarbecht ze ginn. Dëst kann wéinst enger Aufgab sinn déi de Prozessorkär blockéiert, oder soss eppes verhënnert datt de Kär softirq leeft.

Verréngert d'Veraarbechtung op de Kär oder Method

Softirq Verspéidungen si just eng Erklärung fir de Moment. Awer et mécht Sënn, a mir wëssen datt mir eppes ganz ähnlech gesinn. Also de nächste Schrëtt ass dës Theorie ze bestätegen. A wann et bestätegt ass, da fannt Dir de Grond fir d'Verspéidungen.

Komme mer zréck op eis lues Päck:

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

Wéi virdru diskutéiert ginn, ginn dës ICMP Päckchen an eng eenzeg RX NIC Schlaang gehashed a vun engem eenzegen CPU Kär veraarbecht. Wa mir wëllen verstoen wéi Linux funktionnéiert, ass et nëtzlech ze wëssen wou (op wéi engem CPU Kär) a wéi (softirq, ksoftirqd) dës Packagen veraarbecht ginn fir de Prozess ze verfolgen.

Elo ass et Zäit Tools ze benotzen déi Iech erlaben de Linux Kernel an Echtzäit ze iwwerwaachen. Hei hu mir benotzt BCC. Dëse Set vun Tools erlaabt Iech kleng C Programmer ze schreiwen, déi arbiträr Funktiounen am Kärel ukoppelen an d'Evenementer an e User-Raum Python Programm bufferen, deen se veraarbecht kann an d'Resultat un Iech zréckginn. Hooking arbiträr Funktiounen am Kärel ass e komplizéiert Geschäft, awer den Utility ass fir maximal Sécherheet entworf an ass entwéckelt fir genau d'Aart vu Produktiounsprobleemer ze verfolgen déi net einfach an engem Test- oder Entwécklungsëmfeld reproduzéiert ginn.

De Plang hei ass einfach: mir wëssen datt de Kernel dës ICMP Pings veraarbecht, sou datt mir en Hook op d'Kernelfunktioun setzen icmp_echo, deen en erakommende ICMP Echo Ufro Paket akzeptéiert an initiéiert eng ICMP Echo Äntwert ze schécken. Mir kënnen e Paket identifizéieren andeems d'icmp_seq Nummer eropgeet, wat weist hping3 méi héich.

Code bcc skript gesäit komplizéiert aus, awer et ass net sou grujeleg wéi et schéngt. Funktioun icmp_echo vermëttelt struct sk_buff *skb: Dëst ass e Paket mat enger "Echo Ufro". Mir kënnen et verfollegen, d'Sequenz erauszéien echo.sequence (wat vergläicht mat icmp_seq vum hp3 выше), a schéckt et an de Benotzerraum. Et ass och bequem den aktuelle Prozessnumm / ID z'erfëllen. Drënner sinn d'Resultater déi mir direkt gesinn wärend de Kernel Pakete veraarbecht:

TGID PID PROCESS NUMM 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 Spriecherbericht-S 11

Et soll hei feststellen, datt am Kontext softirq Prozesser déi Systemruffe gemaach hunn, erschéngen als "Prozesser" wann et tatsächlech de Kär ass dee sécher Päckchen am Kontext vum Kernel veraarbecht.

Mat dësem Tool kënne mir spezifesch Prozesser mat spezifesche Packagen associéieren, déi e Verzögerung vun weisen hping3. Loosst eis et einfach maachen grep op dëser Erfaassung fir bestëmmte Wäerter icmp_seq. Pakete, déi den uewe genannte icmp_seq Wäerter passen, goufen zesumme mat hirem RTT markéiert, dee mir hei uewen observéiert hunn (an Klammeren sinn déi erwaart RTT Wäerter fir Pakete, déi mir ausgefiltréiert hunn wéinst RTT Wäerter manner wéi 50ms):

TGID PID PROCESS NUMM 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)

D'Resultater soen eis verschidde Saachen. Als éischt ginn all dës Packagen vum Kontext veraarbecht ksoftirqd/11. Dëst bedeit datt fir dëst bestëmmte Pair vu Maschinnen ICMP Päckchen op de Kär 11 um Empfangsend gehat goufen. Mir gesinn och datt wann et e Stau ass, et Pakete sinn déi am Kontext vum Systemruff veraarbecht ginn cadvisorAn. Dunn ksoftirqd iwwerhëlt d'Aufgab a veraarbecht der cumuléierten Schlaang: genee d'Zuel vun de Päckchen, déi duerno gesammelt ass cadvisor.

D'Tatsaach, datt direkt virun et ëmmer Wierker cadvisor, implizéiert seng Bedeelegung un de Problem. Ironescherweis den Zweck cadvisor - "Ressourceverbrauch an d'Leeschtungscharakteristike vu Lafen Container analyséieren" anstatt dëst Leeschtungsprobleem ze verursaachen.

Wéi mat aneren Aspekter vu Container, sinn dës all héich fortgeschratt Tools a kënne erwaart ginn datt se Performanceprobleemer ënner e puer onerwaarten Ëmstänn erliewen.

Wat mécht Cadvisor dat d'Packetschlaang verlangsamt?

Mir hunn elo e relativ gutt Verständnis wéi de Crash geschitt, wat de Prozess et verursaacht, a wéi eng CPU. Mir gesinn datt wéinst haarder Blockéierung de Linux Kernel keng Zäit huet fir ze plangen ksoftirqd. A mir gesinn datt Päckchen am Kontext veraarbecht ginn cadvisor. Et ass logesch dat unzehuelen cadvisor lancéiert e luesen Syscall, no deem all Pakete, déi zu där Zäit accumuléiert sinn, veraarbecht ginn:

Debugging Netzwierk latency a Kubernetes

Dëst ass eng Theorie, awer wéi testen ech se? Wat mir maache kënnen ass den CPU Kär duerch dëse Prozess ze verfolgen, de Punkt ze fannen wou d'Zuel vun de Pakete iwwer de Budget geet an ksoftirqd genannt gëtt, a kuckt dann e bësse méi wäit zréck fir ze kucken wat genau um CPU Kär war just viru deem Punkt . Et ass wéi d'CPU all puer Millisekonnen Röntgenstrahlen. Et wäert sou eppes ausgesinn:

Debugging Netzwierk latency a Kubernetes

Gemittlech kann dat alles mat existéierende Tools gemaach ginn. Zum Beispill, perf Rekord iwwerpréift e bestëmmte CPU Kär op enger spezifizéierter Frequenz a kann en Zäitplang vun Uruff un de lafende System generéieren, dorënner de Benotzerraum an de Linux Kernel. Dir kënnt dëse Rekord huelen an et veraarbecht mat enger klenger Gabel vum Programm FlameGraph vum Brendan Gregg, déi d'Uerdnung vun der Stack Spuer erhaalen. Mir kënnen eenzel-Linn Stack Spure späicheren all 1 ms, an dann Highlight a späicheren eng Prouf 100 Millisekonnen ier d'Spuer Hits 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

Hei d'Resultater:

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

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

Et gi vill Saachen hei, awer den Haapt Saach ass datt mir de "cadvisor virun ksoftirqd" Muster fannen, dee mir virdru am ICMP Tracer gesinn hunn. Wat heescht dat?

All Linn ass eng CPU Spuer op engem spezifeschen Zäitpunkt. All Uruff de Stack op enger Linn erof ass vun engem Semikolon getrennt. An der Mëtt vun de Linnen gesi mir de Syscall genannt: read(): .... ;do_syscall_64;sys_read; .... Sou verbréngt Cadvisor vill Zäit op de System Uruff read()Zesummenhang mat Funktiounen mem_cgroup_* (Uewen vum Uruff Stack / Enn vun der Linn).

Et ass onbequem an engem Uruff Trace ze gesinn wat genee gelies gëtt, also loosst eis lafen strace a loosst eis kucken wat de Cadvisor mécht a Systemruffe méi laang wéi 100ms fannen:

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>

Wéi Dir vläicht erwaart, gesi mir lues Uruff hei read(). Vun den Inhalter vun liesen Operatiounen a Kontext mem_cgroup et ass kloer, datt dës Erausfuerderungen read() kuckt op de Fichier memory.stat, wat d'Erënnerungsverbrauch an d'Cgroup Limiten weist (Docker Ressource Isolatioun Technologie). De Cadvisor-Tool freet dës Datei fir Ressourceverbrauchsinformatioune fir Container ze kréien. Loosst eis kucken ob et de Kernel oder de Cadvisor ass wat eppes onerwaart mécht:

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

Elo kënne mir de Feeler reproduzéieren a verstoen datt de Linux Kernel mat enger Pathologie steet.

Firwat ass d'Liesoperatioun sou lues?

Op dëser Etapp ass et vill méi einfach Messagen vun anere Benotzer iwwer ähnlech Problemer ze fannen. Wéi et sech erausstellt, am Cadvisor Tracker gouf dëse Feeler gemellt als Problem vun exzessive CPU Notzung, et ass just datt keen gemierkt huet datt d'Latenz och zoufälleg am Netzstack reflektéiert gëtt. Et gouf tatsächlech gemierkt datt Cadvisor méi CPU Zäit verbraucht wéi erwaart, awer dëst gouf net vill Bedeitung kritt, well eis Serveren vill CPU Ressourcen hunn, sou datt de Problem net suergfälteg studéiert gouf.

De Problem ass datt cgroups d'Erënnerungsverbrauch am Nummraum (Container) berücksichtegen. Wann all Prozesser an dëser cgroup erausgoen, verëffentlecht Docker d'Erënnerung cgroup. Wéi och ëmmer, "Erënnerung" ass net nëmmen Prozess Erënnerung. Och wann d'Prozess Memory selwer net méi benotzt gëtt, schéngt et datt de Kernel nach ëmmer cachéiert Inhalter zouginn, wéi Zänn an Inoden (Verzeechnes a Datei Metadaten), déi an der Erënnerung cgroup cache sinn. Vun der Problembeschreiwung:

Zombie cgroups: cgroups datt keng Prozesser hunn a geläscht ginn, mee nach Erënnerung zougewisen hunn (a mengem Fall, aus der Zänn Cache, mä et kann och aus der Säit Cache oder tmpfs zougewisen ginn).

De Kärel seng Iwwerpréiwung vun all de Säiten am Cache beim Befreiung vun enger cgroup ka ganz lues sinn, sou datt de faulen Prozess gewielt gëtt: waart bis dës Säiten erëm gefrot ginn, an dann endlech d'cgroup läschen wann d'Erënnerung tatsächlech gebraucht gëtt. Bis zu dësem Zäitpunkt gëtt cgroup nach ëmmer berücksichtegt wann Dir Statistiken sammelt.

Aus engem Leeschtungssiicht hunn se d'Erënnerung fir d'Leeschtung geaffert: déi initial Botzen beschleunegen andeems se e puer cachéiert Erënnerung hannerloossen. Dëst ass gutt. Wann de Kernel déi lescht vun der cachéierter Erënnerung benotzt, gëtt d'cgroup schlussendlech geläscht, sou datt et net e "Leak" genannt ka ginn. Leider, déi spezifesch Ëmsetzung vun der Sich Mechanismus memory.stat an dëser Kernel Versioun (4.9), kombinéiert mat der enorm Quantitéit vun Erënnerung op eise Serveren, heescht, datt et vill méi dauert fir déi lescht cached Donnéeën ze restauréieren an cgroup Zombien läschen.

Et stellt sech eraus datt e puer vun eisen Noden sou vill cgroup Zombien haten datt d'Liesen an d'Latenz eng Sekonn iwwerschratt hunn.

D'Léisung fir de Cadvisor Thema ass fir direkt Zänn / Inoden Cache am ganze System ze befreien, wat direkt d'Lieslatenz wéi och d'Netzlatenz um Host eliminéiert, well d'Cache läschen dréit déi cache cgroup Zombie Säiten op a si sinn och befreit. Dëst ass keng Léisung, awer et bestätegt d'Ursaach vum Problem.

Et huet sech erausgestallt datt an méi neie Kärversioune (4.19+) d'Uruffleistung verbessert gouf memory.stat, also de Wiessel op dëse Kernel fixéiert de Problem. Zur selwechter Zäit hate mir Tools fir problematesch Noden a Kubernetes Cluster z'entdecken, se graziéis ze drainéieren an se nei ze starten. Mir hunn all d'Cluster gekämmt, Wirbelen mat héich genuch latency fonnt an se nei gestart. Dëst huet eis Zäit fir den OS op de verbleiwen Serveren ze aktualiséieren.

Zesummefaassung

Well dëse Feeler d'RX NIC Queue Veraarbechtung fir Honnerte vu Millisekonnen gestoppt huet, huet et gläichzäiteg eng héich Latenz op kuerze Verbindungen a Mid-Connection latency verursaacht, sou wéi tëscht MySQL Ufroen an Äntwertpakete.

D'Performance vun de fundamentalste Systemer ze verstoen an z'erhalen, wéi Kubernetes, ass kritesch fir d'Zouverlässegkeet an d'Geschwindegkeet vun alle Servicer baséiert op hinnen. All System deen Dir leeft profitéiert vu Kubernetes Performance Verbesserungen.

Source: will.com

Setzt e Commentaire