Results for tag "process-explorer"

3 Articles

Conhecendo o Processo do SQL Server no Windows e Linux – Parte 2

Post 2/3. Este post é parte da série: Conhecendo o Processo do SQL Server

No último post da série vimos alguns conceitos básicos sobre processos e threads, e também usamos algumas ferramentas no Windows para obter mais informações sobre o executável de um processo do SQL Server. Hoje vamos abordar mais alguns conceitos importantes e ver como podem ser úteis na prática!

O Executável do SQL Server

O executável do SQL Server é o sqlservr.exe. No Windows você o encontra em:

<ProgramFiles>\Microsoft SQL Server\<Versao>.<NomeInstancia>\MSSQL\Binn

No Linux, ele fica em:

/opt/mssql/bin/sqlservr (sem extensão).

Talvez você nunca tenha precisado interagir diretamente com o executável do SQL Server porque você sempre iniciou ele através de um serviço. Em palavras simples, um serviço está fazendo a mesma coisa que você: pedindo ao sistema operacional que inicie a execução de um arquivo. Mas, no final das contas, ele é apenas um processo. Você pode confirmar isso usando ferramentas do seu sistema operacional que permitem monitorar e gerenciar os processos, como:

Por exemplo, a seguinte imagem demonstra dois processos, cada um referente a uma instância que iniciei através do Configuration Manager:

No Gerenciador de Tarefas do Windows a partir da versão 2012/8, você encontra essas informações na aba “Detalhes” (ou “details”), Há uma linha para cada processo existente no seu sistema operacional. Se há mais de uma instância SQL Server em execução, cada instância irá ser executada em seu próprio processo. O SQL Server Agent também é outro processo, e que usa um executável diferente do SQL:

Assim como o SQL Browser, Analysis Services, etc. Cada um tem seu próprio executável, e aceitam diferentes parâmetros.

O PID

Uma das informações mais importante sobre um processo é seu identificador, ou “Process ID” (PID). O PID é um número exclusivo que um processo ganha ao ser criado no sistema operacional. Nunca existirão dois processos com o mesmo ID em uma mesma sessão do sistema operacional (isto é, depois do  boot). Porém, o ID pode ser reusado quando seu respectivo processo encerrar. Raramente você verá o serviço do SQL Server usar o mesmo ID de processo entre seus restarts. Se ocorrer, é uma bela sorte!

A linha de comando

Repare na última coluna dessa imagem:

A coluna “Linha de comando” (você consegue habilitar mais colunas usando o botão direito do mouse no cabeçalho da tabela e selecionado a opção “Selecionar colunas”) mostra o caminho do executável que foi usado para iniciar o processo. Se você olhar na definição do serviço desta instância, poderá ver a mesma informação:

  1. Abra o gerenciador de serviços do Windows (digite “services.msc” no executar ou em um shell)
  2. Procure o serviço do SQL Server ( o nome é SQL Server (<NOME INSTANCIA>))
  3. Clique com o botão direito, e vá em propridades. Você verá uma imagem semelhante a esta:

Se você selecionar o texto sob “Caminho do Executável”, poderá ver o resto das informações.

Quando o Windows é solicitado para rodar esta linha de comando, seja diretamente pelo usuário, ou através de um serviço, ele cria um novo processo e aponta a primeira thread para o executável. Além disso, após o nome do executável há os parâmetros que devem ser passados ao processo. O Windows se encarrega de disponibilizar esses valores para a primeira thread do processo, e a partir daí ela faz o que quiser com eles.

No caso do sqlservr.exe, o parâmetro “-s” indica que o valor a seguir é um nome de instância. No caso do SQL Agent, é o parâmetro “-i” quem dita essa informação. (No post anterior há uma tabelinha contendo essas informações).

O usuário

