Pse mund të nevojitet replikimi gjysmë-sinkron?

Përshëndetje të gjithëve. Jam Vladislav Rodin. Aktualisht po jap leksione në portalin OTUS për kurset që i kushtohen arkitekturës së software dhe arkitekturës së software që përballon ngarkesa të larta. Para fillimit të një grupi të ri kursi «Arkitekt i ngarkesave të larta» vendosa të shkruaj një material të vogël autorësor, të cilin dëshiroj ta ndaj me ju.

Pse mund të nevojitet replikimi gjysmë-sinkron?

Hyrje

Për shkak se HDD mund të kryejë vetëm rreth 400-700 operacione në sekondë (çka është e papërshtatshme me rps-të tipike që i takojnë një sistemi me ngarkesë të lartë), një bazë të dhënash klasike është një ngushticë në arkitekturë. Prandaj, është e nevojshme të kushtohet vëmendje e veçantë modeleve të zgjerimit të këtij depozite.

Aktualisht ekzistojnë 2 modele zgjerimi të bazës: replikimi dhe shardimi. Shardimi lejon zgjerimin e operacionit të shkruar, dhe, si pasojë, redukton rps për shkruar që i takon një serveri të klasit tuaj. Replikimi lejon të bëhet e njëjta gjë, por me operacionet e leximit. Ky model i dedikohet pikërisht këtij artikulli.

Replikimi

Nëse e shikoni replikimin nga një këndvështrim të thjeshtë, është një gjë e lehtë: keni pasur një server, në të cilin ndodheshin të dhënat, dhe më pas ky server nuk kishte kapacitet të përballonte ngarkesën e leximit të këtyre të dhënave. Shtoni disa serverë të tjerë, sinkronizoni të dhënat në të gjitha serverat, dhe përdoruesi mund të lexojë nga çdo server të klasit tuaj.

Megjithëse duket e thjeshtë, ekzistojnë disa variante klasifikimi të zbatimeve të ndryshme të kësaj skeme:

  • Për rolet në klasë (master-master ose master-slave)
  • Për objektet që dërgohen (row-based, statement-based ose mixed)
  • Për mekanizmin e sinkronizimit të nodeve

Sot do të shqyrtojmë pikën e tretë.

Si ndodh komitimi i transaksionit

Ky temë nuk i përket drejtpërdrejt replikimit, për të cilën mund të shkruhet një artikull i veçantë, megjithatë, duke qenë se pa kuptimin e mekanizmit të komitimit të transaksionit, leximi i mëtejshëm është i padobishëm, lejoni të përmendim gjërat më themelore. Komitimi i transaksionit ndodh në 3 etapa:

  1. Shënimi i transaksionit në jurnal të bazës së të dhënave.
  2. Përzgjedhja e transaksionit në motorin e bazës së të dhënave.
  3. Kthimi i konfirmimit për klientin për përzgjedhjen e suksesshme të transaksionit.

Në baza të ndryshme në këtë algoritëm mund të lindin nuanca: për shembull, në motorin InnoDB të bazës MySQL ekzistojnë 2 revista: një për replikimin (binary log), dhe tjetra për mbajtjen e ACID (undo/redolog), ndërsa në PostgreSQL ekziston një revistë që kryen të dyja funksionet (write ahead log = WAL). Por, e paraqitur më lart është pikërisht koncepti i përgjithshëm, që lejon të injorohen këto nuanca.

Replikimi sinhron (sync)

Le të shtojmë në algoritmin e komitimit të transaksionit logjikën për replikimin e ndryshimeve të marra:

  1. Shënimi i transaksionit në jurnal të bazës së të dhënave.
  2. Përzgjedhja e transaksionit në motorin e bazës së të dhënave.
  3. Dërgimi i të dhënave në të gjitha replikat.
  4. Marrja e konfirmimit nga të gjitha replikat për përmbushjen e transaksionit.
  5. Kthimi i konfirmimit për klientin për përzgjedhjen e suksesshme të transaksionit.

Në këtë qasje, ne hasim disa disavantazhe:

  • klienti pret aplikimin e ndryshimeve në të gjitha replikat.
  • me rritjen e numrit të nodeve në klasë, ne zvogëlojmë probabilitetin që operacioni i shkruar të kalojë me sukses.

Nëse për pikën e parë gjithçka është mëse e qartë, arsyet për pikën e dytë kërkojnë shpjegim. Nëse gjatë replikimit sinhron ne nuk marrim përgjigje nga të paktën një nod, ne rrokim transaksionin. Në këtë mënyrë, duke rritur numrin e nodeve në klasë, rrisni probabilitetin që operacioni i shkruajtur të dështojë.

A mund të presim konfirmimin vetëm nga një pjesë e nodeve, për shembull, nga 51% (quorum)? Po, mundemi, megjithatë, në variantin klasik kërkohet konfirmimi nga të gjitha nodet, sepse vetëm kështu mund të sigurojmë konsistencën e plotë të të dhënave në klasë, që është një avantazh i padiskutueshëm i këtij lloji të replikimit.

