[Թարգմանություն] Բանագնաց թելերի մոդել

Հոդվածի թարգմանությունը. Բանագնաց threading մոդել - https://blog.envoyproxy.io/envoy-threading-model-a8d44b922310

Ինձ համար այս հոդվածը բավականին հետաքրքիր էր, և քանի որ Envoy-ն ամենից հաճախ օգտագործվում է որպես «istio»-ի մաս կամ պարզապես որպես kubernetes-ի «մուտքի վերահսկիչ», մարդկանց մեծամասնությունը չունի նույն անմիջական փոխազդեցությունը դրա հետ, ինչպես, օրինակ, բնորոշ: Nginx կամ Haproxy տեղադրումներ: Այնուամենայնիվ, եթե ինչ-որ բան կոտրվի, լավ կլինի հասկանալ, թե ինչպես է այն աշխատում ներսից։ Ես փորձեցի հնարավորինս շատ տեքստ թարգմանել ռուսերեն, ներառյալ հատուկ բառեր, նրանց համար, ովքեր ցավալի են համարում սա նայելը, բնօրինակները թողեցի փակագծերում: Բարի գալուստ կատու:

Envoy codebase-ի ցածր մակարդակի տեխնիկական փաստաթղթերը ներկայումս բավականին նոսր են: Դա շտկելու համար ես նախատեսում եմ կատարել մի շարք բլոգային գրառումներ Envoy-ի տարբեր ենթահամակարգերի մասին: Քանի որ սա առաջին հոդվածն է, խնդրում եմ տեղեկացրեք ինձ, թե ինչ եք մտածում և ինչ կարող է ձեզ հետաքրքրել ապագա հոդվածներում:

Ամենատարածված տեխնիկական հարցերից մեկը, որ ես ստանում եմ Envoy-ի վերաբերյալ, այն է, որ նա օգտագործում է թելերի մոդելի ցածր մակարդակի նկարագրություն: Այս գրառման մեջ ես նկարագրելու եմ, թե ինչպես է Envoy-ը քարտեզագրում կապերը թելերի հետ, ինչպես նաև Thread Local Storage համակարգը, որն օգտագործում է ներսում՝ ծածկագիրը ավելի զուգահեռ և բարձր արդյունավետություն հաղորդելու համար:

Threading ակնարկ

[Թարգմանություն] Բանագնաց թելերի մոդել

Envoy-ն օգտագործում է երեք տարբեր տեսակի հոսքեր.

  • Հիմնական: Այս շարանը վերահսկում է գործընթացի մեկնարկը և դադարեցումը, XDS (xDiscovery Service) API-ի ողջ մշակումը, ներառյալ DNS-ը, առողջության ստուգումը, ընդհանուր կլաստերի և գործարկման ժամանակի կառավարումը, վիճակագրության վերակայումը, վարչարարությունը և ընդհանուր գործընթացի կառավարումը - Linux ազդանշաններ: տաք վերագործարկում և այլն: տեղի է ունենում այս թեմայում ասինխրոն և «ոչ արգելափակող»: Ընդհանուր առմամբ, հիմնական շարանը համակարգում է բոլոր կարևոր ֆունկցիոնալ գործընթացները, որոնք չեն պահանջում մեծ քանակությամբ պրոցեսոր աշխատելու համար: Սա թույլ է տալիս վերահսկման կոդի մեծամասնությանը գրել այնպես, կարծես այն մեկ թելերով է:
  • Աշխատող: Լռելյայնորեն, Envoy-ը ստեղծում է աշխատանքային շարանը համակարգի յուրաքանչյուր ապարատային թելի համար, որը կարելի է կառավարել՝ օգտագործելով տարբերակը --concurrency. Յուրաքանչյուր աշխատանքային շարանը վարում է «չարգելափակող» իրադարձությունների հանգույց, որը պատասխանատու է յուրաքանչյուր ունկնդրին լսելու համար։ Գրելու պահին (29 հուլիսի, 2017թ.) չկա ունկնդիրի մասնատում, նոր կապեր ընդունելու, ֆիլտրի փաթեթ ստեղծելու համար։ միացումը և մշակելով բոլոր մուտքային/ելքային (IO) գործողությունները միացման ողջ ընթացքում: Կրկին, սա թույլ է տալիս կապի մշակման կոդի մեծամասնությանը գրել այնպես, կարծես այն մեկ շղթայով լինի:
  • Ֆայլերի լվացում. Յուրաքանչյուր ֆայլ, որը գրում է Envoy-ը, հիմնականում մուտքի տեղեկամատյանները, ներկայումս ունի անկախ արգելափակող շարանը: Դա պայմանավորված է նրանով, որ ֆայլային համակարգի կողմից քեշավորված ֆայլերին գրելը նույնիսկ օգտագործելիս O_NONBLOCK երբեմն կարող է արգելափակվել (հառաչել): Երբ աշխատանքային շղթաները պետք է գրեն ֆայլում, տվյալներն իրականում տեղափոխվում են հիշողության բուֆեր, որտեղ այն ի վերջո մաքրվում է շղթայի միջով: ֆայլ լցվել. Սա կոդի մի տարածք է, որտեղ տեխնիկապես բոլոր աշխատող թելերը կարող են արգելափակել նույն կողպեքը՝ փորձելով լրացնել հիշողության բուֆերը:

