[Орчуулга] Envoy threading загвар

Нийтлэлийн орчуулга: Элч залгах загвар - https://blog.envoyproxy.io/envoy-threading-model-a8d44b922310

Энэ нийтлэл надад маш сонирхолтой санагдсан бөгөөд Элчийг ихэвчлэн "istio"-ийн нэг хэсэг эсвэл зүгээр л кубернетийн "оролтын хянагч" болгон ашигладаг тул ихэнх хүмүүс жишээлбэл, ердийнхтэй адил түүнтэй шууд харьцдаггүй. Nginx эсвэл Haproxy суулгацууд. Гэсэн хэдий ч хэрэв ямар нэг зүйл эвдэрсэн бол дотроос нь хэрхэн ажилладагийг ойлгох нь зүйтэй. Би эх бичвэрийг аль болох орос хэл рүү орчуулахыг хичээсэн бөгөөд тусгай үгсийг оруулаад, үүнийг харахад хэцүү байгаа хүмүүст би эхийг нь хаалтанд үлдээв. Муурт тавтай морил.

Envoy кодын доод түвшний техникийн баримт бичиг одоогоор нэлээд сийрэг байна. Үүнийг арилгахын тулд би Envoy-ийн янз бүрийн дэд системүүдийн талаар цуврал блог нийтлэл хийхээр төлөвлөж байна. Энэ бол анхны нийтлэл учраас юу гэж бодож байгаагаа, цаашдын нийтлэлүүдэд юу сонирхож болохыг надад хэлээрэй.

Envoy-ийн талаар надад ирдэг хамгийн түгээмэл техникийн асуултуудын нэг бол түүний ашигладаг урсгалын загварын талаар доод түвшний тайлбарыг асуух явдал юм. Энэ нийтлэлд би Envoy нь урсгалтай холболтыг хэрхэн харуулсан, мөн кодыг илүү параллель, өндөр гүйцэтгэлтэй болгохын тулд дотооддоо ашигладаг Thread Local Storage системийг тайлбарлах болно.

Урсгалын тойм

[Орчуулга] Envoy threading загвар

Элч гурван өөр төрлийн урсгал ашигладаг:

  • Үндсэн: Энэ хэлхээ нь процессыг эхлүүлэх, дуусгах, XDS (xDiscovery Service) API-ийн бүх боловсруулалт, үүнд DNS, эрүүл мэндийн хяналт, ерөнхий кластер болон ажиллах цагийн удирдлага, статистикийг дахин тохируулах, удирдлага болон процессын ерөнхий удирдлага - Линуксийн дохио. халуун дахин эхлүүлэх гэх мэтийг хянадаг. Энэ хэлхээнд тохиолддог зүйл нь асинхрон бөгөөд "блоклохгүй" юм. Ерөнхийдөө үндсэн утас нь ажиллахад их хэмжээний CPU шаарддаггүй бүх чухал үйл ажиллагааны процессуудыг зохицуулдаг. Энэ нь ихэнх хяналтын кодыг нэг урсгалтай мэт бичих боломжийг олгодог.
  • Ажилчин: Өгөгдмөлөөр Envoy нь систем дэх техник хангамжийн хэлхээ бүрт ажилчны утас үүсгэдэг бөгөөд үүнийг тохируулгыг ашиглан удирдаж болно. --concurrency. Ажилчны утас бүр нь сонсогч бүрийг сонсох үүрэгтэй "блоклохгүй" үйл явдлын давталт ажиллуулдаг; бичих үед (29 оны 2017-р сарын XNUMX) сонсогчийг хуваах, шинэ холболтыг хүлээн авах, шүүлтүүрийн стек үүсгэх боломжгүй. холболт болон холболтын ашиглалтын хугацаанд бүх оролт/гаралтын (IO) үйлдлийг боловсруулах. Дахин хэлэхэд энэ нь ихэнх холболтын кодыг нэг урсгалтай мэт бичих боломжийг олгодог.
  • Файл угаагч: Элчлэгчийн бичсэн файл бүр, голчлон бүртгэлд ханддаг, одоогоор бие даасан блоклох урсгалтай байна. Энэ нь файлын системд хадгалагдсан файлуудыг ашиглаж байхдаа ч бичиж байгаатай холбоотой юм O_NONBLOCK заримдаа бөглөрөх боломжтой (санаа алдах). Ажилчны утаснууд файл руу бичих шаардлагатай үед өгөгдөл нь санах ойн буфер руу зөөгдөж, эцэст нь thread-ээр дамждаг. файлыг угаах. Энэ бол санах ойн буферийг дүүргэх гэж оролдох үед техникийн бүх ажилчны утаснууд ижил түгжээг хааж болох кодын нэг хэсэг юм.

