[Çeviri] Elçi iş parçacığı modeli

Makale çevirisi: Elçi iş parçacığı modeli - https://blog.envoyproxy.io/envoy-threading-model-a8d44b922310

Bu makaleyi oldukça ilginç buldum ve Envoy çoğunlukla kubernetes'in "istio"sunun bir parçası olarak veya basitçe "giriş denetleyicisi" olarak kullanıldığından çoğu insan onunla, örneğin tipik ağlarla aynı doğrudan etkileşime sahip değildir. Nginx veya Haproxy kurulumları. Ancak bir şey bozulursa içeriden nasıl çalıştığını anlamak iyi olur. Özel kelimeler de dahil olmak üzere metnin mümkün olduğunca çoğunu Rusçaya çevirmeye çalıştım, buna bakmakta zorluk çekenler için orijinalleri parantez içinde bıraktım. Kedi'ye hoş geldiniz.

Envoy kod tabanına ilişkin düşük düzeyli teknik belgeler şu anda oldukça seyrek. Bu duruma çözüm bulmak için Envoy'un çeşitli alt sistemleri hakkında bir dizi blog yazısı yazmayı planlıyorum. Bu ilk makale olduğundan, lütfen ne düşündüğünüzü ve gelecekteki makalelerde nelerle ilgilenebileceğinizi bana bildirin.

Envoy hakkında aldığım en yaygın teknik sorulardan biri, kullandığı iş parçacığı modelinin alt düzey açıklamasını istemektir. Bu yazıda, Envoy'un bağlantıları iş parçacıklarıyla nasıl eşlediğini ve ayrıca kodu daha paralel ve yüksek performanslı hale getirmek için dahili olarak kullandığı İş Parçacığı Yerel Depolama sistemini açıklayacağım.

İş parçacığına genel bakış

[Çeviri] Elçi iş parçacığı modeli

Elçi üç farklı türde akış kullanır:

  • Ana: Bu iş parçacığı, işlemin başlatılmasını ve sonlandırılmasını, DNS, sağlık kontrolü, genel küme ve çalışma zamanı yönetimi, istatistik sıfırlama, yönetim ve genel süreç yönetimi - Linux çalışırken yeniden başlatma vb. dahil olmak üzere XDS (xDiscovery Hizmeti) API'sinin tüm işlemlerini kontrol eder. Bu iş parçacığında gerçekleşen olaylar eşzamansız ve "engellenmeyen"dir. Genel olarak ana iş parçacığı, çalışması için büyük miktarda CPU gerektirmeyen tüm kritik işlevsellik süreçlerini koordine eder. Bu, çoğu kontrol kodunun tek iş parçacıklıymış gibi yazılmasına olanak tanır.
  • Çalışan: Varsayılan olarak Envoy, sistemdeki her donanım iş parçacığı için bir çalışan iş parçacığı oluşturur; bu seçenek kullanılarak kontrol edilebilir --concurrency. Her çalışan iş parçacığı, her dinleyiciyi dinlemekten sorumlu olan "engellenmeyen" bir olay döngüsü çalıştırır; bu, yazma sırasında (29 Temmuz 2017) dinleyicinin parçalanması, yeni bağlantıların kabul edilmesi, bir filtre yığınının başlatılması söz konusu değildir; bağlantının ömrü boyunca tüm giriş/çıkış (IO) işlemlerini gerçekleştirir. Bu da çoğu bağlantı işleme kodunun tek iş parçacıklıymış gibi yazılmasına olanak tanır.
  • Dosya temizleyici: Envoy'un yazdığı her dosya (çoğunlukla erişim günlükleri) şu anda bağımsız bir engelleme dizisine sahiptir. Bunun nedeni, dosya sistemi tarafından önbelleğe alınan dosyalara yazma işlemi sırasında bile O_NONBLOCK bazen tıkanabilir (iç çekme). Çalışan iş parçacıklarının bir dosyaya yazması gerektiğinde, veriler aslında bellekteki bir arabelleğe taşınır ve burada sonunda iş parçacığı üzerinden temizlenir. dosya temizleme. Bu, teknik olarak tüm çalışan iş parçacıklarının bir bellek arabelleğini doldurmaya çalışırken aynı kilidi engelleyebildiği bir kod alanıdır.

