Surviving the Night

El blog de Pablo Doval sobre .NET, SQL, WinDbg...

Everything: El Resource Governor en SQL Server 2008

En una entrada anterior hablábamos del Query Governor, ese recurso tan interesante como desconocido que nos permitía impedir la ejecución de consultas demasiado pesadas contra un servidor SQL Server. Aunque esta solución resulta interesante en muchos escenarios, en otros impedir la ejecución de la consulta completa puede ser poco operativo o incluso inviable. Como ya adelantamos en aquella entrada, una de las grandes novedades de SQL Server 2008 viene a ayudarnos precisamente en estos escenarios: el Resource Governor.

Como es evidente, para probar las técnicas de éste artículo necesitaremos tener acceso a un servidor SQL Server 2008. Tenemos dos opciones: o bien nos descargamos la última CTP y la instalamos en nuestra máquina (o mejor aún, una máquina virtual, por si acaso! xD) o bien tiramos de un Virtual Lab como éstos (más fácil no nos lo pueden poner).

Introducción al Resource Governor

Como ya comente anteriormente, la idea detrás del Resource Governor es poder controlar consultas determinadas y poder adjudicarles una cantidad específica de recursos. Para lograrlo, todas las conexiones que se realizan contra el SQL Server pasan por un clasificador, que se encarga de asignar un grupo a cada sesión en base a una función de clasificación. A estos grupos les podemos asignar un pool , que se encarga de otorgar y limitar los recursos (CPU y memoria).

Veámoslo de con un pequeño diagrama:

ResourceGovernor 

(Atiende que diagrama.. [cariñoso homenaje a los chicos de Muchachada Nui xD])

Ahora vamos a definir cada uno de los conceptos en negrita con un poco mas de calma :) Estos son, por tanto, los 0tres conceptos fundamentales:

  • Resource Pools:

Los Resource Pools, o simplemente pools, son un contenedor que representa un conjunto de los recursos del servidor. A día de hoy solo soporta solamente dos recursos: Memoria y CPU.

Cada recurso puede especificar dos valores porcentuales: Mínimo y Máximo.

El valor mínimo indica que como mínimo las consultas que se ejecuten dentro de ese pool dispondrán de ese porcentaje de memoria. La conclusión evidente es que la suma de los valores mínimos de todos los pools no puede superar 100. Se trata pues de un factor que nos permite garantizar unos recursos mínimos para la ejecución de las consultas que vayan a este pool.

El valor máximo, por otra parte, indica el limite a partir del cual no se otorgaran mas recursos a una consulta. Es un factor limitante, que nos permite preservar recursos del sistema impidiendo que las consultas que vayan a este pool excedan estos limites.

Hay dos pools especiales o particulares:

  • Por una parte tenemos el Pool Interno (Internal Pool), que representa los recursos consumidos por el propio SQL Server. No hay restricciones a los recursos consumidos dentro de este pool y, de echo, éste puede hacer presión sobre el resto de pools, incluso aunque esto signifique violar los limites establecidos por ellos.
  • El otro pool especial es el Pool por Defecto (Defaul Pool), que es el primer pool 'de usuario' que se crea. Éste puede ser alterado, pero no puede ser eliminado.
  • Workload Groups:

Los workload groups (o grupos) son contenedores para sesiones que cumplen unos mismos criterios. Como explicamos arriba, y veremos en detalle más abajo, cuando se realiza una petición de sesión contra el servidor se le asigna a un grupo en función de unas reglas de clasificación.

Estos grupos nos permiten monitorizar fácilmente todos los recursos que consume un mismo tipo de consultas, así como aplicar políticas a todas a la vez. También nos facilitan el mover todas las sesiones de un grupo de un pool a otro.

Tenemos dos grupos por defecto:

  • El Grupo Interno (Internal Group) esta dedicado a contener las sesiones del propio SQL Server. No podemos cambiar nada que este dentro de este grupo, pero si podemos monitorizar su consumo de recursos.
  • El Grupo por Defecto (Default Group), al que van todas las sesiones que no encajen con reglas de clasificación que los muevan a otros grupos.

