Scalarea încărcăturii aplicațiilor web. Scalare pe verticală și orizontală. Componente apatride

S-au spus deja multe cuvinte pe acest subiect atât pe blogul meu, cât și nu numai. Mi se pare că a venit momentul să trecem de la specific la general și să încercăm să privim acest subiect separat de orice implementare cu succes a acestuia.

Să începem?

Pentru început, este logic să decidem despre ce vom vorbi. În acest context, aplicația web are trei obiective principale:

  • scalabilitate- capacitatea de a răspunde în timp util la creșterea continuă a încărcăturii și afluxurile neașteptate de utilizatori;
  • disponibilitate- asigurarea accesului la aplicație chiar și în caz de urgență;
  • performanţă- chiar si cea mai mica intarziere in incarcarea unei pagini poate lasa o impresie negativa asupra utilizatorului.

Subiectul principal de conversație va fi, după cum ați putea ghici, scalabilitatea, dar nu cred că celelalte obiective vor rămâne deoparte. Aș dori să spun imediat câteva cuvinte despre accesibilitate, pentru a nu reveni la asta mai târziu, adică „este de la sine înțeles”: orice site se străduiește într-un fel sau altul să funcționeze cât mai stabil posibil, adică să fie accesibil la absolut toți potențialii săi vizitatori în absolut fiecare moment, dar uneori se întâmplă tot felul de situații neprevăzute care pot cauza indisponibilitate temporară. Pentru a minimiza impactul potențial asupra disponibilității aplicației, este necesar să se evite existența unor componente în sistem, a căror potențială defecțiune ar duce la indisponibilitatea oricărei funcționalități sau date (sau cel puțin a site-ului în ansamblu). Astfel, fiecare server sau orice altă componentă a sistemului trebuie să aibă cel puțin o copie de rezervă (nu contează în ce mod vor funcționa: în paralel sau unul „face backup” celuilalt, în timp ce se află în modul pasiv), iar datele trebuie replicate în cel puțin două copii (și de preferință nu la nivel RAID, ci pe mașini fizice diferite). Stocarea mai multor copii de rezervă date undeva separat de sistemul principal (de exemplu, on servicii speciale sau pe un cluster separat) va ajuta, de asemenea, la evitarea multor probleme dacă ceva nu merge bine. Nu uitați de partea financiară a problemei: asigurarea în caz de defecțiuni necesită investiții suplimentare semnificative în echipamente, pe care este logic să încercați să le minimizați.

Scalabilitatea este de obicei împărțită în două domenii:

Scalabilitate verticală Creșterea performanței fiecărei componente a sistemului pentru îmbunătățire performanța generală. Scalabilitate orizontală Descompunerea unui sistem în componente structurale mai mici și separarea lor în separat mașini fizice(sau grupurile acestora) și/sau creșterea numărului de servere care îndeplinesc aceeași funcție în paralel.

Într-un fel sau altul, atunci când dezvoltați o strategie de creștere a sistemului, trebuie să căutați un compromis între preț, timp de dezvoltare, performanță finală, stabilitate și o mulțime de alte criterii. Din punct de vedere financiar, scalabilitatea verticală este departe de a fi cea mai atractivă soluție, deoarece prețurile la serverele cu un număr mare de procesoare cresc întotdeauna aproape exponențial în raport cu numărul de procesoare. Acesta este motivul pentru care abordarea orizontală este cea mai interesantă, deoarece este cea care este folosită în majoritatea cazurilor. Dar scalabilitatea verticală are uneori dreptul să existe, mai ales în situațiile în care rolul principal este jucat de timpul și viteza de rezolvare a problemei, și nu de problema financiară: până la urmă, să cumpere Server MARE semnificativ mai rapid decât dezvoltarea practic a unei aplicații de la zero, adaptând-o pentru a funcționa pe un număr mare de servere care rulează în paralel.

După ce am terminat cu in termeni generali hai sa trecem la recenzie probleme potentialeși opțiuni pentru soluțiile lor atunci când scalați orizontal. Vă rugăm să nu criticați prea mult - nu pretind corectitudinea și fiabilitatea absolută, doar „gândesc cu voce tare” și cu siguranță nu voi putea nici măcar să menționez toate punctele despre acest subiect.

Servere de aplicații

În procesul de scalare a aplicațiilor în sine, problemele apar rar dacă în timpul dezvoltării rețineți întotdeauna că fiecare instanță a aplicației nu ar trebui să fie în mod direct în legătură cu „colegii” săi și ar trebui să poată procesa absolut orice solicitare a utilizatorului, indiferent de de unde au fost procesate cererile anterioare utilizator datși ce anume își dorește de la aplicația în ansamblu în acest moment.

Mai mult, asigurarea independenței fiecărui individ rulează aplicația, din ce în ce mai multe pot fi procesate și cantitate mare cereri pe unitatea de timp, pur și simplu prin creșterea numărului de servere de aplicații de operare paralelă care participă la sistem. Totul este destul de simplu (relativ).

Echilibrarea sarcinii

Următoarea sarcină este să distribuiți uniform cererile între serverele de aplicații disponibile. Există multe abordări pentru rezolvarea acestei probleme și chiar mai multe produse care oferă implementarea lor specifică.

Echipamente hardware de rețea, care vă permite să distribuiți încărcătura între mai multe servere, costă de obicei o sumă destul de importantă, dar printre alte opțiuni este de obicei această abordare cea care oferă cea mai mare performanță și stabilitate (în principal datorită calității, plus astfel de echipamente vin uneori în perechi, funcționând conform principiului). Există destul de multe mărci serioase în această industrie care își oferă soluțiile - există o mulțime din care să alegeți: Cisco, Turnătorie, NetScalarși multe altele. Software Există și mai multă diversitate în acest domeniu opțiuni posibile. Nu este atât de ușor să obțineți performanțe software comparabile cu soluțiile hardware, iar HeartBeat va trebui furnizat în software, dar echipamentul pentru funcționarea unei astfel de soluții este un server obișnuit (eventual mai mult de unul). Astfel de produse software destul de multe, de obicei sunt doar servere HTTP care înaintează cererile către colegii lor de pe alte servere în loc să le trimită direct către interpretul limbajului de programare pentru procesare. De exemplu, puteți menționa, să zicem, mod_proxy. În plus, există opțiuni mai exotice bazate pe DNS, adică în procesul de determinare de către client a adresei IP a serverului cu resursele de Internet de care are nevoie, adresa este emisă ținând cont de sarcina de pe serverele disponibile, precum şi unele consideraţii geografice.

Fiecare opțiune are propriul sortiment de părți pozitive și negative, motiv pentru care nu există o soluție clară la această problemă - fiecare opțiune este bună în propria situație specifică. Nu uitați că nimeni nu vă limitează să utilizați doar unul dintre ele; dacă este necesar, o combinație aproape arbitrară a acestora poate fi implementată cu ușurință.

Calcul intensiv în resurse

Multe aplicații folosesc niște mecanisme complexe, acestea ar putea fi conversia videoclipurilor, imaginilor, sunetului sau pur și simplu efectuarea unor calcule care necesită mult resurse. Astfel de sarcini necesită o atenție specială dacă vorbim despre Web, deoarece un utilizator al unei resurse de Internet este puțin probabil să fie mulțumit să vizioneze o pagină încărcată timp de câteva minute, așteptând doar să vadă un mesaj de genul: „Operația a fost finalizată cu succes!”

