L'utilizzo della CPU influisce sul costo dell'accesso NUMA esterno?


21

Scenario

Supponiamo che io abbia un SQL Server con 4 socket con ogni 1 nodo NUMA. Ogni socket ha 4 core fisici. La memoria totale è di 512 GB, quindi ogni nodo NUMA ha 128 GB di RAM.

Una tabella di chiavi viene caricata nel primo nodo NUMA.

Domanda

Supponiamo di leggere molto traffico da quella tabella. Se tutti i core fisici del socket che possiede il nodo NUMA hanno un utilizzo della CPU del 100 percento, ciò influisce negativamente sul costo dell'accesso NUMA non locale proveniente da altri socket? O d'altra parte, il costo dell'accesso NUMA non locale è indifferente da quanto è occupato quel socket?

Spero che la mia domanda abbia un senso. Per favore fatemi sapere se non lo farò cercherò di chiarire.

sfondo

La settimana scorsa abbiamo riscontrato un problema con il database nel nostro server di produzione e alcune delle nostre attività elaborate sono risultate più colpite di altre. Abbiamo ricevuto query con poche letture logiche che richiedevano più di 1 minuto. Abbiamo esaminato l'utilizzo complessivo della CPU che era di circa il 60 percento. Non abbiamo esaminato le metriche CPU specifiche del socket. Le metriche I / O erano nella media.


Se riesci a produrre qualcosa come Kin ha detto, sarà utile. Inoltre, a cosa hai impostato MAXDOP?
user41207,

Risposte:


18

Una domanda importante :-) Descriverò alcuni dei fattori coinvolti. In ogni dato contesto, questi fattori e altri possono variare e produrre un risultato interessante.

