Mail.ru Bulut Çözümleri platformunda hataya dayanıklı web mimarisi nasıl uygulanır?

Mail.ru Bulut Çözümleri platformunda hataya dayanıklı web mimarisi nasıl uygulanır?

Merhaba Habr! Ben Artem Karamyshev, sistem yönetimi ekibinin başkanıyım Mail.Ru Bulut Çözümleri (MCS). Geçtiğimiz yıl birçok yeni ürün lansmanımız oldu. API hizmetlerinin kolayca ölçeklenebilir, hataya dayanıklı ve kullanıcı yükündeki hızlı büyümeye hazır olduğundan emin olmak istedik. Platformumuz OpenStack üzerinde uygulandı ve size hataya dayanıklı bir sistem elde etmek için hangi bileşen hata toleransı sorunlarını çözmemiz gerektiğini anlatmak istiyorum. Bunun da OpenStack üzerinde ürün geliştirenlerin ilgisini çekeceğini düşünüyorum.

Bir platformun genel hata toleransı, bileşenlerinin esnekliğinden oluşur. Yani yavaş yavaş riskleri tespit ettiğimiz ve kapattığımız tüm seviyelerden geçeceğiz.

Ana kaynağı Uptime 4. gün konferansında sunulan bir rapor olan bu hikayenin video versiyonu. ITSumma, görebilirsin Uptime Topluluğu YouTube kanalında.

Fiziksel mimarinin dayanıklılığı

MCS bulutunun halka açık kısmı artık iki Seviye III veri merkezine dayanıyor; bunların arasında, 200 Gbit/s aktarım hızına sahip, fiziksel düzeyde farklı rotalarla ayrılmış kendi karanlık fiberi bulunuyor. Tier III, fiziksel altyapı için gerekli seviyede hata toleransı sağlar.

Koyu fiber hem fiziksel hem de mantıksal düzeyde saklıdır. Kanal rezervasyon süreci yineleniyordu, sorunlar ortaya çıktı ve veri merkezleri arasındaki iletişimi sürekli olarak geliştiriyoruz.

Örneğin, kısa bir süre önce, veri merkezlerinden birinin yakınındaki bir kuyuda çalışırken bir ekskavatör bir boruyu kırdı ve bu borunun içinde hem ana hem de yedek optik kablo vardı. Veri merkeziyle olan hataya dayanıklı iletişim kanalımızın bir noktada, yani kuyuda savunmasız olduğu ortaya çıktı. Buna bağlı olarak altyapının bir kısmını kaybettik. Sonuçlar çıkardık ve bitişikteki kuyuya ek optiklerin takılması da dahil olmak üzere bir dizi önlem aldık.

Veri merkezlerinde BGP aracılığıyla öneklerimizi yayınladığımız iletişim sağlayıcıların varlık noktaları bulunmaktadır. Her ağ yönü için, farklı istemcilere en iyi bağlantı kalitesinin sağlanmasına olanak tanıyan en iyi ölçüm seçilir. Bir sağlayıcı üzerinden iletişim kesilirse, mevcut sağlayıcılar aracılığıyla yönlendirmemizi yeniden oluştururuz.

Bir sağlayıcı başarısız olursa otomatik olarak bir sonrakine geçeriz. Veri merkezlerinden birinin arızalanması durumunda, tüm yükü üstlenen hizmetlerimizin bir kopyasını ikinci veri merkezinde bulunduruyoruz.

Mail.ru Bulut Çözümleri platformunda hataya dayanıklı web mimarisi nasıl uygulanır?
Fiziksel altyapının dayanıklılığı

Uygulama düzeyinde hata toleransı için ne kullanıyoruz?

Hizmetimiz bir dizi açık kaynaklı bileşen üzerine kurulmuştur.

ExaBGP BGP tabanlı dinamik yönlendirme protokolünü kullanarak bir dizi işlevi uygulayan bir hizmettir. Kullanıcıların API'ye eriştiği, beyaz listeye alınmış IP adreslerimizin reklamını yapmak için bunu aktif olarak kullanıyoruz.