Uma outra informação bastante útil vem da coluna “Nome de usuário”. Essa coluna indica com qual conta de usuário o processo está rodando. Todo processo, e, consequentemente, suas Threads, necessitam rodar sob alguma conta de usuário (geralmente, usamos o nome “conta de serviço”, pois estamos falando de uma conta de usuário que irá rodar um serviço. Mas é tudo a mesma coisa). Essa conta é usada pelo sistema operacional para validar o acesso a recursos do sistema operacional, como os arquivos. É comum observar erros de Access Denied a um arquivo ou diretório porque esta conta não tem as devidas permissões.

Uma outra situação comum, é ter que dar direitos específicos para que o SQL Server consiga realizar determinadas operações. Por exemplo, no Windows, o famoso Instant File Initialization é permitido somente se a conta com a qual o serviço está rodando possui um privilégio chamado SeManageVolumePrivilege. Há diversas formas de verificar se o processo tem esse privilégio habilitado e uma delas é usando o Process Explorer:

  1. Abra o process explorer como Administrador e procure o processo do SQL da instância desejada
  2. Clique com o botão direito no nome do processo e vá em “Properties”
  3. Vá na aba “Security”. No final da janela aberta, você verá a lista de privilégios com as quais o processo executa (que foi herdado do usuário associado com esse processo)

  A lista vem ordenada pelo nome do privilégio. Apesar da conta possuir alguns privilégios atribuídos, o de nosso interesse não está na lista. Após adicionar o privilégio, e reiniciar o serviço do SQL Server, conseguimos vê-lo:

Além disso, há uma série de outras informações a respeito do usuário, que podemos discutir melhor em um outro post.


Hoje conhecemos mais alguns conceitos interessantes pertinentes a um processo! No próximo post, vamos aplicar tudo o que vimos no Linux, já que até agora usamos somente Windows. E não deixe de praticar o que foi aprendido hoje:

  • Utilize as várias ferramentas disponíveis e compare os usuários com os quais o processo executa
  • Experimente retirar ou adicionar permissões da conta de serviço utilizada pelo SQL Server,e observe os efeitos na execução do serviço.
  • Reinicie o serviço do SQL Server e compare os PIDs
  • Powershell:  Explore cmdlet Get-Service ou a classe WMI win32_service para obter mais informações sobre um serviço do Windows
  • Pergunta de prova: Duas instâncias, em diferentes computadores, podem compartilhar o mesmo PID?

Conhecendo o Processo do SQL Server no Windows e Linux – Parte 1

Post 1/3. Este post é parte da série: Conhecendo o Processo do SQL Server

Apesar do seu enorme papel nas grandes corporações do mundo, o SQL Server, assim como todos os outros SGBDs, não é nada mais nada menos que apenas um processo do sistema operacional. Assim, conhecer os fundamentos de um processo, é essencial para ter sucesso na hora de lidar com o SQL Server.

Há uma série de informações que você pode coletar apenas usando ferramentas do sistema operacional. Sabendo manipular melhor o processo do SQL você consegue não somente ter um maior controle sobre suas instâncias, mas também ter mais cartas na manga para resolver um problema incomum, e até montar interessantes linhas de raciocínio.

Nesta série, iremos mostrar alguns conceitos e ferramentas úteis para o dia-a-dia de quem Administra instâncias SQL Server, não somente em ambiente Windows, mas em Linux, e até docker.

Processos e threads

Eu sempre digo em minhas apresentações que entender o que é uma Thread é essencial pra entender e dominar o SQL Server. Afinal, tudo se resumem a elas. 

Em simples palavras, uma Thread é sequência de instruções (isso, Assembly, nada de SQL ainda) e cada CPU pode executar uma única Thread por vez.

Um processo é uma espécie de “grupo” de Threads, grosseiramente falando. Os processos definem quais recursos suas threads tem acesso. Tais limites podem ser impostos por um usuário administrador, através de configuração, ou por características de hardware e/ou do sistema operacional.  Há uma série de informações que um processo contém.

Processos são isolados de outros processos. Isso significa que threads de um processo não conseguem acessar recursos, como memória, de outros processos da mesma maneira, que é simples, como fazem com seus próprios recursos. Você verá que isso explica muita coisa quando trabalha com múltiplas instâncias!

 

