¿La utilización de la CPU afecta el costo del acceso externo a NUMA?

21

Guión

Supongamos que tengo un servidor SQL con 4 sockets con cada 1 nodo NUMA. Cada zócalo tiene 4 núcleos físicos. Hay 512 GB de memoria en total, por lo que cada nodo NUMA tiene 128 GB de RAM.

Una tabla de claves se carga en el primer nodo NUMA.

Pregunta

Supongamos que tenemos mucha lectura de tráfico de esa tabla. Si todos los núcleos físicos del socket que posee el nodo NUMA tienen un 100% de utilización de la CPU, ¿eso influye negativamente en el costo del acceso NUMA no local proveniente de otros sockets? O, por otro lado, ¿el costo del acceso no local a NUMA es independiente de cuán ocupado esté ese socket?

Espero que mi pregunta tenga sentido. Avíseme si no es así, intentaré aclararlo.

Fondo

Tuvimos un problema de base de datos en nuestro servidor de producción la semana pasada y algunos de nuestros negocios procesados ​​parecían más afectados que otros. Tuvimos consultas con pocas lecturas lógicas que tomaron más de 1 minuto. Analizamos la utilización general de la CPU, que era de alrededor del 60 por ciento. No analizamos las métricas de CPU específicas del socket. Las métricas de E / S fueron promedio.

xav
fuente
Si puede producir algo como Kin ha mencionado, será útil. Además, ¿en qué has configurado MAXDOP?
user41207

Respuestas:

18

Una pregunta importante :-) Voy a describir algunos de los factores involucrados. En cualquier contexto dado, estos factores y otros pueden variar y producir un resultado interesante.

