Uno de los problemas con los que nos encontramos habitualmente los DBAs es el manejo de conjuntos de cargas no homogéneas. En un mundo ideal, cada instancia o incluso cada servidor, se destinaría a un uso específico y determinado. Esto nos permitiría optimizar mucho mejor su desempeño sin tenernos que preocupar de nada más que de su función principal. Lamentablemente nuestros servidores deben afrontar cargas de trabajo de diferente naturaleza teniendo ellas a su vez diferentes prioridades para los procesos de negocio a los que dan soporte.

Para permitirnos controlar la situación de forma eficaz en SQL Server 2008 disponemos del Resource Governor. Con éste podremos evitar situaciones por todos conocidas como encontrarnos con una consulta que por sus necesidades de CPU o memoria penalice en exceso al resto de consultas concurrentes o bien priorizar la carga de forma que las peticiones de las aplicaciones más importantes reciban prioridad para su procesamiento.

Su funcionamiento se basa en los siguientes sencillos conceptos:

  • Función clasificadora. Es una función que cuando nos llega una sesión la clasificará en alguna de las cargas de trabajo que definamos.
  • Cargas de trabajo (Workload group). Representa a un grupo de peticiones que queremos agrupar y controlar el uso de CPU que realicen, su grado de paralelismo, máximo número de peticiones simultáneas, etc.
  • Pools de recursos (Resource pool). Es un conjunto de recursos básicos de la instancia de SQL Server. En concreto cada pool tendrá asignada una cantidad de memoria y de cpu máxima y mínima.

Por tanto tendremos una función clasificadora y N cargas de trabajo asignadas a M pools. A continuación, un ejemplo clarificador 😉

— Creamos la función que nos clasificará las sesiones a medida que van entrando en función del usuario de la conexión

create FUNCTION dbo.clasificador() returns sysname

with SCHEMABINDING

AS

BEGIN

    return

    CASE USER_NAME()

WHEN ‘Intranet’ THEN ‘Web Corporativa’

WHEN ‘Ecommerce’ THEN ‘Tienda web’

WHEN ‘Extranet’ THEN ‘Extranet’

WHEN ‘ETL’ THEN ‘Procesos ETL’

ELSE null

END

END

go

— Asignamos la nueva función al resource governor

ALTER RESOURCE GOVERNOR

WITH (CLASSIFIER_FUNCTION=dbo.clasificador)

go

— Creamos dos pools de recursos, el primero para aplicaciones críticas con el 50% al 100% de CPU y memoria asignado.

— El segundo para aplicaciones pesadas contará únicamente con el 25% de CPU máximo y con un 0%-50% de la memoria asignada.

CREATE RESOURCE POOL [Aplicaciones críticas]

    WITH(min_cpu_percent=50,

        max_cpu_percent=100,

        min_memory_percent=50,

        max_memory_percent=100)

GO

CREATE RESOURCE POOL [Aplicaciones pesadas]

    WITH(min_cpu_percent=0,

        max_cpu_percent=25,

        max_memory_percent=50)

GO

— Creamos ahora las diferentes cargas de trabajo asociadas a las diferentes aplicaciones específicas.

— Para cada una podemos indicar su importancia, máximo de memoria (% respecto a su pool) y grado de paralelismo.

CREATE WORKLOAD GROUP [Extranet]

    WITH(group_max_requests=50,

        importance=Medium,

        request_max_memory_grant_percent=25,

        max_dop=1) USING [Aplicaciones críticas]

GO

CREATE WORKLOAD GROUP [Tienda web]

    WITH(importance=High,

        request_max_memory_grant_percent=50,

        max_dop=1) USING [Aplicaciones críticas]

GO

CREATE WORKLOAD GROUP [Web Corporativa]

    WITH(group_max_requests=100,

        importance=Low,

        request_max_cpu_time_sec=5,

        request_max_memory_grant_percent=10,

        max_dop=1) USING [Aplicaciones críticas]

GO

— Creamos ahora la carga de trabajo para procesos pesados. Limitamos el número de peticiones a 5 y permitimos paralelismo hasta 4 procesadores.

CREATE WORKLOAD GROUP [Procesos ETL] WITH(group_max_requests=5,

        importance=Medium,

        request_max_cpu_time_sec=0,

        request_max_memory_grant_percent=25,

        request_memory_grant_timeout_sec=0,

        max_dop=4) USING [Aplicaciones pesadas]

GO

— Por defecto el resto de peticiones que puedan llegar, les rebajaremos la

— prioridad a baja pues por defecto vienen configuradas con prioridad media.

ALTER WORKLOAD GROUP [default]

WITH (importance = low)

— Actualizamos finalmente el resource governor con todos los cambios

ALTER RESOURCE GOVERNOR RECONFIGURE

Una vez hecho esto y para comprobar que está funcionando correctamente vamos a simular un par de cargas pesadas provenientes de la tienda web y otra carga procedente de un proceso ETL. Por simplificar, el proceso diseñado consiste simplemente en el cálculo de un número elevado de números aleatorios y los resultados son los siguientes:

Ecommerce(ms)

ETL(ms)

ETL

0

90856

Ecommerce

87395

0

ETL + Ecommerce

131316

184272

De forma individual, la carga de la tienda web tarda 87 segundos en ejecutarse mientras que esta cifra sube a 131 cuando se ejecuta conjuntamente con la carga ETL (+50%). Por otra parte la carga ETL individualmente tarda 90 segundos y conjuntamente 184 (+104%) por lo que vemos que se está priorizando la carga proveniente de la tienda web (debido a la configuración del pool)

 

Rubén Garrigós