Para resumir:

  • Thread: É a coisa que, de fato, executa instruções em uma CPU. Há várias dessas coisas o tempo inteiro em um SO.
  • Processo: É como se fosse um “grupo” de threads. Um processo não executa código, mas contém, no mínimo, uma thread. Além disso, o processo contém uma série de outras informações que limitam os recursos que uma thread pode acessar.

Executável e Argumentos

Todo processo começa a partir de um arquivo binário, contendo as instruções que o processador deverá executar. No Windows, esse binário geralmente tem a extensão .exe, e no Linux sem uma extensão específica. Ele é gerado a partir de alguma linguagem de programação, como C++, que é o caso do SQL Server.

Iniciar um programa significa pedir ao sistema operacional que execute um arquivo binário como esse. Quando o sistema operacional é acionado para tal ação, ele cria um novo processo em sua lista de processos, e também cria a primeira thread desse processo e a aponta para a primeira instrução que se encontra no arquivo binário. A partir daí, a thread seguirá seu fluxo de execução, realizando as mais variadas operações que foram codificadas, como abrir arquivos, receber conexões, processar texto,  fazer cálculos e até criar novas threads.

Todo executável pode receber um ou mais parâmetros, que são strings passadas por quem o iniciou. A sintaxe é:

NomeExecutavel Parametro1 Parametro2 “Parametro 3, com espacos”

O SQL Server contém uma série de parâmetros documentados e não documentados. Quem determina quais parâmetros um executável irá receber é quem o desenvolveu. Uma correta documentação irá dizer quais os parâmetros existem, como devem ser especificados e o que eles causam na execução daquele software.

No caso do SQL server, existem diversos, e os seguintes são bem conhecidos:

Parâmetro Descrição
-e Caminho para o arquivo de error log
-l Caminho para o arquivo de log do banco master
-d Caminho para o arquivo de dados do banco master
-s Nome da instância

Você pode consultar uma lista de parâmetros que o executável do SQL Server aceita neste endereço.

Você pode observar o executável usado para iniciar um processo, e seus argumentos, usando ferramentas como Gerenciador de Tarefas ou o Process Explorer:

Executável e argumentos do processo do sql server no Gerenciador de Tarefas

 

Executável e parâmetros do processo do SQL no Process Explorer

Já com powershell, uma das maneiras, é com os seguintes comandos:

Você verá um resultado como este:

 

Por hoje é só pessoal. No próximo post, veremos mais alguns conceitos e fonte de informações úteis! Até lá

Exercícios para fixar:

  • Baixe o process explorer e tente ver os argumentos dos vários processo que existem em execução
  • Use o Gerenciador de Tarefas para observar as mesmas informações:
    • Vá na aba “Detalhes”
    • Clique com o botão direito no cabeçalho da tabela
    • Escolha “Selecionar Colunas”
    • Procure na lista e marque a opção “Linha de Comando” 
    • Aproveite e explore as outras colunas que existem
  • Abra novos programas, e observe a linha de comando executada
  • Powershell: Explore o cmdlet Get-Process e o comando Get-WmiObject Win32_Process
  • PERGUNTA DE PROVA: O que acontece quando você usa xp_cmdshell?

Kernel Mode vs User Mode

Aprofundar o conhecimento em um software, requer entender muitas características do sistema operacional. No caso de SO’s como o Windows, é comum, em cursos avançados ouvir as expressões “Kernel Mode” e “User Mode”. Com o intuito de fazer um rápido esclarecimento sobre o que significam estes nomes, eu preparei este post.

Certas áreas de memória contém dados vitais para o correto funcionamento do Windows. Por exemplo, imagine que no endereço  0xFFFF0000, o Windows guardasse a quantidade total de memória livre para alocação. Ora, se uma thread qualquer  altera esse valor, o Windows poderia achar que havia mais ou menos memória disponível para alocação. Isso traria instabilidade e incosistência para todo o sistema operacional, e, consequentemente, todos os processos em execução.

