Database
 sql >> Base de Dados >  >> RDS >> Database

Sintomas de sobrecarga do observador e do tipo de espera


Muitas pessoas usam estatísticas de espera como parte de sua metodologia geral de solução de problemas de desempenho, assim como eu, então a pergunta que eu queria explorar neste post é sobre os tipos de espera associados à sobrecarga do observador. Por sobrecarga do observador, quero dizer o impacto na taxa de transferência de carga de trabalho do SQL Server causado pelo SQL Profiler, rastreamentos do lado do servidor ou sessões de eventos estendidos. Para saber mais sobre o assunto da sobrecarga do observador, veja as duas postagens a seguir do meu colega Jonathan Kehayias :
  • Medindo a “sobrecarga do observador” do SQL Trace versus eventos estendidos
  • Impacto do evento estendido query_post_execution_showplan no SQL Server 2012

Portanto, neste post, gostaria de analisar algumas variações da sobrecarga do observador e ver se podemos encontrar tipos de espera consistentes associados à degradação medida. Há várias maneiras pelas quais os usuários do SQL Server implementam o rastreamento em seus ambientes de produção, portanto, seus resultados podem variar, mas eu queria abranger algumas categorias amplas e relatar o que encontrei:
  • Uso da sessão do SQL Profiler
  • Uso de rastreamento do lado do servidor
  • Uso de rastreamento do lado do servidor, gravando em um caminho de E/S lento
  • Uso de eventos estendidos com um destino de buffer de anel
  • Uso de eventos estendidos com um destino de arquivo
  • Uso de eventos estendidos com um destino de arquivo em um caminho de E/S lento
  • Uso de eventos estendidos com um destino de arquivo em um caminho de E/S lento sem perda de evento

Você provavelmente pode pensar em outras variações sobre o tema e convido você a compartilhar quaisquer descobertas interessantes sobre a sobrecarga do observador e as estatísticas de espera como um comentário neste post.

Linha de base


Para o teste, usei uma máquina virtual VMware com quatro vCPUs e 4 GB de RAM. Meu convidado de máquina virtual estava em SSDs OCZ Vertex. O sistema operacional era o Windows Server 2008 R2 Enterprise e a versão do SQL Server é 2012, SP1 CU4.

Quanto à “carga de trabalho”, estou usando uma consulta somente leitura em um loop no banco de dados de amostra de crédito de 2008, definido como GO 10.000.000 vezes.
USE [Credit];
GO
 
SELECT TOP 1 
     [member].[member_no],
     [member].[lastname],
     [payment].[payment_no],
     [payment].[payment_dt],
     [payment].[payment_amt]
FROM [dbo].[payment]
INNER JOIN [dbo].[member]
ON [member].[member_no] = [payment].[member_no];
GO 10000000

Também estou executando essa consulta por meio de 16 sessões simultâneas. O resultado final no meu sistema de teste é 100% de utilização da CPU em todas as vCPUs no convidado virtual e uma média de 14.492 solicitações em lote por segundo em um período de 2 minutos.

Em relação ao rastreamento de eventos, em cada teste usei o Showplan XML Statistics Profile para os testes de rastreamento do SQL Profiler e do lado do servidor – e query_post_execution_showplan para sessões de eventos estendidos. Os eventos do plano de execução são muito caros, e é justamente por isso que eu os escolhi para que eu pudesse ver se em circunstâncias extremas eu poderia ou não derivar temas do tipo espera.

Para testar o acúmulo de tipo de espera durante um período de teste, usei a consulta a seguir. Nada extravagante - apenas limpando as estatísticas, aguardando 2 minutos e coletando as 10 principais acumulações de espera para a instância do SQL Server durante o período de teste de degradação:
-- Clearing the wait stats
 
DBCC SQLPERF('waitstats', clear);
 
WAITFOR DELAY '00:02:00';
GO
 
SELECT TOP 10
     [wait_type],
     [waiting_tasks_count],
     [wait_time_ms]
FROM sys.[dm_os_wait_stats] AS [ws]
ORDER BY [wait_time_ms] DESC;

Observe que não estou filtrando os tipos de espera em segundo plano que normalmente são filtrados, e isso ocorre porque eu não queria eliminar algo que normalmente é benigno - mas nessa circunstância realmente aponta para uma área real para investigar mais.

Sessão do SQL Profiler


A tabela a seguir mostra as solicitações em lote anteriores e posteriores por segundo ao habilitar um rastreamento de rastreamento do SQL Profiler local Showplan XML Statistics Profile (executando na mesma VM que a instância do SQL Server):
Solicitações de lote de linha de base por segundo
(média de 2 minutos)
Solicitações de lote de sessão do SQL Profiler por segundo
(média de 2 minutos)
14.492 1.416

