Călătoria Connatix înspre un nivel de disponibilitate a serviciilor de 99.99% la nivel global este presărată de multe lecții învățate pe parcurs.
Înainte de a explora în detaliu provocările fiecărei etape, este necesară menționarea unor aspecte specifice companiei care au avut o influență majoră asupra deciziilor luate de-a lungul timpului:
Clienții noștri sunt, în mare parte, platforme media (de ex. Reuters, Huffington Post, Daily Mail, Accuweather) care folosesc serviciile web și video playerul Connatix pentru a afișa conținut video - orice potențială întrerupere a serviciilor poate duce la feedback negativ din partea utilizatorilor și scăderea numărului acestora datorită unei experiențe sub-optime.
Complementar afișării conținutului video, Connatix oferă și servicii de monetizare pentru augmentarea veniturilor clienților (afișarea de reclame/publicitate la intervale de timp configurate de către aceștia) - orice potențială întrerupere a serviciilor poate duce la o scădere semnificativă a veniturilor
Secțiunile următoare vor prezenta evoluția în timp a infrastructurii care suportă deservirea celor 450 de miliarde de HTTP requests la nivel global împreună cu factorii interni/externi care au determinat tranziția către etapa următoare. Fiecare etapă adaugă atât complexitate la nivel de aplicație și de infrastructură, cât și costuri adiționale.
Unul din tiparele frecvente de rulare în AWS Cloud a serviciilor web care au nevoie de un nivel mare de disponibilitate este reprezentat de combinația Kubernetes Deployment/Service + Kubernetes HAProxy Ingress Controller într-un cluster AWS EKS + AWS Elastic Load Balancer.
Elasticitatea instanțelor serviciilor web este asigurată automat de Kubernetes HPA (auto-scalarea pe orizontală a podurilor) în funcție de gradul de utilizare al procesorului și/sau al memoriei.
În momentul de față, numărul total de instanțe variază între 70 și 150, privind ciclurile zilnice ale traficului web. În acest fel este prevenită supraîncărcarea serviciilor.
Pentru a asigura disponibilitatea serviciilor și pe parcursul actualizărilor, o altă funcționalitate din Kubernetes vine în ajutor: Rolling Upgrade (actualizări graduale). Astfel, se adaugă treptat instanțe de aplicație cu noua versiune, iar, pe măsură ce acestea încep să deservească HTTP requests, instanțele vechi sunt retrase.
Acest proces este posibil datorită unor reguli stricte din procesul de dezvoltare care necesită ca oricare două versiuni consecutive (care ar putea rula în paralel la un moment dat) să fie compatibile pentru aplicațiile client care efectuează HTTP requests.
Un cluster Kubernetes este asociat cu o regiune geografică în AWS Cloud. Fiecare regiune beneficiază de trei zone de disponibilitate care pot găzdui servere, fiecare dintre ele având propria sursă de energie, propriul sistem de răcire, respectiv propriile legături la nivel de rețea. Ele pot asigura astfel redundanță în caz de avarii localizate.
Pentru a putea beneficia la nivel de aplicație de acest aspect, este necesară configurarea rețelei asociate cu clusterul Kubernetes a mai multor subneturi. Fiecare subnet este asociat cu o zonă de disponibilitate diferită, ceea ce permite ca instanțele EC2 din cluster să fie inițializate în zone diferite, păstrând, în același timp, interconectivitatea.
Efectele secundare se regăsesc, de obicei, și în factura serviciilor Cloud, deoarece transferul de date între zonele de disponibilitate generează costuri adiționale, pe când transferul de date în cadrul unei singure zone este gratuit.
Dacă în etapa anterioară am îmbunătățit disponibilitatea serviciilor, în cazul avariilor cauzate de către furnizorul serviciilor de Cloud (AWS), există în continuare scenarii în care erorile umane cu impact catastrofal pot fi cu greu evitate. Atât schimbări la nivel de aplicație, cât și la nivel de infrastructură pot afecta imediat toate instanțele care deservesc HTTP requests, fără a avea soluții de rezervă.
Abordarea noastră pentru diminuarea rapidă și cu complexitate cât mai redusă a acestor riscuri a fost crearea unui cluster Kubernetes adițional care să preia o parte din HTTP requests. Am ales o configurare Active-Active (ambele seturi de instanțe ale serviciilor web gestionează un număr relativ similar de HTTP requests), care aduce următoarele beneficii:
livrarea de funcționalități în mod incremental doar unui subset de utilizatori pe primul cluster, fără a afecta în întregime traficul web;
Pe lângă modificările necesare în procesul de dezvoltare și de livrare etapizată a funcționalităților, apare un nou element de complexitate: unde decidem în ce cluster ar trebui să ajungă un HTTP request?
Un răspuns parțial la prima întrebare, "Unde?", este "Nu într-un singur loc", tocmai pentru a evita un potențial punct unic de eșec pentru toate requesturile.
Implementarea finală a constat în a redirecționa primul request HTTP de la începutul fiecărei sesiuni către serviciul de Global Load Balancing. Astfel, decizia de alegere a unui anumit clusters-a luat în peste 200 de locații din întreaga lume, cât mai aproape de utilizator, cu o latență minimă.
Motivul pentru care doar primul request HTTP din fiecare sesiune fost gestionat de către Global Load Balancer ține de costurile suplimentare semnificative care ar fi putut fi generate de luarea acestei decizii pentru fiecare din cele 450 de miliarde de HTTP requests.
Alte aspecte care necesită clarificare sunt raționamentul pentru care nu am optat pentru o configurare de tip Active-Passive sau de ce am ales să distribuim o proporție relativ egală a traficului web între cele două clustere.
Explicația este aceeași pentru ambele: în caz că unul din aceste clustere nu mai funcționează corect, celălalt trebuie să aibă deja suficiente instanțe de aplicație pentru a putea prelua instant restul de trafic redirecționat.
Această redirecționare se efectuează de la nivel de Global Load Balancer, fie automat, în funcție de indicatori de integritate ai serviciilor, fie manual, în cazul perioadelor de mentenanță.
Rularea instanțelor de aplicație în mai multe regiuni geografice aduce, la rândul ei, atât avantaje, cât și extra complexitate și costuri.
Printre avantaje regăsim:
Protecție împotriva diverselor "dezastre" regionale de infrastructură la nivelul providerului Cloud (AWS). Până acum ne-am confruntat cu cel puțin o astfel de situație pe an, iar perioada de reparare a serviciilor este imprevizibilă, variind între câteva minute și câteva ore.
Infrastructură mai apropiată de utilizatori (în momentul de față în US East, US West și EU), ceea ce duce la o latență considerabil mai mică și o experiență generală mai bună pentru paginile web ale clienților noștri.
În ce privește elementele de complexitate și costuri adiționale, putem enumera:
Inițiativa de implementare a suportului multi-regional a adus cu el un sub-proiect de schimbare a partenerului de Global Load Balancing, pentru a putea fi capabili să redirecționăm fiecare HTTP request în parte în funcție geolocație și alți parametri către regiunea potrivită, la costuri rezonabile.
O alternativă la redirecționarea de HTTP requests prin intermediul Global Load Balancer este folosirea serviciului de DNS, care poate decide în funcție de geolocație și indicatorii de integritate ai serviciilor către cel mai apropiat cluster.
Dezavantajul major al acestei soluții este cache-ul înregistrărilor de tip DNS realizat de diferitele aplicații sau browsere care nu țin cont întotdeauna de durata de viață prestabilită (TTL). Astfel se reduce semnificativ controlul asupra destinației fiecărui HTTP request, uneori fiind necesare minute sau chiar ore pentru redirecționarea întregului trafic web comparativ cu redirecționarea care se produce instantaneu în cazul soluției alese de noi.
În 2023 am reușit să păstrăm disponibilitatea serviciilor Connatix la un nivel peste 99.99%. Soluțiile alese de noi nu reprezintă o rețetă universală, însă, cu siguranță, sunt o poveste de succes care nu se oprește aici. Etapa următoare va explora redundanță la nivel de Global Load Balancer.
Impactul întreruperii temporare a serviciilor este diferit pentru fiecare companie, ceea ce automat duce la o multitudine de decizii și implementări alternative, în funcție de complexitatea adăugată și costurile suplimentare generate.