Replikimi asinkron (async)

Le të modifikojmë algoritmin e mëparshëm. Të dhënat në replikat do të dërgohen "kur të vijë koha", dhe "kur të vijë koha" ndryshimet do të zbatohen nga replikat:

  1. Shënimi i transaksionit në jurnal të bazës së të dhënave.
  2. Përzgjedhja e transaksionit në motorin e bazës së të dhënave.
  3. Kthimi i konfirmimit për klientin për përzgjedhjen e suksesshme të transaksionit.
  4. Dërgimi i të dhënave në replikat dhe zbatimi i ndryshimeve nga ato.

Kjo qasje sjell që klasa të funksionojë shpejt, sepse ne nuk e mbajmë klientin në pritje derisa të dhënat të arrijnë në replikat dhe gjithashtu të komitohen.

Por kushti për dërgimin e të dhënave në replikat "kur të vijë koha" mund të çojë në humbje të transaksioneve, duke përfshirë humbjen e një transaksioni të konfirmuar nga përdoruesi, sepse nëse të dhënat nuk janë kopjuar me kohë, konfirmimi për klientin për suksesshëm ekzekutimin e operacionit është dërguar, dhe në nodin në të cilin kanë ardhur ndryshimet ka rënë HDD, ne humbasim transaksionin, çka mund të sjellë pasojat shumë të pakëndshme.

Replikimi gjysmë-sinhron (semisync)

Finalmente arritëm te replikimi gjysmë-sinkron. Ky lloj replikimi nuk është shumë i njohur dhe nuk është shumë i zakonshëm, por ai ngjall interes të konsiderueshëm, pasi mund të kombinojë përfitimet e replikimit sinkron dhe asinkron.

Të përpiqemi të bashkohet dy qasjet e mëparshme. Nuk do ta mbajmë klientin shumë gjatë, por do të kërkojmë që të dhënat të replikohen:

  1. Shënimi i transaksionit në jurnal të bazës së të dhënave.
  2. Përzgjedhja e transaksionit në motorin e bazës së të dhënave.
  3. Dërgimi i të dhënave në replika.
  4. Marrja e konfirmimit nga replika për marrjen e ndryshimeve (ato do të aplikohen «ndonjëherë më vonë»).
  5. Kthimi i konfirmimit për klientin për përzgjedhjen e suksesshme të transaksionit.

Vini re se me këtë algoritëm humbja e transaksionit ndodh vetëm në rast se dështojnë si nodi që pranon ndryshimet, ashtu edhe nodi-replika. Probabiliteti i një dështimi të tillë pranohet si i vogël, dhe këto rreziqe pranohen.

Por me këtë qasje, ekziston rreziku i leximeve fantazmë. Imagjinoni skenarin e mëposhtëm: në hapin 4 nuk morëm konfirmim nga asnjë replike. Ne duhet të anulojmë këtë transaksion dhe të mos ia kthejmë konfirmimin klientit. Duke qenë se të dhënat u aplikuan në hapin 2, midis përfundimit të hapit 2 dhe anulimit të transaksionit ndodhet një boshllëk temporal, gjatë së cilës transaksionet paralele mund të shohin ato ndryshime që nuk duhet të ishin në bazën e të dhënave.

Replikimi Lose-less semisync

Nëse mendojmë pak, mund të korrigjojmë problemin e leximeve fantazmë në këtë skenar duke thjesht ndërruar hapat e algoritmit:

  1. Shënimi i transaksionit në jurnal të bazës së të dhënave.
  2. Dërgimi i të dhënave të replikes.
  3. Marrja e konfirmimit nga replika për marrjen e ndryshimeve (ato do të aplikohen «ndonjëherë më vonë»).
  4. Përzgjedhja e transaksionit në motorin e bazës së të dhënave.
  5. Kthimi i konfirmimit për klientin për përzgjedhjen e suksesshme të transaksionit.

Tani ne komitojmë ndryshimet vetëm nëse ato janë replikuar.

Përfundim

Si gjithmonë, nuk ka zgjidhje ideale, ka një grup zgjidhjesh, secila prej të cilave ka përfitimet dhe disavantazhet e veta dhe është e përshtatshme për zgjidhjen e klasave të ndryshme të problemeve. Kjo është krejtësisht e vërtetë edhe për zgjedhjen e mekanizmit të sinkronizimit të të dhënave të bazës së të dhënave të replikuar. Grupi i përfitimeve që ofron replikimi gjysmë-sinkron është mjaft i rëndësishëm dhe interesant, për sa kohë që mund të konsiderohet të vlejë vëmendje, pavarësisht përhapjes së saj të vogël.

Këtu është gjithçka. Mirupafshim në kurs!

Burimi: habr.com

Bleni hostim të besueshëm për faqe me mbrojtje nga DDoS, serverë VPS VDS 🔥 Bleni hostim të besueshëm për faqe me mbrojtje nga DDoS, serverë VPS VDS | ProHoster