Advanced Distributed Scalable Internal Load Balancer

Sefa Pehlivan
hepsiburadatech
Published in
5 min readJan 28, 2022

Hemen hemen tüm dünya micro service mimariye geçiş yapmış durumda. Yüzlerce micro service birbirleri ile konuşma ihtiyacı duyuyor peki ama nasıl? Eğer her şey tek bir Kubernetes cluster’ı üzerinde çalışıyor veya cloud ortamındaysanız herhangi bir probleminiz olmuyor ama yüzlerce micro service, onlarca k8s üzerinde çalışıyor ve bu yapı on-prem’de ise o zaman büyük bir probleminiz var demektir, bu servisleri birbirleri ile konuşturabilmek. Bu sorunu çözebilmek için içerisinde birçok teknoloji kullandığımız özgün bir mimari tasarladık.

Dns Flow — IMG01

DNS Load Balancing

CoreDNS
IMG01 grafiği, projemizin kilit noktası olan DNS flow’u ve kullandığımız teknolojileri içeriyor. Burada iki tane DC bulunuyor her DC üzerindeki DNS request’leri, kendi DC’leri üzerindeki CoreDns sunucularına doğru yapılıyor. Ortamdaki CoreDns sunucuları üzerine her servis için ayrı ayrı aşağıdaki gibi bir dns forwarder ekleyerek istekleri consul sunucularına yönlendiriyoruz. Bu iş için başka bir DNS server kullanabilirdik neden CoreDns diyecek olursanız forward edilen yer Consul olduğu için Consul kendisine gelen DNS query’leri query.<sizin_verdiğiniz_DC> şeklinde kabul ediyor. Consul’e ayak uydurabilmek için CoreDns yeteneklerinden biri olan rewrite özelliğini kullanarak gelen ve dönen dns query’lerine ufak bir takla attırıyoruz. :)

Zone Record — IMG02

CONSUL
Yapımızda n tane layer7 load balancer sunucusu olabilir ve bir servis n tane load balancer sunucusu üzerinden serve edilebilir. Bir servisin hangi load balancer sunucuları üzerinde çalıştığı ve bunların up/down süreçlerini izlemesi için consul’u görevlendirdik. Hepsiburada multi DC üzerinde aktif aktif çalışıyor. Bir servis bir DC üzerinde down olduğunda diğer DC üzerinden kesintisiz yoluna devam edebilmelidir. Yapımızda üç DC üzerinde bulunan Consul’ları birbirleri ile federation kurarak ha yapı sağlıyoruz. Günün sonunda her CoreDns kendi DC üzerindeki Consul’a istekleri forward ediyor eğer Consul, istenilen servis up durumda ise servis ip adreslerini yada adreslerini dönüyor down durumda ise Consul’e girdiğimiz failover query’si sayesinde birinci failover DC ye sorarak oradan dönen cevabı geriye dönüyor, eğer o DC üzerindeki servis de down durumda ise ikinci yazdığımız bizim senaryoda bu public cloud ortamı oluyor ve oradan dönen cevap geriye dönülüyor. Biz ihtiyaçlarımızı göz önünde bulundurduğumuzda Consul’a iki adet health check adresi vermeyi uygun gördük. Birincisi load balancer ip adresi arkasındaki uygulama üzerinde bulunan health check endpoint’i ikincisi ise, load balancer olarak envoy kullanmayı tercih ettik envoy her servis için bir admin arayüz ayağa kaldırıyor arayüzde /ready isminde bir endpoint bulunuyor bu endpoint sayesinde envoy state’ini check edebiliyoruz. Envoy üzerinden uygulama check ediliyor, neden ekstra buna ihtiyaç duydunuz derseniz cevap çok basit kontrollü failover’lar için. Envoy’un bu endpoint’i tamda bu iş için var /ready endpoint’inin dönen cevabını istediğimiz zaman “healthcheck/fail-ok” endpoint’leri ile değiştirebiliyoruz. Manuel bir şekilde Envoy’u fail’e çektiğimizde “/ready” endpoint’i bize artık 200 dönmeyecektir ve Consul o servis için o load balancer’ı dönen cevaplarından kaldıracaktır. İlgili DC üzerinde tüm adresler down durumda ise failover senaryosu çalışarak trafik diğer DC üzerine gönderilecektir. Bu yapıyı verimli kılabilmek için Consul üzerindeki service TTL değerini 1 olarak set ediyoruz.

Consul service Failover conf — IMG03

