I have an AlwaysOn cluster of SQL Server 2019, containing an Availability Group of 3 replicas in Synchronous mode.
According to Microsoft documentation:
- The secondary replica hardens the log and returns an acknowledgement to the primary replica.
- On receiving the confirmation from the secondary replica, the primary replica finishes the commit processing and sends a confirmation message to the client.
This article goes into greater detail and explains that:
- In the secondary replica, Log Receive gets the log records from the primary replica and writes to Log cache. This process is repeated on each secondary replica participating in synchronous-commit mode.
- On each secondary replica, Redo thread exists, and it writes all changes mentioned in log records to the data page and index page. It flushes the log for hardening on secondary database log.
- As stated earlier, in synchronous data commit, primary replica waits for the acknowledgement from the secondary replica. At this stage, secondary replica sends an acknowledgement that transaction hardening is completed on secondary.
- Once Primary replica, receives an acknowledgement from the secondary replica, it sends the transaction completion message to the client.
So if I understand right:
If I update a record via Primary replica successfully, this updated value should be immediately available for clients querying the Secondary replicas.
However, when I test this, this doesn't work so.
I run a simple batch file, looking like this:
sqlcmd -E -S tcp:SQL-AG-Listener -d TestDB -Q "BEGIN TRANSACTION; UPDATE TestSyncTable SET CurrentTime='%currentTime%'; COMMIT TRANSACTION;"
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
So I'm updating the
CurrentTime field via the Primary replica (hosting the AG Listener) and then reading it right away via all three replicas. Each
sqlcmd command is a separate client process, so it opens its own independent TCP connection.
And then I see something like this:
SQL-Server01: CurrentTime = 20:02:19.93
SQL-Server02: CurrentTime = 20:02:16.94
SQL-Server03: CurrentTime = 20:02:19.93
(Reformatted the output for better readability here)
As far as I've seen, the Primary replica always returns the updated value. And the Secondaries also do - but only some short delay.
So the question is: why? Shouldn't Synchronous mode guarantee that the result of reading operation is consistent with the writing one? If the Secondary replica sends acknowledgement only after its Redo thread updates the data page - then how can it be?