У меня есть 4 узла AG установки следующим образом:
Аппаратная конфигурация ВМ всех узлов:
- Microsoft SQL Server 2017 Enterprise Edition (RTM-CU14) (KB4484710)
- 16 виртуальных ЦП
- 356 ГБ ОЗУ (длинный рассказ об этом ...)
- максимальная степень параллелизма: 1 (в соответствии с требованиями поставщика приложений)
- порог стоимости для параллелизма: 50
- максимальная память сервера (МБ): 338944 (331 ГБ)
Конфигурация AG:
- Узел 1: Первичный или синхронный коммит, нечитаемый вторичный, сконфигурированный для автоматического перехода на другой ресурс
- Узел 2. Первичный или синхронный коммит, нечитаемый вторичный, сконфигурированный для автоматического перехода на другой ресурс
- Узел 3: Доступный для чтения вторичный набор с асинхронной фиксацией, настроенный для аварийного переключения вручную
- Узел 4: Доступный для чтения вторичный набор с асинхронной фиксацией, настроенный для аварийного переключения вручную
Вопрос в вопросе:
В этом запросе нет ничего безумного, он предоставляет сводку ожидающих выполнения рабочих элементов в различных очередях в приложении. Вы можете увидеть код по одной из ссылок плана выполнения ниже.
Поведение исполнения на первичном узле:
При выполнении на основном узле время выполнения обычно составляет около 1 секунды. Вот план выполнения , и ниже приведены статистические данные, полученные из STATISTICS IO и STATISTICS TIME от основного узла:
(347 rows affected)
Table 'Worktable'. Scan count 647, logical reads 2491, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'workitemlc'. Scan count 300, logical reads 7125, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Workfile'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'schedulertask'. Scan count 1, logical reads 29, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'wfschedulertask'. Scan count 1, logical reads 9, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'schedulerservice'. Scan count 1, logical reads 12, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'schedulerworkerpool'. Scan count 1, logical reads 3, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'itemlc'. Scan count 1, logical reads 26372, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
(1 row affected)
SQL Server Execution Times:
CPU time = 500 ms, elapsed time = 656 ms.
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
Поведение при выполнении на дополнительном узле только для чтения:
При выполнении на дополнительном узле только для чтения (т. Е. Узле 3 или узле 4) этот запрос использует тот же план выполнения (это другая ссылка на план), и отображается примерно такая же статистика выполнения (например, может быть еще несколько страниц). сканирует, так как эти результаты постоянно меняются), но, за исключением времени процессора, они выглядят очень похоже. Вот статистика, полученная из STATISTICS IO и STATISTICS TIME из вторичного узла только для чтения:
(347 rows affected)
Table 'Worktable'. Scan count 647, logical reads 2491, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'workitemlc'. Scan count 300, logical reads 7125, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Workfile'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'schedulertask'. Scan count 1, logical reads 29, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'wfschedulertask'. Scan count 1, logical reads 9, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'schedulerservice'. Scan count 1, logical reads 12, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'schedulerworkerpool'. Scan count 1, logical reads 3, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'itemlc'. Scan count 1, logical reads 26372, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
(1 row affected)
SQL Server Execution Times:
CPU time = 55719 ms, elapsed time = 56335 ms.
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
Другие детали:
Я также работать как sp_WhoIsActive
и Пол РэндалWaitingTasks.sql
сценарий на вторичной обмотке , а этот запрос выполняется, но я не вижу какие - либо ожидает , что происходит, так когда - либо, что откровенно расстраивает:
Это также не выглядит как случай задержки AG, поскольку состояние синхронизации на самом деле довольно хорошее:
--https://sqlperformance.com/2015/08/monitoring/availability-group-replica-sync
SELECT
ar.replica_server_name,
adc.database_name,
ag.name AS ag_name,
drs.is_local,
drs.synchronization_state_desc,
drs.synchronization_health_desc,
--drs.last_hardened_lsn,
--drs.last_hardened_time,
drs.last_redone_time,
drs.redo_queue_size,
drs.redo_rate,
(drs.redo_queue_size / drs.redo_rate) / 60.0 AS est_redo_completion_time_min,
drs.last_commit_lsn,
drs.last_commit_time
FROM sys.dm_hadr_database_replica_states AS drs
INNER JOIN sys.availability_databases_cluster AS adc
ON drs.group_id = adc.group_id AND
drs.group_database_id = adc.group_database_id
INNER JOIN sys.availability_groups AS ag
ON ag.group_id = drs.group_id
INNER JOIN sys.availability_replicas AS ar
ON drs.group_id = ar.group_id AND
drs.replica_id = ar.replica_id
ORDER BY
ag.name,
ar.replica_server_name,
adc.database_name;
Этот запрос кажется худшим нарушителем. Другие запросы, которые также занимают менее секунды на первичном узле, могут занимать 1–5 секунд на вторичном узле, и, хотя поведение не столь серьезное, оно, похоже, вызывает проблемы.
Наконец, я также посмотрел на серверы и проверил наличие внешних процессов, таких как A / V-сканирование, внешние задания, генерирующие неожиданный ввод-вывод и т. Д., И пришел с пустыми руками. Я не думаю, что это вызвано чем-то вне процесса SQL Server.
Вопрос:
Это только полдень, где я нахожусь, и это был уже долгий день, поэтому я подозреваю, что упускаю что-то очевидное здесь. Либо это, либо у нас что-то неправильно настроено, что возможно, поскольку у нас было несколько обращений к поставщику и MS, связанных с этой средой.
На протяжении всего моего исследования я просто не могу найти причину такой разницы в производительности. Я ожидаю увидеть какое-то ожидание на вторичных узлах, но ничего. Как я могу дополнительно устранить это, чтобы определить основную причину? Кто-нибудь видел такое поведение раньше и нашел способ его решить?
ОБНОВЛЕНИЕ # 1
После обмена состояниями третьего узла (одной из реплик только для чтения) на недоступные для чтения, а затем обратно в читаемые в качестве теста, эта реплика все еще удерживается открытой транзакцией, причем любые клиентские запросы отображают HADR_DATABASE_WAIT_FOR_TRANSITION_TO_VERSIONING
Подождите.
Выполнение DBCC OPENTRAN
команды дает следующие результаты:
Oldest active transaction:
SPID (server process ID): 420s
UID (user ID) : -1
Name : QDS nested transaction
LSN : (941189:33148:8)
Start time : May 7 2019 12:54:06:753PM
SID : 0x0
DBCC execution completed. If DBCC printed error messages, contact your system administrator.
При поиске этого SPID sp_who2
он отображается как BACKGROUND
процесс с QUERY STORE BACK
указанием в качестве команды.
В то время как мы в состоянии взять резервные копии TLOG, я подозреваю , что мы бежим в подобную функциональность этого решено ошибка , поэтому я планирую открыть билет с MS об этом конкретном вопросе сегодня.
В зависимости от результата этого билета я постараюсь записать трассировку стека вызовов по предложению Джо и посмотрим, куда мы пойдем.
Окончательное обновление (проблема решена самостоятельно)
После того, как была отмечена 52-часовая отметка открытой транзакции хранилища запросов (как указано выше), AG решил автоматически выполнить аварийное переключение. До того, как это произошло, я потянул некоторые дополнительные метрики. По этой ссылке , предоставленной Шоном, в рассматриваемой базе данных было очень большое хранилище версий, посвященное этой базе данных, в частности, в один момент я записал 1651360 страниц в reserved_page_count
поле и 13210880 для reserved_space_kb
значения.
Согласно ERRORLOGs, отказоустойчивый произошло после 5 - минутного наводнению сбоев транзакций , связанных с упрочняющими QDS base transaction
и QDS nested transaction
сделки.
Аварийное переключение вызвало сбой около 10 минут в моем случае. База данных размером ~ 6 ТБ и очень активная, так что, на мой взгляд, это было довольно неплохо. Пока новый основной узел был в сети в течение этого времени, ни один клиентский запрос не мог завершиться, поскольку все они ожидали QDS_LOADDB
типа ожидания.
После отработки отказа номера хранилищ версий сократились до 176 для reserved_page_count
и 1408 для reserved_space_kb
. Запросы к вторичным репликам, доступным только для чтения, также начали выполняться так же быстро, как если бы они запускались с первичной, поэтому похоже, что поведение полностью исчезло в результате аварийного переключения.
QDS_LOADDB
- если вы хотите избежать этого в будущем, но при этом оставить Query Store включенным, вы можете использовать эти флаги трассировки, рекомендованные Microsoft. В частности, 7752 разрешит выполнение запросов до инициализации хранилища запросов (поэтому вы можете пропустить некоторые запросы, но ваша база данных будет работать).
7752
выглядит особенно полезным. Спасибо за совет!