Pentru a evita astfel de situații, ar trebui să încercați să minimizați performanța operațiunilor care necesită resurse intensive sincron cu generarea paginilor de Internet. Dacă o anumită operaţie nu afectează pagina noua trimis utilizatorului, puteți pur și simplu să organizați coadă sarcini care trebuie îndeplinite. În acest caz, în momentul în care utilizatorul a finalizat toate acțiunile necesare pentru a începe operația, serverul de aplicații adaugă pur și simplu o nouă sarcină la coadă și începe imediat să genereze următoarea pagină fără a aștepta rezultatele. Dacă sarcina necesită de fapt foarte multă muncă, atunci o astfel de coadă și gestionanții de job pot fi localizate pe un server sau cluster separat.

Dacă rezultatul unei operații este implicat în pagina următoare trimis utilizatorului, atunci dacă este executat asincron, va trebui să trișați puțin și să distragi cumva utilizatorul în timp ce este executat. De exemplu, dacă despre care vorbim despre conversia video în flv, apoi, de exemplu, puteți genera rapid o captură de ecran cu primul cadru în procesul de compilare a unei pagini și să o înlocuiți în locul videoclipului și să adăugați în mod dinamic opțiunea de vizualizare în pagină după finalizarea conversiei.

O altă metodă bună de a gestiona astfel de situații este să ceri pur și simplu utilizatorului să „revenim mai târziu”. De exemplu, dacă serviciul generează capturi de ecran ale site-urilor web de pe browsere diferite pentru a demonstra corectitudinea afișajului lor proprietarilor sau celor pur și simplu interesați, atunci generarea unei pagini cu aceștia poate dura nici măcar secunde, ci minute. Cel mai convenabil pentru utilizator într-o astfel de situație ar fi să ofere să viziteze pagina la adresa specificatăîn atâtea minute și nu așteptați o perioadă nedeterminată de timp lângă mare pentru vreme.

Sesiuni

Aproape toate aplicațiile web interacționează într-un fel cu vizitatorii lor și, în marea majoritate a cazurilor, este necesară urmărirea mișcărilor utilizatorilor pe paginile site-ului. Pentru a rezolva această problemă, se folosește de obicei un mecanism sesiuni, care constă în atribuirea fiecărui vizitator unic numar de identificare, care îi este transmis pentru stocare în cookie-uri sau, în absența cookie-urilor, pentru „tragere” constantă împreună cu sine prin GET. După ce a primit un anumit ID de la utilizator împreună cu următoarea solicitare HTTP, serverul poate analiza lista numerelor deja emise și poate determina fără ambiguitate cine a trimis-o. Fiecare ID poate fi asociat cu un anumit set de date pe care aplicația web le poate folosi la discreția sa; aceste date sunt de obicei stocate implicit într-un fișier într-un director temporar de pe server.

S-ar părea că totul este simplu, dar... dar cererile de la vizitatori pe același site pot fi procesate de mai multe servere deodată, cum se poate determina atunci dacă ID-ul primit a fost emis pe un alt server și unde sunt stocate în general datele acestuia ?

Cele mai comune soluții sunt centralizarea sau descentralizarea datelor de sesiune. O frază oarecum absurdă, dar sperăm că câteva exemple pot clarifica lucrurile:

Stocare centralizată a sesiunii Ideea este simplă: creați o „pușculiță” comună pentru toate serverele, unde acestea să poată pune sesiunile pe care le emit și să învețe despre sesiunile vizitatorilor pe alte servere. Teoretic, rolul unei astfel de „pușculițe” ar putea fi pur și simplu un sistem de fișiere montat în rețea, dar din anumite motive pare mai promițător să folosești un fel de DBMS, deoarece acest lucru elimină o mulțime de probleme asociate cu stocarea datelor de sesiune în fișiere. Dar în varianta cu bază comună date, nu uitați că sarcina pe aceasta va crește în mod constant odată cu creșterea numărului de vizitatori și, de asemenea, merită să oferiți în avans opțiuni pentru rezolvarea situațiilor problematice asociate cu potențiale eșecuri în funcționarea serverului cu acest DBMS. Stocare de sesiune descentralizată Un exemplu bun- stocarea sesiunilor în , conceput inițial pentru stocarea distribuită a datelor în memorie cu acces aleator sistemul va permite tuturor serverelor să primească acces rapid la orice date de sesiune, dar în același timp (spre deosebire de metoda anterioară) orice centru unic nu va exista depozit pentru ei. Acest lucru va evita blocajele în ceea ce privește performanța și stabilitatea în perioadele de încărcare crescută.

Ca alternativă la sesiuni, se folosesc uneori mecanisme similare ca scop, construite pe cookie-uri, adică toate cerute de cerere datele utilizatorului sunt stocate pe partea clientului (probabil criptate) și solicitate după cum este necesar. Dar, pe lângă avantajele evidente asociate cu faptul că nu trebuie să stocați date inutile pe server, apar o serie de probleme de securitate. Datele stocate pe partea clientului, chiar și în formă criptată, reprezintă o potențială amenințare pentru funcționarea multor aplicații, deoarece oricine poate încerca să le modifice în beneficiul său sau pentru a dăuna aplicației. Această abordare este bună numai dacă există încredere că absolut orice manipulare a datelor stocate de utilizatori este sigură. Dar este posibil să fii 100% sigur?

Conținut static

În timp ce volumele de date statice sunt mici - nimeni nu se deranjează să le stocheze în sistemul de fișiere local și să ofere acces la ele pur și simplu printr-un server web ușor, cum ar fi (mă refer în principal la diferite forme de date media), dar mai devreme sau mai târziu serverul limitele de spațiu pe disc sau Limita sistemului de fișiere privind numărul de fișiere dintr-un director va fi atinsă și va trebui să vă gândiți la redistribuirea conținutului. O soluție temporară poate fi distribuirea datelor după tip în servere diferite, sau poate folosind o structură de directoare ierarhică.

Dacă conținutul static joacă unul dintre rolurile principale în funcționarea aplicației, atunci merită să vă gândiți la utilizarea unui sistem de fișiere distribuit pentru a-l stoca. Aceasta este probabil una dintre puținele moduri de a scala volumul pe orizontală spatiu pe disc prin adăugarea de servere suplimentare fără a face modificări fundamentale în funcționarea aplicației în sine. Nu vreau să dau niciun sfat despre ce sistem de fișiere de cluster să aleg acum; am publicat deja mai mult de o revizuire a implementărilor specifice - încercați să le citiți pe toate și să le comparați, dacă acest lucru nu este suficient, restul rețelei este la dispozitia ta.

Poate că această opțiune nu va fi fezabilă din anumite motive, atunci va trebui să „reinventați roata” pentru a implementa la nivel de aplicație principii asemănătoare cu segmentarea datelor în raport cu un SGBD, despre care voi menționa mai târziu. Această opțiune este, de asemenea, destul de eficientă, dar necesită modificarea logicii aplicației și, prin urmare, a execuției muncă în plus dezvoltatori.