Você pode ver que o rastreamento do SQL Profiler causa uma queda significativa na taxa de transferência.

Quanto ao tempo de espera acumulado no mesmo período, os principais tipos de espera foram os seguintes (assim como o restante dos testes neste artigo, fiz algumas execuções de teste e a saída foi geralmente consistente):
wait_type waiting_tasks_count wait_time_ms
TRACEWRITE 67.142 1.149.824
FT_IFTS_SCHEDULER_IDLE_WAIT 4 237.003
SLEEP_TASK 313 180.449
REQUEST_FOR_DEADLOCK_SEARCH 24 120.111
HADR_FILESTREAM_IOMGR_IOCOMPLETION 240 120.086
LAZYWRITER_SLEEP 120 120.059
DIRTY_PAGE_POLL 1.198 120.038
HADR_WORK_QUEUE 12 120.015
LOGMGR_QUEUE 937 120.011
SQLTRACE_INCREMENTAL_FLUSH_SLEEP 30 120.006

O tipo de espera que salta para mim é TRACEWRITE – que é definido pelos Manuais Online como um tipo de espera que “ocorre quando o provedor de rastreamento do conjunto de linhas SQL Trace aguarda um buffer livre ou um buffer com eventos a serem processados”. O restante dos tipos de espera se parece com os tipos de espera em segundo plano padrão que normalmente seriam filtrados do seu conjunto de resultados. Além disso, falei sobre um problema semelhante com rastreamento excessivo em um artigo em 2011 chamado sobrecarga do Observer – os perigos do rastreamento excessivo – então eu estava familiarizado com esse tipo de espera às vezes apontando corretamente para problemas de sobrecarga do observador. Agora, nesse caso específico sobre o qual escrevi no blog, não era o SQL Profiler, mas outro aplicativo usando o provedor de rastreamento de conjunto de linhas (ineficientemente).

Rastreamento do lado do servidor


Isso foi para o SQL Profiler, mas e a sobrecarga de rastreamento do lado do servidor? A tabela a seguir mostra as solicitações de lote antes e depois por segundo ao habilitar uma gravação de rastreamento do lado do servidor local em um arquivo:
Solicitações de lote de linha de base por segundo
(média de 2 minutos)
Solicitações em lote do SQL Profiler por segundo
(média de 2 minutos)
14.492 4.015

Os principais tipos de espera foram os seguintes (fiz algumas execuções de teste e a saída foi consistente):
wait_type waiting_tasks_count wait_time_ms
FT_IFTS_SCHEDULER_IDLE_WAIT 4 237.015
SLEEP_TASK 253 180.871
SQLTRACE_INCREMENTAL_FLUSH_SLEEP 30 120.046
HADR_WORK_QUEUE 12 120.042
REQUEST_FOR_DEADLOCK_SEARCH 24 120.021
XE_DISPATCHER_WAIT 3 120.006
AGUARDE 1 120.000
LOGMGR_QUEUE 931 119.993
DIRTY_PAGE_POLL 1.193 119.958
XE_TIMER_EVENT 55 119.954

Desta vez não vemos TRACEWRITE (estamos usando um provedor de arquivos agora) e o outro tipo de espera relacionado a rastreamento, o não documentado SQLTRACE_INCREMENTAL_FLUSH_SLEEP subiu – mas em comparação com o primeiro teste, tem um tempo de espera acumulado muito semelhante (120.046 vs. 120.006) – e minha colega Erin Stellato (@erinstellato) falou sobre esse tipo de espera específico em seu post Descobrindo quando as estatísticas de espera foram apagadas pela última vez . Portanto, olhando para os outros tipos de espera, nenhum está se destacando como uma bandeira vermelha confiável.

Rastreamento do lado do servidor gravando em um caminho de E/S lento


E se colocarmos o arquivo de rastreamento do lado do servidor em um disco lento? A tabela a seguir mostra as solicitações de lote antes e depois por segundo ao habilitar um rastreamento do lado do servidor local que grava em um arquivo em um pendrive:
Solicitações de lote de linha de base por segundo
(média de 2 minutos)
Solicitações em lote do SQL Profiler por segundo
(média de 2 minutos)
14.492 260

Como podemos ver – o desempenho é significativamente degradado – mesmo em comparação com o teste anterior.

