Minsan mas marami ay mas kaunti. Kapag ang pagbabawas ng load ay nagreresulta sa pagtaas ng latency

Tulad ng sa karamihan sa mga post, may problema sa isang distributed service, tawagin natin itong serbisyong Alvin. Sa pagkakataong ito ay hindi ko nadiskubre ang problema sa aking sarili, ipinaalam sa akin ng mga lalaki mula sa panig ng kliyente.

Isang araw nagising ako sa isang hindi nasisiyahang email dahil sa mahabang pagkaantala kay Alvin, na binalak naming ilunsad sa malapit na hinaharap. Sa partikular, nakaranas ang kliyente ng 99th percentile latency sa rehiyon na 50 ms, na higit sa aming latency na badyet. Ito ay nakakagulat dahil sinubukan ko ang serbisyo nang husto, lalo na sa latency, na isang karaniwang reklamo.

Bago ko ilagay si Alvin sa pagsubok, nagpatakbo ako ng maraming eksperimento na may 40k query per second (QPS), lahat ay nagpapakita ng latency na mas mababa sa 10ms. Handa akong ipahayag na hindi ako sang-ayon sa kanilang mga resulta. Ngunit sa muling pagtingin sa sulat, may napansin akong bago: Hindi ko pa eksaktong nasubok ang mga kondisyong binanggit nila, ang kanilang QPS ay mas mababa kaysa sa akin. Nagtest ako sa 40k QPS, pero nasa 1k lang sila. Nagpatakbo ako ng isa pang eksperimento, sa pagkakataong ito na may mas mababang QPS, para lang mapatahimik sila.

Dahil ako ay nagba-blog tungkol dito, malamang na naisip mo na ang kanilang mga numero ay tama. Sinubukan ko ang aking virtual na kliyente nang paulit-ulit, na may parehong resulta: ang mababang bilang ng mga kahilingan ay hindi lamang nagpapataas ng latency, ngunit nagpapataas ng bilang ng mga kahilingan na may latency na higit sa 10 ms. Sa madaling salita, kung sa 40k QPS humigit-kumulang 50 kahilingan bawat segundo ay lumampas sa 50 ms, pagkatapos ay sa 1k QPS mayroong 100 kahilingan sa itaas 50 ms bawat segundo. Kabalintunaan!

Minsan mas marami ay mas kaunti. Kapag ang pagbabawas ng load ay nagreresulta sa pagtaas ng latency

Pagpapaliit ng paghahanap

Kapag nahaharap sa isang problema sa latency sa isang distributed system na may maraming bahagi, ang unang hakbang ay gumawa ng maikling listahan ng mga suspect. Maghukay tayo nang kaunti sa arkitektura ni Alvin:

Minsan mas marami ay mas kaunti. Kapag ang pagbabawas ng load ay nagreresulta sa pagtaas ng latency

Ang isang magandang panimulang punto ay isang listahan ng mga nakumpletong I/O transition (mga tawag sa network/disk lookup, atbp.). Subukan nating alamin kung saan ang pagkaantala. Bukod sa halatang I/O sa kliyente, gumawa si Alvin ng karagdagang hakbang: ina-access niya ang data store. Gayunpaman, ang storage na ito ay gumagana sa parehong cluster bilang Alvin, kaya ang latency doon ay dapat na mas mababa kaysa sa client. Kaya, ang listahan ng mga suspek:

  1. Network call mula sa kliyente kay Alvin.
  2. Network call mula kay Alvin sa data store.
  3. Maghanap sa disk sa data store.
  4. Network call mula sa data warehouse kay Alvin.
  5. Network call mula kay Alvin sa isang kliyente.

Subukan nating i-cross out ang ilang puntos.

Ang pag-iimbak ng data ay walang kinalaman dito

Ang unang bagay na ginawa ko ay i-convert si Alvin sa isang ping-ping server na hindi nagpoproseso ng mga kahilingan. Kapag nakatanggap ito ng kahilingan, nagbabalik ito ng walang laman na tugon. Kung bumababa ang latency, kung gayon ang isang bug sa pagpapatupad ng Alvin o data warehouse ay walang naririnig. Sa unang eksperimento, nakuha namin ang sumusunod na graph:

Minsan mas marami ay mas kaunti. Kapag ang pagbabawas ng load ay nagreresulta sa pagtaas ng latency

Tulad ng nakikita mo, walang pagpapabuti kapag gumagamit ng ping-ping server. Nangangahulugan ito na ang data warehouse ay hindi nagdaragdag ng latency, at ang listahan ng mga suspek ay pinutol sa kalahati:

  1. Network call mula sa kliyente kay Alvin.
  2. Network call mula kay Alvin sa isang kliyente.

