මීට වසර කිහිපයකට පෙර කුබර්නෙටස්
අත්යවශ්යයෙන්ම, යෙදුම් 100ms හෝ ඊට වඩා වැඩි අහඹු ලෙස ජාල ප්රමාදයක් අත්විඳින අතර, එහි ප්රතිඵලයක් ලෙස කල් ඉකුත්වීම් හෝ නැවත උත්සාහ කිරීම් සිදු වේ. 100ms ට වඩා වේගයෙන් ඉල්ලීම් වලට ප්රතිචාර දැක්වීමට සේවාවන් බලාපොරොත්තු විය. නමුත් සම්බන්ධතාවයට බොහෝ කාලයක් ගත වුවහොත් මෙය කළ නොහැක. වෙන වෙනම, අපි මිලි තත්පර ගත යුතු ඉතා වේගවත් MySQL විමසුම් නිරීක්ෂණය කළ අතර, MySQL මිලි තත්පර වලින් සම්පූර්ණ විය, නමුත් ඉල්ලුම් කරන යෙදුමේ දෘෂ්ටිකෝණයෙන්, ප්රතිචාරය 100ms හෝ ඊට වැඩි කාලයක් ගත විය.
ඇමතුම Kubernetes පිටතින් පැමිණියද, ගැටළුව ඇතිවූයේ Kubernetes node එකක් වෙත සම්බන්ධ කිරීමේදී පමණක් බව වහාම පැහැදිලි විය. ගැටලුව ප්රතිනිෂ්පාදනය කිරීමට පහසුම ක්රමය වන්නේ පරීක්ෂණයකි
අසාර්ථක වීමට තුඩු දෙන දාමයේ අනවශ්ය සංකීර්ණත්වය ඉවත් කිරීම
එකම උදාහරණය ප්රතිනිෂ්පාදනය කිරීමෙන්, අපට අවශ්ය වූයේ ගැටලුවේ අවධානය පටු කිරීමට සහ අනවශ්ය සංකීර්ණ ස්ථර ඉවත් කිරීමට ය. මුලදී, Vegeta සහ Kubernetes කරල් අතර ප්රවාහයේ බොහෝ මූලද්රව්ය තිබුණි. ගැඹුරු ජාල ගැටළුවක් හඳුනා ගැනීම සඳහා, ඔබ ඒවායින් සමහරක් බැහැර කළ යුතුය.
සේවාලාභියා (Vegeta) පොකුරේ ඕනෑම නෝඩයක් සමඟ TCP සම්බන්ධතාවයක් නිර්මාණය කරයි. Kubernetes භාවිතා කරන (පවත්නා දත්ත මධ්යස්ථාන ජාලයට ඉහලින්) උඩැතිරි ජාලයක් ලෙස ක්රියා කරයි
උපයෝගීතාව tcpdump
Vegeta පරීක්ෂණයේදී TCP අතට අත දීමේදී ප්රමාදයක් ඇත (SYN සහ SYN-ACK අතර). මෙම අනවශ්ය සංකීර්ණත්වය ඉවත් කිරීම සඳහා, ඔබට භාවිතා කළ හැකිය hping3
SYN පැකට් සහිත සරල "pings" සඳහා. ප්රතිචාර පැකට්ටුවේ ප්රමාදයක් තිබේදැයි අපි පරීක්ෂා කර, පසුව සම්බන්ධතාවය නැවත සකසන්න. අපට දත්ත පෙරීමට හැක්කේ 100ms ට වඩා විශාල පැකට් පමණක් ඇතුළත් කිරීමට සහ Vegeta හි සම්පූර්ණ ජාල ස්ථරය 7 පරීක්ෂණයට වඩා ගැටලුව ප්රතිනිෂ්පාදනය කිරීමට පහසු ක්රමයක් ලබා ගැනීමටය. මෙන්න කුබර්නෙටේස් නෝඩ් "පිං" TCP SYN/SYN-ACK භාවිතා කරමින් "node port" (30927) සේවාව මත 10ms පරතරයකින්, මන්දගාමී ප්රතිචාර වලින් පෙරා ඇත:
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
වහාම පළමු නිරීක්ෂණය කළ හැකිය. අනුක්රමික සංඛ්යා සහ වේලාවන් අනුව විනිශ්චය කිරීම, මේවා එකවර තදබදයක් නොවන බව පැහැදිලිය. ප්රමාදය බොහෝ විට සමුච්චය වන අතර අවසානයේ සකසනු ලැබේ.
මීලඟට, තදබදය ඇතිවීම සඳහා සම්බන්ධ විය හැකි සංරචක මොනවාදැයි සොයා බැලීමට අපට අවශ්යය. සමහර විට මේවා NAT හි iptables නීති සිය ගණනකින් සමහරක් විය හැකිද? නැතහොත් ජාලයේ IPIP උමං මාර්ග සමඟ ගැටළු තිබේද? මෙය පරීක්ෂා කිරීමට එක් ක්රමයක් නම් පද්ධතියේ සෑම පියවරක්ම එය ඉවත් කිරීමෙන් පරීක්ෂා කිරීමයි. ඔබ NAT සහ ෆයර්වෝල් තර්කය ඉවත් කර IPIP කොටස පමණක් ඉතිරි කළහොත් කුමක් සිදුවේද?
වාසනාවකට මෙන්, යන්ත්රය එකම ජාලයක තිබේ නම් ලිනක්ස් IP ආවරණ ස්ථරයට කෙලින්ම ප්රවේශ වීම පහසු කරයි:
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
ප්රතිඵල අනුව විනිශ්චය කිරීම, ගැටලුව තවමත් පවතී! මෙය iptables සහ NAT බැහැර කරයි. ඉතින් ගැටලුව TCP ද? සාමාන්ය ICMP ping එකක් යන්නේ කෙසේදැයි බලමු:
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
ප්රතිඵලවලින් පෙනී යන්නේ ගැටලුව පහව ගොස් නැති බවයි. සමහර විට මෙය IPIP උමං මාර්ගයක්ද? පරීක්ෂණය තවදුරටත් සරල කරමු:
සියලුම පැකට් මෙම ධාරක දෙක අතර යවා තිබේද?
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
අපි කුබර්නෙටස් නෝඩ් දෙකකට ඕනෑම පැකට්ටුවක්, ICMP පිං එකක් පවා යවන තත්වයට සරල කළෙමු. ඉලක්ක ධාරකය "නරක" (සමහර අනෙක් ඒවාට වඩා නරක) නම් ඔවුන් තවමත් ප්රමාදය දකියි.
දැන් අවසාන ප්රශ්නය: ප්රමාදය kube-node servers වල පමණක් සිදුවන්නේ ඇයි? kube-node යවන්නා හෝ ලබන්නා වූ විට එය සිදුවේද? වාසනාවකට මෙන්, මෙය Kubernetes වෙතින් පිටත සත්කාරකයකුගෙන් පැකට්ටුවක් යැවීමෙන්, නමුත් එම "දන්නා නරක" ලබන්නා සමඟම පහසුවෙන් සොයා ගත හැක. ඔබට පෙනෙන පරිදි, ගැටළුව අතුරුදහන් වී නැත:
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
ඉන්පසුව අපි පෙර මූලාශ්ර kube-node වෙතින් එකම ඉල්ලීම් බාහිර ධාරකය වෙත ක්රියාත්මක කරන්නෙමු (පිං හි RX සහ 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
ප්රමාද පැකට් ග්රහණය කිරීම් පරීක්ෂා කිරීමෙන්, අපි අමතර තොරතුරු කිහිපයක් ලබා ගත්තෙමු. විශේෂයෙන්, යවන්නා (පහළ) මෙම කල් ඉකුත්වීම දකින නමුත්, ලබන්නා (ඉහළ) නොදකින බව - ඩෙල්ටා තීරුව බලන්න (තත්පරවලින්):
මීට අමතරව, ලබන්නාගේ පැත්තේ ඇති TCP සහ ICMP පැකට් (අනුක්රමික අංක අනුව) අනුපිළිවෙලෙහි වෙනස දෙස බැලුවහොත්, ICMP පැකට් සෑම විටම ඒවා යවන ලද අනුපිළිවෙලේම, නමුත් විවිධ කාල නිර්ණයන් සමඟ පැමිණේ. ඒ අතරම, TCP පැකට් සමහර විට අන්තර් සම්බන්ධිත වන අතර සමහර ඒවා සිරවී ඇත. විශේෂයෙන්, ඔබ SYN පැකට් වල වරායන් පරීක්ෂා කරන්නේ නම්, ඒවා යවන්නාගේ පැත්තේ පිළිවෙලට ඇත, නමුත් ග්රාහකයාගේ පැත්තේ නොවේ.
කෙසේද යන්නෙහි සියුම් වෙනසක් ඇත
තවත් නව නිරීක්ෂණයක්: මෙම කාලසීමාව තුළ ධාරක දෙකක් අතර ඇති සියලුම සන්නිවේදනයන්හි ICMP ප්රමාදයන් අපට පෙනේ, නමුත් TCP එසේ නොවේ. මෙය අපට පවසන්නේ හේතුව RX පෝලිම් හැෂිං හා සම්බන්ධ විය හැකි බවයි: තදබදය නිසැකවම RX පැකට් සැකසීමේදී මිස ප්රතිචාර යැවීමේදී නොවේ.
මෙය සිදුවිය හැකි හේතු ලැයිස්තුවෙන් පැකට් යැවීම ඉවත් කරයි. සමහර kube-node servers වල පැකට් සැකසීමේ ගැටලුව ලැබෙන පැත්තේ බව අපි දැන් දනිමු.
ලිනක්ස් කර්නලයේ පැකට් සැකසුම් තේරුම් ගැනීම
සමහර kube-node සේවාදායකයන්හි ග්රාහකයේ ගැටලුව ඇතිවන්නේ මන්දැයි තේරුම් ගැනීමට, Linux කර්නලය පැකට් සකසන ආකාරය බලමු.
සරලම සාම්ප්රදායික ක්රියාත්මක කිරීම වෙත ආපසු යාම, ජාල කාඩ්පත පැකට්ටුව ලබාගෙන යවයි
මෙම සන්දර්භය මාරුවීම මන්දගාමී වේ: 10 ගණන්වල 90Mbps ජාල කාඩ්පත්වල ප්රමාදය සැලකිය නොහැකි විය හැකි නමුත්, තත්පරයකට පැකට් මිලියන 10 ක උපරිම ප්රතිදානයක් සහිත නවීන 15G කාඩ්පත් මත, කුඩා අට-core සේවාදායකයක සෑම හරයකටම මිලියන ගණනක් බාධා කළ හැකිය. තත්පරයට වාර ගණන.
බාධා කිරීම් නිරන්තරයෙන් හසුරුවා නොගැනීම සඳහා, වසර ගණනාවකට පෙර Linux එකතු කරන ලදී
මෙය වඩා වේගවත්, නමුත් වෙනත් ගැටළුවක් ඇති කරයි. බොහෝ පැකට් තිබේ නම්, ජාල කාඩ්පතෙන් පැකට් සැකසීමට මුළු කාලයම වැය වන අතර, පරිශීලක අවකාශ ක්රියාවලීන්ට මෙම පෝලිම් ඇත්ත වශයෙන්ම හිස් කිරීමට කාලය නොමැත (TCP සම්බන්ධතා වලින් කියවීම, ආදිය). අවසානයේදී පෝලිම් පිරී ඇති අතර අපි පැකට් පහත වැටීමට පටන් ගනිමු. ශේෂයක් සෙවීමේ උත්සාහයක දී, softirq සන්දර්භය තුළ සකසන ලද උපරිම පැකට් ගණන සඳහා කර්නලය අයවැයක් සකසයි. මේ අයවැය ඉක්මවා ගිය පසු වෙනම ත්රෙඩ් එකක් අවදි වෙනවා ksoftirqd
(ඔබ ඔවුන්ගෙන් එකක් දකිනු ඇත ps
හරය අනුව) එය සාමාන්ය syscall/interrupt path වලින් පිටත මෙම softirqs හසුරුවයි. සම්පත් සාධාරණ ලෙස වෙන් කිරීමට උත්සාහ කරන සම්මත ක්රියාවලි උපලේඛනය භාවිතයෙන් මෙම පොට කාලසටහන්ගත කර ඇත.
කර්නලය පැකට් සකසන ආකාරය අධ්යයනය කිරීමෙන් පසු, තදබදයේ යම් සම්භාවිතාවක් ඇති බව ඔබට පෙනේ. softirq ඇමතුම් අඩුවෙන් ලැබෙන්නේ නම්, පැකට් ජාල කාඩ්පතේ RX පෝලිමේ සැකසීමට යම් කාලයක් බලා සිටීමට සිදුවනු ඇත. මෙය ප්රොසෙසර හරය අවහිර කරන යම් කාර්යයක් නිසා විය හැකිය, නැතහොත් වෙනත් දෙයක් හරය softirq ක්රියාත්මක වීම වළක්වයි.
සැකසීම හරයට හෝ ක්රමයට පටු කිරීම
Softirq ප්රමාදයන් දැනට අනුමානයක් පමණි. නමුත් එය අර්ථාන්විත වන අතර, අපි බොහෝ සමාන දෙයක් දකින බව අපි දනිමු. එබැවින් ඊළඟ පියවර වන්නේ මෙම න්යාය තහවුරු කිරීමයි. එය තහවුරු කර ඇත්නම්, ප්රමාද වීමට හේතුව සොයා ගන්න.
අපි අපගේ මන්දගාමී පැකට් වෙත ආපසු යමු:
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
කලින් සාකච්ඡා කළ පරිදි, මෙම ICMP පැකට් තනි RX NIC පෝලිමකට හැෂ් කර තනි CPU හරයක් මඟින් සකසනු ලැබේ. අපට ලිනක්ස් ක්රියා කරන ආකාරය තේරුම් ගැනීමට අවශ්ය නම්, ක්රියාවලිය නිරීක්ෂණය කිරීම සඳහා මෙම පැකේජ සැකසෙන්නේ කොතැනද (කුමන CPU හරය මත) සහ (softirq, ksoftirqd) කෙසේද යන්න දැන ගැනීම ප්රයෝජනවත් වේ.
දැන් ඔබට ලිනක්ස් කර්නලය තත්ය කාලීනව නිරීක්ෂණය කිරීමට ඉඩ සලසන මෙවලම් භාවිතා කිරීමට කාලයයි. මෙන්න අපි භාවිතා කළා
මෙහි සැලැස්ම සරලයි: කර්නලය මෙම ICMP පිං සකසන බව අපි දනිමු, එබැවින් අපි කර්නල් ශ්රිතයට කොක්කක් තබමු. hping3
වැඩි.
කේතය icmp_echo
දන්වයි struct sk_buff *skb
: මෙය "echo request" සහිත පැකට්ටුවකි. අපට එය නිරීක්ෂණය කළ හැකිය, අනුපිළිවෙල අදින්න echo.sequence
(සසඳන විට icmp_seq
hping3 මගින් выше
), සහ එය පරිශීලක අවකාශයට යවන්න. වත්මන් ක්රියාවලි නාමය/ID ග්රහණය කර ගැනීම ද පහසු වේ. කර්නලය පැකට් සකසන අතරතුර අපට කෙලින්ම පෙනෙන ප්රතිඵල පහත දැක්වේ:
TGID PID ක්රියාවලියේ නම 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 ප්රකාශ-වාර්තා-s 11
සන්දර්භය තුළ බව මෙහි සඳහන් කළ යුතුය softirq
පද්ධති ඇමතුම් සිදු කරන ලද ක්රියාවලි "ක්රියාවලි" ලෙස දිස්වනු ඇත, ඇත්ත වශයෙන්ම එය කර්නලයේ සන්දර්භය තුළ ආරක්ෂිතව පැකට් සකසන කර්නලය වේ.
මෙම මෙවලම සමඟින් අපට නිශ්චිත ක්රියාවලීන් ප්රමාදයක් පෙන්වන විශේෂිත පැකේජ සමඟ සම්බන්ධ කළ හැක hping3
. අපි එය සරල කරමු grep
සමහර අගයන් සඳහා මෙම ග්රහණය මත icmp_seq
. ඉහත icmp_seq අගයන්ට ගැළපෙන පැකට් අප ඉහත නිරීක්ෂණය කළ RTT සමඟ සලකුණු කර ඇත (වරහන් තුළ අපි 50ms ට අඩු RTT අගයන් නිසා පෙරන ලද පැකට් සඳහා අපේක්ෂිත RTT අගයන් වේ):
TGID PID ක්රියාවලියේ නම ICMP_SEQ ** RTT -- 10137 10436 කැඩ්වයිසර් 1951 10137 10436 කැඩ්වයිසර් 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 ** (මි. 9) -- 10137 10436 කැඩ්වයිසර් 2068 10137 10436 කැඩ්වයිසර් 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)
ප්රතිඵල අපට කරුණු කිහිපයක් කියයි. පළමුව, මෙම සියලු පැකේජ සන්දර්භය අනුව සකසනු ලැබේ ksoftirqd/11
. මෙයින් අදහස් කරන්නේ මෙම විශේෂිත යන්ත්ර යුගල සඳහා, ICMP පැකට් ලැබීමේ කෙළවරේ හරය 11 ට හැෂ් කර ඇති බවයි. තදබදයක් ඇති සෑම විටම පද්ධති ඇමතුමේ සන්දර්භය තුළ සැකසෙන පැකට් ඇති බව අපට පෙනේ cadvisor
. එවිට ksoftirqd
කාර්යය භාරගෙන සමුච්චිත පෝලිම සකසයි: හරියටම පසුව එකතු වී ඇති පැකට් ගණන cadvisor
.
වහාම එය සෑම විටම ක්රියා කිරීමට පෙර බව cadvisor
, ගැටලුවට ඔහුගේ මැදිහත් වීම ඇඟවුම් කරයි. හාස්යජනක ලෙස, අරමුණ
බහාලුම්වල අනෙකුත් අංශ මෙන්ම, මේ සියල්ල ඉතා උසස් මෙවලම් වන අතර සමහර අනපේක්ෂිත තත්වයන් යටතේ කාර්ය සාධන ගැටළු අත්විඳීමට අපේක්ෂා කළ හැකිය.
පැකට් පෝලිම මන්දගාමී කරන කැඩ්වයිසර් කරන්නේ කුමක්ද?
බිඳවැටීම සිදුවන්නේ කෙසේද, එයට හේතු වන ක්රියාවලිය සහ කුමන CPU මතද යන්න පිළිබඳව අපට දැන් හොඳ අවබෝධයක් ඇත. දැඩි අවහිර කිරීම් හේතුවෙන් Linux කර්නලයට කාලසටහන් කිරීමට කාලය නොමැති බව අපට පෙනේ ksoftirqd
. පැකට් සන්දර්භය තුළ සැකසෙන බව අපට පෙනේ cadvisor
. යැයි උපකල්පනය කිරීම තර්කානුකූල ය cadvisor
මන්දගාමී syscal එකක් දියත් කරයි, ඉන්පසු එම අවස්ථාවේ රැස් කරගත් සියලුම පැකට් සකසනු ලැබේ:
මෙය න්යායකි, නමුත් එය පරීක්ෂා කරන්නේ කෙසේද? අපට කළ හැක්කේ මෙම ක්රියාවලිය පුරාවටම CPU හරය ලුහුබැඳීම, පැකට් සංඛ්යාව අයවැය ඉක්මවා යන ලක්ෂ්යය සොයා ගැනීම සහ ksoftirqd ලෙස හඳුන්වනු ලබන අතර, එම ලක්ෂ්යයට මඳක් පෙර CPU හරයේ හරියටම ක්රියාත්මක වූයේ කුමක්දැයි බැලීමට ටිකක් පසුපසට බැලීමයි. . එය මිලි තත්පර කිහිපයකට වරක් CPU එක x-ray කරනවා වගේ. එය මේ වගේ දෙයක් පෙනෙනු ඇත:
පහසුව, මේ සියල්ල පවතින මෙවලම් සමඟ කළ හැකිය. උදාහරණ වශයෙන්, 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
මෙන්න ප්රතිඵල:
(сотни следов, которые выглядят похожими)
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
මෙතන ගොඩක් දේවල් තියෙනවා, නමුත් ප්රධානම දේ තමයි අපි කලින් දැකපු "cadvisor before ksoftirqd" රටාව ICMP tracer එකෙන් හොයාගන්නවා. එයින් අදහස් කරන්නේ කුමක් ද?
සෑම පේළියක්ම නිශ්චිත වේලාවක CPU හෝඩුවාවක් වේ. රේඛාවක් මත ඇති සෑම ඇමතුමක්ම අර්ධ කොමාවකින් වෙන් කරනු ලැබේ. පේළියේ මැද, සිස්කල් ලෙස හඳුන්වනු ලැබේ: read(): .... ;do_syscall_64;sys_read; ...
. එබැවින් cadvisor පද්ධති ඇමතුම මත බොහෝ කාලයක් ගත කරයි read()
කාර්යයන් සම්බන්ධ mem_cgroup_*
(ඇමතුම් තොගයේ ඉහළ/පේළියේ අවසානය).
හරියටම කියවන දේ ඇමතුමක හෝඩුවාවක් තුළ දැකීම අපහසුය, එබැවින් අපි ධාවනය කරමු strace
සහ අපි බලමු cadvisor කරන්නේ කුමක්ද සහ 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>
ඔබ අපේක්ෂා කළ හැකි පරිදි, අපි මෙහි මන්දගාමී ඇමතුම් දකිමු read()
. කියවීමේ මෙහෙයුම් සහ සන්දර්භය අන්තර්ගතයෙන් mem_cgroup
මෙම අභියෝග බව පැහැදිලිය read()
ගොනුව වෙත යොමු කරන්න memory.stat
, මතක භාවිතය සහ cgroup සීමාවන් පෙන්වයි (Docker's resource isolation technology). කන්ටේනර් සඳහා සම්පත් භාවිත තොරතුරු ලබාගැනීමට cadvisor මෙවලම මෙම ගොනුව විමසයි. එය කර්නලය හෝ කැඩ්වයිසර් අනපේක්ෂිත දෙයක් කරන්නේ දැයි පරීක්ෂා කරමු:
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 ~ $
දැන් අපට දෝෂය ප්රතිනිෂ්පාදනය කර ලිනක්ස් කර්නලය ව්යාධි විද්යාවකට මුහුණ දෙන බව තේරුම් ගත හැකිය.
කියවීමේ මෙහෙයුම මෙතරම් මන්දගාමී වන්නේ ඇයි?
මෙම අදියරේදී, සමාන ගැටළු පිළිබඳව වෙනත් පරිශීලකයින්ගෙන් පණිවිඩ සොයා ගැනීම වඩාත් පහසු වේ. එය සිදු වූ පරිදි, cadvisor tracker හි මෙම දෝෂය වාර්තා විය
ගැටළුව වන්නේ cgroups නාම අවකාශයේ (බහාලුම්) මතක භාවිතය සැලකිල්ලට ගැනීමයි. මෙම cgroup හි සියලුම ක්රියාවලි ඉවත් වූ විට, Docker මතක cgroup එක මුදා හරියි. කෙසේ වෙතත්, "මතකය" යනු ක්රියාවලි මතකය පමණක් නොවේ. ක්රියාවලි මතකය තවදුරටත් භාවිතා නොකෙරෙන නමුත්, කර්නලය තවමත් මතක cgroup හි හැඹිලිගත කර ඇති dentries සහ inodes (directory සහ file metadata) වැනි හැඹිලිගත අන්තර්ගතයන් පවරන බව පෙනේ. ගැටළු විස්තරයෙන්:
zombie cgroups: ක්රියාවලි නොමැති සහ මකා දමා ඇති නමුත් තවමත් මතකය වෙන් කර ඇති cgroups (මගේ නඩුවේදී, dentry cache වෙතින්, නමුත් එය පිටු හැඹිලියෙන් හෝ tmpfs වලින්ද වෙන් කළ හැක).
Cgroup එකක් නිදහස් කිරීමේදී හැඹිලියේ ඇති සියලුම පිටු වල කර්නලයේ පරික්ෂාව ඉතා මන්දගාමී විය හැක, එබැවින් කම්මැලි ක්රියාවලිය තෝරා ගනු ලැබේ: මෙම පිටු නැවත ඉල්ලන තෙක් රැඳී සිටින්න, පසුව මතකය ඇත්ත වශයෙන්ම අවශ්ය වූ විට cgroup එක ඉවත් කරන්න. මෙම අවස්ථාව දක්වා, සංඛ්යාලේඛන එකතු කිරීමේදී cgroup තවමත් සැලකිල්ලට ගනී.
කාර්ය සාධන ආස්ථානයෙන්, ඔවුන් කාර්ය සාධනය සඳහා මතකය කැප කළහ: යම් හැඹිලි මතකයක් ඉතිරි කිරීමෙන් මූලික පිරිසිදු කිරීම වේගවත් කිරීම. මේක හොඳයි. කර්නලය හැඹිලි මතකයේ අවසාන කොටස භාවිතා කරන විට, cgroup අවසානයේ ඉවත් කරනු ලැබේ, එබැවින් එය "ලීක්" ලෙස හැඳින්විය නොහැක. අවාසනාවකට, සෙවුම් යාන්ත්රණයේ නිශ්චිත ක්රියාත්මක කිරීම memory.stat
මෙම කර්නල් අනුවාදයේ (4.9), අපගේ සේවාදායකයන්හි ඇති විශාල මතක ප්රමාණය සමඟ ඒකාබද්ධව, නවතම හැඹිලි දත්ත ප්රතිසාධනය කිරීමට සහ cgroup zombies ඉවත් කිරීමට බොහෝ කාලයක් ගත වන බවයි.
අපගේ සමහර නෝඩ් වල කියවීම සහ ප්රමාදය තත්පරයක් ඉක්මවන තරම් cgroup zombies ඇති බව පෙනේ.
cadvisor ගැටලුව සඳහා පිළියමක් වන්නේ පද්ධතිය පුරා dentries/inodes හැඹිලි වහාම නිදහස් කිරීමයි, එය වහාම ධාරකයේ කියවීමේ ප්රමාදය මෙන්ම ජාල ප්රමාදය ඉවත් කරයි, මන්ද හැඹිලිය ඉවත් කිරීමෙන් හැඹිලිගත cgroup zombie පිටු ක්රියාත්මක වන අතර ඒවාද නිදහස් වේ. මෙය විසඳුමක් නොවේ, නමුත් එය ගැටලුවේ හේතුව තහවුරු කරයි.
නව කර්නල් අනුවාදවල (4.19+) ඇමතුම් කාර්ය සාධනය වැඩි දියුණු කර ඇති බව පෙනී ගියේය memory.stat
, එබැවින් මෙම කර්නලය වෙත මාරු වීමෙන් ගැටළුව විසඳා ඇත. ඒ අතරම, Kubernetes පොකුරු වල ගැටලුකාරී නෝඩ් හඳුනා ගැනීමටත්, ඒවා අලංකාර ලෙස ජලය බැසීමට සහ නැවත පණගැන්වීමටත් අපට මෙවලම් තිබුණි. අපි සියලුම පොකුරු පීරා, ප්රමාණවත් තරම් ප්රමාදයක් ඇති නෝඩ් සොයාගෙන ඒවා නැවත ආරම්භ කළෙමු. ඉතිරි සර්වර් වල OS යාවත්කාලීන කිරීමට මෙය අපට කාලය ලබා දුන්නේය.
සාරාංශ කිරීමට
මෙම දෝෂය RX NIC පෝලිම් සැකසීම මිලි තත්පර සිය ගණනක් සඳහා නතර කළ නිසා, එය එකවරම කෙටි සම්බන්ධතා මත ඉහළ ප්රමාදයක් සහ MySQL ඉල්ලීම් සහ ප්රතිචාර පැකට් අතර වැනි මධ්ය සම්බන්ධතා ප්රමාදයක් ඇති කළේය.
Kubernetes වැනි අති මූලික පද්ධතිවල ක්රියාකාරීත්වය අවබෝධ කර ගැනීම සහ නඩත්තු කිරීම, ඒවා මත පදනම් වූ සියලුම සේවාවන්හි විශ්වසනීයත්වය සහ වේගය සඳහා ඉතා වැදගත් වේ. ඔබ ක්රියාත්මක කරන සෑම පද්ධතියක්ම Kubernetes කාර්ය සාධන වැඩිදියුණු කිරීම් වලින් ප්රතිලාභ ලබයි.
මූලාශ්රය: www.habr.com