Evidentemente, a partir de aquí podemos crear todos los grupos que necesitemos a voluntad. Por ejemplo, un grupo para sesiones de nuestro ERP, otro grupo para Reporting, otro exclusivo para el administrador...

  • Clasificador:

Y finalmente llegamos al final... ¿o al principio? En realidad el clasificador es lo primero qué entra en juego, cronológicamente hablando, desde que se lanza la consulta hasta que ésta es procesada, pero parece que tiene más sentido explicar antes lo que es un pool y un grupo, por lo que he dejado el clasificador para el final.

Un clasificador no es mas que un mecanismo que emplea un conjunto de reglas suministradas por el sistema, o bien definidas por el usuario como UDFs, de modo que se permita un mapeo entre una sesión y un grupo.

... y ahora, al turrón! (que para algo es navidad...)

Vamos a hacer un escenario muy simple. ¿Por que muy simple? por mientras escribo esto son las 6.54am del día de Nochebuena (navidad ya!) y no es plan... además, el blog es mío y pongo los escenarios que me apetece :)

Escenario: Queremos limitar las consultas que vengan desde el SqlCmd, de modo que en tal caso obtengan un máximo de un 10% de CPU y un 5% de memoria del sistema. El resto de consultas no deben verse afectadas.

Lo primero que haremos será crear un pool donde limitaremos los recursos. Dentro de este pool será donde se ejecutarán las sesiones que se conecten a través del SqlCmd.

CREATE RESOURCE POOL poolSqlCmd
WITH
(
MAX_CPU_PERCENT=10,
MAX_MEMORY_PERCENT=5
);

Como visteis, muy sencillito todo. Podríamos haber especificado recursos mínimos, pero para este ejemplo no tiene sentido.

Ahora vamos a crear un grupo, que será donde almacenemos todas las sesiones que se conecten desde el SqlCmd. Lo haremos con el siguiente código:

CREATE WORKLOAD GROUP groupLimitado
WITH
(
IMPORTANCE=MEDIUM ,
REQUEST_MAX_MEMORY_GRANT_PERCENT=75,
REQUEST_MAX_CPU_TIME_SEC=600,
MAX_DOP=4,
GROUP_MAX_REQUESTS=10
)
USING poolSqlCmd;

Como podéis ver, las sesiones que entren en este grupo tendrán ciertas propiedades en común, que definimos a nivel de grupo:

  • Por una parte tenemos su importancia, que es simplemente un mecanismo de prioridades. En este caso hemos establecido MEDIUM, que es el valor por defecto.
  • También hemos especificado que no vamos a permitir que entre ninguna sesión cuyos requisitos de memoria sean mayores a un 75% de la memoria máxima asignada al grupo.
  • Tampoco entrara ninguna sesión cuya petición de tiempo de CPU sea mayor a 600 segundos. (Esto es similar al Query Governor que vimos en el otro artículo)
  • El grado máximo de paralelismo que permitiremos dentro del grupo es de 4. Esta limitación puede ser muy útil en entornos multiprocesador complejos.
  • El último parámetro indica que como mucho procesaremos 10 peticiones a la vez, el resto no entraran al grupo hasta que alguna del grupo se libere.

Finalmente, gracias a la cláusula using, vinculamos el grupo a su pool por defecto, que será el pool que creamos previamente.

¡Ferpecto! Ahora solo nos queda vincular las sesiones entrantes a nuestro grupo si es necesario. La regla que habíamos establecido era la siguiente: capamos las consultas que vengan de SqlCmd, y dejamos las demás como estaban. Ok, nos creamos una función que devuelva el nombre del grupo en función del nombre de la aplicación que crea la conexión... algo como esto, vaya...

CREATE FUNCTION fnuClasificador() RETURNS SYSNAME
WITH SCHEMABINDING
AS
BEGIN
DECLARE @grupo SYSNAME
IF (APP_NAME() LIKE 'SQLCMD')
SET @grupo= 'groupLimitado'
ELSE
SET @grupo= 'default'
RETURN @grupo
END;