Կապի կառավարում

Ինչպես հակիրճ քննարկվեց վերևում, բոլոր աշխատանքային շղթաները լսում են բոլոր ունկնդիրներին՝ առանց որևէ բեկման: Այսպիսով, միջուկն օգտագործվում է ընդունված վարդակները նրբագեղորեն աշխատող թելերին ուղարկելու համար: Ժամանակակից միջուկները, ընդհանուր առմամբ, շատ լավ են դրանում, նրանք օգտագործում են այնպիսի գործառույթներ, ինչպիսին է մուտքի/ելքի (IO) առաջնահերթության խթանումը, որպեսզի փորձեն լցնել թեմա աշխատանքով, նախքան նրանք կսկսեն օգտագործել այլ շղթաներ, որոնք նույնպես լսում են նույն վարդակից, ինչպես նաև չօգտագործել կլոր ռոբին: կողպում (Spinlock) յուրաքանչյուր հարցումը մշակելու համար:
Երբ կապն ընդունվում է աշխատող շղթայի վրա, այն երբեք չի լքում այդ շարանը: Կապի հետագա ողջ մշակումն ամբողջությամբ իրականացվում է աշխատանքային շղթայում, ներառյալ փոխանցման ցանկացած վարքագիծ:

Սա ունի մի քանի կարևոր հետևանք.

  • Envoy-ի բոլոր միացման լողավազանները վերագրված են աշխատանքային շղթային: Այսպիսով, թեև HTTP/2 կապի լողավազանները միաժամանակ կատարում են միայն մեկ կապ յուրաքանչյուր հոսանքին հակառակ, եթե կան չորս աշխատանքային շղթաներ, կլինեն չորս HTTP/2 միացումներ յուրաքանչյուր հոսանքին վերև՝ կայուն վիճակում:
  • Պատճառը, թե ինչու է Envoy-ն աշխատում է այսպես, այն է, որ ամեն ինչ պահելով մեկ աշխատանքային շղթայի վրա, գրեթե բոլոր ծածկագրերը կարող են գրվել առանց արգելափակման և կարծես թե այն մեկ շղթայով է: Այս դիզայնը հեշտացնում է շատ կոդ գրելը և անհավատալիորեն չափվում է գրեթե անսահմանափակ թվով աշխատող թելերի համար:
  • Այնուամենայնիվ, հիմնական միջոցներից մեկն այն է, որ հիշողության և կապի արդյունավետության տեսանկյունից, իրականում շատ կարևոր է կարգավորել --concurrency. Անհրաժեշտից ավելի շատ աշխատանքային թելեր ունենալը կկորցնի հիշողությունը, կստեղծի ավելի շատ անգործուն միացումներ և կնվազեցնի կապի միավորման արագությունը: Lyft-ում մեր բանագնաց կողային բեռնարկղերի բեռնարկղերը աշխատում են շատ ցածր համաժամանակությամբ, այնպես որ կատարողականությունը մոտավորապես համընկնում է նրանց կողքին նստած ծառայությունների հետ: Մենք գործարկում ենք Envoy-ը որպես եզրային վստահված անձ միայն առավելագույն միաժամանակության դեպքում:

