Kubernetes'te uzun ömürlü bağlantıları yük dengeleme ve ölçeklendirme

Kubernetes'te uzun ömürlü bağlantıları yük dengeleme ve ölçeklendirme
Bu makale, Kubernetes'te yük dengelemenin nasıl çalıştığını, uzun ömürlü bağlantıları ölçeklendirirken ne olacağını ve HTTP/2, gRPC, RSockets, AMQP veya diğer uzun ömürlü protokolleri kullanıyorsanız neden istemci tarafı dengelemeyi dikkate almanız gerektiğini anlamanıza yardımcı olacaktır. . 

Kubernetes'te trafiğin nasıl yeniden dağıtıldığı hakkında biraz bilgi 

Kubernetes, uygulamaların dağıtımı için iki kullanışlı soyutlama sağlar: Hizmetler ve Dağıtımlar.

Dağıtımlar, uygulamanızın herhangi bir zamanda nasıl ve kaç kopyasının çalıştırılması gerektiğini açıklar. Her uygulamaya bir Pod olarak dağıtılır ve bir IP adresi atanır.

Hizmetler, işlev olarak yük dengeleyiciye benzer. Trafiği birden fazla bölmeye dağıtmak için tasarlanmıştır.

Bakalım neye benziyor.

  1. Aşağıdaki şemada aynı uygulamanın üç örneğini ve bir yük dengeleyiciyi görebilirsiniz:

    Kubernetes'te uzun ömürlü bağlantıları yük dengeleme ve ölçeklendirme

  2. Yük dengeleyiciye Hizmet adı verilir ve bir IP adresi atanır. Gelen herhangi bir istek bölmelerden birine yönlendirilir:

    Kubernetes'te uzun ömürlü bağlantıları yük dengeleme ve ölçeklendirme

  3. Dağıtım senaryosu, uygulamanın örneklerinin sayısını belirler. Neredeyse hiçbir zaman doğrudan aşağıdakileri genişletmeniz gerekmeyecek:

    Kubernetes'te uzun ömürlü bağlantıları yük dengeleme ve ölçeklendirme

  4. Her bölmeye kendi IP adresi atanır:

    Kubernetes'te uzun ömürlü bağlantıları yük dengeleme ve ölçeklendirme

Hizmetleri bir IP adresleri koleksiyonu olarak düşünmek faydalıdır. Hizmete her eriştiğinizde listeden IP adreslerinden biri seçilir ve hedef adres olarak kullanılır.

Şuna benziyor.

  1. Hizmete bir kıvrılma 10.96.45.152 isteği alındı:

    Kubernetes'te uzun ömürlü bağlantıları yük dengeleme ve ölçeklendirme

  2. Hizmet, hedef olarak üç bölme adresinden birini seçer:

    Kubernetes'te uzun ömürlü bağlantıları yük dengeleme ve ölçeklendirme

  3. Trafik belirli bir bölmeye yönlendirilir:

    Kubernetes'te uzun ömürlü bağlantıları yük dengeleme ve ölçeklendirme

Uygulamanız bir ön uç ve bir arka uçtan oluşuyorsa, her biri için hem bir hizmete hem de dağıtıma sahip olursunuz.

Ön uç, arka uca bir istekte bulunduğunda, arka ucun tam olarak kaç bölmeye hizmet ettiğini bilmesine gerek yoktur: bir, on veya yüz olabilir.

Ayrıca ön uç, arka uca hizmet veren bölmelerin adresleri hakkında hiçbir şey bilmiyor.

Ön uç, arka uçtan bir istekte bulunduğunda, arka uç hizmetinin değişmeyen IP adresini kullanır.