Холболтын зохицуулалт

Дээр дурьдсанчлан, бүх ажилчны хэлхээ нь бүх сонсогчдыг ямар ч хэлтэрхийлэлгүйгээр сонсдог. Тиймээс цөм нь хүлээн зөвшөөрөгдсөн залгууруудыг ажилчдын утас руу илгээхэд ашиглагддаг. Орчин үеийн цөмүүд нь ерөнхийдөө энэ тал дээр маш сайн байдаг бөгөөд тэдгээр нь оролт/гаралтын (IO) тэргүүлэх зэрэглэлийг нэмэгдүүлэх зэрэг функцуудыг ашигладаг бөгөөд нэг залгуур дээр сонсож байгаа бусад хэлхээг ашиглаж эхлэхээсээ өмнө утсыг ажилаар дүүргэхийг оролддог, мөн дугуй эргэлтийг ашигладаггүй. хүсэлт бүрийг боловсруулахын тулд түгжих (Spinlock).
Ажилчны утас дээр холболтыг хүлээн авмагц тэр хэлхээг хэзээ ч орхихгүй. Холболтын цаашдын бүх боловсруулалтыг бүхэлд нь ажилчны хэлхээнд, түүний дотор дамжуулалтын үйлдлийг гүйцэтгэдэг.

Энэ нь хэд хэдэн чухал үр дагавартай:

  • Envoy дахь бүх холболтын сангууд нь ажилчны хэлхээнд хуваарилагдсан. Тиймээс, HTTP/2 холболтын сан нь дээд талын хост бүртэй нэг удаад зөвхөн нэг холболт хийдэг ч, хэрэв дөрвөн ажилчин хэлхээтэй бол дээд талын хост бүрт дөрвөн HTTP/2 холболт тогтвортой байх болно.
  • Envoy яагаад ингэж ажилладаг вэ гэвэл бүх зүйлийг нэг ажилчны утас дээр хадгалснаар бараг бүх кодыг блоклохгүйгээр, нэг урсгалтай мэт бичиж болно. Энэхүү загвар нь маш олон код бичихэд хялбар болгож, бараг хязгааргүй тооны ажилчны утас хүртэл гайхалтай сайн масштабтай болгодог.
  • Гэсэн хэдий ч гол санаануудын нэг нь санах ойн сан болон холболтын үр ашгийн үүднээс авч үзвэл тохиргоог хийх нь маш чухал юм. --concurrency. Шаардлагатай хэмжээнээс илүү олон ажилчны утастай байх нь санах ойг дэмий үрж, илүү олон сул холболт үүсгэж, холболтын нэгдлийн хурдыг бууруулдаг. Lyft дээр манай элч нарын хажуугийн савнууд маш бага зэрэгцэн ажилладаг тул гүйцэтгэл нь тэдний хажууд сууж буй үйлчилгээтэй бараг таарч байна. Бид Envoy-г зөвхөн дээд зэрэглэлийн прокси хэлбэрээр ажиллуулдаг.

Блоклохгүй байх нь юу гэсэн үг вэ?

"Блоклохгүй" гэсэн нэр томъёог үндсэн болон ажлын утас хэрхэн ажилладаг талаар ярилцахдаа хэд хэдэн удаа ашигласан. Бүх код нь юу ч хэзээ ч хаагдахгүй гэсэн таамаглал дээр бичигдсэн байдаг. Гэсэн хэдий ч, энэ нь бүхэлдээ үнэн биш (юу нь бүхэлдээ үнэн биш вэ?).