... y por último, le decimos al Resource Governor que a partir de ahora va a emplear nuestra función como función de clasificación: 

ALTER RESOURCE GOVERNOR WITH (CLASSIFIER_FUNCTION=dbo.fnuClasificador);

Finalmente aplicamos los cambios con un RECONFIGURE, que se encargará de hacer que la nueva función de clasificación se empiece a utilizar.

ALTER RESOURCE GOVERNOR RECONFIGURE;

Ahora es cuando podemos probar los resultados. ¿Como? Pues por ejemplo, con la consulta generadora de números que vimos en el post acerca del Query Governor. Estos sin los resultados que he obtenido en mi máquina lanzando la consulta desde el Management Studio y desde el SqlCmd:

Cliente Duración
Management Studio 27.1 s.
SqlCmd 53.5 s.

La razón por la que la ejecución desde SqlCmd es más lenta es bien simple: hemos limitado su uso de recursos, forzándola a ejecutarse  en el pool poolSqlCmd, con lo que no puede rendir lo mismo que la sesión que lanzamos desde el Management Studio, y que se ejecuta en el pool por defecto!

Por último, ¡no os olvides de eliminar nuestra configuración de prueba! Podéis hacerlo con un script como el siguiente, que elimina la función de clasificación, el grupo y finalmente notificar al Resource Governor para que utilice la nueva configuración:

USE master
GO
ALTER RESOURCE GOVERNOR WITH (CLASSIFIER_FUNCTION = NULL);
DROP WORKLOAD GROUP groupLimitado
GO
ALTER RESOURCE GOVERNOR RECONFIGURE;

Conclusiones:

Como hemos visto, el Resource Governor es un mecanismo sencillo y extremadamente versátil para la gestión de recurso de nuestros servidores. Nos permiten ajustar la carga en función del origen o las intenciones de la consulta, de modo que podemos establecer prioridades sobre los recursos de un modo muy sencillo. Además, resulta casi trivial modificar este balance de recursos a lo largo del día mediante scripts gestionados por el Agent que nos cambien la función de clasificación.

Aprovecho para recordaros que podéis obtener información adicional sobre el Resource Governor desde su página en los books online de SQL Server 2008; eso si, no olvidéis que se trata de documentación no definitiva, y así seguirá siendo hasta que el producto no esté en la calle.

Espero y deseo que este post os haya resultado de interés y os emocione al menos una décima parte de lo que a mi me emociona esta característica :)

Feliz Navidad a todos, y Keep Rockin'!!!

Rock Tip:

Si cuando comentamos el Query Governor decíamos que este no era suficiente, y hacíamos alusión al tema 'Not Enough' de Van Halen, en el caso del Resource Governor parece apropiado hacer referencia al temazo 'Everything' de Hardline, el grupo de los hermanos Gioely con Neal Schon a la guitarra. Un grupo bastante desconocido fuera del ámbito del hard rock, pero que estoy seguro de que agradará a más de un profano. Rock clasico, baladones y medios tiempos fantásticos con una voz grandiosa a cargo de Johnny Gioely, y la legendaria guitarra de Neal Schon. Discos como el Double Eclipse deberían ser oídos por todo amante de la música.

Aunque bien pensado, quizá everything tampoco sea muy apropiado... y antes de que me acusen de conformista o condescendiente con todos los productos de Microsoft, aclararé que espero ver en el futuro la posibilidad de limitar recursos de I/O a parte de CPU y memoria, pero bueno, me apetecía poner un tema de los Hardline y este pegaba más o menos :)

Posted: 25/12/2007 5:20 por Pablo Alvarez | con 2 comment(s)
Comparte este post:

Comentarios

DbRunas - Everything: El Resource Governor en SQL Server 2008 ha opinado:

PingBack desde  DbRunas - Everything: El Resource Governor en SQL Server 2008

# December 26, 2007 12:55 AM