Yüzlerce service var dedik peki bu yapıyı manual mi yönetiyoruz? Tabi ki hayır böyle bir yapıyı bir otomasyon süreci olmadan yönetebilmek gerçekten çok zor olabilirdi bunu da düşünerek daha önce burada bahsettiğimiz projemizi fork’ladık ve internal için bir versiyon geliştirdik.

BigBang Controller — IMG04

BIGBANG
Tüm bu yapıyı merkezi bir noktadan yönetebilmek için geliştirdiğimiz uygulamamızın adı BigBang. En belirgin görevleri arasında aşağıdaki maddeler bulunmaktadır.

  1. Auto Machine Provision
    OpenStack ve Vmware üzerine custom ettiğimiz imajları kullanarak load balancer makineleri oluşturmak yada silmek. Makineleri, her iki sanallaştırma platform’u içinde pyvmomi ve openstacksdk kütüphaneleri kullanarak yönetiyoruz. Makineler ilk ayağa kalktığında Jenkins üzerinden parametrik bir pipeline tetiklenerek ilgili makineyi ready hale getiriyoruz. Makinelerin üç interface’i olacak şekilde kurguladık.
    Upstream: Arkadaki sunucular ile konuşmak için kullanılan interface.
    Downstream: Servislerin hizmet verdiği listener interface.
    Management: Yönetimsel işler için kullanılan interface.
  2. Domain Scale UP/DOWN
    Bir servisi birden çok load balancer üzerine dağıtarak Consul kaydı tanımlamak veya var olan bir yerden silerek servisin Consul üzerindeki kaydını güncellemek. Consul api endpoint’leri kullanarak service catalog’unu sürekli güncel tutuyoruz.
  3. Manual Site FailOver
    Bir site üzerinde belirli bir servisi diğer site üzerindeki aynı servise kesintisiz failover etmek. İlgili servisin envoy admin endpoint’i ile oynayarak bu işlemi gerçekleştiriyoruz.
  4. CoreDns & Consul Management
    CoreDns ve Consul üzerindeki kayıtları oluşturmak, silmek ve güncellemek. Cloud üzerindeki servisleri Consul üzerine manuel ekleyip çıkartıyoruz. IMG02 görselindeki kaydı bir servis için ekleme veya silme işini yine BigBang üzerinden CoreDNS sunucuları için yazdığımız lightweight agent’lar ile konuşarak gerçekleştiriyoruz.
  5. Envoy Conf Management
    Envoy için konfigürasyonlar oluşturmak, silmek ve güncellemek.
  6. Dynamic Node Discovery(Valse)
    Gelecekte kullanmayı planladığımız şimdilerde testlerini yaptığımız ClusterApi ile k8s node’ları scale olabilecek. Hepsiburada içerisinde geliştirilen Valse uygulamasını kullanarak servislerin arkasındaki Upstream’leri otomatik güncellemek.
  7. Envoy Control Plane
    Envoy’un LDS, CDS ve EDS resource’larını keşfedebilmesi için ayrı ayrı endpoint’ler sunmak. Envoy’un önyükleme yapabilmesi ve controller’ı keşfedebilmesi için, her domain ve makineye özel bir bootstrap file oluşturuyoruz. Bu dosya domain deploy edildiğinde yada scale up edildiğinde makineye ve servis’e özel oluşturuluyor bu sayede envoy BigBang’e gelerek resource’ları istediğinde BigBang hangi makinenin hangi servis için geldiğini anlıyor. Ayrıca BigBang her verdiği resource için Redis üzerinde “makine_adı+servis_adı+xds” kombinasyonundan oluşan bir key içinde son gönderilen versiyonu tutuyor. Envoy bir sonraki gelişinde BigBang önce Envoy’un üzerinde çalışan versiyon ile cache de bulunan versiyonu karşılaştırarak aynı ise 304 status code ile boş body dönüyor bu sayede envoy değişiklik olmadığını anlıyor. BigBang’de herhangi bir servisin LDS konfigürasyonunda bir değişiklik yaptığımızda ilgili servisin LDS versiyon numarasını bir arttırarak cache üzerindeki kayıtlarını makine bağımsız temizliyoruz. Bu sayede envoy yeni versiyonlu konfigürasyonu çekerek yürütmeye başlıyor.
Envoy Bootstrap File — IMG05

SONUÇ
Tüm bu yapı bize beraberinde orta katmanda gelişmiş loglama, metricler ve alarmlar ile birlikte X bir service için trafiği tek nokta ile sınırlandırmadan istediğimiz kadar dağıtabilme özgürlüğü kazandırmaktadır. Ayrıca servislerin diğer side üzerine otomatik failover olabilme yeteneği ile uptime sürelerine ciddi fayda sağlayacaktır.

--

--