Difa chwilod rhwydwaith hwyrni yn Kubernetes

Difa chwilod rhwydwaith hwyrni yn Kubernetes

Ychydig flynyddoedd yn ôl Kubernetes a drafodwyd eisoes ar y blog swyddogol GitHub. Ers hynny, mae wedi dod yn dechnoleg safonol ar gyfer defnyddio gwasanaethau. Mae Kubernetes bellach yn rheoli cyfran sylweddol o wasanaethau mewnol a chyhoeddus. Wrth i'n clystyrau dyfu ac wrth i ofynion perfformiad ddod yn llymach, dechreuom sylwi bod rhai gwasanaethau ar Kubernetes yn achlysurol yn profi hwyrni na ellid ei esbonio gan lwyth y cais ei hun.

Yn y bôn, mae cymwysiadau yn profi hwyrni rhwydwaith ar hap o hyd at 100ms neu fwy, gan arwain at seibiannau neu ailgeisiadau. Roedd disgwyl i wasanaethau allu ymateb i geisiadau yn gynt o lawer na 100ms. Ond mae hyn yn amhosibl os yw'r cysylltiad ei hun yn cymryd cymaint o amser. Ar wahân, gwelsom ymholiadau MySQL cyflym iawn a ddylai gymryd milieiliadau, a chwblhaodd MySQL mewn milieiliadau, ond o safbwynt y cais a oedd yn gofyn, cymerodd yr ymateb 100 ms neu fwy.

Daeth yn amlwg ar unwaith mai dim ond wrth gysylltu â nod Kubernetes y digwyddodd y broblem, hyd yn oed os daeth yr alwad o'r tu allan i Kubernetes. Y ffordd hawsaf o atgynhyrchu'r broblem yw mewn prawf Llysieuyn, sy'n rhedeg o unrhyw westeiwr mewnol, yn profi gwasanaeth Kubernetes ar borthladd penodol, ac yn achlysurol yn cofrestru hwyrni uchel. Yn yr erthygl hon, byddwn yn edrych ar sut y gallem olrhain achos y broblem hon.

Dileu cymhlethdod diangen yn y gadwyn yn arwain at fethiant

Drwy atgynhyrchu'r un enghraifft, roeddem am gyfyngu ffocws y broblem a chael gwared ar haenau diangen o gymhlethdod. I ddechrau, roedd gormod o elfennau yn y llif rhwng Vegeta a'r codennau Kubernetes. I nodi problem ddyfnach rhwydwaith, mae angen i chi ddiystyru rhai ohonynt.

Difa chwilod rhwydwaith hwyrni yn Kubernetes

Mae'r cleient (Vegeta) yn creu cysylltiad TCP ag unrhyw nod yn y clwstwr. Mae Kubernetes yn gweithredu fel rhwydwaith troshaen (ar ben y rhwydwaith canolfan ddata presennol) sy'n defnyddio IPIP, hynny yw, mae'n crynhoi pecynnau IP y rhwydwaith troshaenu y tu mewn i becynnau IP y ganolfan ddata. Wrth gysylltu â'r nod cyntaf, cyflawnir cyfieithu cyfeiriad rhwydwaith Cyfieithu Cyfeiriadau Rhwydwaith (NAT) yn datganol i gyfieithu'r cyfeiriad IP a phorthladd y nod Kubernetes i'r cyfeiriad IP a'r porthladd yn y rhwydwaith troshaen (yn benodol, y pod gyda'r cais). Ar gyfer pecynnau sy'n dod i mewn, perfformir y dilyniant gwrthdro o gamau gweithredu. Mae'n system gymhleth gyda llawer o gyflwr a llawer o elfennau sy'n cael eu diweddaru a'u newid yn gyson wrth i wasanaethau gael eu defnyddio a'u symud.

Cyfleustodau tcpdump yn y prawf Vegeta mae oedi yn ystod ysgwyd llaw TCP (rhwng SYN a SYN-ACK). I gael gwared ar y cymhlethdod diangen hwn, gallwch chi ei ddefnyddio hping3 am “pings” syml gyda phecynnau SYN. Rydym yn gwirio a oes oedi yn y pecyn ymateb, ac yna ailosod y cysylltiad. Gallwn hidlo'r data i gynnwys pecynnau mwy na 100ms yn unig a chael ffordd haws o atgynhyrchu'r broblem na phrawf haen 7 rhwydwaith llawn Vegeta. Dyma “pings” nod Kubernetes gan ddefnyddio TCP SYN/SYN-ACK ar y gwasanaeth “node port” (30927) ar gyfnodau o 10ms, wedi'i hidlo gan yr ymatebion arafaf:

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