O alternativă la aceste abordări este utilizarea așa-numitelor Rețeaua de livrare de conținut - servicii externe, asigurând disponibilitatea conținutului dvs. pentru utilizatori pentru o anumită recompensă materială a serviciului. Avantajul este evident - nu este nevoie să vă organizați propria infrastructură pentru a rezolva această problemă, dar apare un alt element de cost suplimentar. Nu voi da o listă cu astfel de servicii, dar dacă cineva are nevoie de ea, nu va fi greu de găsit.

Memorarea în cache

Memorarea în cache are sens în toate etapele procesării datelor, dar doar câteva metode de stocare în cache sunt cele mai eficiente pentru diferite tipuri de aplicații.

SGBD Aproape toate SGBD-urile moderne oferă mecanisme încorporate pentru stocarea în cache a rezultatelor anumitor interogări. Această metodă este destul de eficientă dacă sistemul dumneavoastră realizează în mod regulat aceleași mostre de date, dar are și o serie de dezavantaje, principalele fiind invalidarea cache-ului întregului tabel la cea mai mică modificare, precum și locația locală a cache, care este ineficientă dacă există mai multe servere în sistemul de stocare a datelor. Aplicație La nivel de aplicație, obiectele oricărui limbaj de programare sunt de obicei stocate în cache. Această metodă vă permite să evitați complet o parte semnificativă a interogărilor către SGBD, reducând foarte mult sarcina asupra acestuia. Ca și aplicațiile în sine, un astfel de cache trebuie să fie independent de cererea specifică și de serverul pe care este executat, adică trebuie să fie disponibil pentru toate serverele de aplicații în același timp și chiar mai bine, trebuie distribuit pe mai multe mașini pentru o utilizare mai eficientă a memoriei RAM. Liderul în acest aspect al stocării în cache poate fi numit pe bună dreptate, ceea ce am menționat deja la un moment dat. server HTTP Multe servere web au module de stocare în cache precum continut static, și rezultatele scripturilor. Dacă pagina este actualizată rar, atunci folosirea acestei metode vă permite să evitați generarea paginii ca răspuns la o parte destul de mare de solicitări fără nicio modificare vizibilă pentru utilizator. Proxy invers Prin plasarea unui server proxy transparent între utilizator și serverul web, puteți furniza utilizatorului date din cache-ul proxy (care poate fi fie în RAM, fie în disc), fără a trimite solicitări chiar și către serverele HTTP. În cele mai multe cazuri, această abordare este relevantă numai pentru conținutul static, în principal forme diferite date media: imagini, videoclipuri și altele asemenea. Acest lucru permite serverelor web să se concentreze numai pe lucrul cu paginile în sine.

Memorarea în cache, prin însăși natura sa, nu necesită practic costuri suplimentare de hardware, mai ales dacă monitorizați cu atenție utilizarea RAM de către alte componente ale serverului și utilizați toate formele de cache „surplus” disponibile care sunt cele mai potrivite pentru o anumită aplicație.

Invalidarea cache-ului în unele cazuri poate deveni sarcină non-trivială, dar într-un fel sau altul solutie universala toata lumea posibile probleme Nu este posibil să scriu nimic legat de el (cel puțin pentru mine personal), așa că să lăsăm această întrebare pentru vremuri mai bune. ÎN caz general soluția la această problemă cade pe aplicația web însăși, care implementează de obicei un fel de mecanism de invalidare prin ștergerea unui obiect cache printr-un anumit perioada de timp după crearea sa sau folosit ultima data, sau „manual” atunci când este sigur evenimente de la utilizator sau de la alte componente ale sistemului.

Bază de date

Partea cea mai interesantă am lăsat-o pentru aperitiv, deoarece această componentă integrală a oricărei aplicații web provoacă mai multe probleme atunci când sarcina crește decât toate celelalte la un loc. Uneori poate părea chiar că ar trebui să renunțați complet la scalarea orizontală a sistemului de stocare a datelor în favoarea scalarii verticale - doar cumpărați același server MARE pentru o sumă de șase sau șapte cifre de non-ruble și nu vă deranjați cu probleme inutile.

Dar pentru multe proiecte asta este decizie cardinală(și că, în general, temporar) nu este potrivit, ceea ce înseamnă că mai rămâne un singur drum înaintea lor - scalarea orizontală. Să vorbim despre ea.

Calea aproape oricărui proiect web din punct de vedere al bazei de date a început cu unul server simplu, la care a lucrat întreg proiectul. Apoi, la un moment bun, apare nevoia de a muta DBMS-ul pe un server separat, dar în timp începe să nu facă față încărcăturii. Nu are rost să intrăm în detalii despre aceste două etape - totul este relativ banal.

Urmatorul pas se întâmplă de obicei stăpân-sclav cu replicarea asincronă a datelor, modul în care funcționează această schemă a fost deja menționat de mai multe ori pe blog, dar poate o voi repet: cu această abordare, toate operațiunile de scriere sunt efectuate doar pe un singur server (master), iar serverele rămase (slave) ) primesc date direct de la „master”, în timp ce procesează doar cererile de citire a datelor. După cum știți, operațiunile de citire și scriere ale oricărui proiect web cresc întotdeauna proporțional cu încărcarea, în timp ce raportul dintre ambele tipuri de solicitări rămâne aproape fix: pentru fiecare solicitare de actualizare a datelor, există de obicei o medie de aproximativ o duzină de citire. cereri. În timp, încărcarea crește, ceea ce înseamnă că crește și numărul de operațiuni de scriere pe unitatea de timp, dar un singur server le procesează, iar apoi asigură și crearea unui anumit număr de copii pe alte servere. Mai devreme sau mai târziu, costurile operațiunilor de replicare a datelor vor deveni atât de mari încât acest proces va începe să ocupe o parte foarte mare din timpul procesorului fiecărui server, iar fiecare slave va putea procesa doar o parte relativ o cantitate mică de operațiuni de citire și, ca urmare, fiecare server slave suplimentar va începe să crească doar puțin performanța totală, făcând, de asemenea, în cea mai mare parte doar menținând datele sale în conformitate cu „master”.

O soluție temporară la această problemă poate fi înlocuirea serverului principal cu unul mai productiv, dar într-un fel sau altul nu va fi posibilă amânarea la nesfârșit tranziția la următorul „nivel” de dezvoltare a sistemului de stocare a datelor: "fragmentare", căruia i-am dedicat recent. Deci, permiteți-mi să mă opresc doar pe scurt: ideea este să împărțim toate datele în părți în funcție de o anumită caracteristică și să stocăm fiecare parte pe un server sau cluster separat, o astfel de parte a datelor împreună cu sistemul de stocare a datelor în care se află. situat , și se numește un segment sau ciob'om. Această abordare vă permite să evitați costurile asociate cu replicarea datelor (sau să le reduceți de multe ori) și, prin urmare semnificativ crește performanța generală a sistemului de stocare. Dar, din păcate, trecerea la această schemă de organizare a datelor necesită o mulțime de costuri de alt fel. Deoarece nu există o soluție gata făcută pentru implementarea acesteia, trebuie să modificați logica aplicației sau să adăugați un „strat” suplimentar între aplicație și DBMS, iar toate acestea sunt cel mai adesea implementate de dezvoltatorii de proiect. Produsele standard nu pot decât să-și ușureze munca, oferind un cadru pentru construirea arhitecturii de bază a sistemului de stocare a datelor și interacțiunea acestuia cu restul componentelor aplicației.