Malaki! Mabilis na lumiliit ang listahan. Akala ko halos nalaman ko na ang dahilan.

gRPC

Ngayon na ang oras para ipakilala ka sa isang bagong manlalaro: gRPC. Ito ay isang open source na library mula sa Google para sa in-process na komunikasyon RPC... Kahit na gRPC mahusay na na-optimize at malawak na ginagamit, ito ang aking unang pagkakataon na gamitin ito sa isang sistema ng ganitong laki at inaasahan kong ang aking pagpapatupad ay suboptimal - upang sabihin ang hindi bababa sa.

availability gRPC sa stack ay nagbunga ng isang bagong tanong: marahil ito ang aking pagpapatupad o ang aking sarili gRPC nagdudulot ng problema sa latency? Pagdaragdag ng bagong suspek sa listahan:

  1. Tumatawag ang kliyente sa library gRPC
  2. Aklatan gRPC gumagawa ng isang network na tawag sa library sa client gRPC sa server
  3. Aklatan gRPC nakipag-ugnayan kay Alvin (walang operasyon kung sakaling may ping-pong server)

Upang mabigyan ka ng ideya kung ano ang hitsura ng code, ang pagpapatupad ng aking kliyente/Alvin ay hindi gaanong naiiba sa mga client-server. mga halimbawa ng async.

Tandaan: Ang listahan sa itaas ay medyo pinasimple dahil gRPC ginagawang posible na gamitin ang iyong sariling (template?) threading model, kung saan ang execution stack ay magkakaugnay gRPC at pagpapatupad ng gumagamit. Para sa kapakanan ng pagiging simple, mananatili kami sa modelong ito.

Aayusin ng pag-profile ang lahat

Nang ma-cross out ang mga data store, naisip ko na halos tapos na ako: "Ngayon madali na! Ilapat natin ang profile at alamin kung saan nangyayari ang pagkaantala." ako malaking tagahanga ng precision profiling, dahil ang mga CPU ay napakabilis at kadalasan ay hindi ang bottleneck. Karamihan sa mga pagkaantala ay nangyayari kapag ang processor ay dapat huminto sa pagproseso upang gumawa ng iba pa. Ginagawa iyon ng Tumpak na Pag-profile ng CPU: tumpak nitong itinatala ang lahat mga switch ng konteksto at ginagawang malinaw kung saan nagaganap ang mga pagkaantala.

Kumuha ako ng apat na profile: na may mataas na QPS (mababang latency) at may ping-pong server na may mababang QPS (mataas na latency), kapwa sa panig ng kliyente at sa gilid ng server. At kung sakali, kumuha din ako ng sample na profile ng processor. Kapag naghahambing ng mga profile, kadalasan ay naghahanap ako ng maanomalyang stack ng tawag. Halimbawa, sa masamang panig na may mataas na latency, marami pang mga switch ng konteksto (10 beses o higit pa). Ngunit sa aking kaso, ang bilang ng mga switch ng konteksto ay halos pareho. Sa aking takot, walang kabuluhan doon.

Karagdagang Pag-debug

Ako ay desperado. Hindi ko alam kung anong iba pang mga tool ang maaari kong gamitin, at ang aking susunod na plano ay mahalagang ulitin ang mga eksperimento na may iba't ibang mga pagkakaiba-iba sa halip na malinaw na masuri ang problema.

Paano kung

Sa simula pa lang, nag-aalala na ako tungkol sa partikular na 50ms latency. Ito ay isang napakalaking panahon. Napagpasyahan kong gupitin ko ang mga tipak sa code hanggang sa matukoy ko kung aling bahagi ang sanhi ng error na ito. Pagkatapos ay dumating ang isang eksperimento na gumana.

As usual, in hindsight parang obvious na ang lahat. Inilagay ko ang kliyente sa parehong makina bilang Alvin - at nagpadala ng kahilingan sa localhost. At ang pagtaas ng latency ay nawala!

Minsan mas marami ay mas kaunti. Kapag ang pagbabawas ng load ay nagreresulta sa pagtaas ng latency

May mali sa network.

Pag-aaral ng mga kasanayan sa network engineer

Dapat kong aminin: ang aking kaalaman sa mga teknolohiya ng network ay kakila-kilabot, lalo na kung isasaalang-alang ang katotohanan na nakikipagtulungan ako sa kanila araw-araw. Ngunit ang network ang pangunahing pinaghihinalaan, at kailangan kong matutunan kung paano ito i-debug.