Spiacente, non sono riuscito a rendere questo molto più breve ...

  1. CPU accumulata ms vs IO logico
  2. Allineamento dei nodi della memoria logica di SQL Server con nodi NUMA fisici
  3. Contesa Spinlock nell'allocazione della memoria dell'area di lavoro della query
  4. Assegnazione delle attività agli scheduler
  5. Posizionamento dei dati rilevanti nel pool di buffer
  6. Posizionamento della memoria fisica

  1. CPU accumulata ms vs IO logico

    Uso molto spesso grafici di IO logico (o nella terminologia perfmon "ricerche di pagine buffer pool") rispetto all'utilizzo della CPU, al fine di valutare l'efficienza della CPU dei carichi di lavoro e cercare casi inclini agli spinlock.

    Ma SQL Server accumula tempo della CPU con molte altre attività oltre alle ricerche di pagina e agli spinlock:

    • I piani vengono compilati e ricompilati.
    • Il codice CLR viene eseguito.
    • Le funzioni vengono eseguite.

    Molte altre attività masticheranno un significativo tempo di CPU senza essere riflesse nelle ricerche di pagina.

    Nei carichi di lavoro che osservo, il principale tra queste attività "non logiche di I / O intensivo ma inghiottendo la CPU" è l'attività di ordinamento / hashing.

    È logico: considera un esempio inventato di due query su una tabella hash senza indici non cluster. Le due query hanno set di risultati identici, ma uno dei set di risultati è completamente non ordinato e il secondo set di risultati è ordinato da più di una delle colonne selezionate. La seconda query dovrebbe richiedere più tempo CPU, anche se farebbe riferimento allo stesso numero di pagine nel pool di buffer.

    Ulteriori informazioni sulla memoria dell'area di lavoro e su quanto dell'area di lavoro concessa è stata utilizzata, in questi post:


  1. Allineamento dei nodi della memoria logica di SQL Server con nodi NUMA fisici

    SQL Server (poiché incorpora le sue strategie compatibili con NUMA) per impostazione predefinita crea un nodo di memoria SQLOS per ciascun nodo NUMA sul server. Man mano che le allocazioni di memoria aumentano, ogni allocazione è controllata da uno dei nodi di memoria SQLOS.

    Idealmente, i nodi di memoria SQLOS sono completamente allineati con i nodi NUMA fisici. Vale a dire, ogni nodo di memoria SQLOS contiene memoria da un singolo nodo NUMA, senza che nessun altro nodo di memoria SQLOS contenga memoria dello stesso nodo NUMA.

    Tuttavia, quella situazione ideale non è sempre il caso.

    Il seguente post sul blog CSS SQL Engineers Engineers (incluso anche nella risposta di Kin) illustra in dettaglio il comportamento che può portare a persistenti allocazioni di memoria tra i nodi NUMA per i nodi di memoria SQLOS. Quando ciò accade, l'impatto sulle prestazioni può essere devastante.

    Ci sono state alcune correzioni per il caso particolarmente doloroso di riferimento persistente tra nodi NUMA incrociati. Probabilmente anche altri oltre a questi due:


  1. Contesa di spinlock durante l'allocazione della memoria dell'area di lavoro

    È qui che inizia a divertirsi. Ho già descritto che il lavoro di ordinamento e hash nella memoria dell'area di lavoro consuma CPU ma non si riflette nei numeri di ricerca di bpool.

    La contesa con Spinlock è un altro livello di questo particolare divertimento. Quando la memoria viene rubata dal pool di buffer e allocata per l'uso contro una concessione di memoria di query, l'accesso alla memoria viene serializzato con uno spinlock. Per impostazione predefinita, ciò avviene con una risorsa partizionata a livello di nodo NUMA. Pertanto, ogni query sullo stesso nodo NUMA che utilizza la memoria dell'area di lavoro può potenzialmente presentare contese di spinlock quando si ruba la memoria contro le sovvenzioni. Molto importante da notare: questo non è il rischio di contesa "una volta per query", come sarebbe se il punto di contesa fosse al momento della concessione effettiva. Piuttosto, è quando la memoria viene rubata contro la concessione - quindi una query con una concessione di memoria molto grande avrà molte opportunità di contesa con spinlock se utilizza la maggior parte della sua concessione.

    Il flag di traccia 8048 fa un ottimo lavoro per alleviare questa contesa partizionando ulteriormente la risorsa a livello centrale.

    Microsoft dice "considera il flag di traccia 8048 se 8 o più core per socket". Ma ... non è davvero quanti core per socket (purché ce ne siano più), ma piuttosto quante opportunità di contesa nel lavoro svolto su un singolo nodo NUMA.

    Sui processori AMD incollati (12 core per socket, 2 nodi NUMA per socket) c'erano 6 core per nodo NUMA. Ho visto un sistema con 4 di quelle CPU (quindi otto nodi NUMA, 6 core ciascuno) che è stato bloccato in un convoglio spinlock fino a quando non è stato abilitato il flag di traccia 8048.

    Ho visto questa contesa di spinlock ridurre le prestazioni su VM fino a 4 vCPU. Il flag di traccia 8048 ha fatto ciò che doveva quando abilitato su quei sistemi.

    Considerando che ci sono ancora 4 CPU ottimizzate per la frequenza core là fuori, con il giusto carico di lavoro, trarrebbero beneficio anche dal flag di traccia 8048.

    Le attese di CMEMTHREAD accompagnano il tipo di contesa di spinlock che allevia il flag di traccia 8048. Ma un avvertimento: le attese di CMEMTHREAD sono un sintomo corroborante, non la causa principale di questo particolare problema. Ho visto sistemi con "wait start" CMEMTHREAD elevati in cui il flag di traccia 8048 e / o 9024 sono stati ritardati nella distribuzione perché il tempo di attesa CMEMTHREAD accumulato era piuttosto basso. Con gli spinlock, il tempo di attesa accumulato è di solito la cosa sbagliata da guardare. Piuttosto, si desidera esaminare il tempo sprecato della CPU, rappresentato principalmente dagli stessi giri, secondariamente dalle attese associate che rappresentano interruttori di contesto potenzialmente non necessari.


  1. Assegnazione delle attività agli scheduler

    Sui sistemi NUMA, le connessioni sono distribuite ai nodi NUMA (bene - in realtà ai gruppi di scheduler SQLOS associati a loro) round-robin, supponendo che non vi siano punti finali di connessione associati a determinati nodi NUMA. Se una sessione esegue una query parallela, esiste una forte preferenza a utilizzare i lavoratori da un singolo nodo NUMA. Hmmm ... considera un server nodo NUMA 4 con una query complessa suddivisa in 4 percorsi e 0 MAXDOP predefinito. Anche se la query utilizzava solo thread di lavoro MAXDOP, vi sarebbero 4 thread di lavoro per ogni CPU logica sul nodo NUMA. Ma ci sono 4 percorsi nel piano complesso - quindi ogni CPU logica sul nodo NUMA potrebbe avere 16 lavoratori su di essa - tutto per una singola query!

    Questo è il motivo per cui a volte vedrai un nodo NUMA lavorare sodo mentre altri stanno pagando.

    Ci sono alcune altre sfumature nell'assegnazione dei compiti. Ma l'aspetto principale è che la CPU occupata non sarà necessariamente distribuita uniformemente sui nodi NUMA. (Bene anche per rendersi conto che gli inserimenti di pagine di bpool (letture o scritture di prima pagina) andranno nel bpool nel nodo di memoria SQLOS associato allo scheduler su cui si trova il lavoratore. E le pagine rubate provengono preferibilmente dalla memoria SQLOS "locale" anche nodo.

    Ho scoperto che è utile portare maxdop da 0 a non più di 8. A seconda del profilo del carico di lavoro (principalmente per quanto riguarda il numero di query potenzialmente previste con esecuzione prolungata), è possibile arrivare fino a MAXDOP = 2.

    Anche la regolazione della soglia di costo per il parallelismo può essere utile. I sistemi su cui lavoro tendono ad essere consumati con query ad alto costo e raramente incontrano un piano inferiore a 50 o 100, quindi ho avuto più trazione regolando maxdop (oten a livello di gruppo di carico di lavoro) che regolando la soglia di costo.


  1. Rilevante posizionamento dei dati nel pool

    Questa è la condizione che ritengo più intuitiva quando si tratta di server NUMA. Inoltre, in genere, non è estremamente significativo per le prestazioni del carico di lavoro.

    Cosa succede se la tabella viene letta nel bpool sul nodo NUMA 3 e successivamente una query sul nodo NUMA 4 esegue la scansione della tabella eseguendo tutte le ricerche del bpool sui nodi NUMA?

    Linchi Shea ha un ottimo post su questo impatto sulle prestazioni:

    L'accesso alla memoria attraverso i nodi NUMA comporta una piccola quantità di latenza di memoria aggiuntiva. Sono sicuro che ci sono alcuni carichi di lavoro che devono eliminare quella latenza di memoria di base aggiuntiva per prestazioni ottimali - non è stato un problema con i sistemi con cui lavoro.

    Ma - l'accesso cross-node porta anche un altro punto di trasferimento che può potenzialmente saturare. Se c'è così tanta attività che la larghezza di banda di memoria tra i nodi NUMA è satura, la latenza della memoria tra i nodi aumenterà. Lo stesso lavoro richiederà ulteriori cicli della CPU.

    Ancora una volta: sono sicuro che ci sono carichi di lavoro tali che la larghezza di banda della memoria è una considerazione fondamentale. Per i miei sistemi, tuttavia, le altre considerazioni che sto elencando sono state più significative.


  1. Posizionamento della memoria fisica

    Questo è raro ma quando conta, conta davvero. Sulla maggior parte dei server, l'installazione della memoria si bilancerà quasi naturalmente tra i nodi NUMA. Ma in alcuni casi, è necessaria un'attenzione speciale per bilanciare la memoria tra i nodi. Le prestazioni in alcuni sistemi possono essere completamente eliminate se la memoria è stata inserita in modo da non essere bilanciata. Questo è impostato-e-dimenticatelo, però. Abbastanza raro scoprire un problema come questo dopo mesi di servizio di produzione anziché dopo la prima giornata davvero impegnativa :-)