În această etapă, lanțul se termină de obicei, deoarece bazele de date segmentate se pot scala orizontal pentru a satisface pe deplin nevoile chiar și ale celor mai puternic încărcate resurse de Internet. Ar fi potrivit să spunem câteva cuvinte despre structura reală a datelor din bazele de date și organizarea accesului la acestea, dar orice decizie depinde foarte mult de aplicație specificăși implementare, așa că permiteți-mi doar să dau câteva recomandări generale:

Denormalizare Interogările care combină date din mai multe tabele de obicei, toate celelalte lucruri fiind egale, necesită mai mult timp CPU pentru a fi executate decât o interogare care afectează doar un tabel. Iar performanța, așa cum am menționat la începutul poveștii, este extrem de importantă pe Internet. Partiționarea logică a datelor Dacă o parte a datelor este întotdeauna utilizată separat de cea mai mare parte, atunci uneori este logic să o separăm într-un sistem independent de stocare a datelor. Optimizarea interogărilor la nivel scăzut Prin menținerea și analizarea jurnalelor de solicitare, le puteți determina pe cele mai lente. Înlocuirea interogărilor găsite cu altele mai eficiente, cu aceeași funcționalitate, poate ajuta la utilizarea mai eficientă a puterii de calcul.

În această secțiune merită menționat un alt tip, mai specific, de proiecte pe Internet. Astfel de proiecte operează cu date care nu au o structură clar formalizată; în astfel de situații, utilizarea de SGBD relațional ca stocare de date, pentru a spune ușor, este nepractic. În aceste cazuri, folosesc de obicei baze de date mai puțin stricte, cu funcționalități mai primitive în ceea ce privește prelucrarea datelor, dar sunt capabili să prelucreze volume uriașe de informații fără să găsească defecte în ceea ce privește calitatea și conformitatea cu formatul. Un sistem de fișiere în cluster poate servi ca bază pentru o astfel de stocare a datelor și, în acest caz, se folosește un mecanism numit pentru a analiza datele; vă voi spune doar pe scurt principiul funcționării acestuia, deoarece în întreaga sa scară este oarecum dincolo sfera acestei povestiri.

Deci, avem la intrare câteva date arbitrare într-un format care nu este neapărat respectat corect. Ca rezultat, trebuie să obțineți o valoare sau informații finale. Conform acestui mecanism, aproape orice analiză a datelor poate fi efectuată în următoarele două etape:

Hartă Scopul principal această etapă este reprezentarea datelor de intrare arbitrare sub formă de perechi cheie-valoare intermediare care au o anumită semnificație și sunt formalizate. Rezultatele sunt sortate și grupate după cheie și apoi transferate la etapa următoare. Reduce Primit după Hartă valorile sunt utilizate pentru calculul final al totalurilor necesare.

Fiecare etapă a fiecărui calcul specific este implementată ca o mini-aplicație independentă. Această abordare permite paralelizarea aproape nelimitată a calculelor pe un număr imens mașini, care vă permite să procesați volume de date aproape arbitrare într-o clipă. Pentru a face acest lucru, trebuie doar să rulați aceste aplicații pe fiecare server disponibil simultan și apoi puneți toate rezultatele împreună.

Exemplu cadru finit Pentru a implementa procesarea datelor conform acestui principiu, folosiți proiectul opensource al Fundației Apache numit, despre care am vorbit deja de câteva ori înainte și despre care am scris chiar la un moment dat.

În loc de o concluzie

Sincer să fiu, îmi este greu să cred că am reușit să scriu o postare atât de cuprinzătoare și că nu mai aveam aproape nicio energie pentru a o rezuma. Aș dori doar să spun că în dezvoltarea proiectelor mari, fiecare detaliu este important, iar un detaliu nesocotit poate duce la eșec. De aceea, în această chestiune ar trebui să înveți nu din propriile greșeli, ci de la alții.

Deși acest text poate arăta ca un fel de generalizare a tuturor postărilor din serie, este puțin probabil să devină punctul final, sper să găsesc ceva de spus pe acest subiect în viitor, poate într-o zi se va baza pe experienta personala, și nu va fi pur și simplu rezultatul procesării masei de informații primite. Cine ştie?...

Deci ai făcut un site web. Este întotdeauna interesant și incitant să urmăriți cum contorul de vizite crește încet, dar sigur, arătând rezultate mai bune în fiecare zi. Dar într-o zi, când nu te aștepți, cineva va posta un link către resursa ta pe unele știri Reddit sau Hacker (sau pe Habré - aprox. banda), iar serverul tău se va prăbuși.

În loc să obțineți noi utilizatori obișnuiți, veți rămâne cu pagină goală. În acest moment, nimic nu vă va ajuta să restabiliți funcționalitatea serverului, iar traficul se va pierde pentru totdeauna. Cum să evitați astfel de probleme? În acest articol vom vorbi despre optimizare și scalare.

Un pic despre optimizare

Toată lumea știe sfaturile de bază: actualizați la ultima versiune PHP (5.5 are acum OpCache încorporat), se ocupă de indici din baza de date, cache static (pagini modificate rar, cum ar fi „Despre noi”, „FAQs”, etc.).

De asemenea, merită menționat un aspect special al optimizării - difuzarea conținutului static cu un server non-Apache, cum ar fi Nginx, de exemplu.Configurați Nginx să gestioneze tot conținutul static (*.jpg, *.png, *.mp4, *.html). ..), și trimiteți fișiere care necesită procesare pe server către Apache greoi. Se numeste proxy invers.

Scalare

Există două tipuri de scalare - verticală și orizontală.
Din punctul meu de vedere, un site este scalabil dacă poate gestiona traficul fără a schimba software-ul.

Scalare pe verticală.

Imaginați-vă un server care servește o aplicație web. Are 4GB RAM, procesor i5 și HDD de 1TB. Își face treaba bine, dar pentru a face față mai bine unui trafic mai mare, decideți să creșteți memoria RAM la 16 GB, să instalați un procesor i7 și să faceți o schimbare pentru unitate SSD. Acum serverul este mult mai puternic și poate face față sarcinilor mari. Asta e scalare verticală.

Scalare orizontală.

Scalare orizontală este crearea unui cluster de servere interconectate (adesea nu foarte puternice) care deservesc împreună site-ul. În acest caz, se folosește echilibrarea greutății(alias echilibrarea greutății) - o mașină sau un program a cărui funcție principală este de a determina către ce server să trimită o cerere. Serverele dintr-un cluster împărtășesc întreținerea aplicațiilor fără să știe nimic unul despre celălalt, crescând astfel semnificativ debituluiși toleranța la erori a site-ului dvs.

Există două tipuri de echilibrare - hardware și software. Software - instalat pe un server obișnuit și primește tot traficul, transmițându-l gestionarilor corespunzători. Un astfel de echilibrant ar putea fi, de exemplu, Nginx. În secțiunea „Optimizare”, a interceptat toate cererile de fișiere statice și a servit aceste solicitări în sine, fără a încărca Apache. Un alt software popular pentru implementarea echilibrării sarcinii este Squid. Personal, îl folosesc întotdeauna, pentru că... oferă o interfață excelentă, ușor de utilizat, pentru a controla cele mai profunde aspecte ale echilibrării.