HAProxy OSI modelinin farklı seviyelerinde çok esnek trafik dengeleme kurallarını yapılandırmanıza olanak tanıyan yüksek yük dengeleyicidir. Bunu tüm hizmetlerin önünde denge kurmak için kullanıyoruz: veritabanları, mesaj aracıları, API hizmetleri, web hizmetleri, dahili projelerimiz - her şey HAProxy'nin arkasındadır.

API uygulaması — kullanıcının altyapısını ve hizmetini yönettiği, python ile yazılmış bir web uygulaması.

İşçi başvurusu (bundan sonra sadece işçi olarak anılacaktır) - OpenStack hizmetlerinde bu, API komutlarını altyapıya yayınlamanıza olanak tanıyan bir altyapı arka plan programıdır. Örneğin, disk oluşturma, çalışanda gerçekleşir ve oluşturma isteği, uygulama API'sinde gerçekleşir.

Standart OpenStack Uygulama Mimarisi

OpenStack için geliştirilen çoğu hizmet tek bir paradigmayı izlemeye çalışır. Bir hizmet genellikle 2 bölümden oluşur: API ve çalışanlar (arka uç uygulayıcıları). Kural olarak API, bağımsız bir işlem (arka plan programı) olarak veya hazır bir Nginx veya Apache web sunucusu kullanılarak başlatılan, python'da bir WSGI uygulamasıdır. API, kullanıcı isteğini işler ve yürütülmek üzere alt uygulamaya daha fazla talimat iletir. Aktarım bir mesaj komisyoncusu (genellikle RabbitMQ) kullanılarak gerçekleşir, diğerleri yeterince desteklenmez. Mesajlar komisyoncuya ulaştığında çalışanlar tarafından işlenir ve gerekirse bir yanıt verilir.

Bu paradigma izole edilmiş ortak hata noktalarını içerir: RabbitMQ ve veritabanı. Ancak RabbitMQ tek bir hizmet içinde izole edilmiştir ve teorik olarak her hizmet için ayrı olabilir. Bu nedenle MCS'de bu hizmetleri mümkün olduğunca ayırıyoruz; her proje için ayrı bir veritabanı, ayrı bir RabbitMQ oluşturuyoruz. Bu yaklaşım iyidir çünkü bazı hassas noktalarda bir kaza olması durumunda hizmetin tamamı değil, yalnızca bir kısmı bozulur.

Çalışan uygulamalarının sayısı sınırsız olduğundan API, performansı ve hata toleransını artırmak için dengeleyicilerin arkasında yatay olarak kolayca ölçeklenebilir.

Bazı hizmetler, API'ler ve çalışanlar arasında karmaşık sıralı işlemler gerçekleştiğinde hizmet içinde koordinasyon gerektirir. Bu durumda, bir çalışanın diğerine bu görevin kendisine verildiğini (“lütfen almayın”) söylemesine olanak tanıyan Redis, Memcache vb. gibi bir küme sistemi olan tek bir koordinasyon merkezi kullanılır. vb. kullanıyoruz. Kural olarak, işçiler veri tabanıyla aktif olarak iletişim kurar, oradan bilgi yazar ve okur. Multimaster kümesinde bulunan mariadb'yi veritabanı olarak kullanıyoruz.

Bu klasik tekli hizmet, OpenStack için genel olarak kabul edilen bir şekilde düzenlenmiştir. Ölçeklendirme ve hata toleransı yöntemlerinin oldukça açık olduğu kapalı bir sistem olarak düşünülebilir. Örneğin API hata toleransı için önlerine bir dengeleyici koymak yeterlidir. İşçilerin ölçeklendirilmesi sayılarının arttırılmasıyla sağlanır.

Tüm şemadaki zayıf nokta RabbitMQ ve MariaDB'dir. Mimarileri ayrı bir makaleyi hak ediyor. Bu yazıda API hata toleransına odaklanmak istiyorum.

Mail.ru Bulut Çözümleri platformunda hataya dayanıklı web mimarisi nasıl uygulanır?
Openstack Uygulama Mimarisi. Bulut platformunun dengelenmesi ve hata toleransı

ExaBGP kullanarak HAProxy dengeleyiciyi hataya dayanıklı hale getirme