Bağlantı yönetimi

Yukarıda kısaca tartışıldığı gibi, tüm çalışan iş parçacıkları tüm dinleyicileri herhangi bir parçalama olmadan dinler. Böylece çekirdek, kabul edilen yuvaları çalışan iş parçacıklarına zarif bir şekilde göndermek için kullanılır. Modern çekirdekler genellikle bu konuda çok iyidirler; aynı soketi dinleyen diğer iş parçacıklarını kullanmaya başlamadan önce bir iş parçacığını iş ile doldurmaya çalışmak için giriş/çıkış (IO) öncelik artırma gibi özellikleri kullanırlar ve aynı zamanda sıralı sıralamayı kullanmazlar. her isteği işlemek için kilitleme (Spinlock).
Çalışan iş parçacığında bir bağlantı kabul edildiğinde o iş parçacığından asla ayrılmaz. Bağlantının tüm diğer işlemleri, herhangi bir yönlendirme davranışı da dahil olmak üzere tamamen çalışan iş parçacığında gerçekleştirilir.

Bunun birkaç önemli sonucu vardır:

  • Envoy'daki tüm bağlantı havuzları bir çalışan iş parçacığına atanır. Dolayısıyla, HTTP/2 bağlantı havuzları her bir yukarı akış ana bilgisayarına aynı anda yalnızca bir bağlantı yapsa da, dört çalışan iş parçacığı varsa, sabit durumdaki yukarı akış ana makinesi başına dört HTTP/2 bağlantısı olacaktır.
  • Envoy'un bu şekilde çalışmasının nedeni, her şeyi tek bir çalışan iş parçacığı üzerinde tutarak neredeyse tüm kodun engelleme olmadan ve sanki tek iş parçacığıymış gibi yazılabilmesidir. Bu tasarım, çok sayıda kod yazmayı kolaylaştırır ve neredeyse sınırsız sayıda çalışan iş parçacığına inanılmaz derecede iyi ölçeklendirir.
  • Bununla birlikte, ana çıkarımlardan biri, bellek havuzu ve bağlantı verimliliği açısından bakıldığında, yapılandırmanın aslında çok önemli olduğudur. --concurrency. Gerekenden daha fazla çalışan iş parçacığına sahip olmak, belleği boşa harcar, daha fazla boş bağlantı oluşturur ve bağlantı havuzu oluşturma oranını azaltır. Lyft'te elçi sepet konteynerlerimiz çok düşük eşzamanlılıkla çalışır, böylece performans, yanlarında bulundukları hizmetlerle kabaca eşleşir. Envoy'u yalnızca maksimum eşzamanlılıkta uç proxy olarak çalıştırıyoruz.

Engellememe ne anlama geliyor?

"Engellemeyen" terimi, ana ve çalışan iş parçacıklarının nasıl çalıştığını tartışırken şu ana kadar birkaç kez kullanıldı. Tüm kod hiçbir şeyin engellenmediği varsayımıyla yazılmıştır. Ancak bu tamamen doğru değil (tamamen doğru olmayan ne?).