Элч хэд хэдэн урт процессын түгжээг ашигладаг:

  • Хэлэлцэж байгаачлан хандалтын бүртгэлийг бичихдээ санах ойн бүртгэлийн буфер бөглөхөөс өмнө бүх ажилчны хэлхээ ижил түгжээ авдаг. Түгжээ барих хугацаа нь маш бага байх ёстой, гэхдээ цоожны хувьд өндөр зэрэгцэн, өндөр дамжуулалттай байх боломжтой.
  • Envoy нь урсгалын орон нутгийн статистикийг боловсруулахын тулд маш нарийн төвөгтэй системийг ашигладаг. Энэ бол тусдаа нийтлэлийн сэдэв байх болно. Гэсэн хэдий ч орон нутгийн хэмжээнд утаснуудын статистикийг боловсруулахын тулд заримдаа төв "статистикийн дэлгүүр" дээр түгжээ авах шаардлагатай байдаг гэдгийг би товч дурдъя. Ийм түгжээг хэзээ ч хийх шаардлагагүй.
  • Үндсэн утас нь үе үе бүх ажилчны утастай уялдаж байх шаардлагатай. Энэ нь үндсэн хэлхээнээс ажилчин утас руу, заримдаа ажилчин утас руу буцаж үндсэн хэлхээ рүү "хэвлэх" замаар хийгддэг. Илгээх нь түгжээтэй байх шаардлагатай бөгөөд нийтэлсэн мессежийг дараа хүргэхийн тулд дараалалд оруулах боломжтой. Эдгээр түгжээг хэзээ ч ноцтойгоор маргаж болохгүй, гэхдээ тэдгээрийг техникийн хувьд хааж болно.
  • Envoy нь системийн алдааны урсгалд (стандарт алдаа) лог бичих үед бүх процессын түгжээг олж авдаг. Ер нь Элч нарын орон нутгийн мод бэлтгэл нь гүйцэтгэлийн хувьд аймшигтай гэж тооцогддог тул сайжруулах тал дээр төдийлөн анхаарал хандуулаагүй байна.
  • Өөр хэд хэдэн санамсаргүй түгжээ байдаг боловч тэдгээрийн аль нь ч гүйцэтгэлд чухал ач холбогдолтой биш бөгөөд хэзээ ч тулгарах ёсгүй.

Thread local storage

Envoy нь үндсэн утаснуудын үүрэг хариуцлагыг ажилчны утаснуудын үүрэг хариуцлагаас ялгаж салгадаг тул үндсэн утас дээр нарийн төвөгтэй боловсруулалтыг хийж, дараа нь ажилчин утас бүрт маш зэрэгцүүлэн өгөх шаардлагатай байдаг. Энэ хэсэгт Envoy Thread Local Storage (TLS)-ийг өндөр түвшинд тайлбарласан болно. Дараагийн хэсэгт би үүнийг кластерыг удирдахад хэрхэн ашигладаг талаар тайлбарлах болно.
[Орчуулга] Envoy threading загвар

Өмнө дурьдсанчлан, үндсэн утас нь Envoy процессын бараг бүх удирдлага, удирдлагын онгоцны функцийг зохицуулдаг. Удирдлагын онгоц энд бага зэрэг ачаалалтай байгаа хэдий ч та үүнийг Envoy процесс дотроос нь харж, ажилчдын дамжуулагчийн дамжуулалттай харьцуулбал утга учиртай болно. Ерөнхий дүрэм бол үндсэн thread процесс нь тодорхой ажил хийдэг бөгөөд дараа нь тухайн ажлын үр дүнгийн дагуу ажилчны утас бүрийг шинэчлэх шаардлагатай байдаг. Энэ тохиолдолд ажилчны утас нь хандалт бүрт түгжээ авах шаардлагагүй.

Envoy-ийн TLS (Thread local storage) систем нь дараах байдлаар ажилладаг.

  • Үндсэн урсгал дээр ажиллаж байгаа код нь бүх процесст TLS слотыг хуваарилж болно. Хэдийгээр энэ нь хийсвэр байдлаар хийгдсэн боловч бодит байдал дээр энэ нь векторын индекс болж, O(1) хандалтыг хангадаг.
  • Үндсэн хэлхээ нь өөрийн үүрэнд дурын өгөгдлийг суулгаж болно. Үүнийг хийсний дараа өгөгдөл нь ердийн үйл явдлын давталтын үйл явдал болгон ажилчны хэлхээ болгонд нийтлэгдэнэ.
  • Ажилчны хэлхээнүүд нь TLS слотоосоо уншиж, тэнд байгаа урсгалын дотоод өгөгдлийг татаж авах боломжтой.