API'lerimizi ölçeklenebilir, hızlı ve hataya dayanıklı hale getirmek için önlerine bir yük dengeleyici koyduk. HAProxy'yi seçtik. Bana göre görevimiz için gerekli tüm özelliklere sahip: çeşitli OSI seviyelerinde dengeleme, yönetim arayüzü, esneklik ve ölçeklenebilirlik, çok sayıda dengeleme yöntemi, oturum tabloları desteği.

Çözülmesi gereken ilk sorun, dengeleyicinin hata toleransıydı. Basitçe bir dengeleyici kurmak aynı zamanda bir arıza noktası da yaratır: dengeleyici bozulur ve hizmet çöker. Bunun olmasını önlemek için HAProxy'yi ExaBGP ile birlikte kullandık.

ExaBGP, bir hizmetin durumunu kontrol etmek için bir mekanizma uygulamanıza olanak tanır. Bu mekanizmayı HAProxy'nin işlevselliğini kontrol etmek ve sorun olması durumunda HAProxy hizmetini BGP'den devre dışı bırakmak için kullandık.

ExaBGP+HAProxy şeması

  1. Gerekli yazılım olan ExaBGP ve HAProxy'yi üç sunucuya kuruyoruz.
  2. Her sunucuda bir geridöngü arayüzü oluşturuyoruz.
  3. Her üç sunucuda da bu arayüze aynı beyaz IP adresini atarız.
  4. ExaBGP aracılığıyla internete beyaz bir IP adresi duyurulur.

Hata toleransı, üç sunucunun hepsinden aynı IP adresinin duyurulmasıyla sağlanır. Ağ açısından bakıldığında, aynı adrese üç farklı sonraki atlama noktasından erişilebilir. Yönlendirici üç özdeş rota görür, kendi ölçüsüne göre bunların en yüksek önceliğini seçer (bu genellikle aynı seçenektir) ve trafik yalnızca sunuculardan birine gider.

HAProxy'nin çalışmasında sorun olması veya sunucu arızası durumunda ExaBGP rotayı duyurmayı bırakır ve trafik sorunsuz bir şekilde başka bir sunucuya geçer.

Böylece dengeleyicinin hata toleransını sağladık.

Mail.ru Bulut Çözümleri platformunda hataya dayanıklı web mimarisi nasıl uygulanır?
HAProxy dengeleyicilerin hata toleransı

Planın kusurlu olduğu ortaya çıktı: HAProxy'yi nasıl ayıracağımızı öğrendik, ancak yükü hizmetler içinde nasıl dağıtacağımızı öğrenmedik. Bu nedenle bu şemayı biraz genişlettik: birkaç beyaz IP adresi arasında dengelemeye geçtik.

DNS artı BGP'ye dayalı dengeleme

HAProxy'miz için yük dengeleme sorunu çözülmedi. Ancak burada yaptığımız gibi oldukça basit bir şekilde çözülebilir.

Üç sunucuyu dengelemek için 3 beyaz IP adresine ve eski güzel DNS'ye ihtiyacınız olacak. Bu adreslerin her biri, her HAProxy'nin geri döngü arayüzünde belirlenir ve İnternet'e duyurulur.

OpenStack'te kaynakları yönetmek için belirli bir hizmetin uç nokta API'sini belirten bir hizmet dizini kullanılır. Bu dizinde, DNS aracılığıyla üç farklı IP adresiyle çözümlenen public.infra.mail.ru alan adını kaydediyoruz. Sonuç olarak DNS üzerinden üç adres arasında yük dağılımını elde ediyoruz.

Ancak beyaz IP adreslerini duyururken sunucu seçim önceliklerini kontrol edemediğimiz için bu durum henüz dengelenmiyor. Tipik olarak, IP adresi önceliğine göre yalnızca bir sunucu seçilecektir ve diğer ikisi, BGP'de hiçbir ölçüm belirtilmediğinden boşta kalacaktır.

ExaBGP üzerinden farklı metriklerle rota göndermeye başladık. Her dengeleyici üç beyaz IP adresinin tamamını duyurur, ancak bunlardan biri, yani bu dengeleyici için ana olan, minimum ölçümle duyurulur. Yani her üç dengeleyici de çalışırken, birinci IP adresine yapılan çağrılar birinci dengeleyiciye, ikinciye yapılan çağrılar ikinciye ve üçüncüye yapılan çağrılar üçüncüye gider.

