Solución de problemas SOS_SCHEDULER_YIELD wait

14

Al ejecutar nuestro ERP corporativo (Dynamics AX 2012), noté que nuestro entorno de producción parecía mucho más lento que nuestros sistemas de desarrollo.

Después de realizar las mismas actividades tanto en el entorno de desarrollo como en el de producción mientras ejecutaba un seguimiento, confirmó que las consultas SQL se ejecutaban muy lentamente en nuestro entorno de producción en comparación con el desarrollo (10-50 veces más lento en promedio).

Al principio, atribuí esto a la carga, volví a ejecutar las mismas actividades en el entorno de producción durante las horas libres y encontré los mismos resultados en el seguimiento.

Borré mis estadísticas de espera en SQL Server, luego dejé que el servidor se ejecutara bajo su carga de producción normal durante un tiempo y luego ejecuté esta consulta:

WITH [Waits] AS
    (SELECT
        [wait_type],
        [wait_time_ms] / 1000.0 AS [WaitS],
        ([wait_time_ms] - [signal_wait_time_ms]) / 1000.0 AS [ResourceS],
        [signal_wait_time_ms] / 1000.0 AS [SignalS],
        [waiting_tasks_count] AS [WaitCount],
        100.0 * [wait_time_ms] / SUM ([wait_time_ms]) OVER() AS [Percentage],
        ROW_NUMBER() OVER(ORDER BY [wait_time_ms] DESC) AS [RowNum]
    FROM sys.dm_os_wait_stats
    WHERE [wait_type] NOT IN (
        N'CLR_SEMAPHORE',    N'LAZYWRITER_SLEEP',
        N'RESOURCE_QUEUE',   N'SQLTRACE_BUFFER_FLUSH',
        N'SLEEP_TASK',       N'SLEEP_SYSTEMTASK',
        N'WAITFOR',          N'HADR_FILESTREAM_IOMGR_IOCOMPLETION',
        N'CHECKPOINT_QUEUE', N'REQUEST_FOR_DEADLOCK_SEARCH',
        N'XE_TIMER_EVENT',   N'XE_DISPATCHER_JOIN',
        N'LOGMGR_QUEUE',     N'FT_IFTS_SCHEDULER_IDLE_WAIT',
        N'BROKER_TASK_STOP', N'CLR_MANUAL_EVENT',
        N'CLR_AUTO_EVENT',   N'DISPATCHER_QUEUE_SEMAPHORE',
        N'TRACEWRITE',       N'XE_DISPATCHER_WAIT',
        N'BROKER_TO_FLUSH',  N'BROKER_EVENTHANDLER',
        N'FT_IFTSHC_MUTEX',  N'SQLTRACE_INCREMENTAL_FLUSH_SLEEP',
        N'DIRTY_PAGE_POLL',  N'SP_SERVER_DIAGNOSTICS_SLEEP')
    )
SELECT
    [W1].[wait_type] AS [WaitType],
    CAST ([W1].[WaitS] AS DECIMAL(14, 2)) AS [Wait_S],
    CAST ([W1].[ResourceS] AS DECIMAL(14, 2)) AS [Resource_S],
    CAST ([W1].[SignalS] AS DECIMAL(14, 2)) AS [Signal_S],
    [W1].[WaitCount] AS [WaitCount],
    CAST ([W1].[Percentage] AS DECIMAL(4, 2)) AS [Percentage],
    CAST (([W1].[WaitS] / [W1].[WaitCount]) AS DECIMAL (14, 4)) AS [AvgWait_S],
    CAST (([W1].[ResourceS] / [W1].[WaitCount]) AS DECIMAL (14, 4)) AS [AvgRes_S],
    CAST (([W1].[SignalS] / [W1].[WaitCount]) AS DECIMAL (14, 4)) AS [AvgSig_S]