Lo siento, no pude hacer esto mucho más corto ...

  1. CPU acumulada ms vs IO lógico
  2. Alineación de nodos de memoria lógica de SQL Server con nodos NUMA físicos
  3. Contención de Spinlock en la asignación de memoria del espacio de trabajo de consulta
  4. Asignación de tareas a planificadores
  5. Colocación de datos relevantes en el grupo de búferes
  6. Colocación de memoria física

  1. CPU acumulada ms vs IO lógico

    Utilizo gráficos de E / S lógicas (o en la terminología de perfmon "búsquedas de páginas de agrupación de almacenamiento intermedio") contra la utilización de la CPU con mucha frecuencia, para medir la eficiencia de la CPU de las cargas de trabajo y buscar casos propensos al spinlock.

    Pero SQL Server acumula tiempo de CPU con mucha actividad además de búsquedas de páginas y spinlocks:

    • Los planes se compilan y se vuelven a compilar.
    • Se ejecuta el código CLR.
    • Se realizan funciones.

    Muchas otras actividades consumirán mucho tiempo de CPU sin verse reflejado en las búsquedas de la página.

    En las cargas de trabajo que observo, la principal de estas actividades "no lógicas intensivas de E / S pero engullendo la CPU" es la actividad de clasificación / hashing.

    Es lógico: considere un ejemplo artificial de dos consultas contra una tabla hash sin índices no agrupados. Las dos consultas tienen conjuntos de resultados idénticos, pero uno de los conjuntos de resultados está completamente desordenado y el segundo conjunto de resultados está ordenado por más de una de las columnas seleccionadas. Se espera que la segunda consulta consuma más tiempo de CPU, aunque haga referencia al mismo número de páginas en el grupo de búferes.

    Más información sobre la memoria del espacio de trabajo y la cantidad de espacio de trabajo otorgado que se ha utilizado en estas publicaciones:


  1. Alineación de nodos de memoria lógica de SQL Server con nodos NUMA físicos

    SQL Server (desde que incorpora sus estrategias compatibles con NUMA) por defecto crea un nodo de memoria SQLOS para cada nodo NUMA en el servidor. A medida que aumentan las asignaciones de memoria, cada asignación está controlada por uno de los nodos de memoria de SQLOS.

    Idealmente, los nodos de memoria SQLOS están completamente alineados con los nodos físicos NUMA. Es decir, cada nodo de memoria SQLOS contiene memoria de un solo nodo NUMA, y ningún otro nodo de memoria SQLOS también contiene memoria del mismo nodo NUMA.

    Sin embargo, esa situación ideal no siempre es el caso.

    La siguiente publicación de blog de CSS SQL Server Engineers (también incluida en la respuesta de Kin) detalla el comportamiento que puede conducir a la persistencia de asignaciones de memoria de nodo cruzado NUMA para los nodos de memoria SQLOS. Cuando esto sucede, el impacto en el rendimiento puede ser devastador.

    Ha habido algunas soluciones para el caso particularmente doloroso de referencia persistente de nodo cruzado NUMA. Probablemente otros además de estos dos, también:


  1. Contención de Spinlock durante la asignación de memoria de espacio de trabajo

    Aquí es donde comienza a divertirse. Ya he descrito que el trabajo de clasificación y hash en la memoria del espacio de trabajo consume CPU pero no se refleja en los números de búsqueda de bpool.

    La contención de Spinlock es otra capa para esta diversión particular. Cuando se roba memoria del grupo de búferes y se asigna para su uso contra una concesión de memoria de consulta, el acceso a la memoria se serializa con un spinlock. De forma predeterminada, esto tiene lugar con un recurso particionado en el nivel de nodo NUMA. Por lo tanto, cada consulta en el mismo nodo NUMA que usa la memoria del espacio de trabajo puede experimentar potencialmente una contención de spinlock al robar memoria contra concesiones. Muy importante tener en cuenta: esto no es un riesgo de contención "una vez por consulta", como lo sería si el punto de contención estuviera en el momento de la concesión real. Más bien, es cuando se roba la memoria contra la concesión, por lo que una consulta con una concesión de memoria muy grande tendrá muchas oportunidades para la contención de spinlock si utiliza la mayor parte de su concesión.

    La marca de seguimiento 8048 hace un gran trabajo aliviando esta disputa al dividir aún más el recurso en el nivel central.

    Microsoft dice "considere la marca de seguimiento 8048 si 8 o más núcleos por socket". Pero ... no es realmente cuántos núcleos por socket (siempre que sean múltiples), sino cuántas oportunidades de contención en el trabajo que se realiza en un solo nodo NUMA.

    En los procesadores AMD pegados (12 núcleos por zócalo, 2 nodos NUMA por zócalo) había 6 núcleos por nodo NUMA. Vi un sistema con 4 de esas CPU (por lo tanto, ocho nodos NUMA, 6 núcleos cada uno) que estaba atascado en un convoy de spinlock hasta que se habilitó el indicador de rastreo 8048.

    He visto que esta contención de spinlock reduce el rendimiento en máquinas virtuales tan pequeñas como 4 vCPU. El indicador de seguimiento 8048 hizo lo que se suponía que debía hacer cuando estaba habilitado en esos sistemas.

    Teniendo en cuenta que todavía hay algunas CPU de 4 núcleos optimizadas en frecuencia, con la carga de trabajo correcta, también se beneficiarían de la marca de seguimiento 8048.

    Las esperas de CMEMTHREAD acompañan el tipo de contención de spinlock que traza la bandera 8048 alivia. Pero una advertencia: las esperas de CMEMTHREAD son un síntoma corroborante, no la causa principal de este problema en particular. He visto sistemas con un alto "inicio de espera" de CMEMTHREAD donde el indicador de traza 8048 y / o 9024 se retrasaron en la implementación porque el tiempo de espera acumulado de CMEMTHREAD era bastante bajo. Con los spinlocks, el tiempo de espera acumulado suele ser algo incorrecto a la vista. Por el contrario, desea ver el tiempo perdido de la CPU, representado principalmente por los propios giros, en segundo lugar por las esperas asociadas que representan cambios de contexto potencialmente innecesarios.


  1. Asignación de tareas a planificadores

    En los sistemas NUMA, las conexiones se distribuyen a los nodos NUMA (bueno, en realidad a los grupos del planificador de SQLOS asociados con ellos) round-robin, suponiendo que no haya puntos finales de conexión asociados con nodos NUMA particulares. Si una sesión ejecuta una consulta paralela, existe una fuerte preferencia por utilizar trabajadores de un solo nodo NUMA. Hmmm ... considere un servidor de 4 nodos NUMA con una consulta compleja dividida en 4 rutas, y por defecto 0 MAXDOP. Incluso si la consulta utilizara solo subprocesos de trabajo MAXDOP, habría 4 subprocesos de trabajo para cada CPU lógica en el nodo NUMA. Pero hay 4 rutas en el plan complejo, por lo que cada CPU lógica en el nodo NUMA podría tener 16 trabajadores, ¡todo para una sola consulta!

    Es por eso que a veces verá que un nodo NUMA trabaja duro mientras que otros están holgazaneando.

    Hay algunos otros matices para la asignación de tareas. Pero la conclusión principal es que la CPU ocupada no necesariamente se distribuirá uniformemente entre los nodos NUMA. (También es bueno darse cuenta de que las inserciones de página de bpool (lecturas o escrituras de la primera página) irán a la agrupación en el nodo de memoria SQLOS asociado con el planificador en el que está el trabajador. Y las páginas robadas provendrán preferentemente de la memoria SQLOS "local" nodo, también.

    Descubrí que es útil llevar maxdop de 0 a no más de 8. Dependiendo del perfil de carga de trabajo (principalmente en función de la cantidad de consultas simultáneas esperadas potencialmente de larga duración), puede justificarse llegar a MAXDOP = 2.

    Ajustar el umbral de costo para el paralelismo también puede ser útil. Los sistemas en los que trabajo tienden a consumirse con consultas de alto costo y rara vez se encuentran con un plan por debajo de 50 o 100, por lo que he tenido más tracción ajustando maxdop (a menudo a nivel de grupo de carga de trabajo) que ajustando el umbral de costo.


  1. Colocación de datos relevantes en el bpool

    Esta es la condición que creo que es más intuitiva cuando se trata de servidores NUMA. Tampoco suele ser extremadamente significativo para el rendimiento de la carga de trabajo.

    ¿Qué sucede si la tabla se lee en la agrupación en el nodo NUMA 3, y luego una consulta en el nodo NUMA 4 escanea la tabla realizando todas las búsquedas de agrupación en los nodos NUMA?

    Linchi Shea tiene una excelente publicación sobre este impacto en el rendimiento:

    El acceso a la memoria a través de nodos NUMA incurre en una pequeña cantidad de latencia de memoria adicional. Estoy seguro de que hay algunas cargas de trabajo que necesitan eliminar esa latencia de memoria base adicional para un rendimiento óptimo; no ha sido un problema en los sistemas con los que trabajo.

    Pero, el acceso entre nodos también trae otro punto de transferencia que puede saturar potencialmente. Si hay tanta actividad que el ancho de banda de memoria entre los nodos NUMA está saturado, la latencia de memoria entre los nodos aumentará. El mismo trabajo requerirá ciclos de CPU adicionales.

    Una vez más, estoy seguro de que hay cargas de trabajo tales que el ancho de banda de la memoria es una consideración crítica. Sin embargo, para mis sistemas, las otras consideraciones que estoy enumerando han sido más significativas.


  1. Colocación de memoria física

    Este es raro, pero cuando importa, realmente importa. En la mayoría de los servidores, la instalación de memoria se equilibrará casi naturalmente en los nodos NUMA. Pero en algunos casos, se necesita atención especial para equilibrar la memoria entre los nodos. El rendimiento en algunos sistemas puede ser absolutamente basura si la memoria fue ranurada de tal manera que no está equilibrada. Sin embargo, esto es configurarlo y olvidarlo. Es bastante raro descubrir un problema como este después de meses de servicio de producción en lugar de después del primer día realmente ocupado :-)