Elçi birkaç uzun süreç kilidi kullanır:

  • Tartışıldığı gibi, erişim günlüklerini yazarken, tüm çalışan iş parçacıkları, bellek içi günlük arabelleği dolmadan önce aynı kilidi alır. Kilit tutma süresi çok düşük olmalıdır, ancak kilide yüksek eşzamanlılık ve yüksek verimle itiraz edilmesi mümkündür.
  • Envoy, iş parçacığında yerel olan istatistikleri işlemek için çok karmaşık bir sistem kullanıyor. Bu ayrı bir yazının konusu olacak. Ancak, iş parçacığı istatistiklerinin yerel olarak işlenmesinin bir parçası olarak, bazen merkezi bir "istatistik deposu" üzerinde bir kilit elde edilmesinin gerekli olduğunu kısaca belirteceğim. Bu kilitlemeye hiçbir zaman gerek duyulmamalıdır.
  • Ana iş parçacığının periyodik olarak tüm çalışan iş parçacıklarıyla koordine olması gerekir. Bu, ana iş parçacığından çalışan iş parçacıklarına ve bazen de çalışan iş parçacıklarından ana iş parçacığına geri "yayınlama" yoluyla yapılır. Yayınlanan mesajın daha sonra teslim edilmek üzere kuyruğa alınabilmesi için gönderme işlemi bir kilit gerektirir. Bu kilitlere hiçbir zaman ciddi bir şekilde itiraz edilmemelidir, ancak yine de teknik olarak engellenebilirler.
  • Envoy, sistem hata akışına (standart hata) bir günlük yazdığında, tüm süreç üzerinde bir kilit elde eder. Genel olarak, Envoy'un yerel kayıt tutması performans açısından berbat kabul ediliyor, bu nedenle iyileştirilmesine fazla önem verilmedi.
  • Birkaç rastgele kilit daha var, ancak bunların hiçbiri performans açısından kritik değil ve asla sorgulanmamalı.

Yerel depolama birimini iş parçacığı

Envoy'un ana iş parçacığının sorumluluklarını çalışan iş parçacığının sorumluluklarından ayırma şekli nedeniyle, karmaşık işlemlerin ana iş parçacığı üzerinde yapılabilmesi ve daha sonra her bir iş parçacığına son derece eş zamanlı bir şekilde sağlanabilmesi gerekliliği vardır. Bu bölümde Envoy Thread Yerel Depolaması (TLS) yüksek düzeyde açıklanmaktadır. Bir sonraki bölümde bir kümeyi yönetmek için nasıl kullanıldığını anlatacağım.
[Çeviri] Elçi iş parçacığı modeli

Daha önce açıklandığı gibi ana iş parçacığı, Elçi sürecindeki neredeyse tüm yönetim ve kontrol düzlemi işlevlerini yönetir. Kontrol düzlemi burada biraz aşırı yüklenmiştir, ancak buna Envoy sürecinin kendisinde baktığınızda ve bunu çalışan iş parçacıklarının yaptığı iletmeyle karşılaştırdığınızda mantıklı olur. Genel kural, ana iş parçacığı işleminin bir miktar iş yapması ve ardından her bir çalışan iş parçacığının o işin sonucuna göre güncellenmesi gerektiğidir. bu durumda, çalışan iş parçacığının her erişimde bir kilit edinmesine gerek yoktur.

Elçinin TLS (İş parçacığı yerel depolama) sistemi şu şekilde çalışır:

  • Ana iş parçacığında çalışan kod, tüm süreç için bir TLS yuvası tahsis edebilir. Her ne kadar soyutlanmış olsa da pratikte O(1) erişimi sağlayan bir vektöre yönelik bir indekstir.
  • Ana iş parçacığı, yuvasına rastgele veriler yükleyebilir. Bu yapıldığında veriler her bir çalışan iş parçacığına normal bir olay döngüsü olayı olarak yayınlanır.
  • Çalışan iş parçacıkları TLS yuvalarından okuyabilir ve burada mevcut olan iş parçacığı yerel verilerini alabilir.

Çok basit ve inanılmaz derecede güçlü bir paradigma olmasına rağmen RCU(Oku-Kopyala-Güncelle) engelleme kavramına çok benzemektedir. Temel olarak, çalışan iş parçacıkları iş çalışırken TLS yuvalarında hiçbir veri değişikliği görmez. Değişim yalnızca iş olayları arasındaki dinlenme döneminde meydana gelir.

Elçi bunu iki farklı şekilde kullanır:

  • Her bir çalışan iş parçacığına farklı veriler depolanarak verilere herhangi bir engelleme olmaksızın erişilebilir.
  • Her çalışan iş parçacığında salt okunur modda genel verilere yönelik paylaşılan bir işaretçiyi sürdürerek. Bu nedenle, her çalışan iş parçacığının, iş devam ederken azaltılamayan bir veri referans sayısı vardır. Ancak tüm çalışanlar sakinleştiğinde ve yeni paylaşılan veriler yüklediğinde eski veriler imha edilecektir. Bu RCU ile aynıdır.

