A utilização da CPU afeta o custo do acesso NUMA estrangeiro?

21

Cenário

Vamos supor que eu tenha um SQL Server com 4 soquetes com cada 1 nó NUMA. Cada soquete possui 4 núcleos físicos. Há 512 GB de memória total, portanto, cada nó NUMA possui 128 GB de RAM.

Uma tabela de chaves é carregada no primeiro nó NUMA.

Questão

Vamos supor que temos muito tráfego lendo dessa tabela. Se todos os núcleos físicos do soquete que possui o nó NUMA tiverem 100% de utilização da CPU, isso influencia negativamente o custo do acesso não local à NUMA proveniente de outros soquetes? Ou, por outro lado, o custo do acesso não local à NUMA é independente de quão ocupado esse soquete esteja?

Espero que minha pergunta faça sentido. Por favor, deixe-me saber se não, vou tentar esclarecer.

fundo

Tivemos um problema de banco de dados em nosso servidor de produção na semana passada e alguns de nossos negócios processados ​​pareciam mais impactados que outros. Tivemos consultas com poucas leituras lógicas levando mais de um minuto. Analisamos a utilização geral da CPU, que era de cerca de 60%. Não analisamos as métricas de CPU específicas do soquete. As métricas de E / S eram médias.

xav
fonte
Se você pode produzir algo como Kin mencionou, será útil. Além disso, em que você configurou o MAXDOP?
user41207

Respostas:

18

Uma pergunta pesada :-) Vou descrever alguns dos fatores envolvidos. Em qualquer contexto, esses fatores e outros podem variar e produzir um resultado interessante.