İşte nasıl göründüğünü bulunuyor.

  1. 1'in altında dahili arka uç bileşenini talep eder. Arka uç için belirli bir tane seçmek yerine hizmete bir istekte bulunur:

    Kubernetes'te uzun ömürlü bağlantıları yük dengeleme ve ölçeklendirme

  2. Hizmet, hedef adres olarak arka uç bölmelerinden birini seçer:

    Kubernetes'te uzun ömürlü bağlantıları yük dengeleme ve ölçeklendirme

  3. Trafik, hizmet tarafından seçilen Bölme 1'den Bölme 5'e gider:

    Kubernetes'te uzun ömürlü bağlantıları yük dengeleme ve ölçeklendirme

  4. 1 yaş altı, hizmetin arkasında 5 yaş altı gibi kaç bölmenin gizlendiğini tam olarak bilmiyor:

    Kubernetes'te uzun ömürlü bağlantıları yük dengeleme ve ölçeklendirme

Peki hizmet istekleri tam olarak nasıl dağıtıyor? Round-robin dengeleme kullanılmış gibi mi görünüyor? Hadi çözelim. 

Kubernetes hizmetlerinde dengeleme

Kubernetes hizmetleri mevcut değil. IP adresi ve port atanan servise yönelik herhangi bir işlem bulunmamaktadır.

Bunu, kümedeki herhangi bir düğümde oturum açarak ve netstat -ntlp komutunu çalıştırarak doğrulayabilirsiniz.

Hizmete tahsis edilen IP adresini bile bulamazsınız.

Hizmetin IP adresi kontrol katmanında, denetleyicide bulunur ve veritabanına (etcd) kaydedilir. Aynı adres başka bir bileşen tarafından da kullanılıyor - kube-proxy.
Kube-proxy, tüm hizmetler için IP adreslerinin bir listesini alır ve kümedeki her düğümde bir dizi iptables kuralı oluşturur.

Bu kurallar şunu söylüyor: “Hizmetin IP adresini görürsek, isteğin hedef adresini değiştirip onu bölmelerden birine göndermemiz gerekiyor.”

Hizmet IP adresi yalnızca bir giriş noktası olarak kullanılır ve bu IP adresini ve bağlantı noktasını dinleyen herhangi bir işlem tarafından sunulmaz.

Hadi şuna bakalım

  1. Üç düğümden oluşan bir küme düşünün. Her düğümün bölmeleri vardır:

    Kubernetes'te uzun ömürlü bağlantıları yük dengeleme ve ölçeklendirme

  2. Bej boyalı bağlı bölmeler hizmetin bir parçasıdır. Hizmet bir süreç olarak mevcut olmadığından gri renkte gösterilir:

    Kubernetes'te uzun ömürlü bağlantıları yük dengeleme ve ölçeklendirme

  3. İlk bölme bir hizmet ister ve ilgili bölmelerden birine gitmesi gerekir:

    Kubernetes'te uzun ömürlü bağlantıları yük dengeleme ve ölçeklendirme

  4. Ama hizmet yok, süreç yok. O nasıl çalışır?

    Kubernetes'te uzun ömürlü bağlantıları yük dengeleme ve ölçeklendirme

  5. İstek düğümden ayrılmadan önce iptables kurallarından geçer:

    Kubernetes'te uzun ömürlü bağlantıları yük dengeleme ve ölçeklendirme

  6. iptables kuralları, hizmetin mevcut olmadığını bilir ve IP adresini, o hizmetle ilişkili bölmelerin IP adreslerinden biriyle değiştirir:

    Kubernetes'te uzun ömürlü bağlantıları yük dengeleme ve ölçeklendirme

  7. İstek, hedef adres olarak geçerli bir IP adresi alır ve normal şekilde işlenir:

    Kubernetes'te uzun ömürlü bağlantıları yük dengeleme ve ölçeklendirme

  8. Ağ topolojisine bağlı olarak istek sonunda bölmeye ulaşır:

    Kubernetes'te uzun ömürlü bağlantıları yük dengeleme ve ölçeklendirme

İptables yük dengeleme yapabilir mi?

Hayır, iptables filtreleme için kullanılır ve dengeleme için tasarlanmamıştır.