Para se prevenir deste tipo de caso, e outros, o Windows fornece privilégios que permitem ou impedem que uma thread acesse um determinado recurso, como certos endereços de memória. Na verdade, isso é possível graças ao processador: Nos primeiros momentos do boot, ele está livre e sem restrições, então o sistema operacional interage com ele e registra uma série de rotinas e códigos necessários para serem executados quando certos eventos ocorrem durante as execuções das instruções. Alguns destes eventos são disparados justamente quando uma thread necessita acessar algum recurso protegido. Diante disso, o processador irá executar o código que o sistema operacional registrou e o mesmo irá tratar de forma adequada o acesso. No exemplo acima, ao acessar o endereço de memória crítico, o Windows irá impedir a ação de ser executada e gerar um erro para a thread que tentou fazer o acesso.

Mas não é todo momento que uma thread deve ser impedida de acessar recursos críticos. Por exemplo, ao realizar um leitura de arquivo, a thread necessita chamar a função “ReadFile”, da API do Windows. Essa função vai executar um código que requer o acesso a estruturas protegidas pelo sistema operacional. Neste caso, se houver o impedimento por parte do sistema operacinal, a thread não irá conseguir efetuar a leitura do arquivo.

Para resolver isso, o Windows define dois modos de operação das threads:

  • User Mode
    O User Mode é o modo de operação em que as threads executam na maior parte do tempo. Neste modo, a thread não pode acessar recursos vitais para o funcionamento do sistema, como certos endereços de memória e registradores. Para acessar, é necessário entrar no “Kernel Mode”.
  • Kernel Mode
    Este é o modo sob o qual as threads que executam o código do sistema operam, já que o mesmo referencia estruturas internas para completar os serviços oferecidos. A API do Windows contém funções que executam instruções que fazem com que o sistema entre neste modo. Um leitor curioso, pode então, concluir que seria fácil burlar as proteções do Kernel Mode, bastando apenas executar esta instruções que ativam o Kernel Mode. Bom, não é bem assim.

Transição User Mode – Kernel Mode

Quando a thread executa a instrução que faz o modo de operação mudar para Kernel Mode, o processador interrompe a execução da mesma e passa o controle para umas dessas rotinas que o Windows registrou lá no boot. Isso significa, que graças ao suporte que o processador oferece, a thread passa a rodar um código confiável pelo Windows, isto é, que faz parte do kernel. Dessa maneira, ela deixa de executar o seu código original, e passa a executar um código específico para tratar este evento gerado pelo processador. O nome da instrução que solicita essa transição depende da arquitetura e família do processador. No caso de processadores Intel x64, o nome da instrução é syscall (Fonte: Intel® 64 and IA-32 Architectures, Página 1788). Esse processo tambem é conhecido como “uso dos serviços do sistema operacional”, pois é assim que um processo consegue interagir com as centenas de rotinas (os chamados “serviços”) que provê alguma funcionalidade do Windows (como ler arquivos, criar processos, transferir dados via rede, etc.).

Mesmo que o usuário utilizasse a instrução syscall em seu código diretamente, o código do sistema tomaria o controle da execução e impediria o usuário de realizar qualquer modificação que não fosse por parte de um código criado pelos desenvolvedores do Windows.

