De ce ați putea avea nevoie de replicare semi-sincronă?

Salutare tuturor. Vladislav Rodin este în legătură. În prezent, predau cursuri de Arhitectură software și Arhitectură software de mare stres la OTUS. În așteptarea începerii unui nou flux de cursuri „Arhitect de sarcină mare” Am decis să scriu o scurtă bucată de material original pe care vreau să o împărtășesc cu voi.

De ce ați putea avea nevoie de replicare semi-sincronă?

Introducere

Datorită faptului că HDD-ul poate efectua doar aproximativ 400-700 de operații pe secundă (ceea ce este incomparabil cu rps-ul tipic pentru un sistem cu încărcare mare), baza de date clasică de disc este blocajul arhitecturii. Prin urmare, este necesar să se acorde o atenție deosebită modelelor de scalare ale acestui depozit.

În prezent, există 2 modele de scalare a bazei de date: replicare și fragmentare. Sharding vă permite să scalați operația de scriere și, ca rezultat, să reduceți rps-ul per scriere pe server din clusterul dvs. Replicarea vă permite să faceți același lucru, dar cu operații de citire. Acest model îi este dedicat acestui articol.

Replicare

Dacă te uiți la replicare la un nivel foarte înalt, este un lucru simplu: ai avut un server, erau date pe el și atunci acest server nu a mai putut face față sarcinii de citire a acestor date. Mai adăugați câteva servere, sincronizați datele pe toate serverele, iar utilizatorul poate citi de pe orice server din clusterul dvs.

În ciuda simplității sale aparente, există mai multe opțiuni pentru clasificarea diferitelor implementări ale acestei scheme:

  • După roluri din cluster (master-master sau master-slave)
  • După obiectele trimise (pe rând, pe bază de instrucțiuni sau mixte)
  • Conform mecanismului de sincronizare a nodurilor

Astăzi ne vom ocupa de punctul 3.

Cum are loc o comitere de tranzacție?

Acest subiect nu are legătură directă cu replicarea, un articol separat poate fi scris pe el, dar din moment ce citirea ulterioară este inutilă fără a înțelege mecanismul de confirmare a tranzacției, permiteți-mi să vă reamintesc cele mai elementare lucruri. O comitare a tranzacției are loc în 3 etape:

  1. Înregistrarea unei tranzacții în jurnalul bazei de date.
  2. Utilizarea unei tranzacții într-un motor de bază de date.
  3. Returnarea confirmării către client că tranzacția a fost aplicată cu succes.

În diferite baze de date, acest algoritm poate avea nuanțe: de exemplu, în motorul InnoDB al bazei de date MySQL există 2 loguri: unul pentru replicare (jurnal binar), iar celălalt pentru menținerea ACID (undo/redo log), în timp ce în PostgreSQL există un singur jurnal care îndeplinește ambele funcții (write ahead log = WAL). Dar ceea ce este prezentat mai sus este tocmai conceptul general, care permite ca astfel de nuanțe să nu fie luate în considerare.

Replicare sincronă (sincronă).

Să adăugăm o logică pentru a replica modificările primite la algoritmul de comitere a tranzacției:

  1. Înregistrarea unei tranzacții în jurnalul bazei de date.
  2. Utilizarea unei tranzacții într-un motor de bază de date.
  3. Trimiterea datelor către toate replicile.
  4. Primirea confirmării de la toate replicile că o tranzacție a fost finalizată cu acestea.
  5. Returnarea confirmării către client că tranzacția a fost aplicată cu succes.

Cu această abordare obținem o serie de dezavantaje:

  • clientul așteaptă ca modificările să fie aplicate tuturor replicilor.
  • pe măsură ce numărul de noduri din cluster crește, scădem probabilitatea ca operația de scriere să aibă succes.

Dacă totul este mai mult sau mai puțin clar cu primul punct, atunci motivele pentru al 1-lea punct merită explicate. Dacă în timpul replicării sincrone nu primim un răspuns de la cel puțin un nod, derulăm tranzacția înapoi. Astfel, prin creșterea numărului de noduri din cluster, creșteți probabilitatea ca o operație de scriere să eșueze.