Ancak şu şekilde çalışan bir dizi kural yazmak mümkündür: sözde dengeleyici.

Kubernetes'te uygulanan da tam olarak budur.

Üç bölmeniz varsa kube-proxy aşağıdaki kuralları yazacaktır:

  1. %33 olasılıkla ilk alt öğeyi seçin, aksi takdirde bir sonraki kurala geçin.
  2. %50 olasılıkla ikinciyi seçin, aksi takdirde bir sonraki kurala geçin.
  3. Altındaki üçüncüyü seçin.

Bu sistem, her bölmenin %33 olasılıkla seçilmesiyle sonuçlanır.

Kubernetes'te uzun ömürlü bağlantıları yük dengeleme ve ölçeklendirme

Ve Bölme 2'den sonra Bölme 1'nin seçileceğinin garantisi yoktur.

Dikkat: iptables rastgele dağılıma sahip bir istatistiksel modül kullanır. Dolayısıyla dengeleme algoritması rastgele seçime dayanmaktadır.

Artık hizmetlerin nasıl çalıştığını anladığınıza göre daha ilginç hizmet senaryolarına bakalım.

Kubernetes'teki uzun ömürlü bağlantılar varsayılan olarak ölçeklenmez

Ön uçtan arka uca kadar her HTTP isteği, açılan ve kapatılan ayrı bir TCP bağlantısı tarafından sunulur.

Eğer ön uç arka uca saniyede 100 istek gönderirse 100 farklı TCP bağlantısı açılıp kapatılır.

Bir TCP bağlantısı açıp bunu sonraki tüm HTTP istekleri için kullanarak istek işleme süresini ve yükünü azaltabilirsiniz.

HTTP protokolünün, HTTP'yi canlı tutma veya bağlantının yeniden kullanılması adı verilen bir özelliği vardır. Bu durumda birden fazla HTTP isteği ve yanıtı göndermek ve almak için tek bir TCP bağlantısı kullanılır:

Kubernetes'te uzun ömürlü bağlantıları yük dengeleme ve ölçeklendirme

Bu özellik varsayılan olarak etkin değildir: hem sunucunun hem de istemcinin buna göre yapılandırılması gerekir.

Kurulumun kendisi çoğu programlama dili ve ortamı için basit ve erişilebilirdir.

Farklı dillerdeki örneklere bazı bağlantılar:

Bir Kubernetes hizmetinde canlı tutmayı kullanırsak ne olur?
Hem ön uç hem de arka ucun canlı tutmayı desteklediğini varsayalım.

Ön ucun bir kopyasına ve arka ucun üç kopyasına sahibiz. Ön uç ilk isteği yapar ve arka uçla bir TCP bağlantısı açar. İstek servise ulaştığında arka uç bölmelerden biri hedef adres olarak seçilir. Arka uç bir yanıt gönderir ve ön uç bunu alır.

Bir yanıt alındıktan sonra TCP bağlantısının kapatıldığı olağan durumun aksine, artık daha fazla HTTP isteği için açık tutuluyor.

Ön uç arka uca daha fazla istek gönderirse ne olur?

Bu istekleri iletmek için açık bir TCP bağlantısı kullanılacak, tüm istekler ilk isteğin gittiği arka uca gidecektir.

İptables'ın trafiği yeniden dağıtması gerekmez mi?

Bu durumda değil.

Bir TCP bağlantısı oluşturulduğunda, trafiğin gideceği belirli bir arka ucu seçen iptables kurallarından geçer.

Sonraki tüm istekler zaten açık olan bir TCP bağlantısında olduğundan, iptables kuralları artık çağrılmaz.