Dengeleyicilerden biri düştüğünde ne olur? Herhangi bir dengeleyici başarısız olursa, ana adresi yine diğer ikisinden bildirilir ve trafik bunlar arasında yeniden dağıtılır. Böylece kullanıcıya DNS üzerinden birden fazla IP adresini aynı anda vermiş oluyoruz. DNS ve farklı ölçümlerle dengeleme yaparak, yükün üç dengeleyicinin tümüne eşit bir şekilde dağıtılmasını sağlıyoruz. Aynı zamanda hata toleransını da kaybetmiyoruz.

Mail.ru Bulut Çözümleri platformunda hataya dayanıklı web mimarisi nasıl uygulanır?
HAProxy'yi DNS + BGP'ye dayalı olarak dengeleme

ExaBGP ve HAProxy arasındaki etkileşim

Bu nedenle, rota duyurusunun durdurulmasını temel alarak sunucunun ayrılması durumunda hata toleransını uyguladık. Ancak HAProxy, sunucu arızası dışındaki nedenlerle de kapanabilir: yönetim hataları, hizmetteki arızalar. Bu durumlarda bozulan dengeleyiciyi yükün altından çıkarmak istiyoruz ve farklı bir mekanizmaya ihtiyacımız var.

Bu nedenle, önceki şemayı genişleterek ExaBGP ve HAProxy arasında kalp atışı uyguladık. Bu, ExaBGP'nin uygulamaların durumunu kontrol etmek için özel komut dosyaları kullandığı ExaBGP ve HAProxy arasındaki etkileşimin bir yazılım uygulamasıdır.

Bunu yapmak için ExaBGP yapılandırmasında HAProxy'nin durumunu kontrol edebilecek bir sağlık denetleyicisi yapılandırmanız gerekir. Bizim durumumuzda, HAProxy'de sağlık arka ucunu yapılandırdık ve ExaBGP tarafından basit bir GET isteği ile kontrol ediyoruz. Duyuru durdurulursa, HAProxy büyük olasılıkla çalışmıyordur ve reklamını yapmaya gerek yoktur.

Mail.ru Bulut Çözümleri platformunda hataya dayanıklı web mimarisi nasıl uygulanır?
HAProxy Sağlık Kontrolü

HAProxy Eşleri: oturum senkronizasyonu

Yapılacak bir sonraki şey oturumları senkronize etmekti. Dağıtılmış dengeleyiciler üzerinde çalışırken, müşteri oturumları hakkındaki bilgilerin depolanmasını düzenlemek zordur. Ancak HAProxy, Peers işlevselliği (oturum tablolarını farklı HAProxy işlemleri arasında aktarma yeteneği) nedeniyle bunu yapabilen birkaç dengeleyiciden biridir.

Farklı dengeleme yöntemleri vardır: basit olanlar: yuvarlak robin, ve istemcinin oturumu hatırlandığında ve her defasında daha önce olduğu gibi aynı sunucuya geldiğinde uzatılır. Biz ikinci seçeneği uygulamak istedik.

HAProxy, bu mekanizmanın istemci oturumlarını kaydetmek için çubuk tabloları kullanır. İstemcinin orijinal IP adresini, seçilen hedef adresini (arka uç) ve bazı hizmet bilgilerini kaydederler. Çubuk tabloları genellikle bir kaynak-IP + hedef-IP çiftini depolamak için kullanılır; bu, örneğin RoundRobin dengeleme modunda başka bir dengeleyiciye geçerken kullanıcı oturumu bağlamını aktaramayan uygulamalar için özellikle kullanışlıdır.

Bir çubuk tablosuna farklı HAProxy süreçleri arasında (dengelemenin gerçekleştiği) hareket etmesi öğretilirse, dengeleyicilerimiz tek bir çubuk tablo havuzuyla çalışabilecektir. Bu, dengeleyicilerden birinin arızalanması durumunda müşterinin ağını sorunsuz bir şekilde değiştirmeyi mümkün kılacaktır; müşteri oturumlarıyla çalışma, daha önce seçilen aynı arka uçlarda devam edecektir.