Yn gallu gwneud yr arsylwad cyntaf ar unwaith. A barnu yn ôl y dilyniant rhifau ac amseriadau, mae'n amlwg nad yw'r rhain yn dagfeydd un-amser. Mae'r oedi yn aml yn cronni ac yn cael ei brosesu yn y pen draw.

Nesaf, rydym am ddarganfod pa gydrannau a allai fod yn gysylltiedig â thagfeydd. Efallai mai dyma rai o'r cannoedd o reolau iptables yn NAT? Neu a oes unrhyw broblemau gyda thwnelu IPIP ar y rhwydwaith? Un ffordd o wirio hyn yw profi pob cam o'r system trwy ei ddileu. Beth sy'n digwydd os ydych chi'n tynnu NAT a rhesymeg wal dân, gan adael y rhan IPIP yn unig:

Difa chwilod rhwydwaith hwyrni yn Kubernetes

Yn ffodus, mae Linux yn ei gwneud hi'n hawdd cyrchu'r haen troshaen IP yn uniongyrchol os yw'r peiriant ar yr un rhwydwaith:

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 barnu yn ôl y canlyniadau, mae'r broblem yn parhau! Nid yw hyn yn cynnwys iptables a NAT. Felly y broblem yw TCP? Gadewch i ni weld sut mae ping ICMP rheolaidd yn mynd:

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

Mae'r canlyniadau'n dangos nad yw'r broblem wedi diflannu. Efallai mai twnnel IPIP yw hwn? Gadewch i ni symleiddio'r prawf ymhellach:

Difa chwilod rhwydwaith hwyrni yn Kubernetes

A anfonir pob pecyn rhwng y ddau westeiwr hyn?

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

Rydym wedi symleiddio'r sefyllfa i ddau nod Kubernetes anfon unrhyw becyn at ei gilydd, hyd yn oed ping ICMP. Maent yn dal i weld hwyrni os yw'r gwesteiwr targed yn "ddrwg" (rhai yn waeth nag eraill).

Nawr y cwestiwn olaf: pam mai dim ond ar weinyddion kube-node y mae'r oedi yn digwydd? Ac a yw'n digwydd pan mai kube-node yw'r anfonwr neu'r derbynnydd? Yn ffodus, mae hyn hefyd yn eithaf hawdd ei ddarganfod trwy anfon pecyn gan westeiwr y tu allan i Kubernetes, ond gyda'r un derbynnydd “drwg hysbys”. Fel y gwelwch, nid yw'r broblem wedi diflannu:

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