Хэдийгээр энэ нь маш энгийн бөгөөд гайхалтай хүчирхэг парадигм боловч RCU (Унших-Хуулбар-Шинэчлэх) блоклох үзэл баримтлалтай маш төстэй юм. Үндсэндээ ажил хийгдэж байх үед ажилчны хэлхээнүүд TLS слотуудын өгөгдлийн өөрчлөлтийг хэзээ ч хардаггүй. Өөрчлөлт нь зөвхөн ажлын үйл явдлын хоорондох амралтын хугацаанд л тохиолддог.

Элч үүнийг хоёр өөр аргаар ашигладаг:

  • Ажилчны утас бүр дээр өөр өөр өгөгдлийг хадгалснаар өгөгдөлд ямар ч хаалтгүйгээр хандах боломжтой.
  • Ажилчны хэлхээ бүр дээр зөвхөн унших горимд дэлхийн өгөгдөлд хуваалцсан заагчийг хадгалах замаар. Тиймээс ажилчны утас бүр нь өгөгдлийн лавлагааны тоотой байдаг бөгөөд үүнийг ажил ажиллаж байх үед багасгах боломжгүй. Бүх ажилчид тайвширч, шинэ хуваалцсан өгөгдлийг байршуулах үед л хуучин өгөгдөл устах болно. Энэ нь RCU-тай адил юм.

Кластер шинэчлэх урсгал

Энэ хэсэгт би кластерыг удирдахад TLS (Thread local storage) хэрхэн ашиглагдаж байгааг тайлбарлах болно. Кластерын удирдлагад xDS API ба/эсвэл DNS боловсруулалт, эрүүл мэндийн үзлэг орно.
[Орчуулга] Envoy threading загвар

Кластерын урсгалын удирдлага нь дараах бүрэлдэхүүн хэсгүүд болон алхмуудыг агуулна.

  1. Кластерын менежер нь Элчлэгч доторх бүх мэдэгдэж буй кластерын дээд урсгал, Cluster Discovery Service (CDS) API, Secret Discovery Service (SDS) болон Endpoint Discovery Service (EDS) APIs, 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 нь шинэчлэлтийн үйл явдлуудыг өдөөж болох тул ачаалал тэнцвэржүүлэгч болон бусад бүрэлдэхүүн хэсгүүд кэш, өгөгдлийн бүтэц гэх мэтийг дахин тооцоолох боломжтой гэдгийг анхаарна уу. Энэ нь энэ нийтлэлийн хамрах хүрээнээс хэтэрсэн боловч кодын янз бүрийн хэсэгт хэрэглэгддэг.

Дээрх процедурыг ашиглан Элч хүсэлт бүрийг ямар ч блоклохгүйгээр (өмнө тайлбарласнаас бусад тохиолдолд) боловсруулах боломжтой. TLS кодын нарийн төвөгтэй байдлаас гадна ихэнх код нь олон урсгалт хэрхэн ажилладагийг ойлгох шаардлагагүй бөгөөд нэг урсгалтай бичиж болно. Энэ нь дээд зэргийн гүйцэтгэлээс гадна ихэнх кодын бичихэд хялбар болгодог.

TLS ашигладаг бусад дэд системүүд

TLS (Thread local storage) болон RCU (Read Copy Update) нь Envoy-д өргөн хэрэглэгддэг.

Хэрэглэх жишээ:

  • Гүйцэтгэх явцад функцийг өөрчлөх механизм: Идэвхжүүлсэн функцүүдийн одоогийн жагсаалтыг үндсэн хэлхээнд тооцсон болно. Дараа нь ажилчны утас бүрт RCU семантик ашиглан зөвхөн уншигдах хормын хувилбарыг өгнө.
  • Маршрутын хүснэгтүүдийг солих: RDS (Route Discovery Service)-ээс өгсөн маршрутын хүснэгтүүдийн хувьд чиглүүлэлтийн хүснэгтүүдийг үндсэн урсгал дээр үүсгэсэн. Зөвхөн унших боломжтой агшин зуурын зургийг дараа нь RCU (Read Copy Update) семантик ашиглан ажилчин хэлхээ бүрт өгөх болно. Энэ нь маршрутын хүснэгтийг өөрчлөхөд атомын үр ашигтай болгодог.
  • HTTP толгой хэсгийг кэшлэх: Эндээс харахад хүсэлт тус бүрийн HTTP толгойг тооцоолох нь (нэг цөмд ~25K+ RPS ажиллуулах үед) нэлээд үнэтэй байдаг. Элч нь толгойг ойролцоогоор хагас секунд тутамд төвлөрсөн байдлаар тооцоолж, TLS болон RCU-ээр дамжуулан ажилтан бүрт өгдөг.

