Am un cluster AlwaysOn al SQL Server 2019, care conține un grup de disponibilitate de 3 replici în modul sincron.
Conform documentația Microsoft:
- Replica secundară întărește jurnalul și returnează o confirmare la replica primară.
- La primirea confirmării de la replica secundară, replica primară termină procesarea de comitere și trimite un mesaj de confirmare clientului.
Acest articol intră în mai multe detalii și explică că:
- În replica secundară, Log Receive primește înregistrările jurnal din replica principală și scrie în Log cache. Acest proces se repetă pe fiecare replică secundară care participă în modul de confirmare sincronă.
- Pe fiecare replică secundară, există firul Redo și scrie toate modificările menționate în înregistrările de jurnal în pagina de date și în pagina de index. Acesta șterge jurnalul pentru întărire pe jurnalul secundar al bazei de date.
- După cum sa menționat mai devreme, în comiterea datelor sincrone, replica primară așteaptă confirmarea de la replica secundară. În această etapă, replica secundară trimite o confirmare că întărirea tranzacției este finalizată pe secundar.
- Odată ce replica primară primește o confirmare de la replica secundară, aceasta trimite clientului mesajul de finalizare a tranzacției.
Deci daca am inteles bine:
Dacă actualizez cu succes o înregistrare prin replica primară, această valoare actualizată ar trebui să fie imediat disponibil pentru clienții care interoghează replicile secundare.
Totuși, când testez asta, asta nu merge asa.
Rulez un fișier batch simplu, arătând astfel:
sqlcmd -E -S tcp:SQL-AG-Listener -d TestDB -Q "ÎNCEPE TRANZACȚIA; UPDATE TestSyncTable SET CurrentTime='%currentTime%'; COMMIT TRANZACȚIE;"
sqlcmd -E -S tcp:SQL-Server01 -d TestDB -Q „SELECT * FROM TestSyncTable” -K ReadOnly
sqlcmd -E -S tcp:SQL-Server02 -d TestDB -Q „SELECT * FROM TestSyncTable” -K ReadOnly
sqlcmd -E -S tcp:SQL-Server03 -d TestDB -Q „SELECT * FROM TestSyncTable” -K ReadOnly
Așa că actualizez Ora curentă
câmp prin replica principală (găzduind ascultătorul AG) și apoi citiți-l imediat prin toate cele trei replici. Fiecare sqlcmd
comanda este un proces client separat, deci își deschide propria conexiune TCP independentă.
Și apoi văd ceva de genul:
SQL-Server01: CurrentTime = 20:02:19.93
SQL-Server02: CurrentTime = 20:02:16.94
SQL-Server03: CurrentTime = 20:02:19.93
(Reformatat ieșirea pentru o mai bună lizibilitate aici)
Din câte am văzut, replica primară returnează întotdeauna valoarea actualizată. Și secundarele o fac, dar doar o scurtă întârziere.
Deci intrebarea este: De ce? Modul Sincron nu ar trebui să garanteze că rezultatul operației de citire este în concordanță cu cel de scriere? Dacă replica secundară trimite confirmarea numai după ce firul său Redo actualizează pagina de date - atunci cum poate fi?
Mulțumiri,
Mucius.