Desculpe, eu não fui capaz de fazer isso muito mais curto ...

  1. CPU acumulada ms vs IO lógico
  2. Alinhamento do nó de memória lógica do SQL Server com os nós NUMA físicos
  3. Contenção de spinlock na alocação de memória da área de trabalho da consulta
  4. Designação de Tarefa para Agendadores
  5. Colocação de dados relevantes no buffer pool
  6. Posicionamento da memória física

  1. CPU acumulada ms vs IO lógico

    Uso gráficos de E / S lógica (ou na terminologia perfmon "pesquisas de páginas do buffer pool") contra a utilização da CPU com frequência, para avaliar a eficiência da CPU de cargas de trabalho e procurar casos propensos a spinlock.

    Mas o SQL Server acumula tempo de CPU com muita atividade além de pesquisas de página e spinlocks:

    • Os planos são compilados e recompilados.
    • O código CLR é executado.
    • Funções são executadas.

    Muitas outras atividades reduzirão o tempo significativo da CPU sem serem refletidas nas pesquisas da página.

    Nas cargas de trabalho que observo, a principal dessas atividades "intensivas de IO não lógicas, mas devoradoras de CPU" é a atividade de classificação / hash.

    É lógico: considere um exemplo artificial de duas consultas em uma hashtable sem índices não clusterizados. As duas consultas têm conjuntos de resultados idênticos, mas um deles é completamente desordenado e o segundo é ordenado por mais de uma das colunas selecionadas. Espera-se que a segunda consulta consuma mais tempo da CPU, mesmo que faça referência ao mesmo número de páginas no buffer pool.

    Mais sobre a memória do espaço de trabalho e quanto do espaço de trabalho concedido foi usado nessas postagens:


  1. Alinhamento do nó de memória lógica do SQL Server com os nós NUMA físicos

    O SQL Server (desde que incorporou suas estratégias compatíveis com NUMA) por padrão cria um nó de memória SQLOS para cada nó NUMA no servidor. À medida que as alocações de memória aumentam, cada alocação é controlada por um dos nós de memória do SQLOS.

    Idealmente, os nós de memória SQLOS estão completamente alinhados com os nós NUMA físicos. Ou seja, cada nó de memória SQLOS contém memória de um único nó NUMA, com nenhum outro nó de memória SQLOS também contendo memória desse mesmo nó NUMA.

    No entanto, essa situação ideal nem sempre é o caso.

    A seguinte postagem no blog dos CSS SQL Server Engineers (também incluída na resposta do Kin) detalha o comportamento que pode levar a persistentes alocações de memória entre nós NUMA para os nós de memória SQLOS. Quando isso acontece, o impacto no desempenho pode ser devastador.

    Houve algumas correções para o caso particularmente doloroso de referência persistente de nó entre NUMA. Provavelmente outros além desses dois também:


  1. Contenção de spinlock durante a alocação de memória da área de trabalho

    É aqui que começa a se divertir. Eu já descrevi que o trabalho de classificação e hash na memória da área de trabalho consome CPU, mas não é refletido nos números de pesquisa de bpool.

    A contenção de Spinlock é outra camada dessa diversão em particular. Quando a memória é roubada do conjunto de buffers e alocada para uso em uma concessão de memória de consulta, o acesso à memória é serializado com um spinlock. Por padrão, isso ocorre com um recurso particionado no nível do nó NUMA. Portanto, toda consulta no mesmo nó NUMA que usa memória da área de trabalho pode enfrentar contenção de spinlock ao roubar memória contra concessões. É muito importante observar: esse não é o risco de contenção "uma vez por consulta", como seria se o ponto de contenção estivesse no momento da concessão real. Em vez disso, é quando a memória é roubada contra a concessão - portanto, uma consulta com uma concessão de memória muito grande terá muitas oportunidades para contenção de spinlock se ela usar a maior parte de sua concessão.

    O sinalizador de rastreamento 8048 faz um ótimo trabalho para aliviar essa contenção particionando ainda mais o recurso no nível principal.

    A Microsoft diz "considere o sinalizador de rastreamento 8048 se 8 ou mais núcleos por soquete". Mas ... não é realmente quantos núcleos por soquete (contanto que haja vários), mas sim quantas oportunidades de contenção no trabalho que está sendo feito em um único nó NUMA.

    Nos processadores AMD colados (12 núcleos por soquete, 2 nós NUMA por soquete), havia 6 núcleos por nó NUMA. Eu vi um sistema com 4 dessas CPUs (então oito nós NUMA, 6 núcleos cada) que estavam atolados no comboio de spinlock até o sinalizador de rastreamento 8048 ser ativado.

    Eu já vi essa contenção de spinlock diminuir o desempenho em VMs tão pequenas quanto 4 vCPUs. O sinalizador de rastreamento 8048 fez o que deveria quando ativado nesses sistemas.

    Considerando que ainda existem algumas CPUs otimizadas para frequência de 4 núcleos por aí, com a carga de trabalho correta, elas também se beneficiariam do sinalizador de rastreamento 8048.

    As esperas do CMEMTHREAD acompanham o tipo de contenção de spinlock que o sinalizador de rastreamento 8048 alivia. Mas uma palavra de cautela: as esperas do CMEMTHREAD são um sintoma corroborado, não a causa raiz desse problema em particular. Vi sistemas com alto "CMEMTHREAD" espera começa, onde o sinalizador de rastreamento 8048 e / ou 9024 foi atrasado na implantação porque o tempo de espera acumulado do CMEMTHREAD era bastante baixo. Com spinlocks, o tempo de espera acumulado geralmente é a coisa errada a se considerar. Em vez disso, você deseja examinar o tempo desperdiçado da CPU - representado principalmente pelas próprias rotações, secundariamente pelas esperas associadas, que representam opções de contexto potencialmente desnecessárias.


  1. Designação de Tarefa para Agendadores

    Nos sistemas NUMA, as conexões são distribuídas para nós NUMA (bem - na verdade, para os grupos de agendadores SQLOS associados a eles) round-robin, assumindo que não haja pontos finais de conexão associados a nós NUMA específicos. Se uma sessão executar uma consulta paralela, há uma forte preferência pelo uso de trabalhadores de um único nó NUMA. Hmmm ... considere um servidor de 4 nós NUMA com uma consulta complexa dividida em 4 caminhos e o padrão 0 MAXDOP. Mesmo se a consulta usasse apenas threads de trabalho MAXDOP, haveria 4 threads de trabalho para cada CPU lógica no nó NUMA. Mas existem 4 caminhos no plano complexo - portanto, cada CPU lógica no nó NUMA pode ter 16 trabalhadores - todos para uma única consulta!

    É por isso que às vezes você vê um nó NUMA trabalhando duro enquanto outros estão vagando.

    Existem algumas outras nuances na atribuição de tarefas. Mas o principal argumento é que a CPU ocupada não será necessariamente distribuída igualmente entre os nós da NUMA. (Também é bom perceber que as inserções de página de pool (leituras ou gravações na primeira página) entrarão no pool no nó de memória SQLOS associado ao agendador em que o trabalhador está. E as páginas roubadas virão preferencialmente da memória "local" do SQLOS nó também.

    Descobri que trazer o maxdop de 0 a não mais que 8 é útil. Dependendo do perfil da carga de trabalho (principalmente no número de consultas simultâneas esperadas potencialmente de longa duração), pode ser necessário ir até MAXDOP = 2.

    Ajustar o limite de custo para o paralelismo também pode ser útil. Os sistemas em que trabalho tendem a ser consumidos com consultas de alto custo e raramente encontram um plano abaixo de 50 ou 100; portanto, tive mais tração ajustando o maxdop (geralmente no nível do grupo de carga de trabalho) do que o limite de custo.


  1. Posicionamento de dados relevantes no bpool

    Essa é a condição que eu acho mais intuitiva ao lidar com servidores NUMA. Além disso, normalmente, não é extremamente significativo para o desempenho da carga de trabalho.

    O que acontece se a tabela for lida no bpool no nó NUMA 3 e, posteriormente, uma consulta no nó 4 do NUMA varre a tabela executando todas as pesquisas de bpool nos nós NUMA?

    Linchi Shea tem um ótimo post sobre esse impacto no desempenho:

    O acesso à memória através dos nós NUMA incorre em uma pequena quantidade de latência adicional na memória. Tenho certeza de que existem algumas cargas de trabalho que precisam eliminar a latência adicional da memória base para obter o desempenho ideal - isso não foi um problema nos sistemas com os quais trabalho.

    Mas o acesso entre nós também traz outro ponto de transferência que pode potencialmente saturar. Se houver tanta atividade que a largura de banda da memória entre os nós NUMA estiver saturada, a latência da memória entre os nós aumentará. O mesmo trabalho exigirá ciclos adicionais da CPU.

    Mais uma vez - tenho certeza de que existem cargas de trabalho que a largura de banda da memória é uma consideração crítica. Para meus sistemas, no entanto, as outras considerações que estou listando foram mais significativas.


  1. Posicionamento da memória física

    Este é raro, mas quando importa, realmente importa. Na maioria dos servidores, a instalação da memória é quase naturalmente equilibrada entre os nós NUMA. Mas, em alguns casos, é necessária atenção especial para equilibrar a memória entre os nós. O desempenho em alguns sistemas pode ser absolutamente prejudicado se a memória for entalhada de forma que não seja equilibrada. Isso é "faça e esqueça", no entanto. Muito raro descobrir um problema como esse após meses de serviço de produção, em vez de após o primeiro dia realmente ocupado :-)