Yna byddwn yn rhedeg yr un ceisiadau o'r ffynhonnell kube-node blaenorol i'r gwesteiwr allanol (sy'n eithrio'r gwesteiwr ffynhonnell gan fod y ping yn cynnwys cydran RX a 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

Trwy archwilio cipio pecynnau hwyrni, cawsom rywfaint o wybodaeth ychwanegol. Yn benodol, bod yr anfonwr (gwaelod) yn gweld y terfyn amser hwn, ond nid yw'r derbynnydd (uchaf) - gweler y golofn Delta (mewn eiliadau):

Difa chwilod rhwydwaith hwyrni yn Kubernetes

Yn ogystal, os edrychwch ar y gwahaniaeth yn nhrefn pecynnau TCP ac ICMP (yn ôl rhifau dilyniant) ar ochr y derbynnydd, mae pecynnau ICMP bob amser yn cyrraedd yn yr un dilyniant ag y cawsant eu hanfon, ond gydag amseriad gwahanol. Ar yr un pryd, mae pecynnau TCP weithiau'n rhyngddalennog, ac mae rhai ohonyn nhw'n mynd yn sownd. Yn benodol, os edrychwch ar borthladdoedd pecynnau SYN, maent mewn trefn ar ochr yr anfonwr, ond nid ar ochr y derbynnydd.

Mae gwahaniaeth cynnil o ran sut cardiau rhwydwaith mae gweinyddwyr modern (fel y rhai yn ein canolfan ddata) yn prosesu pecynnau sy'n cynnwys TCP neu ICMP. Pan fydd pecyn yn cyrraedd, mae'r addasydd rhwydwaith yn "ei hashesu fesul cysylltiad", hynny yw, mae'n ceisio torri'r cysylltiadau yn giwiau ac anfon pob ciw i graidd prosesydd ar wahân. Ar gyfer TCP, mae'r hash hwn yn cynnwys cyfeiriad IP ffynhonnell a chyrchfan a phorthladd. Mewn geiriau eraill, mae pob cysylltiad yn cael ei stwnsio (o bosibl) yn wahanol. Ar gyfer ICMP, dim ond cyfeiriadau IP sy'n cael eu stwnsio, gan nad oes unrhyw borthladdoedd.

Sylw newydd arall: yn ystod y cyfnod hwn gwelwn oedi ICMP ar bob cyfathrebiad rhwng dau westeiwr, ond nid yw TCP yn gwneud hynny. Mae hyn yn dweud wrthym fod yr achos yn debygol o fod yn gysylltiedig â stwnsio ciw RX: mae'r tagfeydd bron yn sicr wrth brosesu pecynnau RX, nid wrth anfon ymatebion.

Mae hyn yn dileu anfon pecynnau o'r rhestr o achosion posibl. Rydym bellach yn gwybod bod y broblem prosesu pecynnau ar yr ochr dderbyn ar rai gweinyddwyr kube-nod.

Deall prosesu pecynnau yn y cnewyllyn Linux

I ddeall pam mae'r broblem yn digwydd yn y derbynnydd ar rai gweinyddwyr nod kube, gadewch i ni edrych ar sut mae cnewyllyn Linux yn prosesu pecynnau.

Gan ddychwelyd i'r gweithredu traddodiadol symlaf, mae'r cerdyn rhwydwaith yn derbyn y pecyn ac yn ei anfon torri ar draws y cnewyllyn Linux bod yna becyn y mae angen ei brosesu. Mae'r cnewyllyn yn atal gwaith arall, yn newid cyd-destun i'r triniwr ymyriad, yn prosesu'r pecyn, ac yna'n dychwelyd i'r tasgau cyfredol.

Difa chwilod rhwydwaith hwyrni yn Kubernetes

Mae'r newid cyd-destun hwn yn araf: efallai na fyddai hwyrni wedi bod yn amlwg ar gardiau rhwydwaith 10Mbps yn y 90au, ond ar gardiau 10G modern gydag uchafswm trwybwn o 15 miliwn o becynnau yr eiliad, gellir torri miliynau ar bob craidd o weinydd wyth craidd bach. o weithiau yr eiliad.

Er mwyn peidio â thrin ymyriadau yn gyson, flynyddoedd lawer yn ôl ychwanegodd Linux NAPI: API Rhwydwaith y mae pob gyrrwr modern yn ei ddefnyddio i wella perfformiad ar gyflymder uchel. Ar gyflymder isel mae'r cnewyllyn yn dal i dderbyn ymyriadau o'r cerdyn rhwydwaith yn yr hen ffordd. Unwaith y bydd digon o becynnau'n cyrraedd sy'n fwy na'r trothwy, mae'r cnewyllyn yn analluogi yn torri ar draws ac yn lle hynny yn dechrau pleidleisio'r addasydd rhwydwaith a chodi pecynnau mewn talpiau. Perfformir prosesu mewn softirq, hynny yw, mewn cyd-destun ymyriadau meddalwedd ar ôl galwadau system a chaledwedd yn torri ar draws, pan fydd y cnewyllyn (yn hytrach na gofod defnyddiwr) eisoes yn rhedeg.

Difa chwilod rhwydwaith hwyrni yn Kubernetes

Mae hyn yn llawer cyflymach, ond mae'n achosi problem wahanol. Os oes gormod o becynnau, yna treulir yr holl amser yn prosesu pecynnau o'r cerdyn rhwydwaith, ac nid oes gan brosesau gofod defnyddwyr amser i wagio'r ciwiau hyn mewn gwirionedd (darllen o gysylltiadau TCP, ac ati). Yn y pen draw mae'r ciwiau'n llenwi ac rydyn ni'n dechrau gollwng pecynnau. Mewn ymgais i ddod o hyd i falans, mae'r cnewyllyn yn gosod cyllideb ar gyfer uchafswm nifer y pecynnau a brosesir yng nghyd-destun softirq. Unwaith y rhagorir ar y gyllideb hon, deffroir llinyn ar wahân ksoftirqd (fe welwch un ohonyn nhw yn ps fesul craidd) sy'n trin y softirqs hyn y tu allan i'r llwybr syscall/ymyrraeth arferol. Mae'r edefyn hwn wedi'i amserlennu gan ddefnyddio'r trefnydd proses safonol, sy'n ceisio dyrannu adnoddau'n deg.

Difa chwilod rhwydwaith hwyrni yn Kubernetes

Ar ôl astudio sut mae'r cnewyllyn yn prosesu pecynnau, gallwch weld bod yna debygolrwydd penodol o dagfeydd. Os derbynnir galwadau softirq yn llai aml, bydd yn rhaid i becynnau aros am beth amser i gael eu prosesu yn y ciw RX ar y cerdyn rhwydwaith. Gall hyn fod oherwydd bod rhywfaint o dasg yn rhwystro craidd y prosesydd, neu fod rhywbeth arall yn atal y craidd rhag rhedeg softirq.

Culhau'r prosesu i lawr i'r craidd neu'r dull

Dim ond dyfalu am y tro yw oedi Softirq. Ond mae'n gwneud synnwyr, ac rydyn ni'n gwybod ein bod ni'n gweld rhywbeth tebyg iawn. Felly y cam nesaf yw cadarnhau'r ddamcaniaeth hon. Ac os caiff ei gadarnhau, yna darganfyddwch y rheswm dros yr oedi.

Gadewch i ni ddychwelyd at ein pecynnau araf:

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

Fel y trafodwyd yn gynharach, mae'r pecynnau ICMP hyn yn cael eu stwnsio i mewn i un ciw RX NIC a'u prosesu gan un craidd CPU. Os ydym am ddeall sut mae Linux yn gweithio, mae'n ddefnyddiol gwybod ble (ar ba graidd CPU) a sut (softirq, ksoftirqd) y caiff y pecynnau hyn eu prosesu er mwyn olrhain y broses.

Nawr mae'n bryd defnyddio offer sy'n eich galluogi i fonitro'r cnewyllyn Linux mewn amser real. Yma rydym yn defnyddio bcc. Mae'r set hon o offer yn eich galluogi i ysgrifennu rhaglenni C bach sy'n bachu swyddogaethau mympwyol yn y cnewyllyn ac yn clustogi'r digwyddiadau i mewn i raglen Python gofod defnyddiwr a all eu prosesu a dychwelyd y canlyniad i chi. Mae bachau ar gyfer swyddogaethau mympwyol yn y cnewyllyn yn fater cymhleth, ond mae'r cyfleustodau wedi'i gynllunio ar gyfer y diogelwch mwyaf ac wedi'i gynllunio i olrhain yn union y math o faterion cynhyrchu nad ydynt yn hawdd eu hatgynhyrchu mewn amgylchedd prawf neu ddatblygu.

Mae'r cynllun yma yn syml: rydym yn gwybod bod y cnewyllyn yn prosesu'r pings ICMP hyn, felly byddwn yn rhoi bachyn ar swyddogaeth y cnewyllyn icmp_echo, sy'n derbyn pecyn cais adlais ICMP sy'n dod i mewn ac yn cychwyn anfon ymateb adlais ICMP. Gallwn adnabod pecyn trwy gynyddu'r rhif icmp_seq, sy'n dangos hping3 uwch.

Cod sgript bcc edrych yn gymhleth, ond nid yw mor frawychus ag y mae'n ymddangos. Swyddogaeth icmp_echo trosglwyddiadau struct sk_buff *skb: Mae hwn yn becyn gyda "cais adlais". Gallwn ei olrhain, tynnu'r dilyniant allan echo.sequence (sy'n cymharu â icmp_seq gan hping3 выше), a'i anfon i ofod defnyddiwr. Mae hefyd yn gyfleus i ddal enw/ID y broses gyfredol. Isod mae'r canlyniadau a welwn yn uniongyrchol tra bod y cnewyllyn yn prosesu pecynnau:

ENW PROSES PID TGID 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 pro swapper/775 0 0 11 swapper/776 0 0 11 swapper per/777 0 0 11 swapper/778 4512 4542 779 spokes-report-s XNUMX

Dylid nodi yma yn y cyd-destun softirq bydd prosesau a wnaeth alwadau system yn ymddangos fel "prosesau" pan mewn gwirionedd y cnewyllyn sy'n prosesu pecynnau'n ddiogel yng nghyd-destun y cnewyllyn.

Gyda'r offeryn hwn gallwn gysylltu prosesau penodol â phecynnau penodol sy'n dangos oedi o hping3. Gadewch i ni ei wneud yn syml grep ar y cipio hwn ar gyfer gwerthoedd penodol icmp_seq. Nodwyd pecynnau sy'n cyfateb i'r gwerthoedd icmp_seq uchod ynghyd â'u RTT a welsom uchod (mewn cromfachau mae'r gwerthoedd RTT disgwyliedig ar gyfer pecynnau y gwnaethom eu hidlo allan oherwydd gwerthoedd RTT llai na 50 ms):

ENW PROSES PID TGID ICMP_SEQ ** RTT -- 10137 10436 cadvisor 1951 10137 10436 cadvisor 1952 76 76 ksoftirqd/11 1953 ** 99ms 76 76 ksoftirqd/11 1954 ksoftirqd/89 76 ksoftirqd/76 11 ksoftirqd/1955 79 ksoftirqd/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 ksoftirqd/2068 10137 ksoftirqd/10436 d/2069 / 76 76 ** (11ms) 2070 75 ksoftirqd/76 76 ** (11ms) -- 2071 65 cadvisor 76 76 11 cadvisor 2072 55 76 ksoftirqd/76 11 2073 ksoftirqd/45 76 76 11 ksoftirqd/2074 35 76 ksoftirqd/76 11 2075 ksoftirqd/25 76 76 ksoftirqd/11 2076 15 ms. 76ms 76 11 ksoftirqd/ 2077 5 ** XNUMXms XNUMX XNUMX ksoftirqd/XNUMX XNUMX ** (XNUMXms) XNUMX XNUMX ksoftirqd/XNUMX XNUMX ** (XNUMXms) XNUMX XNUMX ksoftirqd/XNUMX XNUMX ** (XNUMXmsXNUMX) XNUMX ksoftirqd/XNUMX XNUMX ** (XNUMXms) XNUMX XNUMX ksoftirqd/XNUMX XNUMX ** (XNUMXmsXNUMX) XNUMX XNUMX ksoftirqd/XNUMX XNUMX ** (XNUMXmsXNUMX) XNUMX XNUMX XNUMX ms ) XNUMX XNUMX ksoftirqd/XNUMX XNUMX ** (XNUMXms)