¡EL GRAN ACABADO!

Alguien más señaló que la mala elección del plan, tal vez debido a estadísticas obsoletas, podría provocar los síntomas que ha visto. Ese no ha sido el caso en mi experiencia. Los planes deficientes pueden hacer que una consulta tarde más de lo esperado, pero generalmente porque se están realizando más IO lógicas de las necesarias. O debido al derrame a tempdb. El derrame masivo a tempdb debería ser evidente al observar el servidor, y en lugar de una CPU alta, uno esperaría un tiempo de espera medible para las escrituras de disco relacionadas con el derrame.

En cambio, si la situación que observó está relacionada con NUMA, esperaría que fuera una combinación de los factores enumerados anteriormente, principalmente:

  1. uso de la memoria del espacio de trabajo (que no aparecerá en recuentos lógicos de E / S)

  2. que puede ser un nodo cruzado NUMA debido a una condición de memoria externa persistente (si este es el caso, busque soluciones relevantes)

  3. y que puede incurrir en contención de spinlock dentro del nodo NUMA cada vez que se realiza una asignación contra una subvención (arreglo con T8048)

  4. y puede ser realizado por trabajadores en CPU lógicas sobrecargadas por otros trabajadores de consultas paralelas (ajuste maxdop y / o umbral de costo de paralelismo según sea necesario)