Küme güncelleştirme iş parçacığı

Bu bölümde bir kümeyi yönetmek için TLS'nin (Thread local Storage) nasıl kullanıldığını anlatacağım. Küme yönetimi, xDS API ve/veya DNS işlemenin yanı sıra durum denetimini de içerir.
[Çeviri] Elçi iş parçacığı modeli

Küme akışı yönetimi aşağıdaki bileşenleri ve adımları içerir:

  1. Küme Yöneticisi, Envoy'un bilinen tüm küme yukarı akışlarını, Küme Keşif Hizmeti (CDS) API'sini, Gizli Keşif Hizmeti (SDS) ve Uç Nokta Keşif Hizmeti (EDS) API'lerini, DNS'yi ve etkin harici durum denetimlerini yöneten bir bileşenidir. Keşfedilen ana bilgisayarların yanı sıra sağlık durumunu da içeren her yukarı akış kümesinin "nihayetinde tutarlı" bir görünümünü oluşturmaktan sorumludur.
  2. Sistem durumu denetleyicisi, etkin bir sistem durumu denetimi gerçekleştirir ve sistem durumu değişikliklerini küme yöneticisine bildirir.
  3. Küme üyeliğinin belirlenmesi için CDS (Cluster Discovery Service) / SDS (Gizli Discovery Service) / EDS (Endpoint Discovery Service) / DNS işlemleri gerçekleştirilir. Durum değişikliği küme yöneticisine iade edilir.
  4. Her çalışan iş parçacığı sürekli olarak bir olay döngüsünü yürütür.
  5. Küme yöneticisi bir kümenin durumunun değiştiğini belirlediğinde, kümenin durumunun salt okunur yeni bir anlık görüntüsünü oluşturur ve bunu her çalışan iş parçacığına gönderir.
  6. Bir sonraki sessiz dönemde, çalışan iş parçacığı tahsis edilen TLS yuvasındaki anlık görüntüyü güncelleyecektir.
  7. Ana bilgisayar ile yük dengesini belirlemesi gereken bir G/Ç olayı sırasında, yük dengeleyici, ana bilgisayar hakkında bilgi edinmek için bir TLS (İş parçacığı yerel depolama) yuvası talep edecektir. Bu kilit gerektirmez. Ayrıca TLS'nin, yük dengeleyicilerin ve diğer bileşenlerin önbellekleri, veri yapılarını vb. yeniden hesaplayabilmesi için güncelleme olaylarını da tetikleyebileceğini unutmayın. Bu, bu yazının kapsamı dışındadır ancak kodun çeşitli yerlerinde kullanılmaktadır.

Yukarıdaki prosedürü kullanarak Envoy, her talebi herhangi bir engelleme olmaksızın işleyebilir (daha önce açıklanan durumlar hariç). TLS kodunun karmaşıklığının yanı sıra, kodun çoğunun çoklu iş parçacığının nasıl çalıştığını anlamasına gerek yoktur ve tek iş parçacıklı olarak yazılabilir. Bu, üstün performansın yanı sıra kodun çoğunun yazılmasını kolaylaştırır.

TLS'yi kullanan diğer alt sistemler

TLS (İş parçacığı yerel depolaması) ve RCU (Kopyayı Oku Güncellemesi), Envoy'da yaygın olarak kullanılmaktadır.

