Eu tenho uma configuração AG de 4 nós da seguinte maneira:
Configuração de hardware da VM de todos os nós:
- Microsoft SQL Server 2017 Enterprise Edition (RTM-CU14) (KB4484710)
- 16 vCPUs
- 356 GB de RAM (longa história desta ...)
- grau máximo de paralelismo: 1 (conforme exigido pelo fornecedor do aplicativo)
- limiar de custo para paralelismo: 50
- memória máxima do servidor (MB): 338944 (331 GB)
Configuração AG:
- Nó 1: Confirmação primária ou síncrona Secundária não legível, configurada para failover automático
- Nó 2: Confirmação primária ou síncrona Secundária não legível, configurada para failover automático
- Nó 3: Conjunto secundário legível com confirmação assíncrona, configurado para failover manual
- Nó 4: Conjunto secundário legível com confirmação assíncrona, configurado para failover manual
A consulta em questão:
Não há nada de louco nessa consulta, ela fornece um resumo dos itens de trabalho pendentes em várias filas no aplicativo. Você pode ver o código em um dos links do plano de execução abaixo.
Comportamento de execução no nó primário:
Quando executado no nó Primário, o tempo de execução geralmente fica em torno da marca de 1 segundo. Aqui está o plano de execução , e abaixo estão as estatísticas capturadas do STATISTICS IO e STATISTICS TIME do nó primário:
(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.
Comportamento de execução no nó secundário somente leitura:
Ao executar no Nó Secundário Somente Leitura (ou seja, Nó 3 ou Nó 4), essa consulta usa o mesmo plano de execução (este é um link de plano diferente) e aproximadamente as mesmas estatísticas de execução são mostradas (por exemplo, pode haver mais algumas páginas varreduras, pois esses resultados estão sempre mudando), mas, com exceção do tempo de CPU, eles parecem muito semelhantes. Aqui estão as estatísticas capturadas do STATISTICS IO e STATISTICS TIME do nó secundário somente leitura:
(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.
Outros detalhes:
Eu também tenho que correr tanto sp_WhoIsActive
e de Paul RandalWaitingTasks.sql
script no secundário, enquanto esta consulta está em execução, mas não estou a ver qualquer aguarda ocorrendo o que tão sempre, o que é francamente frustrante:
Isso também não parece ser um caso de latência de AG, pois o status de sincronização é realmente muito bom:
--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;
Essa consulta parece ser o pior infrator. Outras consultas que também levam segundos de segundos no nó principal podem levar de 1 a 5 segundos no nó secundário e, embora o comportamento não seja tão grave, parece estar causando problemas.
Por fim, também examinei os servidores e verifiquei processos externos, como verificações de A / V, trabalhos externos que geram E / S inesperadas etc., e saí de mãos vazias. Eu não acho que isso esteja sendo causado por algo fora do processo do SQL Server.
A questão:
É só meio-dia em que estou e já faz um longo dia, então suspeito que estou perdendo algo óbvio aqui. Ou isso, ou temos algo mal configurado, o que é possível, pois tivemos várias chamadas para o fornecedor e a MS relacionadas a esse ambiente.
Durante toda a minha investigação, não consigo encontrar o que está causando essa diferença de desempenho. Eu esperaria ver algum tipo de espera ocorrendo nos nós secundários, mas nada. Como posso solucionar mais isso para identificar a causa raiz? Alguém já viu esse comportamento antes e encontrou uma maneira de resolvê-lo?
ATUALIZAÇÃO # 1
Depois de trocar os estados do terceiro nó (uma das réplicas somente leitura) para não legíveis e depois voltar a legíveis como teste, essa réplica ainda está sendo mantida por uma transação aberta, com qualquer consulta de cliente exibindo o HADR_DATABASE_WAIT_FOR_TRANSITION_TO_VERSIONING
esperar.
A execução de um DBCC OPENTRAN
comando produz os seguintes 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.
Ao procurar esse SPID sp_who2
, ele é mostrado como um BACKGROUND
processo QUERY STORE BACK
listado como o comando.
Enquanto nós são capazes de tirar backups tlog, eu suspeito que estamos executando em funcionalidade semelhante de este erro seja resolvido , então estou pensando em abrir um ticket com o MS sobre esta questão em particular hoje.
Dependendo do resultado desse ticket, tentarei capturar um rastreamento de pilha de chamadas de acordo com a sugestão de Joe e ver para onde vamos.
Atualização final (problema resolvido automaticamente)
Depois de eclipsar a marca de 52 horas da transação do Query Store sendo aberta (como identificado acima), o AG decidiu fazer failover automaticamente. Antes disso, eu puxei algumas métricas adicionais. Por esse link , fornecido por Sean, o banco de dados em questão tinha um repositório de versões muito grande dedicado a esse banco de dados, especificamente em um ponto em que gravei 1651360 páginas no reserved_page_count
campo e 13210880 para o reserved_space_kb
valor.
De acordo com os ERRORLOGs, o failover ocorreu após um dilúvio de 5 minutos de falhas de proteção de transações relacionadas a QDS base transaction
e QDS nested transaction
transações.
O failover causou uma interrupção de cerca de 10 minutos no meu caso. O banco de dados tem ~ 6 TB de tamanho e é muito ativo, o que foi realmente muito bom na minha opinião. Enquanto o novo nó principal estava online durante esse período, nenhuma consulta do cliente pôde ser concluída, pois todos aguardavam o QDS_LOADDB
tipo de espera.
Após o failover, os números de armazenamento de versão foram reduzidos para 176 reserved_page_count
e 1408 para reserved_space_kb
. As consultas contra as réplicas secundárias somente leitura também começaram a ser executadas tão rapidamente quanto se fossem executadas a partir do primário, portanto, parece que o comportamento desapareceu completamente, como resultado do failover.
QDS_LOADDB
- se você quiser evitar isso no futuro, mas ainda manter o Query Store ativado, poderá usar esses sinalizadores de rastreamento recomendados pela Microsoft. Em particular, o 7752 permitirá que as consultas sejam executadas antes da inicialização do Query Store (portanto, você pode perder algumas consultas, mas seu banco de dados estará ativo).
7752
parece particularmente útil. Obrigado pela dica!