É comum observar nas literaturas a respeito da arquitetura do Windows, o fato de que a API do Windows possui uma parte User Mode e uma parte Kernel Mode. Utilizar a instrução syscall diretamente seria chato e complexo para os desenvolvedores. Ao realizar a transição para Kernel Mode, é necessário informar uma série de parâmetros (via registradores da CPU), que o código do Windows irá validar para determinar o que deverá ser feito a partir dali. Ao invés do desenvolvedor ter que decorar as centenas de códigos que são definidos, o Windows disponibiliza uma série de funções em DLLs como “kernel32.dll” e “user32.dll”. Essa funções são responsáveis por preparar os parâmetros e executar a instrução “syscall”.  Então, por isso, até que a instrução “syscall” seja executada, o código da DLL que faz parte do Windows, ainda estava rodando em User Mode, isto é, se houvesse uma tentativa de acessar um recurso protegido nesse momento, haveria uma falha (o que seria um bug no sistema operacional, já que a DLL faz parte do Windows). Por exemplo, a função ReadFile é definida na DLL “Kernel32.dll” (Fonte: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365467%28v=vs.85%29.aspx). Essa é a função que deve ser usada sempre que um processo necessita ler um arquivo (ou uma de suas variações, como ReadFileEx). O SQL Server faz uso dessa função para ler o conteúdo dos arquivos de dados e log. Ao iniciar a sua execução, a função irá realizar todas as validações necessárias e irá executar outras funções que estão defindias em outras DLLs do Windows. E são essas funções que irão preparar e executar a instrução syscall.

Transição Kernel Mode – User Mode

Depois que o código do sistema operacional termina seu trabalho, é necessário retomar a execução do código original, isto é, o codigo que causou a transição para Kernel Mode. Mas antes, é necessário voltar ao User Mode, caso contrário, toda o esquema de proteção feito até aqui seria inútil.  Assim como existem instruções para entrar em Kernel Mode, existem para sair. De novo, o nome vai depender da família e arquitetura do processador. No caso de x64 , a instrução é a sysret ( Fonte: Intel® 64 and IA-32 Architectures, Página 1796  ). Quando o código do sistema operacional termina de fazer o que lhe foi solicitado, então ele executa a instrução sysret, saindo do Kernel Mode e retomando a execução do código após o syscall que causou a transição para Kernel Mode.

Mais alguns comentários…

 

Antes de encerrar, é importante fortalecer alguns pontos.

  1. Tudo isso foi um resumo do resumo da resenha do rascunho do que é realmente o Kernel Mode e o User Mode, e como ocorre toda essas transições. Se você quer se aprofundar no assunto, pode usar a referência que deixei no final do artigo (e, se ainda não o fez, aproveita para estudar C++ e Assembly, pois vai facilitar o entendimento de muita coisa).
  2. User Mode e Kernel Mode não são threads ou processos diferentes. Uma thread pode em um determinado momento estar em User Mode, e um outro determinado momento em Kernel Mode. O que muda é que em Kernel Mode ela estara executando um código do sistema operacional ou driver. Isso indica que se a thread passa muito tempo em Kernel Mode, é uma grande chance de ser um problema de hardware, uso intenso de recursos do SO ou bug do sistema (este último com chances bem menores, mas não impossível).

    Vida da thread e modos de operação

  3. Algumas ferramentas, como o gerenciador de tarefas e o Process Explorer, permite que você monitore o uso de CPU em Kernel Mode. Por exemplo, você consegue determinar quanto de tempo foi gasto pelas threads executando em Kernel Mode.

    O gráfico em vermelho mostra o tempo gasto pela CPU executando instruções sob o modo Kernel Mode. Também, é possivel obter informações por processo. Na imagem, é possível observar o texto “Kernel Time” na janela da direita. Esta informação indica o tempo total gasto em Kernel Mode pelo processo. O mesmo vale pro “User Time”.

  4. O que tudo isso tem a ver com SQL Server? Não somente com SQL Server, mas com qualquer software que rode no Windows. Todos eles fazem uso constante de serviços do sistema. Assim, entender o que é o Kernel Mode é útil para determinar se um possível problema está no sistema operacional ou no software. A transição para Kernel Mode é algo muito custoso do ponto de vista de um processo. Envolve a execução de mais algumas centenas instruções, acesso a memória, recursos compartilhados, etc. O SQL Server foi desenvolvido para evitar ao máximo fazer transições de User Mode para Kernel Mode, para salvar a perfomance. É obvio que existem casos onde não é possivel evitar isso, como no momento em que é necessário ler ou escrever dos arquivos. Mas é sempre bom estar de olho nas métricas relativo ao uso dos recursos em Kernel Mode.

 

Referências: