Tengo una configuración AG de 4 nodos de la siguiente manera:
Configuración de hardware de VM de todos los nodos:
- Microsoft SQL Server 2017 Enterprise Edition (RTM-CU14) (KB4484710)
- 16 vCPU
- 356 GB de RAM (larga historia para este ...)
- grado máximo de paralelismo: 1 (según lo requiera el proveedor de la aplicación)
- umbral de costo para paralelismo: 50
- memoria máxima del servidor (MB): 338944 (331 GB)
Configuración AG:
- Nodo 1: Compromiso primario o sincrónico Secundario no legible, configurado para conmutación por error automática
- Nodo 2: Compromiso primario o sincrónico Secundario no legible, configurado para conmutación por error automática
- Nodo 3: conjunto secundario legible con confirmación asincrónica, configurado para conmutación por error manual
- Nodo 4: conjunto secundario legible con confirmación asincrónica, configurado para conmutación por error manual
La consulta en cuestión:
No hay nada terriblemente loco en esta consulta, proporciona un resumen de elementos de trabajo pendientes en varias colas dentro de la aplicación. Puede ver el código de uno de los enlaces del plan de ejecución a continuación.
Comportamiento de ejecución en el nodo primario:
Cuando se ejecuta en el nodo primario, el tiempo de ejecución es generalmente alrededor de la marca de 1 segundo. Aquí está el plan de ejecución , y a continuación se muestran las estadísticas capturadas de STATISTICS IO y STATISTICS TIME del nodo primario:
(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.
Comportamiento de ejecución en el nodo secundario de solo lectura:
Cuando se ejecuta en Nodo secundario de solo lectura (es decir, Nodo 3 o Nodo 4), esta consulta usa el mismo plan de ejecución (este es un enlace de plan diferente) y se muestran aproximadamente las mismas estadísticas de ejecución (por ejemplo, puede haber algunas páginas más escaneos ya que estos resultados siempre están cambiando), pero con la excepción del tiempo de CPU, se ven muy similares. Aquí están las estadísticas capturadas de STATISTICS IO y STATISTICS TIME del nodo secundario de solo lectura:
(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.
Otros detalles:
También ejecuté el script de Paul Randalsp_WhoIsActive
y ambos en el secundario mientras se ejecuta esta consulta, pero no veo que ocurra ninguna espera, lo que es francamente frustrante:WaitingTasks.sql
Esto tampoco parece ser un caso de latencia AG ya que el estado de sincronización es bastante bueno:
--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;
Esta consulta parece ser el peor delincuente. Otras consultas que también tardan menos de un segundo en el nodo primario pueden tardar de 1 a 5 segundos en el nodo secundario, y aunque el comportamiento no es tan grave, parece estar causando problemas.
Finalmente, también examiné los servidores y verifiqué los procesos externos, tales como escaneos de A / V, trabajos externos que generan E / S inesperadas, etc. y he llegado con las manos vacías. No creo que esto sea causado por algo fuera del proceso de SQL Server.
La pregunta:
Es solo mediodía donde estoy y ya ha sido un día largo, así que sospecho que me estoy perdiendo algo obvio aquí. O eso, o tenemos algo mal configurado, lo cual es posible ya que hemos recibido varias llamadas al Proveedor y MS relacionadas con este entorno.
Para toda mi investigación, parece que no puedo encontrar lo que está causando esta diferencia en el rendimiento. Esperaría ver algún tipo de espera en los nodos secundarios, pero nada. ¿Cómo puedo solucionar esto para identificar la causa raíz? ¿Alguien ha visto este comportamiento antes y ha encontrado una manera de resolverlo?
ACTUALIZACIÓN # 1
Después de cambiar los estados del tercer nodo (una de las réplicas de solo lectura) a no legible y luego de nuevo a legible como prueba, esa réplica todavía está retenida por una transacción abierta, y cualquier consulta del cliente muestra el HADR_DATABASE_WAIT_FOR_TRANSITION_TO_VERSIONING
Espere.
Ejecutar un DBCC OPENTRAN
comando produce los siguientes resultados:
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.
Al buscar este SPID sp_who2
, lo muestra como un BACKGROUND
proceso con el QUERY STORE BACK
listado.
A pesar de que somos capaces de realizar copias de seguridad tlog, sospecho que se están ejecutando en funcionalidad similar de este error corregido , por lo que tengo la intención de abrir un ticket con EM sobre este tema en particular hoy en día.
Dependiendo del resultado de ese ticket, intentaré capturar un seguimiento de la pila de llamadas según la sugerencia de Joe y ver a dónde vamos.
Actualización final (problema con resolución propia)
Después de eclipsar la marca de 52 horas de la transacción de Query Store abierta (como se identificó anteriormente), el AG decidió realizar una conmutación por error automática. Antes de que esto sucediera, extraje algunas métricas adicionales. Según este enlace , proporcionado por Sean, la base de datos en cuestión tenía una tienda de versiones muy grande dedicada a esta base de datos, específicamente en un momento había registrado 1651360 páginas en el reserved_page_count
campo y 13210880 por el reserved_space_kb
valor.
Según los ERRORLOG, la conmutación por error se produjo después de un diluvio de 5 minutos de fallas de endurecimiento de transacciones relacionadas QDS base transaction
y QDS nested transaction
transacciones.
La conmutación por error causó una interrupción de aproximadamente 10 minutos en mi caso. La base de datos tiene un tamaño de ~ 6 TB y es muy activa, por lo que en mi opinión eso fue bastante bueno. Mientras el nuevo nodo primario estuvo en línea durante este tiempo, no se pudieron completar consultas de clientes ya que todos estaban esperando el QDS_LOADDB
tipo de espera.
Después de la conmutación por error, los números de la tienda de versiones se redujeron a 176 para reserved_page_count
y 1408 para reserved_space_kb
. Las consultas contra las réplicas secundarias de solo lectura también comenzaron a ejecutarse tan rápido como si se ejecutaran desde la primaria, por lo que parece que el comportamiento desapareció por completo, como resultado de la conmutación por error.
QDS_LOADDB
: si desea evitar eso en el futuro, pero aún tiene Query Store activado, puede usar estos indicadores de seguimiento recomendados por Microsoft. En particular, 7752 permitirá que las consultas se ejecuten antes de que el Almacén de consultas se haya inicializado (por lo que puede perder algunas consultas, pero su base de datos estará activa).
7752
parece particularmente útil. ¡Gracias por el consejo!