Düzgün çalışması için oturumun kurulduğu dengeleyicinin kaynak IP adresi sorununun çözülmesi gerekir. Bizim durumumuzda bu, geridöngü arayüzündeki dinamik bir adrestir.

Akranların doğru çalışması ancak belirli koşullar altında sağlanır. Yani, TCP zaman aşımlarının yeterince büyük olması veya TCP oturumunun sonlandırılacak zamanı kalmaması için geçişin yeterince hızlı olması gerekir. Ancak kesintisiz geçişe izin verir.

IaaS'de aynı teknolojiyi kullanarak oluşturulmuş bir hizmetimiz var. Bu OpenStack için bir hizmet olarak Yük DengeleyiciOctavia denir. İki HAProxy sürecine dayanmaktadır ve başlangıçta eşler için destek içerir. Bu hizmette mükemmel olduklarını kanıtladılar.

Resim, eş tabloların üç HAProxy örneği arasındaki hareketini şematik olarak göstermektedir; bunun nasıl yapılandırılabileceğine ilişkin bir yapılandırma önerilmektedir:

Mail.ru Bulut Çözümleri platformunda hataya dayanıklı web mimarisi nasıl uygulanır?
HAProxy Eşleri (oturum senkronizasyonu)

Aynı şemayı uygularsanız işleyişi dikkatle test edilmelidir. Her zaman aynı biçimde çalışacağı bir gerçek değil. Ancak en azından müşterinin kaynak IP'sini hatırlamanız gerektiğinde çubuk tablolarını kaybetmezsiniz.

Aynı istemciden gelen eşzamanlı isteklerin sayısını sınırlama

API'lerimiz de dahil olmak üzere halka açık tüm hizmetler, talep çığlarına maruz kalabilir. Bunların nedenleri kullanıcı hatalarından hedefli saldırılara kadar tamamen farklı olabilir. Periyodik olarak IP adreslerine göre DDoS işlemine tabi tutuluyoruz. Müşteriler genellikle komut dosyalarında hata yapar ve bize mini DDoS'ler verir.

Öyle ya da böyle ek koruma sağlanmalıdır. Açık çözüm, API isteklerinin sayısını sınırlamak ve kötü niyetli istekleri işlemek için CPU zamanını boşa harcamamaktır.

Bu tür kısıtlamaları uygulamak için, aynı çubuk tabloları kullanılarak HAProxy temelinde düzenlenen hız limitlerini kullanıyoruz. Sınırları ayarlamak oldukça basittir ve kullanıcıyı API'ye yapılan istek sayısına göre sınırlamanıza olanak tanır. Algoritma, isteklerin yapıldığı kaynak IP'yi hatırlar ve bir kullanıcıdan gelen eşzamanlı isteklerin sayısını sınırlar. Elbette her hizmet için ortalama API yük profilini hesapladık ve bu değerin ≈ 10 katı kadar bir sınır belirledik. Durumu yakından takip etmeye ve parmağımızı nabzında tutmaya devam ediyoruz.

Bu pratikte neye benziyor? Otomatik ölçeklendirme için API'lerimizi düzenli olarak kullanan müşterilerimiz var. Sabah yaklaşık 1000-XNUMX arası sanal makine oluşturup akşam siliyor. OpenStack için, PaaS hizmetlerini de içeren bir sanal makine oluşturmak, hizmetler arasındaki etkileşim de API aracılığıyla gerçekleştiğinden en az XNUMX API isteği gerektirir.

Bu tür görev aktarımı oldukça büyük bir yüke neden olur. Bu yükü değerlendirdik, günlük zirveleri topladık, on katına çıkardık ve bu bizim oran limitimiz oldu. Parmağımızı nabzın üzerinde tutuyoruz. Çalıştırılabilecek herhangi bir CGA betiğimizin olup olmadığını görmek için bize bakmaya çalışan botları ve tarayıcıları sık sık görüyoruz, onları aktif olarak kesiyoruz.

Kullanıcılar fark etmeden kod tabanınızı nasıl güncelleyebilirsiniz?

Ayrıca kod dağıtım süreçleri düzeyinde hata toleransını da uyguluyoruz. Kullanıma sunma sırasında aksaklıklar olabilir ancak bunların hizmet kullanılabilirliği üzerindeki etkisi en aza indirilebilir.

Hizmetlerimizi sürekli olarak güncelliyoruz ve kod tabanının kullanıcıları etkilemeden güncellendiğinden emin olmalıyız. HAProxy'nin yönetim yeteneklerini ve hizmetlerimizde Graceful Shutdown uygulamasını kullanarak bu sorunu çözmeyi başardık.

Bu sorunu çözmek için dengeleyicinin kontrolünü ve hizmetlerin "doğru" kapatılmasını sağlamak gerekiyordu:

  • HAProxy durumunda kontrol, aslında bir soket olan ve HAProxy yapılandırmasında tanımlanan bir istatistik dosyası aracılığıyla gerçekleştirilir. Stdio aracılığıyla komutları gönderebilirsiniz. Ancak ana konfigürasyon kontrol aracımız Ansible'dır, dolayısıyla HAProxy'yi yönetmek için yerleşik bir modüle sahiptir. Aktif olarak kullandığımız.
  • API ve Motor hizmetlerimizin çoğu, zarif kapatma teknolojilerini destekler: Kapatırken, ister bir http isteği ister bir hizmet görevi olsun, mevcut görevin tamamlanmasını beklerler. Aynı şey işçinin başına da gelir. Yaptığı tüm görevleri bilir ve her şeyi başarıyla tamamladığında sona erer.

Bu iki nokta sayesinde dağıtımımızın güvenli algoritması şu şekilde görünüyor.

  1. Geliştirici yeni bir kod paketi derler (bizim için bu RPM'dir), onu geliştirme ortamında test eder, aşamada test eder ve onu aşama deposunda bırakır.
  2. Geliştirici, dağıtım görevini "yapıların" en ayrıntılı açıklamasıyla belirler: yeni paketin sürümü, yeni işlevselliğin açıklaması ve gerekirse dağıtımla ilgili diğer ayrıntılar.
  3. Sistem yöneticisi güncellemeyi başlatır. Ansible çalışma kitabını başlatır ve bu da aşağıdakileri yapar:
    • Aşama deposundan bir paket alır ve bunu, paketin ürün deposundaki sürümünü güncellemek için kullanır.
    • Güncellenen hizmetin arka uçlarının bir listesini derler.
    • HAProxy'de güncellenecek ilk hizmeti kapatır ve işlemlerinin çalışmasının bitmesini bekler. Sorunsuz kapatma sayesinde mevcut tüm müşteri isteklerinin başarıyla tamamlanacağından eminiz.
    • API ve çalışanlar tamamen durdurulduktan ve HAProxy kapatıldıktan sonra kod güncellenir.
    • Ansible hizmetleri çalıştırır.
    • Her hizmet için, önceden tanımlanmış bir dizi anahtar test üzerinde birim testi gerçekleştiren belirli "tutamaçlar" çekilir. Yeni kodun temel kontrolü gerçekleştirilir.
    • Önceki adımda herhangi bir hata bulunmazsa arka uç etkinleştirilir.
    • Bir sonraki arka uca geçelim.
  4. Tüm arka uçlar güncellendikten sonra işlevsel testler başlatılır. Bunlar eksikse geliştirici, yarattığı yeni işlevlere bakar.

Bu, dağıtımı tamamlar.

Mail.ru Bulut Çözümleri platformunda hataya dayanıklı web mimarisi nasıl uygulanır?
Hizmet güncelleme döngüsü

Tek bir kuralımız olmasaydı bu plan işe yaramazdı. Savaşta hem eski hem de yeni versiyonları destekliyoruz. Yazılım geliştirme aşamasında, hizmet veri tabanında değişiklik olsa bile önceki kodu bozmayacağı önceden ortaya konmuştur. Sonuç olarak kod tabanı yavaş yavaş güncellenmektedir.

Sonuç

Hataya dayanıklı bir WEB mimarisi hakkında kendi düşüncelerimi paylaşarak, bunun önemli noktalarına bir kez daha dikkat çekmek istiyorum:

  • fiziksel hata toleransı;
  • ağ hatası toleransı (dengeleyiciler, BGP);
  • Kullanılan ve geliştirilen yazılımın hata toleransı.

Herkes için istikrarlı çalışma süresi!

Kaynak: habr.com

Yorum ekle