J'ai une configuration AG à 4 nœuds comme suit:
Configuration matérielle VM de tous les nœuds:
- Microsoft SQL Server 2017 Enterprise Edition (RTM-CU14) (KB4484710)
- 16 processeurs virtuels
- 356 Go de RAM (longue histoire à celle-ci ...)
- degré maximal de parallélisme: 1 (tel que requis par le fournisseur de l'application)
- seuil de coût pour le parallélisme: 50
- mémoire serveur maximale (Mo): 338944 (331 Go)
Configuration AG:
- Noeud 1: validation primaire ou synchrone secondaire non lisible, configuré pour le basculement automatique
- Noeud 2: validation primaire ou synchrone secondaire non lisible, configuré pour le basculement automatique
- Noeud 3: ensemble secondaire lisible avec validation asynchrone, configuré pour le basculement manuel
- Noeud 4: ensemble secondaire lisible avec validation asynchrone, configuré pour le basculement manuel
La requête en question:
Il n'y a rien de terriblement fou dans cette requête, elle fournit un résumé des éléments de travail en suspens dans diverses files d'attente au sein de l'application. Vous pouvez voir le code à partir de l'un des liens du plan d'exécution ci-dessous.
Comportement d'exécution sur le nœud principal:
Lorsqu'il est exécuté sur le nœud principal, le temps d'exécution se situe généralement autour de la marque 1 seconde. Voici le plan d'exécution , et ci-dessous sont les statistiques capturées à partir de STATISTICS IO et STATISTICS TIME à partir du nœud principal:
(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.
Comportement d'exécution sur le nœud secondaire en lecture seule:
Lors de l'exécution sur un nœud secondaire en lecture seule (c.-à-d. Nœud 3 ou nœud 4), cette requête utilise le même plan d'exécution (il s'agit d'un lien de plan différent) et à peu près les mêmes statistiques d'exécution sont affichées (par exemple, il peut y avoir quelques pages supplémentaires scans car ces résultats changent toujours), mais à l'exception du temps CPU, ils se ressemblent beaucoup. Voici les statistiques capturées à partir de STATISTICS IO et STATISTICS TIME à partir du nœud secondaire en lecture seule:
(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.
Autres détails:
J'ai également exécuté les deux sp_WhoIsActive
et leWaitingTasks.sql
script de Paul Randal sur le secondaire pendant l'exécution de cette requête, mais je ne vois aucune attente se produire quoi que ce soit, ce qui est franchement frustrant:
Cela ne semble pas non plus être un cas de latence AG car l'état de synchronisation est en fait assez bon:
--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;
Cette requête semble être le pire délinquant. Les autres requêtes qui prennent également moins d'une seconde sur le nœud principal peuvent prendre de 1 à 5 secondes sur le nœud secondaire, et bien que le comportement ne soit pas aussi grave, il semble causer des problèmes.
Enfin, j'ai également regardé les serveurs et vérifié les processus externes tels que les analyses A / V, les travaux externes générant des E / S inattendues, etc. et je suis arrivé les mains vides. Je ne pense pas que cela soit causé par quoi que ce soit en dehors du processus SQL Server.
La question:
Il est seulement midi où je suis et la journée a déjà été longue, donc je soupçonne que je manque quelque chose d'évident ici. Soit cela, soit nous avons quelque chose de mal configuré, ce qui est possible car nous avons eu un certain nombre d'appels au fournisseur et à la MS liés à cet environnement.
Pour toute mon enquête, je n'arrive pas à trouver ce qui cause cette différence de performances. Je m'attendrais à voir une sorte d'attente se produire sur les nœuds secondaires, mais rien. Comment puis-je résoudre davantage ce problème pour identifier la cause première? Quelqu'un a-t-il déjà vu ce comportement et trouvé un moyen de le résoudre?
MISE À JOUR # 1
Après avoir échangé les états du troisième noeud (l'une des réplicas en lecture seule) sur non lisible, puis de nouveau sur lisible en tant que test, cette réplique est toujours bloquée par une transaction ouverte, toutes les requêtes des clients affichant le HADR_DATABASE_WAIT_FOR_TRANSITION_TO_VERSIONING
attendre.
L'exécution d'une DBCC OPENTRAN
commande donne les résultats suivants:
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.
Lorsque vous recherchez ce SPID dans sp_who2
, il l'affiche comme un BACKGROUND
processus QUERY STORE BACK
répertorié comme commande.
Alors que nous sommes en mesure de prendre des sauvegardes tlogs, je pense que nous courons dans les mêmes fonctionnalités de ce bug résolu , donc je prévois d' ouvrir un ticket avec MS à propos de cette question aujourd'hui.
Selon le résultat de ce ticket, j'essaierai de capturer une trace de pile d'appels selon la suggestion de Joe et de voir où nous allons.
Mise à jour finale (problème auto-résolu)
Après avoir éclipsé la marque de 52 heures de l'ouverture de la transaction Query Store (comme identifié ci-dessus), l'AG a décidé de basculer automatiquement. Avant cela, j'ai extrait quelques mesures supplémentaires. Par ce lien , fourni par Sean, la base de données en question avait un très grand magasin de versions dédié à cette base de données, spécifiquement à un moment donné, j'avais enregistré 1651360 pages sur le reserved_page_count
terrain et 13210880 pour la reserved_space_kb
valeur.
Selon les ERRORLOG, le basculement s'est produit après un déluge de 5 minutes d'échecs de durcissement des transactions liés aux transactions QDS base transaction
et aux QDS nested transaction
transactions.
Le basculement a provoqué une panne d'environ 10 minutes dans mon cas. La base de données a une taille de ~ 6 To et est très active, donc c'était en fait assez bon à mon avis. Pendant que le nouveau nœud principal était en ligne pendant cette période, aucune requête client ne pouvait se terminer car ils attendaient tous sur le QDS_LOADDB
type d'attente.
Après le basculement, le nombre de magasins de versions a été réduit à 176 pour reserved_page_count
et 1408 pour reserved_space_kb
. Les requêtes sur les réplicas en lecture seule secondaires ont également commencé à s'exécuter aussi rapidement que si elles étaient exécutées à partir du serveur principal, il semble donc que le comportement ait complètement disparu à la suite du basculement.
QDS_LOADDB
- si vous voulez éviter cela à l'avenir, tout en conservant Query Store, vous pouvez utiliser ces indicateurs de trace recommandés par Microsoft. En particulier, 7752 laissera les requêtes s'exécuter avant l'initialisation du magasin de requêtes (vous risquez donc de manquer certaines requêtes, mais votre base de données sera active).
7752
semble particulièrement utile. Merci pour le conseil!