Ի՞նչ է նշանակում չարգելափակել:

«Չարգելափակող» տերմինը մինչ այժմ մի քանի անգամ օգտագործվել է, երբ քննարկվում էր, թե ինչպես են աշխատում հիմնական և աշխատանքային թելերը: Ամբողջ ծածկագիրը գրված է այն ենթադրությամբ, որ ոչինչ երբեք արգելափակված չէ: Այնուամենայնիվ, սա ամբողջությամբ չի համապատասխանում իրականությանը (ինչը լիովին ճիշտ չէ):

Envoy-ն օգտագործում է մի քանի երկար գործընթացի կողպեքներ.

  • Ինչպես քննարկվեց, մուտքի տեղեկամատյանները գրելիս բոլոր աշխատանքային շղթաները ձեռք են բերում նույն կողպեքը, նախքան հիշողության մատյան բուֆերը լցված: Կողպեքի պահպանման ժամանակը պետք է լինի շատ ցածր, բայց հնարավոր է, որ կողպեքը վիճարկվի բարձր միաժամանակության և բարձր թողունակության դեպքում:
  • Envoy-ն օգտագործում է շատ բարդ համակարգ՝ թեմայի համար տեղական վիճակագրություն վարելու համար: Սա կլինի առանձին գրառման թեմա: Այնուամենայնիվ, ես համառոտ նշեմ, որ որպես տեղական թեմայի վիճակագրության մշակման մաս, երբեմն անհրաժեշտ է լինում կողպեք ձեռք բերել կենտրոնական «վիճակագրության խանութում»: Այս կողպումը երբեք չպետք է պահանջվի:
  • Հիմնական շարանը պարբերաբար պետք է համակարգվի բոլոր աշխատող թելերի հետ: Դա արվում է «հրապարակելով» հիմնական թելից դեպի աշխատանքային թելեր, իսկ երբեմն էլ բանվորական թելերից վերադառնում է հիմնական թեմա։ Ուղարկելու համար անհրաժեշտ է կողպեք, որպեսզի հրապարակված հաղորդագրությունը հերթագրվի հետագա առաքման համար: Այս կողպեքները երբեք չպետք է լուրջ վիճարկվեն, բայց դրանք տեխնիկապես դեռ կարող են արգելափակվել:
  • Երբ Envoy-ը գրանցամատյան է գրում համակարգի սխալների հոսքում (ստանդարտ սխալ), այն ձեռք է բերում կողպեք ամբողջ գործընթացի վրա: Ընդհանուր առմամբ, Envoy-ի տեղական անտառահատումները կատարողականի տեսանկյունից սարսափելի են համարվում, ուստի մեծ ուշադրություն չի դարձվել դրա բարելավմանը:
  • Կան մի քանի այլ պատահական կողպեքներ, բայց դրանցից ոչ մեկը կարևոր չէ կատարողականի վրա և երբեք չպետք է վիճարկվի:

Թելերի տեղական պահեստավորում

Քանի որ Էնվոյը տարանջատում է հիմնական թելի պարտականությունները աշխատանքային թելի պարտականություններից, պահանջ կա, որ բարդ վերամշակումը կարող է կատարվել հիմնական թելի վրա և այնուհետև տրամադրվել յուրաքանչյուր աշխատանքային շղթային խիստ միաժամանակյա ձևով: Այս բաժինը բարձր մակարդակով նկարագրում է Envoy Thread Local Storage-ը (TLS): Հաջորդ բաժնում ես նկարագրելու եմ, թե ինչպես է այն օգտագործվում կլաստերի կառավարման համար:
[Թարգմանություն] Բանագնաց թելերի մոդել