Bakalım neye benziyor.

  1. İlk bölme hizmete bir istek gönderir:

    Kubernetes'te uzun ömürlü bağlantıları yük dengeleme ve ölçeklendirme

  2. Bundan sonra ne olacağını zaten biliyorsun. Hizmet mevcut değil ancak isteği işleyecek iptables kuralları var:

    Kubernetes'te uzun ömürlü bağlantıları yük dengeleme ve ölçeklendirme

  3. Arka uç bölmelerinden biri hedef adres olarak seçilecektir:

    Kubernetes'te uzun ömürlü bağlantıları yük dengeleme ve ölçeklendirme

  4. İstek bölmeye ulaşır. Bu noktada iki bölme arasında kalıcı bir TCP bağlantısı kurulacaktır:

    Kubernetes'te uzun ömürlü bağlantıları yük dengeleme ve ölçeklendirme

  5. İlk bölmeden gelecek herhangi bir istek, önceden kurulmuş olan bağlantıdan geçecektir:

    Kubernetes'te uzun ömürlü bağlantıları yük dengeleme ve ölçeklendirme

Sonuç olarak daha hızlı tepki süresi ve daha yüksek verim elde edilir, ancak arka ucu ölçeklendirme yeteneğinizi kaybedersiniz.

Arka uçta sürekli bağlantıya sahip iki bölmeniz olsa bile trafik her zaman bunlardan birine gidecektir.

Bu düzeltilebilir mi?

Kubernetes kalıcı bağlantıları nasıl dengeleyeceğini bilmediğinden bu görev size düşüyor.

Hizmetler, uç noktalar adı verilen IP adresleri ve bağlantı noktalarının bir koleksiyonudur.

Uygulamanız hizmetten uç noktaların bir listesini alabilir ve isteklerin bunlar arasında nasıl dağıtılacağına karar verebilir. Her bölmeye kalıcı bir bağlantı açabilir ve bu bağlantılar arasındaki istekleri bir kez denemeyi kullanarak dengeleyebilirsiniz.

Veya daha fazlasını uygulayın karmaşık dengeleme algoritmaları.

Dengelemeden sorumlu olan istemci tarafı kodu şu mantığı izlemelidir:

  1. Hizmetten uç noktaların bir listesini alın.
  2. Her uç nokta için kalıcı bir bağlantı açın.
  3. Bir istek yapılması gerektiğinde açık bağlantılardan birini kullanın.
  4. Uç noktaların listesini düzenli olarak güncelleyin, yenilerini oluşturun veya liste değişirse eski kalıcı bağlantıları kapatın.

İşte böyle görünecek.

  1. İsteği hizmete gönderen ilk bölme yerine, istemci tarafındaki istekleri dengeleyebilirsiniz:

    Kubernetes'te uzun ömürlü bağlantıları yük dengeleme ve ölçeklendirme

  2. Hangi bölmelerin hizmetin parçası olduğunu soran bir kod yazmanız gerekir:

    Kubernetes'te uzun ömürlü bağlantıları yük dengeleme ve ölçeklendirme

  3. Listeyi aldıktan sonra istemci tarafına kaydedin ve bölmelere bağlanmak için kullanın:

    Kubernetes'te uzun ömürlü bağlantıları yük dengeleme ve ölçeklendirme

  4. Yük dengeleme algoritmasından siz sorumlusunuz:

    Kubernetes'te uzun ömürlü bağlantıları yük dengeleme ve ölçeklendirme

Şimdi şu soru ortaya çıkıyor: Bu sorun yalnızca HTTP'yi canlı tutma için mi geçerli?

İstemci tarafı yük dengeleme

Kalıcı TCP bağlantılarını kullanabilen tek protokol HTTP değildir.

Uygulamanız bir veritabanı kullanıyorsa, her istekte bulunmanız veya veritabanından belge almanız gerektiğinde TCP bağlantısı açılmaz. 

Bunun yerine veritabanına kalıcı bir TCP bağlantısı açılır ve kullanılır.

Veritabanınız Kubernetes üzerinde konuşlandırılıyorsa ve erişim hizmet olarak sağlanıyorsa bir önceki bölümde anlatılan sorunların aynılarıyla karşılaşırsınız.