O GRANDE ACABAMENTO!

Outra pessoa afirmou que a má escolha do plano, talvez devido a estatísticas desatualizadas, poderia resultar nos sintomas que você já viu. Esse não foi o caso na minha experiência. Planos ruins podem facilmente fazer com que uma consulta demore mais do que o esperado - mas geralmente porque mais IO lógicas do que o necessário estão sendo executadas. Ou devido a derramamento em tempdb. Derramamento massivo para tempdb deve ser evidente ao observar o servidor - e, em vez de CPU alta, seria de esperar um tempo de espera mensurável para as gravações em disco relacionadas ao derramamento.

Em vez disso, se a situação observada estiver relacionada ao NUMA, seria de esperar que fosse uma combinação dos fatores enumerados acima, principalmente:

  1. uso da memória da área de trabalho (que não será exibida nas contagens lógicas de E / S)

  2. que pode ser um nó NUMA cruzado devido a uma condição de memória externa persistente (se esse for o caso, procure correções relevantes)

  3. e que podem incorrer em contenção de spinlock no nó NUMA cada vez que uma alocação é feita contra uma concessão (correção com T8048)

  4. e pode ser executada por trabalhadores em CPUs lógicas sobrecarregadas por outros trabalhadores de consulta paralela (ajuste maxdop e / ou limite de custo do paralelismo, conforme necessário)