Un echilibrator hardware este o mașină dedicată al cărei singur scop este distribuirea sarcinii. De obicei, această mașină nu mai rulează niciun alt software decât cel dezvoltat de producător. Puteți citi despre echilibrarea încărcării hardware.

Vă rugăm să rețineți că aceste două metode nu se exclud reciproc. Puteți scala pe verticală orice mașină (alias Nodu) pe sistemul dvs.
În acest articol discutăm despre scalarea orizontală deoarece... este mai ieftin și mai eficient, deși mai greu de implementat.

Conexiune permanentă

La scalarea aplicațiilor PHP, apar câteva probleme dificile. Una dintre ele lucrează cu datele sesiunii utilizator. La urma urmei, dacă te-ai autentificat pe site și echilibrerul a trimis următoarea ta cerere către o altă mașină, atunci mașină nouă nu va ști că sunteți deja autentificat. În acest caz, puteți utiliza o conexiune persistentă. Aceasta înseamnă că echilibratorul își amintește la ce nod a fost trimisă ultima dată cererea utilizatorului și trimite acolo următoarea solicitare. Cu toate acestea, se dovedește că echilibrerul este prea supraîncărcat cu funcții; pe lângă procesarea sute de mii de solicitări, trebuie să-și amintească exact cum le-a procesat, drept urmare echilibrerul însuși devine un blocaj în sistem.

Schimbul local de date.

Partajarea datelor sesiunii utilizator între toate nodurile din cluster pare o idee bună. Și, deși această abordare necesită unele modificări în arhitectura aplicației dvs., merită - echilibratorul de încărcare este descărcat și întregul cluster devine mai tolerant la erori. Moartea unuia dintre servere nu afectează deloc funcționarea întregului sistem.
După cum știm, datele sesiunii sunt stocate într-o matrice superglobală $_SESSION, care scrie și preia date dintr-un fișier de pe disc. Dacă această unitate este pe un server, evident că alte servere nu o pot accesa. Cum îl putem face disponibil pe mai multe mașini?
În primul rând, vă rugăm să rețineți că Managerul de sesiune în PHP poate fi suprascris. Puteți implementa propria clasă de sesiune.

Utilizarea unei baze de date pentru stocarea sesiunilor

Folosind propriul manipulator sesiuni, le putem stoca în baza de date. Baza de date poate fi pe un server separat (sau chiar pe un cluster). De obicei, această metodă funcționează excelent, dar când într-adevăr trafic mare, Baza de date devine un blocaj(și dacă baza de date este pierdută, pierdem complet funcționalitatea), deoarece trebuie să deservească toate serverele, fiecare dintre ele încercând să scrie sau să citească datele de sesiune.

Sistem de fișiere distribuit

S-ar putea să vă gândiți că ar fi o idee bună să configurați o rețea Sistemul de fișiere, unde toate serverele ar putea scrie date de sesiune. Nu face aia! Aceasta este o abordare foarte lentă, care duce la deteriorarea sau chiar pierderea datelor. Dacă, dintr-un motiv oarecare, tot decideți să utilizați această metodă, vă recomand GlusterFS

Memcached

De asemenea, puteți utiliza memcached pentru a stoca datele sesiunii în RAM. Cu toate acestea, acest lucru nu este sigur, deoarece datele din memcached sunt suprascrise dacă se epuizează loc liber. Probabil vă întrebați, RAM nu este partajată între mașini? Cum se aplică întregului cluster? Memcached are capacitatea de a combina disponibilă pe mașini diferite RAM într-un singur pool.

Cu cât aveți mai multe mașini, cu atât mai multe puteți aloca acestui pool de memorie. Nu trebuie să puneți în comun toate memoria mașinilor, dar puteți și puteți dona o cantitate arbitrară de memorie de la fiecare mașină la pool. Deci, există o oportunitate de a părăsi b O cea mai mare parte a memoriei pentru utilizare normală, și alocați o bucată pentru cache, care vă va permite să stocați în cache nu numai sesiuni, ci și alte informații relevante. Memcached este o soluție excelentă și răspândită.

Pentru a utiliza această abordare, trebuie să editați puțin php.ini

Session.save_handler = memcache session.save_path = "tcp://path.to.memcached.server:port"

cluster Redis

Redis - stocarea datelor NoSQL. Stochează baza de date în RAM. Spre deosebire de memcached, acceptă stocarea persistentă a datelor și tipuri de date mai complexe. Redis nu acceptă gruparea, deci folosirea lui pentru scalarea orizontală este oarecum dificilă, totuși, aceasta este temporară, iar versiunea alfa a soluției de cluster a fost deja lansată.

Alte solutii

Total

După cum puteți vedea, scalarea orizontală a aplicațiilor PHP nu este atât de ușoară. Sunt multe dificultăți, majoritatea soluțiilor nu sunt interschimbabile, așa că trebuie să alegi una și să te ții de ea până la final, pentru că atunci când traficul iese din scară, nu mai există posibilitatea de a trece fără probleme la altceva.

Sper că acest mic ghid vă va ajuta să alegeți o abordare de scalare pentru proiectul dvs.

În a doua parte a articolului vom vorbi despre scalarea bazei de date.

) Buna ziua! Sunt Alexander Makarov și poate mă cunoașteți din cadrul Yii - sunt unul dintre dezvoltatorii acestuia. Am și un job full-time – iar acesta nu mai este un startup – Stay.com, care se ocupă de călătorii.

Astăzi voi vorbi despre scalarea orizontală, dar în termeni foarte, foarte generali.

Ce este scalarea, oricum? Aceasta este o oportunitate de a crește productivitatea proiectului pentru timp minim prin adăugarea de resurse.

De obicei, scalarea nu implică rescrierea codului, ci fie adăugarea de servere, fie creșterea resurselor unuia existent. Acest tip include scalarea verticală și orizontală.

Verticală este atunci când sunt adăugate mai multe RAM, discuri etc. pe un server deja existent și orizontal este atunci când se instalează mai multe servere la centrele de date, iar serverele de acolo deja interacționează cumva.

Cea mai tare întrebare pe care o pun este: de ce este nevoie dacă totul funcționează bine pentru mine pe un singur server? De fapt, trebuie să verificăm ce se va întâmpla. Adică funcționează acum, dar ce se va întâmpla mai târziu? Există două utilități minunate - ab și siege, care par să ajungă din urmă cu un nor de utilizatori ai concurenților care încep să lovească serverul, încearcă să solicite pagini, să trimită unele solicitări. Trebuie să le spui ce să facă, iar utilitățile generează rapoarte de genul acesta:

Principalii doi parametri: n - numărul de solicitări care trebuie făcute, c - numărul de solicitări simultane. Astfel ei verifică concurența.

La ieșire obținem RPS, adică numărul de solicitări pe secundă pe care serverul este capabil să le proceseze, din care va deveni clar câți utilizatori poate gestiona. Totul, desigur, depinde de proiect, variază, dar de obicei necesită atenție.

Mai există un parametru - Timpul de răspuns - timpul de răspuns în care serverul a servit în medie o pagină. Variază, dar se știe că aproximativ 300 ms sunt norma, iar orice mai mare nu este foarte bine, pentru că acești 300 ms sunt procesați de server, iar la aceasta se adaugă alți 300-600 ms, care sunt procesați de client. , adică În timp ce totul se încarcă - stiluri, imagini și restul - trece și timpul.