Putem aștepta confirmarea doar de la un anumit procent de noduri, de exemplu, de la 51% (cvorum)? Da, putem, dar în versiunea clasică este necesară confirmarea de la toate nodurile, pentru că așa putem asigura o consistență completă a datelor în cluster, ceea ce este un avantaj incontestabil al acestui tip de replicare.

Replicare asincronă (async).

Să modificăm algoritmul anterior. Vom trimite date la replici „cândva mai târziu”, iar „cândva mai târziu” modificările vor fi aplicate replicilor:

  1. Înregistrarea unei tranzacții în jurnalul bazei de date.
  2. Utilizarea unei tranzacții într-un motor de bază de date.
  3. Returnarea confirmării către client că tranzacția a fost aplicată cu succes.
  4. Trimiterea datelor către replici și aplicarea modificărilor acestora.

Această abordare duce la faptul că clusterul funcționează rapid, pentru că nu îl ținem pe client să aștepte ca datele să ajungă la replici și chiar să fie comise.

Dar condiția de dumping a datelor pe replici „uneori mai târziu” poate duce la pierderea unei tranzacții și la pierderea unei tranzacții confirmate de utilizator, deoarece dacă datele nu au avut timp să fie replicate, o confirmare către client. despre succesul operațiunii a fost trimis, iar nodul la care au ajuns modificările a prăbușit HDD-ul, pierdem tranzacția, ceea ce poate duce la consecințe foarte neplăcute.

Replicare semisincronă

În cele din urmă ajungem la replicarea semi-sincronă. Acest tip de replicare nu este foarte cunoscut sau foarte comun, dar prezintă un interes considerabil deoarece poate combina avantajele atât ale replicării sincrone, cât și ale asincrone.

Să încercăm să combinăm cele 2 abordări anterioare. Nu vom păstra clientul pentru mult timp, dar vom cere ca datele să fie replicate:

  1. Înregistrarea unei tranzacții în jurnalul bazei de date.
  2. Utilizarea unei tranzacții într-un motor de bază de date.
  3. Trimiterea datelor către replici.
  4. Primirea confirmării de la replică că modificările au fost primite (vor fi aplicate „cândva mai târziu”).
  5. Returnarea confirmării către client că tranzacția a fost aplicată cu succes.

Vă rugăm să rețineți că, cu acest algoritm, pierderea tranzacției are loc numai dacă atât nodul care primește modificările, cât și nodul replica eșuează. Probabilitatea unui astfel de eșec este considerată scăzută, iar aceste riscuri sunt acceptate.

Dar cu această abordare există un posibil risc de citire fantomă. Să ne imaginăm următorul scenariu: la pasul 4, nu am primit confirmare de la nicio replică. Trebuie să anulăm această tranzacție și să nu returnăm o confirmare clientului. Deoarece datele au fost aplicate în pasul 2, există un interval de timp între sfârșitul pasului 2 și rollback-ul tranzacției, timp în care tranzacțiile paralele pot vedea modificări care nu ar trebui să fie în baza de date.

Replicare semisincronă fără pierderi

Dacă te gândești puțin, poți doar să inversezi pașii algoritmului și să rezolvi problema citirilor fantomă în acest scenariu:

  1. Înregistrarea unei tranzacții în jurnalul bazei de date.
  2. Trimiterea datelor replici.
  3. Primirea confirmării de la replică că modificările au fost primite (vor fi aplicate „cândva mai târziu”).
  4. Utilizarea unei tranzacții într-un motor de bază de date.
  5. Returnarea confirmării către client că tranzacția a fost aplicată cu succes.

Acum comitem modificări numai dacă au fost replicate.

Producție

Ca întotdeauna, nu există soluții ideale, există un set de soluții, fiecare dintre ele având propriile avantaje și dezavantaje și este potrivită pentru rezolvarea diferitelor clase de probleme. Acest lucru este absolut adevărat pentru alegerea unui mecanism de sincronizare a datelor într-o bază de date replicată. Setul de avantaje pe care le are replicarea semisincronă este suficient de solid și de interesant încât poate fi considerată demnă de atenție, în ciuda prevalenței sale scăzute.

Asta e tot. Ne vedem la curs!

Sursa: www.habr.com

Cumpărați găzduire de încredere pentru site-uri cu protecție DDoS, servere VPS VDS 🔥 Cumpără găzduire web fiabilă cu protecție DDoS, servere VPS VDS | ProHoster