Kullanım örnekleri:

  • Yürütme sırasında işlevselliği değiştirme mekanizması: Etkinleştirilen işlevlerin geçerli listesi ana ileti dizisinde hesaplanır. Daha sonra her bir çalışan iş parçacığına RCU semantiği kullanılarak salt okunur bir anlık görüntü verilir.
  • Rota tablolarını değiştirme: RDS (Rota Keşif Hizmeti) tarafından sağlanan rota tabloları için rota tabloları ana iş parçacığında oluşturulur. Salt okunur anlık görüntü daha sonra RCU (Okuma Kopyası Güncellemesi) semantiği kullanılarak her bir çalışan iş parçacığına sağlanacaktır. Bu, rota tablolarının değiştirilmesini atomik olarak verimli hale getirir.
  • HTTP üstbilgisini önbelleğe alma: Görünen o ki, her istek için HTTP başlığını hesaplamak (çekirdek başına ~25K+ RPS çalıştırırken) oldukça pahalı. Elçi, başlığı yaklaşık olarak her yarım saniyede bir merkezi olarak hesaplar ve bunu her çalışana TLS ve RCU aracılığıyla sağlar.

Başka durumlar da vardır ancak önceki örnekler TLS'nin ne için kullanıldığına dair iyi bir anlayış sağlamalıdır.

Bilinen performans tuzakları

Envoy genel olarak oldukça iyi performans gösterse de, çok yüksek eşzamanlılık ve aktarım hızıyla kullanıldığında dikkat edilmesi gereken birkaç önemli alan vardır:

  • Bu makalede açıklandığı gibi, şu anda tüm çalışan iş parçacıkları erişim günlüğü bellek arabelleğine yazarken bir kilit alıyor. Yüksek eşzamanlılık ve yüksek aktarım hızında, son dosyaya yazarken sıra dışı teslimat pahasına her çalışan iş parçacığı için erişim günlüklerini toplu halde toplamanız gerekecektir. Alternatif olarak, her çalışan iş parçacığı için ayrı bir erişim günlüğü oluşturabilirsiniz.
  • İstatistikler yüksek düzeyde optimize edilmiş olsa da, çok yüksek eşzamanlılık ve verimde, bireysel istatistikler üzerinde büyük olasılıkla atomik çekişme olacaktır. Bu sorunun çözümü, merkezi sayaçların periyodik olarak sıfırlanmasıyla çalışan iş parçacığı başına sayaçların kullanılmasıdır. Bu, bir sonraki yazıda tartışılacaktır.
  • Envoy, önemli miktarda işlem kaynağı gerektiren çok az bağlantının olduğu bir senaryoda dağıtılırsa mevcut mimari iyi çalışmayacaktır. Bağlantıların çalışan iş parçacıkları arasında eşit şekilde dağıtılacağına dair bir garanti yoktur. Bu, çalışan iş parçacıkları arasında bağlantı alışverişine izin verecek olan çalışan bağlantı dengelemesi uygulanarak çözülebilir.

Çözüm

Envoy'un iş parçacığı modeli, doğru şekilde yapılandırılmadığı takdirde potansiyel olarak israfa neden olan bellek ve bağlantılar pahasına, programlama kolaylığı ve büyük paralellik sağlayacak şekilde tasarlanmıştır. Bu model, çok yüksek iş parçacığı sayılarında ve verimde çok iyi performans göstermesine olanak tanır.
Twitter'da kısaca bahsettiğim gibi tasarım, DPDK (Veri Düzlemi Geliştirme Kiti) gibi tam kullanıcı modu ağ yığınının üzerinde de çalışabilir; bu da geleneksel sunucuların tam L7 işlemeyle saniyede milyonlarca isteği işlemesine neden olabilir. Önümüzdeki birkaç yıl içinde neyin inşa edileceğini görmek çok ilginç olacak.
Son bir kısa yorum: Birçok kez Envoy için neden C++'ı seçtiğimiz soruldu. Bunun nedeni, bu yazıda anlatılan mimarinin inşa edilebileceği, yaygın olarak kullanılan tek endüstriyel sınıf dilin hala bu dil olmasıdır. C++ kesinlikle tüm projelere, hatta çoğu projeye uygun değildir, ancak belirli kullanım durumları için hala işi bitirecek tek araçtır.

Kod bağlantıları

Bu yazıda tartışılan arayüzlere ve başlık uygulamalarına sahip dosyalara bağlantılar:

Kaynak: habr.com

Yorum ekle