Бусад тохиолдлууд байдаг, гэхдээ өмнөх жишээнүүд нь TLS-ийг юунд ашигладаг талаар сайн ойлголт өгөх ёстой.

Мэдэгдэж буй гүйцэтгэлийн алдаанууд

Элч ерөнхийдөө нэлээд сайн ажиллаж байгаа хэдий ч үүнийг маш өндөр зэрэгцэн, дамжуулах чадвартай ашиглахад анхаарах хэд хэдэн анхаарал татахуйц хэсэг байдаг:

  • Энэ нийтлэлд дурдсанчлан, одоогоор бүх ажилчны хэлхээ нь хандалтын бүртгэлийн санах ойн буферт бичих үед түгжээ авдаг. Зэрэгцээ өндөр, дамжуулах чадвар өндөртэй үед та эцсийн файл руу бичихдээ дараалалгүй хүргэлтийн зардлаар ажилчны утас бүрийн хандалтын бүртгэлийг багцлах шаардлагатай болно. Эсвэл та ажилчны хэлхээ бүрт тусдаа хандалтын бүртгэл үүсгэж болно.
  • Хэдийгээр статистикийг маш оновчтой болгосон боловч маш өндөр зэрэгцэл, дамжуулах хүчин чадалтай үед бие даасан статистик дээр атомын маргаан гарах магадлалтай. Энэ асуудлын шийдэл нь төв тоолуурыг үе үе дахин тохируулдаг нэг ажилчинд ногдох тоолуур юм. Үүнийг дараагийн нийтлэлд хэлэлцэх болно.
  • Их хэмжээний боловсруулалтын нөөц шаарддаг маш цөөхөн холболттой хувилбарт Envoy-г байршуулсан тохиолдолд одоогийн архитектур сайн ажиллахгүй. Холболтуудыг ажилчдын утаснуудад жигд хуваарилах баталгаа байхгүй. Үүнийг ажилчдын холболтын тэнцвэржүүлэлтийг хэрэгжүүлэх замаар шийдэж болох бөгөөд энэ нь ажилчдын утас хоорондын холболтыг солилцох боломжийг олгоно.

Дүгнэлт

Envoy-ийн урсгалтай загвар нь зөв тохируулаагүй тохиолдолд санах ой, холболтыг үр ашиггүй зарцуулж болзошгүй тул програмчлалын хялбар байдал, асар их параллель байдлыг хангах зорилготой юм. Энэ загвар нь маш өндөр утас тоо, дамжуулах чадварт маш сайн ажиллах боломжийг олгодог.
Твиттер дээр би товч дурьдсанчлан уг загвар нь DPDK (Data Plane Development Kit) гэх мэт хэрэглэгчийн горимын сүлжээний стек дээр ажиллах боломжтой бөгөөд энэ нь ердийн серверүүд L7-г бүрэн боловсруулснаар секундэд сая сая хүсэлтийг боловсруулахад хүргэдэг. Ойрын хэдэн жилд юу баригдахыг харах нь маш сонирхолтой байх болно.
Сүүлчийн хурдан тайлбар: Бид яагаад C++-г Элчээр сонгосон бэ гэж надаас олон удаа асуусан. Үүний шалтгаан нь энэ нийтлэлд тайлбарласан архитектурыг барьж болох цорын ганц өргөн хэрэглэгддэг үйлдвэрлэлийн түвшний хэл хэвээр байна. C++ нь бүх төсөл эсвэл бүр олон төсөлд тохиромжгүй, гэхдээ зарим тохиолдолд энэ нь ажлыг гүйцэтгэх цорын ганц хэрэгсэл хэвээр байна.

Кодын холбоосууд

Энэ нийтлэлд хэлэлцсэн интерфэйс болон толгой хэсгийн хэрэгжилт бүхий файлуудын холбоосууд:

Эх сурвалж: www.habr.com

сэтгэгдэл нэмэх