ARQUITETURA SQL Server Parte 5: SQL Server Workers

Olá Pessoal! Neste quinto post da série vou falar sobre as Workers! 

Uma worker pode ser tanto uma fibra quanto uma thread gerenciada por um scheduler. Cada scheduler contém um número de workers limitado baseado no parâmetro “max worker threads” ou pela arquitetura, o parâmetro “max worker threads” pode determinar o número de workers que serão criadas, desde que seja ajustado para um valor diferente de 0, o que não é recomendado. Se o valor de “max worker threads” estiver ajustado para 0, o número máximo de workers que podem ser criadas é baseado na arquitetura e no número de processadores que a instância do SQL Server está enxergando. Cada scheduler é responsável por criar e destruir as suas workers conforme seja necessário. Uma worker não se movimenta entre os schedulers, porem como são criadas e destruídas, pode parecer que elas estão migrando por entre os schedulers. 

Quando um scheduler recebe uma nova requisição e ele não encontra uma worker disponível, uma nova é criada por ele. Existem basicamente duas condições para que uma worker seja destruída: se ela ficar 15 minutos sem utilização ou se a instância do SQL Server estiver sob pressão de memória. Em sistemas 32 bits uma worker utiliza ao menos 500 KB de memória e em 64 bits pelo menos 2 MB.

Normalmente o SQL Server gerencia muito bem as workers, mesmo em sistemas extremamente carregados, o número de workers acaba ficando bem abaixo do máximo configurado através do parâmetro Max Worker Threads. O número máximo de workers para a instância do SQL Server é determinado da seguinte forma: 

Arquitetura
Processadores lógicos
Max Worker Threads
x86
Até 4
256
x86
Mais de 4
256 + ((# Procs – 4) * 8)
x64
Até 4
512
x64
Mais de 4 e até 64
512 + ((# Procs – 4) * 16)
x64
Mais que 64
512 + ((# Procs – 4) * 32)

Obs.: A linha em amarelo foi adicionada recentemente.

Para saber quantas workers podem ser criadas numa instância do SQL Server utilize a query abaixo:

SELECT max_workers_count
FROM sys.dm_os_sys_info

O parâmetro “max worker threads” você pode configurar usando o sp_configure:



Links de referência utilizados para o post:



Livro de referência utilizado para o post: 

Microsoft SQL Server 2008 Internals – Kalen Delaney 

Até a próxima galera!

ARQUITETURA SQL Server Parte 4: Execution Model



Pessoal primeiramente peço desculpas pela demora em postar coisas novas, o assunto deste post é mais delicado e acabei demorando mais tempo para escreve-lo, Execution Model do SQL Server, vamos começar pelas requisições para que fique explicado da melhor forma possível desde o começo!

Quando uma requisição de usuário é enviada ao SQL Server, conhecida como SPID ou SESSION_ID, é feito um controle sobre ela através do UMS (User Mode Scheduler), antes de falar sobre ele é importante manter em mente sobre as requisições que:


1. Uma conexão está mapeada para um sessão após o login (SPID ou SESSION_ID).

2. Cada sessão submete requisições (requests) para execução.

3. Cada requisição (ou batch) é mapeada para uma ou mais tarefas (tasks).

4. As tarefas (tasks) são submetidas para os schedulers para execução, com base no fator de carga.

5. No scheduler a tarefa é mapeada para um thread, e continua com esta thread (running, suspended, runnable) até que seja finalizada.


 Voltando ao UMS, este não substitui o scheduler do Windows, apenas garante que as threads submetidas para execução privilegiam o modelo de execução do SQL Server. 


Cada requisição (ou tarefa) é submetida para um UMS para execução e associada a uma thread. Formalmente, o UMS está associado a uma CPU específica apenas quando o affinity mask está definido. Existe um UMS (ou scheduler) para cada CPU visível para uma instância do SQL Server. O UMS é composto por algumas filas e listas, que são usadas para gerenciar as suas threads (workers) e requisições associadas. 


Cada UMS ira ter no máximo uma requisição executando, uma fila chamada de runnable queue, a qual mantem as requisições executando porém que já gastaram seu tempo na CPU e estão aguardando a mesma ficar disponível novamente para voltarem a efetivamente executar, uma lista chamada de waiter list, a qual armazena as requisições que aguardam por demais recursos, por exemplo, uma query com status RESOURCE_SEMAPHORE está aguardando um “grant” de memória, e por último, uma “work queue”, fila de requisições aguardando por worker threads. 
  
Cada worker thread está associado a uma thread do Windows e junto com outras, são agrupadas nos schedulers. O fluxo, resumidamente, seria mais ou menos o abaixo:
 
            Uma requisição rodando que precisa esperar por algo (disco por exemplo) é movida para a Wait Queue > Se houver alguma requisição na Runnable Queue ela será colocada para executar > As requisições da Wait Queue que já possuem os recursos para executar entram no final da Runnable Queue.


    Acredito que uma boa analogia seja um jogo de vôlei:


Imagine que o jogador na quadra está em “running” porem já esgotou suas forças (atingiu o quantum de CPU) e precisa descansar e então é substituído (enviado para a Runnable Queue), um jogador que estava fora mais que já havia jogado volta à quadra (sai da Runnable Queue), os jogadores que estavam se aquecendo já estão prontos para irem a quadra (saem da Waiter list) e esperam apenas o chamado do técnico (vão para o final da Runnable Queue).


Este mecanismo que fez nascer uma metodologia relacionada a tuning chamada de Waits and Queues, irei falar mais pra frente das esperas mais importantes, mais detalhes vocês também encontram no documento do link abaixo que também foi usado para a escrita deste post:





Outras referências: 


Livro Microsoft SQL Server 2008 Internals – Kalen Delaney



Qualquer dúvida estou à disposição pessoal! Um abraço!