LA GRANDE FINITURA!

Qualcun altro ha sottolineato che la scelta sbagliata del piano, forse a causa di statistiche obsolete, potrebbe causare i sintomi che hai visto. Non è stato il caso della mia esperienza. I piani inadeguati possono facilmente far sì che una query impieghi più tempo del previsto, ma di solito perché vengono eseguiti più IO logici del necessario. O a causa della fuoriuscita in tempdb. Quando si osserva il server, dovrebbe essere evidente un massiccio sversamento su tempdb e piuttosto che una CPU elevata ci si aspetterebbe un tempo di attesa misurabile per le scritture del disco relative allo sversamento.

Invece, se la situazione che hai osservato è correlata alla NUMA, mi aspetto che sia una combinazione dei fattori sopra elencati, principalmente:

  1. utilizzo della memoria dell'area di lavoro (che non verrà visualizzata nei conteggi logici di I / O)

  2. che può essere nodo cross-NUMA a causa di condizioni persistenti di memoria esterna (in questo caso, cercare le correzioni pertinenti)

  3. e che può comportare contese di spinlock all'interno del nodo NUMA ogni volta che viene effettuata un'allocazione a fronte di una sovvenzione (correzione con T8048)

  4. e può essere eseguito da lavoratori su CPU logiche sovraccaricate da altri operatori di query parallele (regolare maxdop e / o la soglia di costo del parallelismo, se necessario)


