У меня есть кластер AlwaysOn SQL Server 2019, содержащий группу доступности из 3 реплик в синхронном режиме.
Согласно с документация Майкрософт:
- Вторичная реплика укрепляет журнал и возвращает подтверждение первичной реплике.
- Получив подтверждение от вторичной реплики, первичная реплика завершает обработку фиксации и отправляет клиенту подтверждающее сообщение.
эта статья вникает в подробности и поясняет, что:
- Во вторичной реплике Log Receive получает записи журнала из первичной реплики и записывает их в кэш журналов. Этот процесс повторяется для каждой вторичной реплики, участвующей в режиме синхронной фиксации.
- На каждой вторичной реплике существует поток Redo, который записывает все изменения, упомянутые в записях журнала, на страницу данных и страницу индекса. Он очищает журнал для защиты в журнале вторичной базы данных.
- Как указывалось ранее, при синхронной фиксации данных первичная реплика ожидает подтверждения от вторичной реплики. На этом этапе вторичная реплика отправляет подтверждение того, что усиление транзакции на вторичном сервере завершено.
- Как только первичная реплика получает подтверждение от вторичной реплики, она отправляет клиенту сообщение о завершении транзакции.
Итак, если я правильно понимаю:
Если я успешно обновлю запись через Первичную реплику, это обновленное значение должно быть немедленно доступны для клиентов, запрашивающих вторичные реплики.
Однако, когда я проверяю это, это так не работает.
Я запускаю простой пакетный файл, который выглядит так:
sqlcmd -E -S tcp:SQL-AG-Listener -d TestDB -Q "НАЧАТЬ ТРАНЗАКЦИЮ; ОБНОВИТЬ TestSyncTable SET CurrentTime='%currentTime%'; СОВЕРШИТЬ ТРАНЗАКЦИЮ;"
sqlcmd -E -S tcp:SQL-Server01 -d TestDB -Q "SELECT * FROM TestSyncTable" -K Только для чтения
sqlcmd -E -S tcp:SQL-Server02 -d TestDB -Q "SELECT * FROM TestSyncTable" -K Только для чтения
sqlcmd -E -S tcp:SQL-Server03 -d TestDB -Q "SELECT * FROM TestSyncTable" -K Только для чтения
Итак, я обновляю Текущее время
поле через основную реплику (где размещается прослушиватель AG), а затем сразу считывает его через все три реплики. Каждый sqlcmd
Команда — это отдельный клиентский процесс, поэтому он открывает собственное независимое TCP-соединение.
И тут я вижу что-то вроде этого:
SQL-Server01: текущее время = 20:02:19,93
SQL-Server02: текущее время = 20:02:16,94
SQL-Server03: текущее время = 20:02:19,93
(Переформатирован вывод для лучшей читабельности здесь)
Насколько я видел, первичная реплика всегда возвращает обновленное значение. И Второстепенные тоже - но только с небольшой задержкой.
Итак, вопрос: Почему? Разве синхронный режим не должен гарантировать, что результат операции чтения соответствует результату записи? Если Вторичная реплика отправляет подтверждение только после того, как ее Redo-поток обновит страницу данных — то как же быть?
Спасибо,
Муций.