Bir veritabanı kopyası diğerlerinden daha fazla yüklenecektir. Kube-proxy ve Kubernetes, bağlantıları dengelemeye yardımcı olmayacaktır. Veritabanınızdaki sorguları dengelemeye dikkat etmelisiniz.

Veritabanına bağlanmak için hangi kütüphaneyi kullandığınıza bağlı olarak bu sorunu çözmek için farklı seçenekleriniz olabilir.

Aşağıda Node.js'den MySQL veritabanı kümesine erişmenin bir örneği verilmiştir:

var mysql = require('mysql');
var poolCluster = mysql.createPoolCluster();

var endpoints = /* retrieve endpoints from the Service */

for (var [index, endpoint] of endpoints) {
  poolCluster.add(`mysql-replica-${index}`, endpoint);
}

// Make queries to the clustered MySQL database

Kalıcı TCP bağlantılarını kullanan başka birçok protokol vardır:

  • WebSocket'ler ve güvenli WebSocket'ler
  • HTTP / 2
  • gRPC
  • RSoketler
  • AMQP

Bu protokollerin çoğuna zaten aşina olmalısınız.

Ancak bu protokoller bu kadar popülerse neden standartlaştırılmış bir dengeleme çözümü yok? İstemci mantığının neden değişmesi gerekiyor? Yerel bir Kubernetes çözümü var mı?

Kube-proxy ve iptables, Kubernetes'e dağıtım sırasında en yaygın kullanım durumlarını kapsayacak şekilde tasarlanmıştır. Bu kolaylık sağlamak içindir.

REST API'sini kullanıma sunan bir web hizmeti kullanıyorsanız şanslısınız; bu durumda kalıcı TCP bağlantıları kullanılmaz; herhangi bir Kubernetes hizmetini kullanabilirsiniz.

Ancak kalıcı TCP bağlantılarını kullanmaya başladığınızda, yükü arka uçlara nasıl eşit şekilde dağıtacağınızı bulmanız gerekecektir. Kubernetes bu duruma yönelik hazır çözümler içermiyor.

Ancak kesinlikle yardımcı olabilecek seçenekler var.

Kubernetes'te uzun ömürlü bağlantıları dengeleme

Kubernetes'te dört tür hizmet vardır:

  1. Küme IP'si
  2. Düğüm Bağlantı Noktası
  3. Yük dengeleyici
  4. Kafasız

İlk üç hizmet, kube-proxy tarafından iptables kuralları oluşturmak için kullanılan sanal bir IP adresine dayalı olarak çalışır. Ancak tüm hizmetlerin temel temeli başsız bir hizmettir.

Başsız hizmetin kendisiyle ilişkili herhangi bir IP adresi yoktur ve yalnızca kendisiyle ilişkili bölmelerin (uç noktalar) IP adresleri ve bağlantı noktalarının bir listesini almak için bir mekanizma sağlar.

Tüm hizmetler başsız hizmeti temel alır.

ClusterIP hizmeti, bazı eklemelere sahip, başsız bir hizmettir: 

  1. Yönetim katmanı ona bir IP adresi atar.
  2. Kube-proxy gerekli iptables kurallarını oluşturur.

Bu şekilde kube-proxy'yi göz ardı edebilir ve uygulamanızın yükünü dengelemek için başsız hizmetten elde edilen uç noktaların listesini doğrudan kullanabilirsiniz.

Ancak kümede konuşlandırılan tüm uygulamalara benzer mantığı nasıl ekleyebiliriz?

Uygulamanız zaten konuşlandırılmışsa bu görev imkansız görünebilir. Ancak alternatif bir seçenek de var.

Service Mesh size yardımcı olacaktır

Muhtemelen istemci tarafı yük dengeleme stratejisinin oldukça standart olduğunu fark etmişsinizdir.