Se întâmplă că, de fapt, nu este nevoie să vă faceți griji cu privire la scalare - mergem la server, actualizăm PHP, obținem o creștere de 40% a performanței și totul este cool. Apoi, configurăm Opcache și îl reglam. Opcache, apropo, este reglat în același mod ca APC, cu un script care poate fi găsit în depozitul lui Rasmus Lerdorf și care arată hit-uri și rateuri, unde hit-urile sunt de câte ori PHP a mers în cache, iar ratele sunt de câte ori a mers la sistemul de fișiere obține fișiere. Dacă rulăm întregul site sau rulăm un fel de crawler pe link-uri sau îl introducem manual, atunci vom avea statistici despre aceste accesări și rateuri. Dacă există 100% accesări și 0% rateuri, atunci totul este în regulă, dar dacă există rateuri, atunci trebuie să evidențiați mai multa memorie astfel încât tot codul nostru să se încadreze în Opcache. Acest greseala comuna, ceea ce ei recunosc - se pare că Opcache este acolo, dar ceva nu funcționează...

De asemenea, deseori încep să se extindă, dar nu se uită deloc la asta, motiv pentru care totul funcționează încet. Cel mai adesea intrăm în baza de date, uite - nu există indici, punem indici - totul funcționează imediat, suficient pentru încă 2 ani, frumusețe!

Ei bine, trebuie să activați și memoria cache, să înlocuiți apache cu nginx și php-fpm pentru a economisi memorie. Totul va fi grozav.

Toate cele de mai sus sunt destul de simple și vă oferă timp. Este timp pentru faptul că într-o zi acest lucru nu va fi suficient și trebuie să ne pregătim pentru asta acum.

Cum, în general, puteți înțelege care este problema? Fie că aveți deja o sarcină mare, iar acesta nu este neapărat un număr nebun de solicitări etc., este atunci când proiectul dvs. nu poate face față sarcinii și acest lucru nu mai poate fi rezolvat în moduri banale. Trebuie să crești fie mai lat, fie mai sus. Trebuie făcut ceva și, cel mai probabil, este puțin timp pentru asta; trebuie inventat ceva.

Prima regulă este că nu trebuie să faci niciodată nimic orbește, de exemplu. avem nevoie de o monitorizare excelentă. În primul rând, câștigăm timp pentru o optimizare evidentă, cum ar fi activarea unui cache sau stocarea în cache a paginii de pornire etc. Apoi punem la punct monitorizarea, ne arată ce lipsește. Și toate acestea se repetă de multe ori - nu puteți opri niciodată monitorizarea și îmbunătățirea.

Ce poate arăta monitorizarea? Ne putem odihni de disc, adică. la sistemul de fișiere, la memorie, la procesor, la rețea... Și se poate ca totul să pară mai mult sau mai puțin, dar apar niște erori. Toate acestea se rezolvă în moduri diferite. Puteți rezolva o problemă cu, de exemplu, un disc adăugând un nou disc pe același server sau puteți instala un al doilea server care se va ocupa doar de fișiere.

La ce ar trebui să fiți atenți acum când monitorizați? Acest:

  1. accesibilitate, adică dacă serverul este viu sau nu;
  2. lipsa resurselor de disc, procesor etc.;
  3. erori.
Cum să monitorizezi toate acestea?

Iată o listă de instrumente grozave care vă permit să monitorizați resursele și să afișați rezultatele într-un mod foarte convenabil:

Acest raport este o transcriere a uneia dintre cele mai bune prezentări de la conferința de formare pentru dezvoltatorii de sisteme de mare sarcină din 2015.

Lucruri vechi! - tu spui.
- Valori eterne! - vom răspunde. Adaugă etichete

Scalabilitatea este o astfel de proprietate sistem de calcul, care asigură o creștere previzibilă caracteristicile sistemului, de exemplu, numărul de utilizatori acceptați, capacitatea de răspuns, performanța generală etc., atunci când adăugați resurse de calcul la acesta. În cazul unui server DBMS, pot fi luate în considerare două metode de scalare - verticală și orizontală (Fig. 2).

Cu scalarea orizontală, numărul de servere DBMS crește, eventual interacționând între ele într-un mod transparent, separând astfel sarcina totala sisteme. Este posibil ca această soluție să devină din ce în ce mai populară pe măsură ce suportul pentru arhitecturile slab cuplate crește și baze de date distribuite date, dar se caracterizează de obicei printr-o administrare complexă.

Scalare verticală implică creșterea puterii unui server DBMS separat și se realizează prin înlocuire hardware(procesor, discuri) la unul mai rapid sau prin adăugarea de noduri suplimentare. Un exemplu bun O creștere a numărului de procesoare în platformele SMP (simetric multiprocessor) poate servi drept stimulent. În acest caz, software-ul serverului nu trebuie schimbat (în special, nu puteți solicita achiziția module suplimentare), deoarece acest lucru ar crește complexitatea administrării și ar reduce predictibilitatea comportamentului sistemului. Indiferent de metoda de scalare utilizată, câștigul este determinat de cât de complet utilizează programele de server resursele de calcul disponibile. În evaluările ulterioare, vom lua în considerare scalarea verticală, care, potrivit analiștilor, se confruntă cu cea mai mare creștere pe piața modernă a computerelor.

Proprietatea de scalabilitate este relevantă din două motive principale. În primul rând, condițiile moderne de afaceri se schimbă atât de repede încât fac imposibilă planificarea pe termen lung, care necesită o analiză cuprinzătoare și îndelungată a datelor deja învechite, chiar și pentru acele organizații care își permit. În schimb, vine o strategie de creștere a puterii treptat, pas cu pas sisteme de informare. Pe de altă parte, schimbările în tehnologie duc la apariția a tot mai multe soluții noi și a prețurilor hardware mai mici, ceea ce poate face ca arhitectura sistemelor informaționale să fie mai flexibilă. În același timp, interoperabilitatea și deschiderea produselor software și hardware se extind diferiți producători, deși până acum eforturile lor de conformitate au fost consecvente doar în sectoarele de piață înguste. Fără a lua în considerare acești factori, consumatorul nu va putea profita de noile tehnologii fără a îngheța fondurile investite în tehnologii care nu sunt suficient de deschise sau care s-au dovedit a fi nepromițătoare. În zona stocării și procesării datelor, acest lucru necesită ca atât DBMS, cât și serverul să fie scalabili. Astăzi, parametrii cheie de scalabilitate sunt:

  • suport pentru multiprocesare;
  • flexibilitate arhitecturală.

Sisteme multiprocesor

Pentru scalarea verticală, sistemele multiprocesor simetrice (SMP) sunt din ce în ce mai utilizate, deoarece în acest caz nu este necesară schimbarea platformei, adică. sistem de operare, hardware și abilități de administrare. În acest scop, este posibil să se utilizeze și sisteme cu paralelism masiv (MPP), dar până acum utilizarea lor este limitată la sarcini speciale, de exemplu, cele de calcul. Atunci când se evaluează un server DBMS cu arhitectură paralelă, este indicat să se acorde atenție două caracteristici principale ale extensibilității arhitecturii: adecvarea și transparența.