FROM [Waits] AS [W1] INNER JOIN [Waits] AS [W2] ON [W2].[RowNum] <= [W1].[RowNum]
GROUP BY [W1].[RowNum], [W1].[wait_type], [W1].[WaitS],
    [W1].[ResourceS], [W1].[SignalS], [W1].[WaitCount], [W1].[Percentage]
HAVING SUM ([W2].[Percentage]) - [W1].[Percentage] < 95; -- percentage threshold

Mis resultados son los siguientes:

WaitType               Wait_S  Resource_S  Signal_S  WaitCount  Percentage  AvgWait_S  AvgRes_S  AvgSig_S
SOS_SCHEDULER_YIELD   4162.52        3.64   4158.88    4450085       77.33     0.0009    0.0000    0.0009
ASYNC_NETWORK_IO       457.98      331.59    126.39     351113        8.51     0.0013    0.0009    0.0004
PAGELATCH_EX           252.94        5.14    247.80     796348        4.70     0.0003    0.0000    0.0003
WRITELOG               166.01       48.01    118.00     302209        3.08     0.0005    0.0002    0.0004
LCK_M_U                145.47      145.45      0.02        123        2.70     1.1827    1.1825    0.0002

Aparentemente, la espera más grande es SOS_Scheduler_Yield por mucho tiempo, y busqué en Google y descubrí que generalmente se relaciona con que la CPU no puede mantenerse al día.

Luego ejecuté esta consulta varias veces seguidas.

SELECT *
FROM sys.dm_os_schedulers
WHERE scheduler_id < 255

Sé que se supone que debo estar buscando programadores con runnable_tasks_count o pendientes_disk_io_count distintos de cero, pero es básicamente cero casi todo el tiempo.

También debo mencionar que el Grado máximo de paralelismo se estableció en 1, ya que la carga de trabajo de Dynamics AX es típicamente de naturaleza OLTP, y cambiarla 8 no hizo mucha diferencia en las estadísticas de espera anteriores, se volvieron casi exactamente iguales con el mismo problemas de rendimiento

No sé a dónde ir desde aquí, básicamente tengo un servidor SQL que aparentemente está atorado por la CPU pero no espera runnable_tasks o IO.

Sé que el subsistema IO de este SQL Server no es muy bueno, porque ejecutar SQLIO en la unidad que contiene las bases de datos reales puede generar números bastante bajos (piense 10 MB por segundo para ciertos tipos de lecturas / escrituras), dicho eso, no parece que SQL esté esperando eso debido a la cantidad de memoria en el servidor que almacena en caché la mayoría de las bases de datos.

Aquí hay información del entorno para ayudar:

Entorno de producción:

  • servidor SQL
  • HP ProLian DL360p Gen8
  • Intel Xeon E5-2650 0 @ 2.00GHz x 2 con hyperthreading (32 núcleos lógicos)
  • 184 GB de memoria
  • Windows Server 2012
  • 2 instancias de SQL Server 2012 Standard (RTM, sin parchear)
  • Raid 1 279GB de unidades (15k) C: unidad, contiene bases de datos y sistema operativo
  • Archivo de página y TempDB en unidades distintas y separadas (estado sólido)

Mi DEV:

  • Servidor SQL alojado Hyper-V y servidor AOS Dynamics AX 2012
  • Core i7 3.4ghz con hyperthreading (8 núcleos lógicos)
  • 8GB de memoria
  • Windows Server 2008 R2
  • SSD para toda la VM.

Agradecería cualquier aportación sobre otras cosas a tener en cuenta.

Nicholas Peterson
fuente

Respuestas:

16

Así que resolví esto, resulta que las funciones de administración de energía estaban habilitadas en nuestro servidor SQL que aumentaban y disminuían la frecuencia de la CPU, pero no lo suficientemente rápido como para satisfacer la pequeña demanda e introdujeron la espera SOS_Scheduler_Yield. Después de cambiarlo para que se ejecute siempre en alto rendimiento, el problema desapareció y ahora las esperas son más normales (cosas de tipo LatchIO).

Nicholas Peterson
fuente