Uygulama başladığında:

  1. Hizmetten IP adreslerinin bir listesini alır.
  2. Bir bağlantı havuzunu açar ve bakımını yapar.
  3. Uç noktaları ekleyerek veya kaldırarak havuzu düzenli aralıklarla günceller.

Uygulama bir istekte bulunmak istediğinde:

  1. Bir mantık kullanarak (örneğin, hepsini bir kez deneme) kullanılabilir bir bağlantıyı seçer.
  2. İsteği yürütür.

Bu adımlar hem WebSockets, gRPC hem de AMQP bağlantılarında işe yarar.

Bu mantığı ayrı bir kütüphaneye ayırıp uygulamalarınızda kullanabilirsiniz.

Ancak bunun yerine Istio veya Linkerd gibi servis ağlarını kullanabilirsiniz.

Service Mesh, uygulamanızı aşağıdakileri gerçekleştiren bir süreçle geliştirir:

  1. Hizmet IP adreslerini otomatik olarak arar.
  2. WebSockets ve gRPC gibi bağlantıları test eder.
  3. Doğru protokolü kullanarak istekleri dengeler.

Service Mesh, küme içindeki trafiğin yönetilmesine yardımcı olur ancak kaynak açısından oldukça yoğundur. Diğer seçenekler Netflix Ribbon gibi üçüncü taraf kitaplıkları veya Envoy gibi programlanabilir proxy'leri kullanmaktır.

Dengeleme sorunlarını görmezden gelirseniz ne olur?

Yük dengelemeyi kullanmamayı tercih edebilir ve yine de herhangi bir değişiklik fark etmeyebilirsiniz. Birkaç çalışma senaryosuna bakalım.

Sunuculardan daha fazla müşteriniz varsa, bu o kadar da büyük bir sorun değildir.

Diyelim ki iki sunucuya bağlanan beş istemci var. Dengeleme olmasa bile her iki sunucu da kullanılacaktır:

Kubernetes'te uzun ömürlü bağlantıları yük dengeleme ve ölçeklendirme

Bağlantılar eşit şekilde dağıtılmamış olabilir: aynı sunucuya dört istemci bağlı olabilir, ancak her iki sunucunun da kullanılması ihtimali yüksektir.

Daha sorunlu olan ise tam tersi senaryodur.

Daha az istemciniz ve daha fazla sunucunuz varsa, kaynaklarınız yeterince kullanılamayabilir ve potansiyel bir darboğaz ortaya çıkabilir.

Diyelim ki iki istemci ve beş sunucu var. En iyi durumda, beş sunucudan ikisine iki kalıcı bağlantı olacaktır.

Kalan sunucular boşta kalacak:

Kubernetes'te uzun ömürlü bağlantıları yük dengeleme ve ölçeklendirme

Bu iki sunucu istemci isteklerini karşılayamıyorsa yatay ölçeklendirmenin bir faydası olmaz.

Sonuç

Kubernetes hizmetleri çoğu standart web uygulaması senaryosunda çalışacak şekilde tasarlanmıştır.

Ancak veritabanları, gRPC veya WebSockets gibi kalıcı TCP bağlantıları kullanan uygulama protokolleriyle çalışmaya başladığınızda hizmetler artık uygun değildir. Kubernetes, kalıcı TCP bağlantılarını dengelemek için dahili mekanizmalar sağlamaz.

Bu, uygulamaları istemci tarafı dengelemeyi göz önünde bulundurarak yazmanız gerektiği anlamına gelir.

Ekibin hazırladığı çeviri Mail.ru'dan Kubernetes aaS.

Konuyla ilgili başka ne okunmalı?:

  1. Kubernetes'te üç otomatik ölçeklendirme düzeyi ve bunların etkili bir şekilde nasıl kullanılacağı
  2. Uygulamaya yönelik bir şablonla korsanlık ruhuna sahip Kubernet'ler.
  3. Dijital dönüşümle ilgili Telegram kanalımız.

Kaynak: habr.com

Yorum ekle