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)