Согласованность данных в группе доступности SQL AlwaysOn
У меня есть кластер AlwaysOn SQL Server 2019, содержащий группу доступности из трех реплик в синхронном режиме. Согласно документации Microsoft :
- Вторичная реплика укрепляет журнал и возвращает подтверждение первичной реплике.
- Получив подтверждение от вторичной реплики, первичная реплика завершает обработку фиксации и отправляет клиенту подтверждающее сообщение.
В этой статье более подробно объясняется, что:
- Во вторичной реплике функция получения журнала получает записи журнала из первичной реплики и записывает их в кэш журнала. Этот процесс повторяется для каждой вторичной реплики, участвующей в режиме синхронной фиксации.
- В каждой вторичной реплике существует поток Redo, который записывает все изменения, упомянутые в записях журнала, на страницу данных и страницу индекса. Он очищает журнал для усиления защиты в журнале вторичной базы данных.
- Как говорилось ранее, при синхронной фиксации данных первичная реплика ожидает подтверждения от вторичной реплики. На этом этапе вторичная реплика отправляет подтверждение о завершении усиления транзакций на вторичной реплике.
- Как только первичная реплика получает подтверждение от вторичной реплики, она отправляет клиенту сообщение о завершении транзакции.
Итак, если я правильно понимаю: если я успешно обновлю запись через первичную реплику, это обновленное значение должно быть немедленно доступно для клиентов, запрашивающих вторичные реплики.
Однако, когда я тестирую это, это не работает . Я запускаю простой командный файл, который выглядит так:
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
Поэтому я обновляюCurrentTime
поле через первичную реплику (где размещается прослушиватель AG), а затем сразу же прочитать его через все три реплики. Каждыйsqlcmd
Команда является отдельным клиентским процессом, поэтому она открывает собственное независимое TCP-соединение.
И тут я вижу что-то вроде этого:
SQL-Server01: CurrentTime = 20:02:19.93
SQL-Server02: CurrentTime = 20:02:16.94
SQL-Server03: CurrentTime = 20:02:19.93
(Здесь переформатирован вывод для лучшей читаемости)
Насколько я видел, первичная реплика всегда возвращает обновленное значение. И вторичные тоже делают, но только с небольшой задержкой.
Итак, вопрос: почему? Разве синхронный режим не должен гарантировать, что результат операции чтения соответствует результату записи? Если Secondary реплика отправляет подтверждение только после того, как ее поток Redo обновит страницу данных — то как это может быть?
Спасибо, Муций.
1 ответ
Из той же статьи SQL Shack, которую вы цитировали в своем вопросе:
- Вторичная реплика также содержит поток повторного выполнения и не зависит от процесса блокировки журнала в SQL Server. Всегда включено. Потоки повтора считывают журналы из кэша журналов. Возможна задержка в обработке потоком повторного выполнения, а записи журнала могут быть недоступны в кэше журнала, поскольку он уже зафиксирован на диске. В этом случае поток повтора читает блоки журнала с диска журнала.
Я понимаю, что это означает, что процесс усиления безопасности журнала не делает изменения немедленно доступными в базе данных-получателе, а скорее, что поток повторения на вторичной базе данных должен сначала их обработать.