sql_handle
fuente
7

( actualice su pregunta con la coreinfo -vsalida (una utilidad sysinternal) para obtener un mejor contexto de su CPU / sockets y distribución NUMA )

Analizamos la utilización general de la CPU, que era de alrededor del 60 por ciento. No analizamos las métricas de CPU específicas del socket. Las métricas de E / S fueron promedio.

Me parece que estás ladrando al árbol equivocado. SQL Server lo NUMAsabe. Hay una penalización de rendimiento mucho menor por hacer acceso cruzado a la memoria NUMA . También puede usar esta consulta para ver cuántos NUMAnodos tiene y qué CPU y núcleos están asignados a cuáles NUMA:

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

O solo cuantos NUMA:

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

Tuvimos consultas con pocas lecturas lógicas que tomaron más de 1 minuto.

Esto normalmente ocurre cuando se generan malos planes de consulta debido a estadísticas desactualizadas. Asegúrese de tener sus estadísticas actualizadas y sus índices estén desfragmentados correctamente .

Además, debe establecer MAXDOP en un valor más sensible para evitar el hambre del subproceso de trabajo .

Establecer su cost threshold of parallelism valor predeterminado de 5 en un buen valor inicial como 45 y luego monitoree ese valor y ajústelo según su entorno.

Si está ejecutando muchas consultas ad hoc, enciéndalo (configurado en 1) optimize for ad hoc workloads para evitar que el caché del plan se hinche.

Use con precaución: puede usar T8048 si está ejecutando SQL Server 2008/2008 R2 en máquinas más nuevas con más de 8 CPU presentadas por nodo NUMA y hay una revisión si está en SQL Server 2012 o 2014 .

Le recomiendo que comience a recopilar estadísticas de espera información de sobre la instancia del servidor de su base de datos.

Consulte: Cómo funciona: SQL Server (NUMA bloques de memoria locales, externos y ausentes)

Kin Shah
fuente
1

Puramente desde una perspectiva de hardware, la gestión de la memoria principal desde la arquitectura Nehalem en adelante es administrada por un controlador de memoria integrado, esto está en la parte "Un-core" de la matriz de la CPU que está separada de la parte en la que viven los núcleos reales, Debido a que la memoria está efectivamente 'cableada' a cada CPU, el acceso a la memoria externa AFAIK es a través de la interconexión de ruta rápida (nuevamente desde Nehalem en adelante), por lo tanto, diría que la saturación del núcleo de la CPU en un nodo NUMA local no debería afectar el acceso remoto a esa memoria.

Puede encontrar este enlace útil:

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

Chris

Chris Adkin
fuente