Ինչպես արդեն նկարագրված է, հիմնական շարանը գործնականում իրականացնում է կառավարման և վերահսկման հարթության բոլոր գործառույթները Envoy գործընթացում: Վերահսկիչ ինքնաթիռն այստեղ մի փոքր ծանրաբեռնված է, բայց երբ դուք դրան նայում եք հենց Envoy-ի գործընթացում և համեմատում այն ​​փոխանցման հետ, որն անում են աշխատող թելերը, դա իմաստալից է: Ընդհանուր կանոնն այն է, որ հիմնական շարանը որոշակի աշխատանք է կատարում, և այնուհետև այն պետք է թարմացնի յուրաքանչյուր աշխատանքային շարանը՝ ըստ այդ աշխատանքի արդյունքի: Այս դեպքում, աշխատանքային շարանը կարիք չունի կողպեք ձեռք բերել յուրաքանչյուր մուտքի վրա.

Envoy-ի TLS (Thread local storage) համակարգը աշխատում է հետևյալ կերպ.

  • Հիմնական թեմայի վրա աշխատող ծածկագիրը կարող է ամբողջ գործընթացի համար հատկացնել TLS բնիկ: Թեև սա վերացական է, գործնականում այն ​​վեկտորի ինդեքս է, որն ապահովում է O(1) հասանելիություն:
  • Հիմնական շարանը կարող է կամայական տվյալներ տեղադրել իր բնիկում: Երբ դա արվում է, տվյալները հրապարակվում են յուրաքանչյուր աշխատանքային շղթայում որպես սովորական իրադարձությունների հանգույց:
  • Աշխատող շղթաները կարող են կարդալ իրենց TLS բնիկից և առբերել այնտեղ առկա ցանկացած շղթա-տեղական տվյալ:

Չնայած այն շատ պարզ և աներևակայելի հզոր պարադիգմ է, այն շատ նման է RCU (Read-Copy-Update) արգելափակման հայեցակարգին: Ըստ էության, աշխատանքային թելերը երբեք չեն տեսնում տվյալների որևէ փոփոխություն TLS սլոտներում, մինչ աշխատանքը աշխատում է: Փոփոխությունը տեղի է ունենում միայն աշխատանքային իրադարձությունների միջև ընկած ժամանակահատվածում:

Բանագնացը սա օգտագործում է երկու տարբեր ձևերով.

  • Պահպանելով տարբեր տվյալներ յուրաքանչյուր աշխատանքային շղթայի վրա՝ տվյալներին կարելի է մուտք գործել առանց որևէ արգելափակման:
  • Յուրաքանչյուր աշխատանքային շղթայի վրա միայն կարդալու ռեժիմում գլոբալ տվյալների ընդհանուր ցուցիչ պահելով: Այսպիսով, յուրաքանչյուր աշխատանքային շարանը ունի տվյալների հղման քանակ, որը չի կարող կրճատվել աշխատանքի ընթացքում: Միայն այն ժամանակ, երբ բոլոր աշխատողները հանդարտվեն և վերբեռնեն նոր ընդհանուր տվյալներ, հին տվյալները կկործանվեն: Սա նույնական է RCU-ին:

Կլաստերների թարմացման շղթաներ

Այս բաժնում ես նկարագրելու եմ, թե ինչպես է TLS (Thread local storage) օգտագործվում կլաստերը կառավարելու համար: Կլաստերի կառավարումը ներառում է xDS API և/կամ DNS մշակում, ինչպես նաև առողջության ստուգում:
[Թարգմանություն] Բանագնաց թելերի մոդել