Mae'r canlyniadau'n dweud sawl peth wrthym. Yn gyntaf, mae'r holl becynnau hyn yn cael eu prosesu gan y cyd-destun ksoftirqd/11. Mae hyn yn golygu, ar gyfer y pâr penodol hwn o beiriannau, bod pecynnau ICMP wedi'u stwnsio i graidd 11 ar y pen derbyn. Rydym hefyd yn gweld, pryd bynnag y bydd jam, bod pecynnau sy'n cael eu prosesu yng nghyd-destun yr alwad system cadvisor... Yna ksoftirqd yn cymryd drosodd y dasg ac yn prosesu'r ciw cronedig: union nifer y pecynnau sydd wedi cronni ar ôl hynny cadvisor.

Mae'r ffaith bod yn union cyn ei fod bob amser yn gweithio cadvisor, yn awgrymu ei ran yn y broblem. Yn eironig, y pwrpas cynghorwr - "dadansoddi defnydd adnoddau a nodweddion perfformiad cynwysyddion rhedeg" yn hytrach nag achosi'r mater perfformiad hwn.

Yn yr un modd ag agweddau eraill ar gynwysyddion, mae'r rhain i gyd yn offer hynod ddatblygedig a gellir disgwyl iddynt brofi problemau perfformiad o dan rai amgylchiadau nas rhagwelwyd.