Proprietatea de adecvare necesită ca arhitectura serverului să suporte în mod egal unul sau zece procesoare fără reinstalare sau modificări semnificative de configurare, precum și alte module software. O astfel de arhitectură va fi la fel de utilă și eficientă atât într-un sistem cu un singur procesor, cât și, pe măsură ce complexitatea sarcinilor de rezolvat crește, pe mai multe sau chiar mai multe procesoare (MPP). În general, consumatorul nu trebuie să cumpere sau să învețe noi opțiuni software.

Oferirea de transparență arhitecturii serverului, la rândul său, face posibilă ascunderea modificărilor configurației hardware din aplicații, de exemplu. garantează portabilitatea aplicațiilor sisteme software. În special, în arhitecturile multiprocesoare strâns cuplate, aplicația poate comunica cu serverul printr-un segment de memorie partajată, în timp ce în sistemele multiserver cuplate liber (clustere), un mecanism de mesaje poate fi utilizat în acest scop. Aplicația nu trebuie să țină cont de capacitățile de implementare ale arhitecturii hardware - metodele de manipulare a datelor și interfața software pentru accesarea bazei de date trebuie să rămână aceleași și la fel de eficiente.

Suportul de înaltă calitate pentru multiprocesare necesită ca serverul de baze de date să poată programa independent execuția multor interogări care urmează să fie servite, ceea ce ar asigura cea mai completă împărțire a resurselor de calcul disponibile între sarcinile serverului. Cererile pot fi procesate secvenţial de mai multe sarcini sau împărţite în subsarcini, care, la rândul lor, pot fi executate în paralel (Fig. 3). Acesta din urmă este mai optim deoarece implementarea corectă a acestui mecanism oferă beneficii care sunt independente de tipurile de cereri și aplicații. Eficiența procesării este foarte influențată de nivelul de granularitate al operațiunilor luate în considerare de sarcina de planificare. Cu o granularitate grosieră, de exemplu, la nivelul interogărilor SQL individuale, împărțirea resurselor sistemului informatic (procesoare, memorie, discuri) nu va fi optimă - sarcina va fi inactivă, așteptând sfârșitul operațiunilor I/O necesare pentru a finaliza interogarea SQL, cel puțin în coada de așteptare. Au existat alte interogări care au necesitat o muncă de calcul semnificativă. Cu o granularitate mai fină, divizarea resurselor are loc chiar și în cadrul unei singure interogări SQL, ceea ce este și mai clar atunci când procesare paralelă mai multe cereri. Utilizarea unui planificator asigură că resursele mari ale sistemului sunt utilizate pentru a rezolva sarcinile reale de întreținere a bazei de date și minimizează timpul de nefuncționare.

Flexibilitate arhitecturală

Indiferent de gradul de portabilitate, suport pentru standarde, paralelism și alte calități utile, performanța unui SGBD, care are limitări arhitecturale încorporate semnificative, nu poate fi crescută în mod liber. Prezența unor restricții documentate sau practice privind numărul și dimensiunile obiectelor bazei de date și a bufferelor de memorie, numărul conexiuni simultane, profunzimea recursiunii în procedurile de apelare și subinterogări sau declanșarea declanșatoarelor bazei de date este aceeași limitare a aplicabilității SGBD, cum ar fi, de exemplu, imposibilitatea portarii pe mai multe platforme de calcul. Parametrii care limitează complexitatea interogărilor bazei de date, în special dimensiunile bufferelor dinamice și dimensiunea stivei pentru apelurile recursive, ar trebui să fie configurabili dinamic și să nu necesite oprirea sistemului pentru reconfigurare. Nu are rost să achiziționați un nou server puternic dacă așteptările nu pot fi îndeplinite din cauza limitărilor interne ale SGBD.

De obicei, blocajul este incapacitatea de a ajusta dinamic caracteristicile programelor de server de baze de date. Abilitatea de a determina parametrii din mers, cum ar fi cantitatea de memorie consumată, numărul de procesoare ocupate, numărul de fire de execuție paralele (fie fire reale, procese ale sistemului de operare sau procesoare virtuale) și numărul de fragmente de tabele de baze de date și indici, precum și distribuția acestora By discuri fizice FĂRĂ oprirea și repornirea sistemului este o cerință care decurge din esența aplicațiilor moderne. În mod ideal, fiecare dintre acești parametri ar putea fi modificați dinamic în limitele specifice utilizatorului.

Pe măsură ce popularitatea unei aplicații web crește, suportul acesteia începe inevitabil să necesite din ce în ce mai multe resurse. La început, încărcarea poate (și, fără îndoială, ar trebui) să fie tratată prin optimizarea algoritmilor și/sau arhitecturii aplicației în sine. Cu toate acestea, ce să faceți dacă tot ceea ce ar putea fi optimizat a fost deja optimizat, dar aplicația încă nu poate face față sarcinii?

Optimizare

Primul lucru pe care ar trebui să-l faci este să te așezi și să te gândești dacă ai reușit deja să optimizezi totul:
  • Interogările bazei de date sunt optime (analiza EXPLAIN, utilizarea indecșilor)?
  • datele sunt stocate corect (SQL vs NoSQL)?
  • este folosită cache?
  • Există solicitări inutile către sistemul de fișiere sau baza de date?
  • Sunt algoritmii de procesare a datelor optimi?
  • Sunt setările de mediu optime: Apache/Nginx, MySQL/PostgreSQL, PHP/Python?
Despre fiecare dintre aceste puncte ar putea fi scris un articol separat, astfel încât o analiză detaliată a acestora în cadrul acestui articol este în mod evident redundantă. Este important doar să înțelegeți că, înainte de a începe scalarea unei aplicații, este foarte de dorit să optimizați funcționarea acesteia cât mai mult posibil - la urma urmei, poate că atunci nu va fi necesară scalarea.

Scalare

Și așa, să spunem că optimizarea a fost deja efectuată, dar aplicația încă nu poate face față sarcinii. În acest caz, soluția problemei poate fi, evident, distribuirea acesteia pe mai multe gazde pentru a crește performanța generală a aplicației prin creșterea resurselor disponibile. Această abordare are denumirea oficială – „scalarea” aplicației. Mai precis, „scalabilitatea” se referă la capacitatea unui sistem de a-și crește performanța pe măsură ce crește numărul de resurse alocate acestuia. Există două metode de scalare: verticală și orizontală. Scalare verticală implică o creștere a performanței aplicației atunci când se adaugă resurse (procesor, memorie, disc) într-un singur nod (gazdă). Scalare orizontală este tipică pentru aplicațiile distribuite și implică o creștere a performanței aplicației atunci când se adaugă un alt nod (gazdă).

Este clar că cel mai mult într-un mod simplu va exista un simplu upgrade de hardware (procesor, memorie, disc) - adică scalare verticală. În plus, această abordare nu necesită modificări ale aplicației. Cu toate acestea, scalarea verticală își atinge foarte repede limita, după care dezvoltatorul și administratorul nu au de ales decât să treacă la scalarea orizontală a aplicației.

Arhitectura aplicatiei

Majoritatea aplicațiilor web sunt distribuite a priori, deoarece în arhitectura lor se pot distinge cel puțin trei straturi: server web, logica de afaceri (aplicație), date (bază de date, statică).