Կլաստերային հոսքի կառավարումը ներառում է հետևյալ բաղադրիչներն ու քայլերը.

  1. Կլաստերի կառավարիչը Envoy-ի մի բաղադրիչ է, որը կառավարում է բոլոր հայտնի կլաստերի վերին հոսքերը, Cluster Discovery Service (CDS) API, Secret Discovery Service (SDS) և Endpoint Discovery Service (EDS) API-ներ, DNS և ակտիվ արտաքին ստուգումներ: առողջության ստուգում: Այն պատասխանատու է յուրաքանչյուր վերին հոսքի կլաստերի «ի վերջո հետևողական» տեսակետ ստեղծելու համար, որը ներառում է հայտնաբերված հյուրընկալողներ, ինչպես նաև առողջական վիճակը:
  2. Առողջության ստուգիչը կատարում է ակտիվ առողջական ստուգում և կլաստերի կառավարչին հայտնում առողջական վիճակի փոփոխությունների մասին:
  3. CDS (Cluster Discovery Service) / SDS (Secret Discovery Service) / EDS (Endpoint Discovery Service) / DNS իրականացվում են կլաստերի անդամակցությունը որոշելու համար: Պետական ​​փոփոխությունը վերադարձվում է կլաստերի կառավարչին:
  4. Յուրաքանչյուր աշխատանքային շարանը շարունակաբար կատարում է իրադարձությունների հանգույց:
  5. Երբ կլաստերի կառավարիչը որոշում է, որ կլաստերի վիճակը փոխվել է, նա ստեղծում է կլաստերի վիճակի նոր պատկեր՝ միայն կարդալու համար և ուղարկում այն ​​յուրաքանչյուր աշխատանքային շղթային:
  6. Հաջորդ հանգիստ ժամանակահատվածում աշխատանքային շարանը կթարմացնի պատկերը հատկացված TLS բնիկում:
  7. I/O իրադարձության ժամանակ, որը պետք է որոշի հոսթը՝ բեռնելու հաշվեկշիռը, բեռնվածության հավասարակշռիչը կպահանջի TLS (Thread local storage) բնիկ՝ հյուրընկալողի մասին տեղեկություններ ստանալու համար: Սա չի պահանջում կողպեքներ: Նկատի ունեցեք նաև, որ TLS-ը կարող է նաև գործարկել թարմացման իրադարձությունները, որպեսզի բեռի հավասարակշռողները և այլ բաղադրիչները կարողանան վերահաշվարկել քեշերը, տվյալների կառուցվածքները և այլն: Սա դուրս է այս գրառման շրջանակներից, բայց օգտագործվում է կոդի տարբեր վայրերում:

Օգտագործելով վերը նշված ընթացակարգը, Envoy-ը կարող է մշակել յուրաքանչյուր հարցում առանց որևէ արգելափակման (բացառությամբ նախկինում նկարագրվածի): Բացի բուն TLS կոդի բարդությունից, կոդի մեծ մասը կարիք չունի հասկանալու, թե ինչպես է աշխատում բազմաթելերը և կարող է գրվել միայնակ թելերով: Սա հեշտացնում է կոդի մեծ մասը՝ ի լրումն գերազանց կատարման:

Այլ ենթահամակարգեր, որոնք օգտագործում են TLS

Envoy-ում լայնորեն օգտագործվում են TLS (Thread local storage) և RCU (Read Copy Update):

Օգտագործման օրինակներ.

  • Կատարման ընթացքում ֆունկցիոնալությունը փոխելու մեխանիզմ. Միացված ֆունկցիոնալության ընթացիկ ցանկը հաշվարկվում է հիմնական թեմայում: Այնուհետև յուրաքանչյուր աշխատանքային շարանը տրվում է միայն կարդալու պատկեր՝ օգտագործելով RCU իմաստաբանությունը:
  • Երթուղիների աղյուսակների փոխարինումRDS-ի (Route Discovery Service) կողմից տրամադրված երթուղիների աղյուսակների համար երթուղիների աղյուսակները ստեղծվում են հիմնական թեմայում: Միայն կարդալու պատկերը հետագայում կտրամադրվի յուրաքանչյուր աշխատանքային շղթային՝ օգտագործելով RCU (Կարդալ պատճենի թարմացում) իմաստաբանությունը: Սա երթուղիների աղյուսակների փոփոխությունը դարձնում է ատոմային արդյունավետ:
  • HTTP վերնագրի քեշավորում. Ինչպես պարզվում է, յուրաքանչյուր հարցման համար HTTP վերնագրի հաշվարկը (մինչև ~25K+ RPS մեկ միջուկի համար) բավականին թանկ է: Envoy-ը կենտրոնացված կերպով հաշվարկում է վերնագիրը մոտավորապես յուրաքանչյուր կես վայրկյանը մեկ և այն տրամադրում յուրաքանչյուր աշխատողի TLS-ի և RCU-ի միջոցով:

Կան այլ դեպքեր, բայց նախորդ օրինակները պետք է լավ պատկերացում տան, թե ինչի համար է օգտագործվում TLS-ը:

Հայտնի կատարողական թակարդներ

Թեև Envoy-ն ընդհանուր առմամբ բավականին լավ է գործում, կան մի քանի ուշագրավ ոլորտներ, որոնք ուշադրություն են պահանջում, երբ այն օգտագործվում է շատ բարձր միաժամանակությամբ և թողունակությամբ.

  • Ինչպես նկարագրված է այս հոդվածում, ներկայումս բոլոր աշխատանքային թելերը կողպվում են մուտքի տեղեկամատյան հիշողության բուֆերում գրելիս: Բարձր միաժամանակության և բարձր թողունակության դեպքում դուք պետք է հավաքեք մուտքի տեղեկամատյանները յուրաքանչյուր աշխատանքային շղթայի համար՝ վերջնական ֆայլը գրելիս անկանոն առաքման հաշվին: Որպես այլընտրանք, դուք կարող եք ստեղծել առանձին մուտքի մատյան յուրաքանչյուր աշխատող շղթայի համար:
  • Չնայած վիճակագրությունը խիստ օպտիմիզացված է, շատ բարձր միաժամանակության և թողունակության դեպքում, հավանաբար, առանձին վիճակագրության վերաբերյալ ատոմային վեճեր կլինեն: Այս խնդրի լուծումը մեկ աշխատող շղթայի համար նախատեսված հաշվիչներն են՝ կենտրոնական հաշվիչների պարբերական վերակայմամբ: Սա կքննարկվի հաջորդ գրառման մեջ:
  • Ներկայիս ճարտարապետությունը լավ չի աշխատի, եթե Envoy-ը տեղակայվի այնպիսի սցենարով, որտեղ շատ քիչ կապեր կան, որոնք պահանջում են զգալի մշակման ռեսուրսներ: Չկա երաշխիք, որ միացումները հավասարաչափ կբաշխվեն աշխատող թելերի միջև: Սա կարող է լուծվել բանվորական կապի հավասարակշռման միջոցով, որը թույլ կտա կապերի փոխանակում աշխատող թելերի միջև:

Եզրակացություն

Envoy-ի թելերի մոդելը նախագծված է ապահովելու ծրագրավորման հեշտություն և զանգվածային զուգահեռականություն՝ հնարավոր վատնող հիշողության և կապերի հաշվին, եթե ճիշտ կազմաձևված չէ: Այս մոդելը թույլ է տալիս նրան շատ լավ աշխատել թելերի շատ բարձր քանակի և թողունակության դեպքում:
Ինչպես ես հակիրճ նշեցի Twitter-ում, դիզայնը կարող է նաև աշխատել ամբողջական օգտագործողի ռեժիմով ցանցային փաթեթի վրա, ինչպիսին է DPDK-ը (Data Plane Development Kit), որը կարող է հանգեցնել սովորական սերվերների՝ միլիոնավոր հարցումների մշակման մեկ վայրկյանում ամբողջական L7 մշակմամբ: Շատ հետաքրքիր կլինի տեսնել, թե ինչ կկառուցվի առաջիկա մի քանի տարիներին։
Մի վերջին արագ մեկնաբանություն. Ինձ բազմիցս հարցրել են, թե ինչու ենք Envoy-ի համար ընտրել C++-ը: Պատճառը մնում է այն, որ այն դեռևս միակ լայնորեն օգտագործվող արդյունաբերական կարգի լեզուն է, որով կարելի է կառուցել այս գրառման մեջ նկարագրված ճարտարապետությունը: C++-ը հաստատ հարմար չէ բոլոր կամ նույնիսկ շատ նախագծերի համար, բայց որոշակի օգտագործման դեպքերի համար այն դեռ միակ գործիքն է աշխատանքն ավարտելու համար:

Հղումներ դեպի կոդը

Այս գրառման մեջ քննարկված ինտերֆեյսներով և վերնագրերի ներդրմամբ ֆայլերի հղումներ.

Source: www.habr.com

Добавить комментарий