Sa kabutihang palad, mahal ng Internet ang mga gustong matuto. Ang kumbinasyon ng ping at tracert ay tila isang magandang simula sa pag-debug ng mga problema sa transportasyon ng network.

Una, inilunsad ko PsPing sa TCP port ni Alvin. Ginamit ko ang mga default na setting - walang espesyal. Sa higit sa isang libong ping, walang lumampas sa 10 ms, maliban sa una para sa warming up. Taliwas ito sa naobserbahang pagtaas ng latency na 50 ms sa ika-99 na porsyento: doon, para sa bawat 100 kahilingan, dapat ay nakita natin ang tungkol sa isang kahilingan na may latency na 50 ms.

Tapos sinubukan ko tagasubaybay: Maaaring may problema sa isa sa mga node sa ruta sa pagitan ni Alvin at ng kliyente. Ngunit bumalik din ang tracer na walang dala.

Kaya't hindi ang aking code, ang pagpapatupad ng gRPC, o ang network ang naging sanhi ng pagkaantala. Nagsimula akong mag-alala na hindi ko maintindihan ito.

Ngayon kung anong OS tayo

gRPC malawakang ginagamit sa Linux, ngunit kakaiba sa Windows. Nagpasya akong subukan ang isang eksperimento, na nagtrabaho: Gumawa ako ng Linux virtual machine, pinagsama-sama ang Alvin para sa Linux, at na-deploy ito.

Minsan mas marami ay mas kaunti. Kapag ang pagbabawas ng load ay nagreresulta sa pagtaas ng latency

At narito ang nangyari: ang Linux ping-pong server ay walang parehong pagkaantala gaya ng isang katulad na host ng Windows, bagama't ang data source ay hindi naiiba. Lumalabas na ang problema ay nasa pagpapatupad ng gRPC para sa Windows.

Ang algorithm ni Nagle

All this time akala ko wala akong flag gRPC. Ngayon naiintindihan ko na kung ano talaga gRPC Nawawala ang Windows flag. Nakakita ako ng panloob na library ng RPC na tiwala akong gagana nang maayos para sa lahat ng nakatakdang flag Winsock. Pagkatapos ay idinagdag ko ang lahat ng mga flag na ito sa gRPC at na-deploy si Alvin sa Windows, sa isang naka-patch na Windows ping-pong server!

Minsan mas marami ay mas kaunti. Kapag ang pagbabawas ng load ay nagreresulta sa pagtaas ng latency

Halos Tapos na: Sinimulan kong tanggalin ang mga idinagdag na flag nang paisa-isa hanggang sa bumalik ang regression para matukoy ko ang dahilan. Ito ay kasumpa-sumpa TCP_NODELAY, switch ng algorithm ni Nagle.

Ang algorithm ni Nagle sinusubukang bawasan ang bilang ng mga packet na ipinadala sa isang network sa pamamagitan ng pagkaantala sa pagpapadala ng mga mensahe hanggang sa lumampas ang laki ng packet sa isang tiyak na bilang ng mga byte. Bagama't ito ay maaaring maganda para sa karaniwang gumagamit, ito ay mapanira para sa mga real-time na server dahil ang OS ay maaantala ang ilang mga mensahe, na magdudulot ng mga pagkahuli sa mababang QPS. U gRPC ang flag na ito ay itinakda sa pagpapatupad ng Linux para sa mga TCP socket, ngunit hindi sa Windows. Ako ito naitama.

Konklusyon

Ang mas mataas na latency sa mababang QPS ay sanhi ng OS optimization. Sa pagbabalik-tanaw, hindi nakita ng profiling ang latency dahil ginawa ito sa kernel mode kaysa sa in mode ng gumagamit. Hindi ko alam kung ang algorithm ng Nagle ay maaaring obserbahan sa pamamagitan ng ETW captures, ngunit ito ay magiging kawili-wili.

Tulad ng para sa eksperimento sa localhost, malamang na hindi nito nahawakan ang aktwal na networking code at ang algorithm ng Nagle ay hindi tumakbo, kaya nawala ang mga isyu sa latency nang maabot ng kliyente si Alvin sa pamamagitan ng localhost.

Sa susunod na makakita ka ng pagtaas sa latency habang bumababa ang bilang ng mga kahilingan sa bawat segundo, ang algorithm ng Nagle ay dapat nasa iyong listahan ng mga pinaghihinalaan!

Pinagmulan: www.habr.com

Magdagdag ng komento