Beth mae cadvisor yn ei wneud sy'n arafu'r ciw paced?

Bellach mae gennym ddealltwriaeth eithaf da o sut mae'r ddamwain yn digwydd, pa broses sy'n ei achosi, ac ar ba CPU. Gwelwn, oherwydd blocio caled, nad oes gan y cnewyllyn Linux amser i amserlennu ksoftirqd. A gwelwn fod pecynnau'n cael eu prosesu yn eu cyd-destun cadvisor. Mae'n rhesymegol tybio hynny cadvisor yn lansio syscall araf, ac ar ôl hynny mae'r holl becynnau a gronnwyd ar y pryd yn cael eu prosesu:

Difa chwilod rhwydwaith hwyrni yn Kubernetes

Theori yw hon, ond sut i'w phrofi? Yr hyn y gallwn ei wneud yw olrhain craidd y CPU trwy gydol y broses hon, darganfyddwch y pwynt lle mae nifer y pecynnau yn mynd dros y gyllideb a gelwir ksoftirqd, ac yna edrychwch ychydig ymhellach yn ôl i weld beth yn union oedd yn rhedeg ar y craidd CPU ychydig cyn y pwynt hwnnw . Mae fel pelydr-x y CPU bob ychydig milieiliadau. Bydd yn edrych rhywbeth fel hyn:

Difa chwilod rhwydwaith hwyrni yn Kubernetes

Yn gyfleus, gellir gwneud hyn i gyd gyda'r offer presennol. Er enghraifft, cofnod perf yn gwirio craidd CPU penodol ar amlder penodol a gall gynhyrchu amserlen o alwadau i'r system redeg, gan gynnwys gofod defnyddiwr a'r cnewyllyn Linux. Gallwch chi gymryd y cofnod hwn a'i brosesu gan ddefnyddio fforc fach o'r rhaglen Fflamgraff gan Brendan Gregg, sy'n cadw trefn yr olion pentwr. Gallwn arbed olion stac un llinell bob 1 ms, ac yna amlygu ac arbed sampl 100 milieiliad cyn i'r olrhain gyrraedd 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

Dyma'r canlyniadau:

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

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

Mae yna lawer o bethau yma, ond y prif beth yw ein bod ni'n dod o hyd i'r patrwm “cadvisor before ksoftirqd” a welsom yn gynharach yn y tracer ICMP. Beth mae'n ei olygu?

Mae pob llinell yn olrhain CPU ar adeg benodol. Mae pob galwad i lawr y pentwr ar linell yn cael ei wahanu gan hanner colon. Yng nghanol y llinellau gwelwn y syscall yn cael ei alw: read(): .... ;do_syscall_64;sys_read; .... Felly mae cadvisor yn treulio llawer o amser ar yr alwad system read()gysylltiedig â swyddogaethau mem_cgroup_* (pen y pentwr galwadau/diwedd y llinell).

Mae'n anghyfleus gweld mewn galwad olrhain beth yn union sy'n cael ei ddarllen, felly gadewch i ni redeg strace a gadewch i ni weld beth mae cadvisor yn ei wneud a dod o hyd i alwadau system sy'n hirach na 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>

Fel y gallech ddisgwyl, rydym yn gweld galwadau araf yma read(). O gynnwys gweithrediadau darllen a chyd-destun mem_cgroup mae'n amlwg bod yr heriau hyn read() cyfeiriwch at y ffeil memory.stat, sy'n dangos defnydd cof a chyfyngiadau cgroup (technoleg ynysu adnoddau Docker). Mae'r offeryn cadvisor yn cwestiynu'r ffeil hon i gael gwybodaeth am ddefnydd adnoddau ar gyfer cynwysyddion. Gadewch i ni wirio a yw'r cnewyllyn neu'r cynghorydd yn gwneud rhywbeth annisgwyl:

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

Nawr gallwn atgynhyrchu'r nam a deall bod cnewyllyn Linux yn wynebu patholeg.

Pam mae'r llawdriniaeth darllen mor araf?

Ar y cam hwn, mae'n llawer haws dod o hyd i negeseuon gan ddefnyddwyr eraill am broblemau tebyg. Fel y digwyddodd, yn y traciwr cadvisor adroddwyd bod y byg hwn problem defnydd gormodol o CPU, 'i' jyst nad oes neb yn sylwi bod y latency hefyd yn cael ei adlewyrchu ar hap yn y pentwr rhwydwaith. Yn wir, sylwyd bod cadvisor yn cymryd mwy o amser CPU na'r disgwyl, ond ni roddwyd llawer o bwysigrwydd i hyn, gan fod gan ein gweinyddwyr lawer o adnoddau CPU, felly ni astudiwyd y broblem yn ofalus.

