Spinlock (Parte III)

Após comentar sobre os spinlock nos posts Spinlock Parte I e Parte II, agora vamos para o lado prático.

 

Monitorando os Spinlocks

O comando DBCC SQLPERF(SPINLOCKSTATS) não é documentado, mas auxilia na monitoração dos spinlocks. Enquanto escrevia esse post, descobri que existe uma DMV também.

 SELECT * FROM sys.dm_os_spinlock_stats

O resultado será apresentado:

image

 

Impacto no Servidor

O que esperar do spinlock e qual será seu risco para o servidor? Em situações de contenção por spinlock, observa-se uma série de threads bloqueadas por um único ponto de contenção – são vários “loops infinitos” tentando obter o spinlock. Cada contenção é contabilizada como collision, sendo possível determinar o número de “rodadas” (spins) efetuada por cada thread através de spins_per_collision. O ideal é que esses números sejam ZERO – mas é tolerável (e normal) encontrar valores entre 0 e 1000.

Conforme o número de spins/collision aumenta, o servidor começa a perder mais tempo dentro do bloqueio do que executando tarefas. Nesse momento, a CPU dispara para 100% e entra em um loop infinito. Esse é um comportamento transitório de milissegundos porque, por outro lado, existe um limite máximo de spins. Quando a thread ultrapassa esse valor, ela entra entra em um estado de dormência (sleep) – denominado backoff:

Backoff – Após um alto número de spins para obter o spinlock e sem sucesso, o SQL Server coloca a thread no estado inativo durante alguns milissegundos. Durante o período de backoff, a thread deixa de executar suas tarefas e fica esperando pelo lock.

A partir do número de backoff e o tempo em dormência (sleep time), fica mais fácil compreender o impacto no desempenho do servidor. Esses contadores devem ser zero, pois qualquer outro valor indica uma contenção.

 

Analisando o Resultado

Se você encontrar um servidor que apresente as colunas spins, sleep time e backoff diferente de zero, não há motivos para desespero. Contenção sempre existe e para isso que servem os spinlocks.

Tenho utilizado uma estratégia de comparação entre os locks. Há estruturas em memória que apresentam mais contenção que outras, como por exemplo os Locks e Buffers.

A regra proposta é observar o número de spins/collision e backoff dos spinlocks chamados LOCK_HASH e BUF_HASH. Esses servem como baseline. Depois, procuramos por qualquer outro spinlock que apresente um maior número de spins/backoff. Esses serão os “possíveis spinlocks” com problemas.

Não há uma resolução simples para esse tipo de contenção. Normalmente, a causa está relacionada com uma limitação na arquitetura do SQL Server ou uma situação de Bug. Por isso, acredito que o DBA não tem controle sobre a situação. Seu papel é monitorar o servidor e identificar os problemas antes que se tornem críticos. Além disso, aplicar Service Pack e patches de correção podem resolver a situação.

 

Exemplos

Aqui seguem dois exemplos que ilustram contenção por spinlock. Nos dois casos, veja ambos ultrapassam 10000 spins/collision – chegando a quase 180000. Consequentemente, há backoff nas threads e sleep time.

1. Contenção no Spinlock MUTEX.

Contention on Large Sized Security Cache

2. Contenção no Procedure Cache (SQL Manager)

Spinlock Contention

 

Se alguém quiser compartilhar algum exemplo, envie o resultado do DBCC SQLPERF(SPINLOCKSTATS) e deixarei disponível a análise no blog.