Fiecare dintre aceste straturi poate fi scalat. Prin urmare, dacă în sistemul dvs. aplicația și baza de date trăiesc pe aceeași gazdă, primul pas, desigur, ar trebui să fie să le distribuiți pe diferite gazde.

Gâtul de sticlă

Când începeți să scalați sistemul, primul pas este să determinați care strat este „gâtul de sticlă” - adică funcționează mai lent decât restul sistemului. Pentru început, puteți folosi utilități banale precum top (htop) pentru a estima consumul de procesor/memorie și df, iostat pentru a estima consumul de disc. Cu toate acestea, este recomandabil să alocați o gazdă separată cu emulare a încărcăturii de luptă (folosind sau JMeter), pe care va fi posibil să profilați funcționarea aplicației folosind utilități precum xdebug și așa mai departe. Pentru a identifica interogări restrânse la baza de date, puteți utiliza utilitare precum pgFouine (este clar că este mai bine să faceți acest lucru pe baza jurnalelor de pe serverul de producție).

De obicei depinde de arhitectura aplicației, dar cei mai probabili candidați pentru un blocaj în general sunt baza de date și codul. Dacă aplicația dvs. funcționează cu o cantitate mare de date de utilizator, atunci blocajul va fi cel mai probabil stocarea statică.

Scalare baze de date

După cum am menționat mai sus, adesea blocajul aplicatii moderne este o bază de date. Problemele cu acesta sunt împărțite, de regulă, în două clase: cerințe de performanță și de stocare cantitate mare date.

Puteți reduce încărcarea bazei de date prin răspândirea acesteia pe mai multe gazde. Totodată, devine acută problema sincronizării dintre ele, care poate fi rezolvată prin implementarea unei scheme master/slave cu replicare sincronă sau asincronă. În cazul PostgreSQL, puteți implementa replicarea sincronă folosind Slony-I, replicarea asincronă folosind PgPool-II sau WAL (9.0). Problema separării cererilor de citire și scriere, precum și echilibrarea sarcinii între slave existenți, poate fi rezolvată prin configurarea unui nivel special de acces la baza de date (PgPool-II).

Problema stocării unor cantități mari de date atunci când se utilizează SGBD-uri relaționale poate fi rezolvată folosind mecanismul de partiționare („partiționare” în PostgreSQL) sau prin implementarea bazelor de date pe sisteme de fișiere distribuite, cum ar fi Hadoop DFS.

Cu toate acestea, pentru stocarea unor cantități mari de date cea mai bună soluție Va exista „sharding” a datelor, care este un beneficiu încorporat al majorității bazelor de date NoSQL (de exemplu, MongoDB).

În plus, bazele de date NoSQL funcționează în general mai rapid decât frații lor SQL, datorită absenței supraîncărcării pentru analiza/optimizarea interogărilor, verificarea integrității structurii datelor etc. Subiectul comparării bazelor de date relaționale și NoSQL este, de asemenea, destul de extins și merită un articol separat.

Separat demn de remarcat experiență Facebook, care este folosit de MySQL fără selectări JOIN. Această strategie le permite să scaleze baza de date mult mai ușor, transferând în același timp încărcarea din baza de date în cod, care, așa cum va fi descris mai jos, se scalează mai ușor decât baza de date.

Scalare de cod

Dificultatea de a scala codul depinde de câte resurse partajate au nevoie gazdele pentru a rula aplicația dvs. Vor fi doar sesiuni sau va necesita un cache partajat și fișiere? În orice caz, primul pas este să rulezi copii ale aplicației pe mai multe gazde cu același mediu.

În continuare, trebuie să configurați echilibrarea încărcării/cererilor între aceste gazde. Acest lucru se poate face după cum urmează: Nivelul TCP(haproxy) și pe HTTP (nginx) sau DNS.

Următorul pas este să vă asigurați că fișierele statice, memoria cache și sesiunile de aplicații web sunt disponibile pe fiecare gazdă. Pentru sesiuni, puteți utiliza un server care rulează în rețea (de exemplu, memcached). Este destul de rezonabil să folosiți același memcached ca un server cache, dar, desigur, pe o altă gazdă.

Fișierele statice pot fi montate din unele comune Stocarea fișierelor prin NFS/CIFS sau utilizați un sistem de fișiere distribuit (HDFS, GlusterFS, Ceph).

De asemenea, puteți stoca fișiere într-o bază de date (de exemplu, Mongo GridFS), rezolvând astfel problemele de disponibilitate și scalabilitate (ținând cont de faptul că pentru bazele de date NoSQL problema de scalabilitate este rezolvată din cauza sharding-ului).

Separat, merită remarcată problema implementării pe mai multe gazde. Cum se face astfel încât utilizatorul să nu vadă când face clic pe „Actualizare” versiuni diferite aplicatii? Cea mai simplă soluție, după părerea mea, ar fi să excludem gazdele neactualizate din configurația load balancer (server web) și să le pornești secvenţial pe măsură ce sunt actualizate. De asemenea, puteți lega utilizatori la anumite gazde prin cookie sau IP. Dacă actualizarea necesită schimbări semnificativeîn baza de date, cel mai simplu mod este să închideți temporar proiectul.

Scalare FS

Dacă este necesară stocarea unei cantități mari de date statice, pot fi identificate două probleme: lipsa spațiului și viteza de acces la date. După cum am scris deja mai sus, problema cu lipsa spațiului poate fi rezolvată în cel puțin trei moduri: un sistem de fișiere distribuit, stocarea datelor într-o bază de date cu suport pentru sharding și organizarea sharding-ului „manual” la nivel de cod.

În același timp, merită să înțelegem că nici distribuția staticii nu este cea mai bună sarcină simplă, cand vine vorba de sarcini mari. Prin urmare, este destul de rezonabil să aveți multe servere dedicate distribuirii fișierelor statice. Mai mult, dacă avem o stocare de date partajată (sistem de fișiere distribuite sau bază de date), atunci când salvăm un fișier, putem salva numele acestuia fără să luăm în considerare gazda și să înlocuim numele gazdei la întâmplare la crearea unei pagini (echilibrez aleatoriu sarcina dintre serverele web care distribuie statică). În cazul în care sharding-ul este implementat manual (adică logica din cod este responsabilă pentru alegerea gazdei în care vor fi încărcate datele), informațiile despre gazda de încărcare trebuie fie să fie calculate pe baza fișierului în sine, fie generate pe baza pe terțe date (informații despre utilizator, cantitatea de spațiu pe discurile de stocare) și salvate împreună cu numele fișierului în baza de date.

Monitorizarea

Este clar că mare și un sistem complex necesită monitorizare constantă. Soluția, în opinia mea, este standard aici - zabbix, care monitorizează încărcarea/funcționarea nodurilor de sistem și monitorizează demonii pentru backup.

Concluzie

Cele de mai sus discută pe scurt multe opțiuni pentru rezolvarea problemelor de scalare a unei aplicații web. Fiecare dintre ele are propriile sale avantaje și dezavantaje. Nu există o rețetă despre cum să faci totul bine și dintr-o dată - pentru fiecare sarcină există multe soluții cu propriile argumente pro și contra. Pe care să o alegi depinde de tine.