sql_handle
fonte
7

( atualize sua pergunta com coreinfo -va saída (um utilitário sysinternal) para obter um melhor contexto de sua CPU / soquetes e distribuição NUMA )

Analisamos a utilização geral da CPU, que era de cerca de 60%. Não analisamos as métricas de CPU específicas do soquete. As métricas de E / S eram médias.

Parece-me que você está latindo para a árvore errada. O SQL Server está NUMAciente. Há uma penalidade de desempenho muito menor ao realizar o acesso à memória NUMA cruzada . Você também pode usar esta consulta para ver quantos NUMAnós você possui e qual CPU e núcleos estão atribuídos a quaisNUMA :

SELECT parent_node_id, scheduler_id, cpu_id
FROM sys.dm_os_schedulers WITH (NOLOCK) 
WHERE [status] = N'VISIBLE ONLINE';

Ou quantas NUMA:

select COUNT(distinct Parent_node_id)
from sys.dm_os_schedulers
where [STATUS] = 'VISIBLE ONLINE'
    and Parent_node_ID < 64

Tivemos consultas com poucas leituras lógicas levando mais de um minuto.

Isso normalmente acontece quando você tem planos de consulta incorretos gerados devido a estatísticas desatualizadas. Certifique-se de ter seu estatísticas estão atualizadas e se os índices estão desfragmentados corretamente .

Além disso, você precisa definir MAXDOP para um valor mais sensível para evitar a inanição do encadeamento do trabalhador .

Defina seu cost threshold of parallelism valor padrão como 5 como um bom valor inicial, como 45, depois monitore esse valor e ajuste-o conforme o seu ambiente.

Se você estiver executando muitas consultas ad-hoc, ative (defina como 1) optimize for ad hoc workloads para evitar o inchaço do cache do plano.

Use com cuidado: você pode usar o T8048 se estiver executando o SQL Server 2008/2008 R2 em máquinas mais recentes com mais de 8 CPUs apresentadas por nó NUMA e houver um hotfix se estiver no SQL Server 2012 ou 2014 .

É altamente recomendável que você comece a coletar informações de estatísticas de espera sobre a instância do servidor de banco de dados.

Consulte: Como funciona: SQL Server (blocos de memória local, externa e externa NUMA)

Kin Shah
fonte
1

Puramente do ponto de vista de hardware, o gerenciamento da memória principal a partir da arquitetura Nehalem é gerenciado por um controlador de memória integrado; isso é na parte "Un-core" da matriz da CPU, que é separada da parte em que os núcleos reais vivem, Como a memória é efetivamente 'conectada' a cada CPU, o acesso à memória externa AFAIK é por meio da interconexão de caminho rápido (novamente a partir de Nehalem), eu diria que a saturação do núcleo da CPU em um nó NUMA local não deve afetar o acesso remoto a essa memória.

Você pode achar este link útil:

http://cs.nyu.edu/~lerner/spring10/projects/NUMA.pdf

Chris

Chris Adkin
fonte