Os principais tipos de espera foram os seguintes:
wait_type waiting_tasks_count wait_time_ms
SQLTRACE_FILE_BUFFER 357 351.174
SP_SERVER_DIAGNOSTICS_SLEEP 2.273 299.995
SLEEP_TASK 240 194.264
FT_IFTS_SCHEDULER_IDLE_WAIT 2 181.458
REQUEST_FOR_DEADLOCK_SEARCH 25 125.007
LAZYWRITER_SLEEP 63 124.437
LOGMGR_QUEUE 941 120.559
HADR_FILESTREAM_IOMGR_IOCOMPLETION 67 120.516
AGUARDE 1 120.515
DIRTY_PAGE_POLL 1.204 120.513

Um tipo de espera que salta para este teste é o não documentado SQLTRACE_FILE_BUFFER . Não muito documentado neste, mas com base no nome, podemos fazer um palpite (especialmente devido à configuração desse teste específico).

Eventos estendidos para o destino do buffer de anel


Em seguida, vamos revisar as descobertas para os equivalentes da sessão do Extended Event. Eu usei a seguinte definição de sessão:
CREATE EVENT SESSION [ApplicationXYZ] ON SERVER
  ADD EVENT sqlserver.query_post_execution_showplan,
  ADD TARGET package0.ring_buffer(SET max_events_limit=(1000))
  WITH (STARTUP_STATE=ON);
GO

A tabela a seguir mostra as solicitações de lote antes e depois por segundo ao habilitar uma sessão XE com um destino de buffer de anel (capturando o query_post_execution_showplan evento):
Solicitações de lote de linha de base por segundo
(média de 2 minutos)
Solicitações em lote do SQL Profiler por segundo
(média de 2 minutos)
14.492 4.737

Os principais tipos de espera foram os seguintes:
wait_type waiting_tasks_count wait_time_ms
SP_SERVER_DIAGNOSTICS_SLEEP 612 299.992
FT_IFTS_SCHEDULER_IDLE_WAIT 4 237.006
SLEEP_TASK 240 181.739
LAZYWRITER_SLEEP 120 120.219
HADR_WORK_QUEUE 12 120.038
DIRTY_PAGE_POLL 1.198 120.035
REQUEST_FOR_DEADLOCK_SEARCH 24 120.017
SQLTRACE_INCREMENTAL_FLUSH_SLEEP 30 120.011
LOGMGR_QUEUE 936 120.008
AGUARDE 1 120.001

Nada saltou como relacionado ao XE, apenas “ruído” da tarefa em segundo plano.

Eventos estendidos para um destino de arquivo


Que tal alterar a sessão para usar um destino de arquivo em vez de um destino de buffer de anel? A tabela a seguir mostra as solicitações de lote antes e depois por segundo ao habilitar uma sessão XE com um destino de arquivo em vez de um destino de buffer de anel:
Solicitações de lote de linha de base por segundo
(média de 2 minutos)
Solicitações em lote do SQL Profiler por segundo
(média de 2 minutos)
14.492 4.299

Os principais tipos de espera foram os seguintes:
wait_type waiting_tasks_count wait_time_ms
SP_SERVER_DIAGNOSTICS_SLEEP 2.103 299.996
FT_IFTS_SCHEDULER_IDLE_WAIT 4 237.003
SLEEP_TASK 253 180.663
LAZYWRITER_SLEEP 120 120.187
HADR_WORK_QUEUE 12 120.029
SQLTRACE_INCREMENTAL_FLUSH_SLEEP 30 120.019
REQUEST_FOR_DEADLOCK_SEARCH 24 120.011
AGUARDE 1 120.001
XE_TIMER_EVENT 59 119.966
LOGMGR_QUEUE 935 119.957

Nada, com exceção de XE_TIMER_EVENT , saltou como relacionado ao XE. O Wait Type Repository de Bob Ward refere-se a este como seguro para ignorar, a menos que haja algo possivelmente errado - mas, realisticamente, você notaria esse tipo de espera geralmente benigno se estivesse em 9º lugar em seu sistema durante uma degradação de desempenho? E se você já estiver filtrando por causa de sua natureza normalmente benigna?

Eventos estendidos para um destino de arquivo de caminho de E/S lento


Agora, e se eu colocar o arquivo em um caminho de E/S lento? A tabela a seguir mostra as solicitações de lote antes e depois por segundo ao habilitar uma sessão XE com um destino de arquivo em um pendrive:
Solicitações de lote de linha de base por segundo
(média de 2 minutos)
Solicitações em lote do SQL Profiler por segundo
(média de 2 minutos)
14.492 4.386

Os principais tipos de espera foram os seguintes:
wait_type waiting_tasks_count wait_time_ms
FT_IFTS_SCHEDULER_IDLE_WAIT 4 237.046
SLEEP_TASK 253 180.719
HADR_FILESTREAM_IOMGR_IOCOMPLETION 240 120.427
LAZYWRITER_SLEEP 120 120.190
HADR_WORK_QUEUE 12 120.025
SQLTRACE_INCREMENTAL_FLUSH_SLEEP 30 120.013
REQUEST_FOR_DEADLOCK_SEARCH 24 120.011
AGUARDE 1 120.002
DIRTY_PAGE_POLL 1.197 119.977
XE_TIMER_EVENT 59 119.949

Novamente, nada relacionado ao XE saltando, exceto para o XE_TIMER_EVENT .

Eventos estendidos para um destino de arquivo de caminho de E/S lento, sem perda de evento


A tabela a seguir mostra as solicitações de lote antes e depois por segundo ao habilitar uma sessão XE com um destino de arquivo em um pendrive, mas desta vez sem permitir a perda de eventos (EVENT_RETENTION_MODE=NO_EVENT_LOSS) – o que não é recomendado e você verá nos resultados por que isso pode ser:
Solicitações de lote de linha de base por segundo
(média de 2 minutos)
Solicitações em lote do SQL Profiler por segundo
(média de 2 minutos)
14.492 539

Os principais tipos de espera foram os seguintes:
wait_type waiting_tasks_count wait_time_ms
XE_BUFFERMGR_FREEBUF_EVENT 8.773 1.707.845
FT_IFTS_SCHEDULER_IDLE_WAIT 4 237.003
SLEEP_TASK 337 180.446
LAZYWRITER_SLEEP 120 120.032
DIRTY_PAGE_POLL 1.198 120.026
HADR_WORK_QUEUE 12 120.009
REQUEST_FOR_DEADLOCK_SEARCH 24 120.007
SQLTRACE_INCREMENTAL_FLUSH_SLEEP 30 120.006
AGUARDE 1 120.000
XE_TIMER_EVENT 59 119.944

Com a redução extrema da taxa de transferência, vemos XE_BUFFERMGR_FREEBUF_EVENT salte para a posição número um em nossos resultados de tempo de espera acumulados. Este é documentado nos Manuais Online, e a Microsoft nos informa que esse evento está associado a sessões XE configuradas para nenhuma perda de evento e onde todos os buffers da sessão estão cheios.

Impacto do Observador


Deixando de lado os tipos de espera, foi interessante observar o impacto que cada método de observação teve na capacidade de nossa carga de trabalho de processar solicitações em lote:


Impacto de diferentes métodos de observação em solicitações de lote por segundo

Para todas as abordagens, houve um acerto significativo – mas não chocante – em comparação com nossa linha de base (sem observação); a maior dor, no entanto, foi sentida ao usar o Profiler, ao usar o Rastreamento do lado do servidor para um caminho de E/S lento ou Eventos estendidos para um destino de arquivo em um caminho de E/S lento – mas somente quando configurado para nenhuma perda de evento. Com a perda de eventos, essa configuração realmente foi executada no mesmo nível de um destino de arquivo para um caminho de E/S rápido, presumivelmente porque foi capaz de descartar muito mais eventos.

Resumo


Eu não testei todos os cenários possíveis e certamente existem outras combinações interessantes (sem mencionar comportamentos diferentes com base na versão do SQL Server), mas a principal conclusão que tiro dessa exploração é que você não pode sempre confiar em um acúmulo óbvio de tipo de espera ponteiro ao enfrentar um cenário de sobrecarga do observador. Com base nos testes desta postagem, apenas três dos sete cenários manifestaram um tipo de espera específico que poderia ajudar a apontar na direção certa. Mesmo assim – esses testes estavam em um sistema controlado – e muitas vezes as pessoas filtram os tipos de espera mencionados acima como tipos de plano de fundo benignos – para que você não os veja.

Diante disso, o que você pode fazer? Para degradação de desempenho sem sintomas claros ou óbvios, recomendo ampliar o escopo para perguntar sobre rastreamentos e sessões XE (como um aparte – também recomendo ampliar seu escopo se o sistema estiver virtualizado ou tiver opções de energia incorretas). Por exemplo, como parte da solução de problemas de um sistema, verifique sys.[traces] e sys.[dm_xe_sessions] para ver se algo está sendo executado no sistema que é inesperado. É uma camada extra para o que você precisa se preocupar, mas fazer algumas validações rápidas pode economizar uma quantidade significativa de tempo.