Y broblem yw bod cgroups yn ystyried defnydd cof o fewn y gofod enw (cynhwysydd). Pan fydd yr holl brosesau yn yr allanfa cgroup hwn, mae Docker yn rhyddhau'r cgroup cof. Fodd bynnag, nid cof proses yn unig yw "cof". Er nad yw'r cof proses ei hun yn cael ei ddefnyddio mwyach, mae'n ymddangos bod y cnewyllyn yn dal i aseinio cynnwys wedi'i storio, megis dannedd gosod ac inodes (metadata cyfeiriadur a ffeil), sy'n cael eu storio yn y cgroup cof. O'r disgrifiad o'r broblem:

cgroups zombie: cgroups nad oes ganddynt unrhyw brosesau ac sydd wedi'u dileu, ond sy'n dal i gael cof wedi'i ddyrannu (yn fy achos i, o'r storfa ddeintyddol, ond gellir ei ddyrannu hefyd o storfa'r dudalen neu tmpfs).

Gall gwiriad y cnewyllyn o'r holl dudalennau yn y storfa wrth ryddhau cgroup fod yn araf iawn, felly dewisir y broses ddiog: arhoswch nes gofynnir am y tudalennau hyn eto, ac yna cliriwch y cgroup o'r diwedd pan fydd gwir angen y cof. Hyd at y pwynt hwn, mae cgroup yn dal i gael ei ystyried wrth gasglu ystadegau.

O safbwynt perfformiad, fe wnaethant aberthu cof ar gyfer perfformiad: gan gyflymu'r glanhau cychwynnol trwy adael rhywfaint o gof wedi'i storio ar ôl. Mae hyn yn iawn. Pan fydd y cnewyllyn yn defnyddio'r olaf o'r cof wedi'i storio, caiff y cgroup ei glirio yn y pen draw, felly ni ellir ei alw'n "gollyngiad". Yn anffodus, mae gweithrediad penodol y mecanwaith chwilio memory.stat yn y fersiwn cnewyllyn hwn (4.9), ynghyd â'r swm enfawr o gof ar ein gweinyddwyr, yn golygu ei bod yn cymryd llawer mwy o amser i adfer y data cached diweddaraf a chlirio zombies cgroup.

Mae'n ymddangos bod gan rai o'n nodau gymaint o zombies cgroup nes bod y darlleniad a'r hwyrni yn fwy nag eiliad.

Y datrysiad ar gyfer problem cadvisor yw rhyddhau celciau dannedd gosod / inod ar unwaith ledled y system, sy'n dileu hwyrni darllen yn ogystal â hwyrni rhwydwaith ar y gwesteiwr, gan fod clirio'r storfa'n troi'r tudalennau cgroup zombie sydd wedi'u storio ymlaen ac yn eu rhyddhau hefyd. Nid yw hyn yn ateb, ond mae'n cadarnhau achos y broblem.

Daeth i'r amlwg bod perfformiad galwadau wedi gwella mewn fersiynau cnewyllyn mwy newydd (4.19+). memory.stat, felly roedd newid i'r cnewyllyn hwn yn datrys y broblem. Ar yr un pryd, roedd gennym offer i ganfod nodau problemus mewn clystyrau Kubernetes, eu draenio'n osgeiddig a'u hailgychwyn. Fe wnaethon ni gribo'r holl glystyrau, dod o hyd i nodau â hwyrni digon uchel a'u hailgychwyn. Rhoddodd hyn amser i ni ddiweddaru'r OS ar weddill y gweinyddwyr.

Crynhoi

Oherwydd bod y nam hwn wedi atal prosesu ciw RX NIC am gannoedd o filieiliadau, roedd ar yr un pryd yn achosi hwyrni uchel ar gysylltiadau byr a hwyrni cysylltiad canol, megis rhwng ceisiadau MySQL a phecynnau ymateb.

Mae deall a chynnal perfformiad y systemau mwyaf sylfaenol, fel Kubernetes, yn hanfodol i ddibynadwyedd a chyflymder yr holl wasanaethau sy'n seiliedig arnynt. Mae pob system rydych chi'n ei rhedeg yn elwa o welliannau perfformiad Kubernetes.

Ffynhonnell: hab.com

Ychwanegu sylw