7

( aggiorna la tua domanda con l' coreinfo -voutput (un'utilità sysinternal) per ottenere un contesto migliore della tua CPU / socket e distribuzione NUMA )

Abbiamo esaminato l'utilizzo complessivo della CPU che era di circa il 60 percento. Non abbiamo esaminato le metriche CPU specifiche del socket. Le metriche I / O erano nella media.

Mi sembra che tu stia abbaiando all'albero sbagliato. SQL Server è a NUMAconoscenza. Vi è una penalità molto più bassa per l'accesso incrociato alla memoria NUMA . Puoi anche usare questa query per vedere quanti NUMAnodi hai e a quale CPU e core sono assegnati a quali NUMA:

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

O solo quanti NUMA:

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

Abbiamo ricevuto query con poche letture logiche che richiedevano più di 1 minuto.

Ciò si verifica in genere quando si generano piani di query non validi a causa di statistiche obsolete. Assicurati di avere aggiornato le tue statistiche e che gli indici siano deframmentati correttamente .

Inoltre, è necessario impostare MAXDOP su un valore più ragionevole per evitare la fame nel thread di lavoro .

Imposta il cost threshold of parallelismvalore predefinito di 5 su un buon valore iniziale come 45, quindi monitora quel valore e regolalo secondo l'ambiente.

Se stai eseguendo molte query ad hoc, attiva (impostato su 1) optimize for ad hoc workloadsper impedire il gonfiore della cache del piano.

Utilizzare con cautela: è possibile utilizzare T8048 se si esegue SQL Server 2008/2008 R2 su macchine più recenti con più di 8 CPU presentate per nodo NUMA e c'è un aggiornamento rapido se si è su SQL Server 2012 o 2014 .

Consiglio vivamente di iniziare a raccogliere le informazioni sulle statistiche di attesa sull'istanza del server di database.

Consultare: Come funziona: SQL Server (blocchi di memoria NUMA locali, esterni e esterni)


1

Puramente dal punto di vista hardware, la gestione della memoria principale dall'architettura Nehalem in poi è la gestione da parte di un controller di memoria integrato, questo è nella parte "Un-core" della matrice della CPU che è separata dalla parte su cui vivono i nuclei reali, poiché la memoria è effettivamente "cablata" a ciascuna CPU, l'accesso alla memoria esterna AFAIK avviene tramite l'interconnessione del percorso rapido (sempre da Nehalem in poi), pertanto direi che la saturazione del core della CPU su un nodo NUMA locale non dovrebbe influire sull'accesso remoto a quella memoria.

Questo link potrebbe essere utile:

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

Chris

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.