Let’s Get Rocked – SQL Server 2008 February CTP

Hoy toca entrada relámpago; estos días no tengo tiempo para actualizar el blog, ni seguir los eventos de la comunidad y los foros como me gustaría, pero con un poco de suerte en breves volverá la normalidad y os tocará volver a aguantarme 😉

Por lo pronto, la entrada de hoy era obligada: como ya se había anunciado, una nueva CTP de SQL Server estaría disponible antes de los eventos de lanzamiento de la semana que viene, y así ha sido. Desde el siguiente enlace os podéis descargar la última CTP, que entre otras novedades incluye el nuevo renderizado de informes directamente desde Word, el Integrated Full-Text Search (iFTS), la compresión de datos y, sobre todo, la integración con Visual Studio 2008!

Espero que tengáis tiempo de descargarlo y jugar con el, sobre todo los que tenéis pensado asistir a las sesiones de lanzamiento; así podréis aprovechar las sesiones y los Ask The Experts para preguntar y resolver dudas sobre estas nuevas características.

Rock Tip:

Hoy le toca el turno a los chicos de Def Leppard y su ‘Let’s Get Rocked‘, de su disco Adrenalize. Ya sabéis, descargaros el último juguetito en versión CTP y… let’s get rocked!!!

Walk This Way: Jugando con el Call Stack

Bueno, dado que soy el dueño y señor indiscutible de los reinos del metal en esta casa, y que puedo permitirme un descanso entre tema y tema con el Guitar Hero, he conseguido sacar un poco de tiempo para ir escribiendo el siguiente artículo sobre depuración con WinDbg.

El pequeño artículo de hoy se limitará a describir la pila de llamadas (en adelante lo llamaré por su termino sajón: call stack. Es común referirse a él con esta terminología, y además en inglés tiene un cool factor mucho mayor 😛 ), a visualizarlos mediante WinDbg y a explorar algunos comandos nuevos que nos permitirán ver las variables locales, ver el contenido de una variable de un tipo concreto, establecer un punto de parada, etc.

Eso si, antes de ponernos manos a la obra, un pequeño detalle. Como alguno de vosotros me hizo llegar por correo, en el artículo anterior de la serie los volcados se realizaron sobre una aplicación de 64 bits, lo que se reflejaba en unas direcciones de memoria aberrantemente grandes. Si bien hasta hace poco no eran habituales, las máquinas de 64 bits ya están a la orden del día; lo he pensado un poco y he decidido continuar realizando las demos de los siguientes artículos sobre una máquina de 64 bits, pero me gustaría tener feedback vuestro para saber que preferís. Si preferís trabajar con las direcciones de memoria a las que estamos acostumbrados, me monto una máquina virtual y hacemos las siguientes entradas de la serie en 32 bits, y más adelante daremos, si os apetece y me seguís leyendo, el salto a los 64 bits 🙂 En fin, como vosotros veáis.

El Call Stack

Supongo que casi todos estaremos familiarizados con el concepto de Call Stack, por lo que no me extenderé en su descripción. Simplemente recordaré que es una estructura que almacena la información necesaria para poder anidar llamadas a funciones o métodos, y poder retornar al punto de origen de la llamada a la función una vez que ésta termina.

En el diagrama que os pongo a continuación (¡cómo me gusta hacer dibujitos!) os muestro un ejemplo de un proceso de Windows, con múltiples hilos de ejecución, y dentro de cada hilo de ejecución podemos ver su pila de llamadas, que almacena los diferentes frames o contextos de ejecución.

Descripcion de los Call Stacks

Como vemos en el ejemplo, el primer hilo comienza con el punto de entrada de la aplicación (lo deducimos del primer frame, cuyo nombre de función es Main), y a continuación invoca a un método llamado Init() en la clase App. Supongamos, para nuestro ejemplo, que dentro de este método se crean otros hilos auxiliares (del hilo 2 al hilo n, en el diagrama) que se encargarán de otras actividades (monitorización, worker threads, etc). Cada uno de estos hilos adicionales tendrá su propio call stack, con sus frames independientes.

Continuando con nuestro ejemplo, podemos deducir que hubo algún problema durante la inicialización de la clase App, y la aplicación decidió generar un volcado de memoria (por el método Dump, en la clase ErrMgr). Todo esto lo intuimos gracias a la semántica contenida en los símbolos, que nos permiten ver los nombres de las funciones en el call stack, como comentamos en el anterior artículo.

He comentado el concepto de frame muy brevemente, y he sido injusto, ya que es la estructura clave del Call Stack; almacena toda la información relevante, como son las variables locales de la función, la dirección de retorno de la misma (para volver, una vez finalizada la ejecución del método o función, a la siguiente instrucción en el frame anterior), los registros almacenados, las cookies de seguridad, etc.

A continuación os pongo el aspecto que tiene un frame de una aplicación compilada con Visual Studio 2003.

Descripcion del Frame No voy a entrar ahora en detalles como el manejador de excepciones del frame, o las Cookies de Seguridad (para las que tengo un articulo en mente). Me conformo con que os quedéis con la idea de que dentro de cada frame tenemos acceso a la lista de parámetros que se le han pasado a la función o método, así como a todas las variables locales al frame y, por supuesto, la dirección de retorno de ka función.

 

 

minesweeper.exe: el proceso

Después de este poquito de teoría, vamos a pasar a la practica diseccionando alguna aplicación del sistema ya conocida. Si en el post anterior usamos como conejillo de indias el notepad.exe, en esta caso vamos a utilizar al eterno buscaminas, en esta ocasión en su encarnación bajo Windows Vista.

Captura del MineSweeper.exe

Con nuestro objetivo claro, ejecutamos el buscaminas y a continuación abrimos el WinDbg (si estamos en Windows Vista nos aseguramos de ejecutarlo como administrador). Siguiendo las instrucciones que ya detallamos en el post anterior, adjuntamos el WinDbg al proceso minesweeper.exe (F6), recargamos los símbolos, y podemos comprobar como el depurador se ha adjuntado y nos permite explorar el proceso, mientras que si cambiamos a la ventana del buscaminas podemos ver como la interfaz de usuario se encuentra congelada. Esto se debe a que el proceso realmente esta congelado por el depurador, y eso impide que la interfaz de usuario responda a los eventos de la bomba de mensajes de Windows.

Ok, vamos a empezar explorando todos los hilos del proceso y visualizando sus stacks. Para ello, y cómo ya vimos en su día, empleamos el comando ~*k (recordemos que ~ significa hilo, * significa todos y k ordena mostrar el call stack. Si hubiéramos querido mostrar solo el stack del hilo 4 podríamos haber lanzado un ~4k, etc.). El resultado es el siguiente:

0:008> ~*k

   0  Id: 440.1224 Suspend: 1 Teb: 000007ff`fffde000 Unfrozen
Child-SP          RetAddr           Call Site
00000000`0011efa8 00000000`779fd908 ntdll!NtDelayExecution+0xa
00000000`0011efb0 00000000`ffe65fa3 kernel32!SleepEx+0x84
00000000`0011f030 00000000`ffe65d23 MineSweeper!RunEngine+0x125
00000000`0011f060 00000000`ffe4dec8 MineSweeper!InitializeEngine+0x11a2
00000000`0011f7b0 00000000`ffeaf525 MineSweeper!WinMain+0x150
00000000`0011f830 00000000`779fcdcd MineSweeper!operator new[]+0x27f
00000000`0011f8f0 00000000`77b4c6e1 kernel32!BaseThreadInitThunk+0xd
00000000`0011f920 00000000`00000000 ntdll!RtlUserThreadStart+0x1d

...

#  8  Id: 440.7d8 Suspend: 1 Teb: 000007ff`fffaa000 Unfrozen
Child-SP          RetAddr           Call Site
00000000`0a7bf758 00000000`77be33e8 ntdll!DbgBreakPoint
00000000`0a7bf760 00000000`779fcdcd ntdll!DbgUiRemoteBreakin+0x38
00000000`0a7bf790 00000000`77b4c6e1 kernel32!BaseThreadInitThunk+0xd
00000000`0a7bf7c0 00000000`00000000 ntdll!RtlUserThreadStart+0x1d

(Solo he mostrado el primer y último de los 9 hilos que había en el proceso en el momento que se adjunto el depurador.)

Podemos ver que el primer hilo (con identificador 0) es el que contiene el punto de entrada de la aplicación, ya que su cuarto frame es el método WinMain. Vamos a ponernos en este hilo (~0s, con la s indicando step, es decir, situarnos sobre el hilo 0) y a mostrar el stack, pero esta vez con el comando kn, que nos agrega el identificador de frame a cada elemento del stack:

0:008> ~0s
ntdll!NtDelayExecution+0xa:
00000000`77b505ba c3              ret
0:000> kn
 # Child-SP          RetAddr           Call Site
00 00000000`0011efa8 00000000`779fd908 ntdll!NtDelayExecution+0xa
01 00000000`0011efb0 00000000`ffe65fa3 kernel32!SleepEx+0x84
02 00000000`0011f030 00000000`ffe65d23 MineSweeper!RunEngine+0x125
03 00000000`0011f060 00000000`ffe4dec8 MineSweeper!InitializeEngine+0x11a2
04 00000000`0011f7b0 00000000`ffeaf525 MineSweeper!WinMain+0x150
05 00000000`0011f830 00000000`779fcdcd MineSweeper!operator new[]+0x27f
06 00000000`0011f8f0 00000000`77b4c6e1 kernel32!BaseThreadInitThunk+0xd
07 00000000`0011f920 00000000`00000000 ntdll!RtlUserThreadStart+0x1d

¿Veis el método MineSweeper.InitializeEngine()? No se a vosotros, pero a mi me suena interesante la idea de meterme en ese contexto y ver que variables locales están definidas en ese método. ¿Como podemos hacerlo? Bueno, primero usamos el comando .frame para poder meternos en el contexto de ese método:

0:000> .frame 03
03 00000000`0011f060 00000000`ffe4dec8 MineSweeper!InitializeEngine+0x11a2

Ok, y ahora ¿como vemos las variables locales? Tenemos dos posibilidades, usar el comando x (explore) sin parámetros, o bien usar el dv (dump variables). Vamos a probar…

0:000> x
0:000> dv
Unable to enumerate locals, HRESULT 0x80004005
Private symbols (symbols.pri) are required for locals.
Type ".hh dbgerr005" for details.

Ups.. esto no tiene buena pinta. El comando x no nos devuelve nada, y el dv nos indica que necesitamos símbolos privados para poder acceder a las variables locales. En este caso estamos trabajando con los símbolos públicos que expone Microsoft en http://msdl.microsoft.com/download/symbols, por lo que podemos decir que nuestro gozo en un pozo… 🙁

De todos modos, no todo esta perdido… conociendo la estructura del frame podemos acceder a los parámetros y a las varaibles locales incluso sin tener símbolos, aunque es un poco más laborioso. Esto lo dejaremos para la siguiente entrada de ésta serie.

Para terminar vamos a devolver el control al proceso de modo que vuelva a responder a los mensajes de Windows, de modo que su interfaz de usuario vuelva a funcionar correctamente. Para ello emplearemos el comando g (go) del depurador. Una vez lanzado, el control solo volverá al depurador cuando se encuentre con un punto de parada (breakpoint) o cuando pulsemos la combinación de teclas Crtl+Intr desde la ventana de WinDbg.

Conclusiones:

Como hemos podido ver, el mero hecho de visualizar los call stack de los diferentes hilos de un proceso nos puede dar muchísima información útil para procesos de troubleshooting o de ingeniería inversa, o simplemente para pasar un buen rato usando el WinDbg 🙂

La lista de comandos que hemos usado de WinDbg no ha crecido mucho desde el primer artículo, y es que realmente no es necesario recordar de memoria la tremenda cantidad de mnemónicos expuestos por el depurador; con un puñado tenemos suficiente para hacer virguerías… Virguerías que, por cierto, espero empezar a hacer en el próximo artículo, ¡si decidís acompañarme nuevamente! 🙂

Rock Tip:

Este post viene acompañado del temazo ‘Walk this Way’ de Aerosmith. ¿Que decir de Aerosmith? Unos músicos como la copa de un pino, divertidos, eternos… A parte de ello, yo creo que el amigo Perry y el amigo Tyler han triunfado allí donde fracasó Don Juan Ponce de León… (y ahora es cuando vosotros pensáis que se me acaba de ir la pinza una vez más :D) Me explico: estos dos señores tienen mas años que mis padres, y mientras a mis padres les cuesta subir la escalera de casa, a estos elementos se les ve noche tras noche pegando botes y carreras de un lado al otro de un escenario del tamaño de un campo de fútbol, y todo ello después de más de 4 décadas de excesos… ¿como es posible? Sólo se me ocurre que hayan encontrado la fuente de la eterna juventud. O eso, o el tema de venta de alma al diablo.. pero esa se la reservamos a Robert Johnson.

Pero… ¿que relación tiene este tema con el post? Pues poca… francamente poca 🙂 Pero resulta que veréis mucho la expresión ‘walk down the stack’ o simplemente ‘walk the stack’ cuando se recorre el call stack desapilando frames, y siempre que leo/oigo/digo esa expresión me acuerdo de este tema de Aerosmith.

A Day Late, A Dollar Short: VS2005 + SQL Server 2008 CTP = KB942246

En entradas anteriores ya he tratado de convencer a los indecisos de probar la última CTP de SQL Server 2008, donde os esperan nuevos amigos como el Declarative Management Framework (ups, perdón, ahora se llama Policy-Based Management), el Capture Data Change, el Resource Governor y otras muchas novedades con las que entretenernos un buen rato.

Una razón adicional para ir familiarizándonos con estas tecnologías es que en breve comenzará la gira de lanzamiento de Visual Studio 2008, SQL Server 2008 y Windows Server 2008, y si llevamos ‘los deberes adelantados’ le podremos sacar mucho más partido a las sesiones y a los ponentes, y de paso, los chicos del Ask The Experts se aburrirán menos 😉

Bien… ahora que os tengo convencidos y os estáis descargando la CTP de Noviembre de SQL Server 2008, os cuento un secreto: si tratáis de conectaros a vuestra nueva y flamante instancia de SQL Server 2008 desde el VS 2005, os vais a dar de bruces con un error como el siguiente:

“This server version is not supported. Only servers up to Microsoft SQL Server 2005 are supported.”

Como podéis ver, esto limita bastante la utilidad de la CTP a la hora de realizar desarrollos sobre ella. Sin embargo, BillG no nos iba a dejar tirados (¡por la cuenta que le trae!) y aparto unos cuantos US$ de su cuenta corriente para hacernos felices con un fix. De este modo, para poder conectaros a la instancia SQL Server 2008 lo que debemos de hacer es aplicar un parche sobre VS2005 que podéis localizar aquí.

Una vez aplicado el fix podemos conectarnos a la instancia, editar y visualizar los objetos (procedimientos almacenados, tablas…), crear proyectos de SQL CLR y desplegarlos sobre un servidor, realizar sesiones de depuración (tanto de T-SQL como de SQL CLR), etc.

Aun tiene algunos problemillas (os recomiendo leer la documentación del artículo de KB) pero es indispensable si queremos empezar a desarrollar con nuestros DATE, TIME, tipos geo-espaciales y demás goodies de Katmai 🙂

Rock Tip:

Ya que antes hacíamos una jocosa(¿?) mención al uso de la cuenta corriente de BillG, no he podido evitar que me viniera a la mente el tema ‘A Day Late, A Dollar Short‘, de los geniales Hanoi Rocks.

Hanoi Rocks han sido una de mis bandas favoritas desde que la descubriera no hace demasiados años. Lo han tenido todo, para lo bueno y para lo malo; una historia plagada de temas excelentes y discos para el olvido, éxito y tragedia, y escaso reconocimiento fuera de las fronteras de su Finlandia natal. Muchos grupos de mayor éxito comercial han estado abierta y reconocidamente inspirados por la banda de Michael Monroe y Andy McCoy, como los mismísimos Guns N’ Roses, pero ellos no han tenido ese reconocimiento hasta hace escasos años, que se han convertido en una especie de banda de culto.

Se volvieron a reunir en 2002, después de un larguísimo parón, y desde entonces han sacado tres de sus mejores álbumes. Un grupo más que recomendable si os atrevéis a una mezcla de hard rock, glam y una pizca de punk clásico ochentero.

Malas Noticias: Nos ha dejado Ken Henderson

Hace unos minutos, mientras hacía mi recorrido bloguero habitual, me encontré con esta triste noticia en el blog de Kalen Delaney.

Ken Henderson, desarrollador del grupo de producto de SQL Server y uno de los mejores divulgadores de SQL Server (desde mi punto de vista), nos dejó el pasado 27 de Enero. Sirva este post para recordarle, para expresar mis mejores deseos para su familia, y para presentar su trabajo a quienes aun no lo conozcan. Como esta última parte es la más relevante para la comunidad, ahí os dejo la referencia de los que para mi son sus dos libros mas interesantes, y un par de artículos suyos geniales:

  • SQL Server 2005 Practical Troubleshooting:

Un libro genial sobre el proceso de resolución de problemas en SQL Server. En este enlace tenéis su entrada en Amazon.

  • The Guru’s Guide to SQL Server Architecture and Internals

Este libro es una de mis recomendaciones sobre arquitectura del producto, complementando al Inside SQL Server 2000 de Kalen Delaney (o su versión de 2005, The Storage Engine). Sencillamente genial, imprescindible para conocer esos detalles del producto y la arquitectura que acaban marcando la diferencia, y sobre todo, capaz de hacernos entender por qué es importante conocer los internals.

Aquí tenéis su entrada en Amazon.

  • The Perils of Fiber Mode (Artículo de la MSDN)

En este artículo de la MSDN, Ken Henderson nos hablaba sobre el modo de ‘lightweight threading’, o ‘fiber mode’.

  • Inside SQL Server 2000’s Memory Management Facilities (Artículo de la MSDN)

Uno de mis temas de conversación favoritos al hablar sobre SQL Server es la gestión de memoria; no solo por lo bonito que puede llegar a ser el tema a nivel técnico, sino porque es uno de los pilares fundamentales sobre los que se sustenta el producto, y comprender como funciona la gestión de memoria nos ayuda en gran medida a tener nuestro sistema en un estado saludable y con un buen rendimiento. Un de los primeros artículos que leí sobre el tema fue este, y aún sigo recomendándolo como introducción a la gestión de memoria para máquinas de 32 bits.

Otra de las grandísimas contribuciones de Ken, junto con Bart Duncan, es la herramienta SQL Nexus, a la que espero dedicar un post en breves.

En fin, una gran perdida, justo un año después de la desaparición de Jim Gray… parece que Enero no es un buen mes para los Data Guys 🙁

Rock Tip:

Para acompañar este triste post hoy les pediré a los Suaves, los eternos rockeros ourensanos, que me dejen prestado su ya clásico ‘Malas Noticias‘.

Round And Round: Retraso para el SQL Server 2008 RTM

Acabo de leer la noticia en este post de The Data Platform Insider, y la verdad es que no me ha cogido por sorpresa: la versión final de SQL Server 2008 (Katmai para los amigos) se retrasa hasta el Q3 de 2008.

¿Y como afecta eso a los eventos de lanzamiento previstos para finales de septiembre? Pues realmente no les afecta en absoluto, ya que era sabido que se iban a realizar con una CTP. Las buenas noticias son que para este evento saldrá una nueva CTP que debería implementar toda la funcionalidad que se va a encontrar disponible en el producto final, y que en Q2 tendremos una RC a nuestra disposición que debería contener prácticamente los bits finales.

Personalmente el retraso del producto no me parece sorprendente, ni lo considero una mala señal; prefiero que el producto salga bien, y de paso, nos dan mas tiempo para ponernos las pilas con las CTP y RCs antes de plantearnos siquiera moverlo a producción. Sin embargo, me gustaría saber vuestra opinión 🙂

Rock Tip:

No se porque razón, si es que hay alguna, pero para describir esta noticia solo se me viene a la cabeza el temazo de RATT "Round And Round", de su disco Out of the Cellar, pero tampoco le daré vueltas, ya que nunca es mal momento para escuchar este trallazo de 1984 🙂

El tema nunca pasará de moda, y ahí no acepto discusión. Pero el vídeo… el vídeo es sencillamente genial: una mansión de una familia rica, un grupo de melenudos que furtivamente se meten en su casa a tocar en el ático, una chica guapa y un mayordomo que acaba convertido en heavy… ¿alguien da mas? Y si, por si alguien se lo pregunta, ¡realmente me encantan! 🙂

Here Comes The Sun: Sun Compra a MySQL

Hoy traigo noticias frescas. Quizá no sean tan impactantes para el público no-geek como los últimos acontecimientos de la política nacional, o la expectación ante el derbi madrileño, o la aberrante propuesta a letra del himno nacional; sin embargo, estoy seguro de que vosotros si comprenderéis la importancia que tiene en nuestro terreno.

En fin, ahí va la noticia prometida:

(Redoble de tambores por favor… )

¡¡Sun Microsystems ha comprado a MySQL AB!!

¿Sorprendidos? Pues no deberíais, que para algo puse la noticia en el titulo del post 😀

En fin, me parece que esta noticia va a ser seria, ya que Sun lleva tiempo queriendo meterse en el negocio de las bases de datos, y así, de paso, se hace con la M del stack LAMP. Por otra parte, MySQL realmente necesitaba el empujón que una multi-nacional como Sun puede aportarles, por lo que parece una situación en la que las dos empresas salen ganando. Del mismo modo, estoy seguro que los usuarios de MySQL también lo recibirán como una buena noticia.

¿Como nos afecta esta noticia a los geeks de Microsoft?

Bueno, esta claro que MySQL es un producto en competencia directa con SQL Server Express, y como buenos profesionales debemos conocer el producto que empleamos, así como las alternativas en el mercado. Y creedme que hasta yo, que no soy precisamente un fiel seguidor de MySQL, dedicaré mi tiempo a seguir los frutos de esta unión y evaluar los productos que saquen.

En fin, estoy ansioso de que saquen un producto nuevo… como siempre digo para mi todo son juguetes, ¡y estoy dispuesto a jugar con ellos mientras me entretengan! 😉

Rock Tip:

El rock tip de este post era evidente, ‘Here Comes the Sun’ de The Beatles. No obstante, como veréis si pincháis en el enlace, os sugiero la versión que Bon Jovi hizo en el concierto de homenaje a George Harrison en 2001. Una versión preciosa de una canción aun mas bonita si cabe. Se que no es un Rock tip propiamente dicho, pero no podía dejarla escapar 😉 Si buscáis algo más rockero ¡no os perdáis el tema apócrifo de Europe del mismo nombre!

En fin, Sun… sun… sun… here it comes 😉

Rock and Roll All Nite: ¡Nuevo Foro de SQL Server!

A lo mejor alguno de vosotros ya se ha fijado: los reyes magos nos han traído un nuevo foro a geeks.ms, que estará dedicado a SQL Server. Espero que podamos animarlo a base de curiosidades, puzzles de SQL, encuestas y como no, resolución de problemas; eso si, ¡espero que esta última categoría sea la menos frecuente!

Por tanto este post es un llamamiento a toda la comunidad de eseculeros (con perdón :P): Si tenéis problemas con un SQL Server cabezón que no quiere arrancar, o con uno que va mas despacito que mi amigo el pezuñas después de pulsar el botón que no debía, o simplemente queréis comentar alguna curiosidad del producto, no dejéis de hacerlo en el nuevo foro. Si no tenéis ninguna duda, ¡pasaros también para ayudarnos a los que podamos tenerlas! 😛

También me veo en la obligación moral de comentaros que seguramente no me pase por este nuevo foro durante unos días, ni termine el siguiente artículo sobre WinDbg; los reyes me han regalado un Guitar Hero para la Wii y hasta que no logre esto no dejare de practicar… por lo que estaré uno o dos días ocupadillo 🙂

Rock Tip:

Para la entrada de hoy no me he podido resistir a poner como Rock Tip el ‘Rock and Roll All Nite’, del album ‘Dressed to Kill’ de KISS. Primero, porque sale en el Guitar Hero. Segundo, porque ya era hora de poner un Rock Tip dedicado a los KISS, y por ultimo ¡porque es lo que tengo pensado hacer! ¡Rockanrolear toda la noche(*)! 😀

(*) ¡Con el guitar Hero! ¡Malpensaos! 😛

Teaser: Descubriendo WinDbg

Que triste será el día en que yo sea abuelo, y cuando mis nietos me pidan que les cuente mis locuras de juventud solo se me ocurran cosas como la noche en que algunos compañeros de Plain Concepts nos pusimos a crackear el buscaminas con el WinDdg a eso de las 2:00 am.

La verdad es que siempre he sido un poco raro para estas cosas: de pequeño no se me daba nada bien jugar a los juegos de plataformas, así que tiraba de SoftIce (el viejo, para DOS, de NuMega 🙂 ) y me dejaba matar algunas vidas, miraba a ver que direcciones de memoria seguían un patrón de decrecimiento, y cuando localizaba la dirección de memoria que almacenaba el número de vidas, lo ponía a FF, y voilá, 256 vidas 😉 ¡El proceso era más divertido muchas veces que el propio juego!

Supongo que debido a este oscuro pasado mío, mis ojos se abrieron como platos cuando descubrí la depuración postmortem de la mano,principalmente, de Nacho Alonso y David Salgado, y del resto de mis compañeros de Soporte en Microsoft, a los que les debo un buen cacho de lo que soy (¡¡un abrazote a todos!!). Desde ese momento me enganche al WinDbg, y hasta hoy me dura la tontería 😉

Espero poder dedicar algunas entradas de este blog a introducir el WinDbg, así como escenarios útiles (y no tan útiles! XD) de uso.

Que es el WinDbg

Microsoft pone a nuestra disposición (bajo licencia BTF, esto es, By The Face XD) las Debugging Tools for Windows, una suite de aplicaciones y documentación destinadas a la depuración en sistemas Windows. WinDbg es una de éstas herramientas: concretamente es un depurador que nos permite adjuntarnos a procesos de usuario y al kernel del sistema operativo (por tanto, soporta tanto user mode debugging como kernel mode debugging), que permite tanto la depuración en vivo (live debugging), que consiste en adjuntarse a un proceso que está en ejecución, como la depuración postmortem, mediante el análisis de volcados de memoria generados por la aplicación o el sistema operativo en momentos determinados. Y además de todo esto, ¡dispone de una interfaz gráfica! Bueno, o eso al menos dicen los de Redmond, porque muy gráfica la verdad es que no lo es 🙂 Os adjunto un pantallazo de una sesión de depuración:

 WinDbg1

Como podéis ver, la ventana de comandos parece cualquier cosa menos gráfica 🙂 Esto tiene una explicación: todos los depuradores de Microsoft tratan de mantener la compatibilidad a nivel de comandos. Si sabemos utilizar WinDbg, podremos saltar fácilmente a KD, CDB o NTSD, que son los depuradores de consola de Windows.

La diferencia mas notable entre el WinDbg y los otros tres depuradores comentados es la extensibilidad mediante módulos; algunos de las extensiones más conocidas son la Son of Strike (sos.dll), que nos permite depurar código administrado, y la SIEExtPub.dll, que entre otras cosas permite listar regiones criticas.

Un ejemplo: depurando el notepad.exe

Ok, ya sabemos lo que es el WinDbg, y sabemos donde encontrarlo, así que si os animáis, acompañadme en una demo muy corta para familiarizarnos con él. Simplemente vamos a adjuntar el depurador a un proceso existente, en este caso el notepad.exe.

Para empezar, nos descargamos las Debugging Tools for Windows y las instalamos en nuestra máquina. A continuación, arrancamos WinDbg.exe y, ta-dah!, ahí tenemos nuestro depurador gráfico 🙂

Ahora necesitaremos el proceso al que nos vamos a adjuntar (en inglés debugee), que será en este caso el notepad.exe. Vamos a abrir el notepad y simulamos que vamos a abrir un fichero; pulsamos Ctrl+O y nos aparecerá la ventana donde podemos seleccionar el archivo a abrir. Ok, con esto, sin cerrar esa ventana ni abrir ningún fichero, hemos terminado de preparar nuestro debuggee. Debería aparecer como la imagen siguiente:

winDbg2

Volvemos ahora al WinDbg, pulsamos F6 (que es el acceso rápido para adjuntarse a un proceso de la máquina) y nos aparecerá una ventana como la siguiente, donde podemos seleccionar el proceso al cual nos queremos adjuntar.

image

El checkbox que aparece en la parte inferior de la ventana con el nombre de Noninvasive es muy importante. No vamos a entrar en mucho detalle ya que es el primer artículo de la serie, pero os adelantaré que si ese checkbox no esta marcado, cuando cerremos la sesión de depuración el proceso depurado se cerrará también. Como veis, es un detalle muy importante, sobre todo si estamos trabajando en un servidor de producción: yo me se de alguno que se olvido de poner el modo no invasivo mientras depuraba un SQL Server en producción… titiriti, titiriti…. 😀

El otro detalle a destacar es que si bien los nombres del proceso ayudan, en muchas ocasiones no es suficiente para identificar el proceso exacto al que queremos adjuntarnos. Por ejemplo, si quisiéremos depurar una instancia concreta en un servidor con múltiples instancias, necesitaríamos recurrir al identificador del proceso (PID), ya que el nombre sería el mismo para todas las instancias (sqlservr.exe).

De todos modos, nosotros lo tenemos bien fácil en este caso: seleccionamos el notepad.exe y le damos al Ok. A continuación os aparecerá una ventana en la que se muestra un chorrazo de texto, que aunque no vamos a describir en detalle, os adelanto que es la lista de todos los módulos (ejecutable, dlls, etc) que conforman el proceso notepad.exe.

A partir de aquí el proceso a depurar esta detenido, y nosotros podemos empezar a lanzar comandos al WinDbg para analizar o modificar el proceso. Por ejemplo, si lanzamos el comando lm (acnonimo de List Modules) nos listará todos los módulos en memoria de ese proceso. A continuación os pongo un extracto de ésta salida en mi máquina:

0:011> lm
start             end                 module name
00000000`777d0000 00000000`77901000   kernel32   (deferred)             
00000000`77910000 00000000`779da000   USER32     (deferred)             
00000000`779e0000 00000000`77b5a000   ntdll      (export symbols)       C:Windowssystem32ntdll.dll
00000000`fffa0000 00000000`fffcf000   notepad    (deferred)             
00000001`80000000 00000001`80083000   sfShellTools64   (deferred)             
000007fe`f47d0000 000007fe`f4858000   tiptsf     (deferred)             
000007fe`f5c10000 000007fe`f62d2000   ieframe    (deferred)             
000007fe`f7080000 000007fe`f7178000   actxprxy   (deferred)             
000007fe`f7390000 000007fe`f73eb000   ntshrui    (deferred)             
000007fe`f73f0000 000007fe`f7442000   msshsq     (deferred)             
000007fe`f7530000 000007fe`f75d7000   cscui      (deferred)             
...          

Como se puede ver, tenemos un modulo que se llama notepad. Podemos tratar de visualizar todas las funciones que expone mediante el comando x. Este nos muestra una lista de todos los indentificadores (nombres de funciones, de variables…)de un modulo, o los que cumplan cierto criterio mediante una expresión regular. En el siguiente ejemplo vamos a pedir que nos muestre todos los identificadores del modulo notepad:

0:011> x notepad!*

*** ERROR: Module load completed but symbols could not be loaded for C:WindowsSystem32notepad.exe

Uuups, algo no está bien. Dice que faltan unos símbolos, y no nos muestra nada… bueno, vamos a ignorar de momento este mensaje. Fijaros simplemente en que la expresion que le pasamos fue <NombreModulo>!<expresionDeBusqueda>.

Vamos a intentar mostrar otra cosa interesante: los volcados de pila de todos los hilos del proceso. Para ello, nada mas simple que el terriblemente intuitivo comando ~*k. En mi máquina me ha devuelto 12 hilos, pero aqui voy a limitar la salida a un solo hilo:

0:011> ~*k

   0  Id: 1798.1548 Suspend: 1 Teb: 000007ff`fffdc000 Unfrozen
Child-SP          RetAddr           Call Site
00000000`000df348 00000000`7780ed73 ntdll!NtWaitForMultipleObjects+0xa
00000000`000df350 00000000`7792e96d kernel32!WaitForMultipleObjectsEx+0x113
00000000`000df460 000007fe`fccb1ab6 USER32!MsgWaitForMultipleObjectsEx+0x13d
00000000`000df500 000007fe`fccb371f DUser+0x1ab6
00000000`000df550 000007fe`fccb3696 DUser!DeleteHandle+0x7df
00000000`000df590 00000000`7791bd1a DUser!DeleteHandle+0x756
00000000`000df5c0 00000000`77a32016 USER32!CopyIcon+0x8a
00000000`000df610 00000000`7792df2a ntdll!KiUserCallbackDispatcher+0x1f
00000000`000df678 00000000`779173e9 USER32!WaitMessage+0xa
00000000`000df680 00000000`7791760a USER32!LockWindowUpdate+0x249
00000000`000df700 00000000`779174c6 USER32!DialogBoxIndirectParamAorW+0x19a
00000000`000df760 00000000`77917918 USER32!DialogBoxIndirectParamAorW+0x56
00000000`000df7a0 000007fe`fe473d2e USER32!DialogBoxIndirectParamW+0x18
00000000`000df7e0 00000000`fffa5146 COMDLG32!GetFileTitleW+0x121e
00000000`000df850 00000000`fffa547e notepad+0x5146
00000000`000df8c0 00000000`fffa5b98 notepad+0x547e
00000000`000df920 00000000`fffa6d33 notepad+0x5b98
00000000`000dfa50 00000000`7792e25a notepad+0x6d33
00000000`000dfaa0 00000000`7792cbaf USER32!GetWindowLongPtrW+0x13a
00000000`000dfb60 00000000`7792cdcd USER32!ReleaseDC+0x9f

   1  Id: 1798.310 Suspend: 1 Teb: 000007ff`fffda000 Unfrozen
Child-SP          RetAddr           Call Site
00000000`0304f528 00000000`7780ed73 ntdll!NtWaitForMultipleObjects+0xa
00000000`0304f530 00000000`7792e96d kernel32!WaitForMultipleObjectsEx+0x113
00000000`0304f640 000007fe`fccb1ab6 USER32!MsgWaitForMultipleObjectsEx+0x13d
00000000`0304f6e0 000007fe`fccb1aef DUser+0x1ab6
00000000`0304f730 000007fe`fccbe4ad DUser+0x1aef
00000000`0304f7a0 000007fe`fccbe3cc DUser!GetMessageExA+0x6d
00000000`0304f7f0 000007fe`fea994e7 DUser!RemoveGadgetProperty+0x59c
00000000`0304f880 000007fe`fea9967d msvcrt!_crtCompareStringW+0xf7
00000000`0304f8b0 00000000`7780cdcd msvcrt!beginthreadex+0x13d
00000000`0304f8e0 00000000`77a2c6e1 kernel32!BaseThreadInitThunk+0xd
00000000`0304f910 00000000`00000000 ntdll!RtlUserThreadStart+0x21

Si nos fijamos, podemos ver que algunos módulos, como kernel32, muestran los nombres de los métodos en cada frame de la pila, mientras que otros, como los de notepad, solamente nos muestran el nombre del módulo y un número hexadecimal al lado. Nuevamente, esto se debe a que no tenemos disponibles símbolos para el modulo notepad.exe (y muchos otros)….

Símbolos: Qué son, para qué nos sirven y dónde los conseguimos

¿Alguna vez os fijasteis en los ficheros de extensión .pdb que acompañan a vuestros binarios en la caperta bindebug? Pues si no los conocíais de antes, os los presento: son los símbolos de vuestro código. Su extensión es un acrónimo de Program Data Base, y su objetivo es servir de traducción entre direcciones de memoria u offsets dentro de un módulo y el nombre que se le ha dado a ese elemento durante el desarrollo, es decir, su identificador.

¿Y para que nos sirven? Precisamente para evitar lo que nos sucede en el ejemplo del notepad de arriba, en el cual no podemos ver casi ninguna información del módulo. A modo de ejemplo, imaginemos que tenemos libreria llamada matematicas.dll y un método dentro de ella llamado Sumar. Si tuviera los símbolos de ésta librería, desde WinDbg podria ver algo como matematicas!Sumar como nombre del método, pero si no tuvieramos los símbolos seguramente veríamos algo parecido a matematicas+0x1ab6, lo cual no nos da ninguna pista de lo que realiza ese método.

Para obtener los símbolos evidentemente hay que recurrir al desarrollador del producto. Si es un producto nuestro, tenemos que asegurarnos de tener los .pdb tanto para las versiones de debug como release (por defecto en Visual Studio, al compilar en modo release, no se generan los símbolos). Si se trata de un producto de terceros dependemos de que la empresa desarrolladora los distribuya. En el caso de Microsoft estamos parcialmente de enhorabuena, ya que gran cantidad de sus productos distribuyen los símbolos; eso si, una versión limitada de ellos, los llamados símbolos públicos.

WinDbg incorpora una gestión de símbolos muy avanzada, de modo que podemos montarnos nuestro propio servidor de símbolos en nuestro disco duro o en un directorio compartido de la red, lo cual es buena idea a medida que la colección va creciendo. Ya veréis como al final acabáis coleccionando símbolos como si fueran cromos 😀

En mi caso, tengo una carpeta local con los símbolos (C:Symbols), y en ella se descargan todos los símbolos que voy obteniendo. El propio WinDbg se encarga de ordenarla en directorios para que no haya problemas de versiones. Sin embargo, con la carpeta local no es suficiente, hay que especificar también servidores desde donde nos podamos descargar los símbolos que no tenemos. En este caso, solo os puedo dar uno, el servidor de símbolos públicos de Microsoft, que se encuentra en http://msdl.microsoft.com/download/symbols. Para especificar la ruta de símbolos podemos establecer la variable de entorno NT_SYMBOL_PATH o modificarla desde la interfaz de usuario del WinDbg (Ctrl+S o menú File -> File Symbol Path…). Para que no digáis que os hago pensar ni un poquitín, os dejo la cadena de símbolos que estoy utilizando para esta demo:

SRV*c:symbols*http://msdl.microsoft.com/download/symbols

Una vez establecido nuestro servidor de símbolos, volvamos a la demo…

… y de vuelta a WinDbg

Con nuestros símbolos en orden, vamos a forzar a WinDbg a que nos vuelva a cargar los módulos y busque por los símbolos apropiados. Para ello emplearemos el comando .reload, que carga los símbolos de nuevo, y le pasamos los parámetros /v (verbose, es decir, nos imprime información detallada de los símbolos durante el proceso de carga) y /f (fuerza la carga de los símbolos. Si no se especifica este parámetro, los símbolos se cargan de modo perezoso, solo cuando son necesitados). A continuación pongo un fragmento de la salida en mi máquina:

0:011> .reload /v /f
Reloading current modules
AddImage: C:Windowssystem32USER32.dll
 DllBase  = 00000000`77950000
 Size     = 000ca000
 Checksum = 000ce438
 TimeDateStamp = 45d3ee19
AddImage: C:Windowssystem32kernel32.dll
 DllBase  = 00000000`77a20000
 Size     = 00131000
 Checksum = 0013758a
 TimeDateStamp = 4549d328
AddImage: C:Windowssystem32ntdll.dll
 DllBase  = 00000000`77b60000
 Size     = 0017a000
 Checksum = 0017b5ee
 TimeDateStamp = 4549d372
AddImage: C:Windowssystem32notepad.exe
 DllBase  = 00000000`fffe0000
 Size     = 0002f000
 Checksum = 0003024b
 TimeDateStamp = 4549bb19
...

Podemos ver como se están cargando los módulos, sus direcciones base, tamaño de los módulos, etc. Si queremos obtener un listado de todos los módulos y su estado, podemos repetir el comando lm que ya lanzamos antes. Esta vez la salida será similar a esta:

0:011> lm
start             end                 module name
00000000`77950000 00000000`77a1a000   USER32     (pdb symbols) (...)
00000000`77a20000 00000000`77b51000   kernel32   (pdb symbols) (...)
00000000`77b60000 00000000`77cda000   ntdll      (pdb symbols) (...)
00000000`fffe0000 00000001`0000f000   notepad    (pdb symbols) (...)
...

Podemos ver que los módulos ya están cargados (en lugar de deferred, nos aparece la etiqueta pdb symbols, o export symbols, etc.). Vamos a tratar de realizar las dos pruebas de antes, esto es, consultar todos los identificadores expuestos por el modulo notepad, y listar los call stack de algunos hilos para hacernos a la idea de lo que hacen.

En el primer caso, volvemos a lanzar el comando x para consultar información expuesta por el modulo (podemos pensar que x viene de eXplore… estaremos equivocados, pero funciona como regla mnemotécnica :P). En mi máquina tengo la siguiente salida:

0:011> x notepad!*
(...)
00000000`ffff1600 notepad!PrintTime = <no type information>
(...)
00000000`fffe7564 notepad!AlertBox = <no type information>
00000000`ffff0630 notepad!szLoadDrvFail = <no type information>
00000000`fffe25f0 notepad!IID_IQuickFilterPriv = <no type information>
00000000`fffe10b8 notepad!_imp_GetTextExtentPoint32W = <no type information>
(...)
00000000`ffff0578 notepad!szUntitled = <no type information>
(...)

Si recordáis, antes de tener los símbolos cargados no obteníamos ninguna salida al ejecutar este comando, mientras que ahora tenemos una lista enorme con todos los identificadores del módulo. Imaginaros que nos interesa buscar todos los métodos relacionados con la acción de guardar el fichero; podemos intentar lanzar una consulta como la siguiente:

0:011> x notepad!*Save*
00000000`fffe635c notepad!CheckSaveTaskDlgBox = <no type information>
00000000`fffe5068 notepad!ShowOpenSaveDialog = <no type information>
00000000`fffe8268 notepad!SaveGlobals = <no type information>
00000000`fffe54c4 notepad!InvokeLegacySaveDialog = <no type information>
00000000`ffff1384 notepad!fInSaveAsDlg = <no type information>
00000000`fffe32f0 notepad!IID_IViewSaveRestriction = <no type information>
00000000`fffe24d0 notepad!IID_IFileSaveDialogOld = <no type information>
00000000`ffff20c0 notepad!szSaveFilterSpec = <no type information>
00000000`fffe4548 notepad!s_SaveAsHelpIDs = <no type information>
00000000`fffe17a0 notepad!IID_IFileSaveDialog = <no type information>
00000000`fffe55f4 notepad!InvokeSaveDialog = <no type information>
00000000`fffe24a0 notepad!IID_IFileSaveDialogPrivate = <no type information>
00000000`ffff20b0 notepad!g_ftSaveAs = <no type information>
00000000`fffe64c0 notepad!CheckSave = <no type information>
00000000`ffff0620 notepad!szSaveCaption = <no type information>
00000000`fffe7a90 notepad!NpSaveDialogHookProc = <no type information>
00000000`fffe17e0 notepad!CLSID_FileSaveDialog = <no type information>
00000000`fffe33c0 notepad!CLSID_ScreenSaverPage = <no type information>
00000000`fffe9e00 notepad!SaveFile = <no type information>
00000000`fffe1050 notepad!_imp_GetSaveFileNameW = <no type information>

Ahora vamos a comprobar como se ven la pila de llamadas de un hilo del proceso:

0:011> ~*k

   0  Id: ff4.6cc Suspend: 1 Teb: 000007ff`fffdc000 Unfrozen
Child-SP          RetAddr           Call Site
00000000`0010f288 00000000`77a5ed73 ntdll!NtWaitForMultipleObjects+0xa
00000000`0010f290 00000000`7796e96d kernel32!WaitForMultipleObjectsEx+0x10b
00000000`0010f3a0 000007fe`fcf31ab6 USER32!RealMsgWaitForMultipleObjectsEx+0x129
00000000`0010f440 000007fe`fcf3371f DUser!CoreSC::Wait+0x62
00000000`0010f490 000007fe`fcf33696 DUser!CoreSC::WaitMessage+0x6f
00000000`0010f4d0 00000000`7795bd1a DUser!MphWaitMessageEx+0x36
00000000`0010f500 00000000`77bb2016 USER32!_ClientWaitMessageExMPH+0x1a
00000000`0010f550 00000000`7796df2a ntdll!KiUserCallbackDispatcherContinue
00000000`0010f5b8 00000000`779573e9 USER32!ZwUserWaitMessage+0xa
00000000`0010f5c0 00000000`7795760a USER32!DialogBox2+0x261
00000000`0010f640 00000000`779574c6 USER32!InternalDialogBox+0x134
00000000`0010f6a0 00000000`77957918 USER32!DialogBoxIndirectParamAorW+0x58
00000000`0010f6e0 000007fe`fe623d2e USER32!DialogBoxIndirectParamW+0x18
00000000`0010f720 00000000`fffe5146 COMDLG32!CFileOpenSave::Show+0x143
00000000`0010f790 00000000`fffe547e notepad!ShowOpenSaveDialog+0xde
00000000`0010f800 00000000`fffe5b98 notepad!InvokeOpenDialog+0x136
00000000`0010f860 00000000`fffe6d33 notepad!NPCommand+0x380
00000000`0010f990 00000000`7796e25a notepad!NPWndProc+0x55b
00000000`0010f9e0 00000000`7796cbaf USER32!UserCallWinProcCheckWow+0x1ad
00000000`0010faa0 00000000`7796cdcd USER32!DispatchClientMessage+0xc3
(...)

Ahora, a diferencia de cuando los símbolos no estaban cargados, podemos ver mucha mas información en la pila de llamadas, como los nombres de los métodos del módulo de notepad que antes no veíamos. Podemos ver que este hilo en cuestión invoca la ventana para abrir o guardar un fichero, mediante las llamadas a InvokeOpenDialog en notepad, y posteriormente la llamada al método Show de un CFileOpenSave en el modulo COMDLG32, que a su vez llama a… no sigo, que creo que se entiende suficientemente bien y ya me voy cansando 🙂

En fin, con esto hemos dado un repaso general a WinDbg, aunque no hemos hecho nada mas que rascar la superficie. No os preocupéis por los comandos, por las pilas de llamadas ni por nada mas, lo iremos viendo con calma en los siguientes posts (¡si es que os interesan!). Me conformo por ahora con que hayáis podido abrir el WinDbg, adjuntaros a un proceso y comprendido la importancia de los símbolos.

Conclusiones:

En este post hemos comentado las herramientas principales que vamos a emplear, hemos hablado de los símbolos y hemos realizado nuestra primera sesión de depuración con WinDbg: no esta mal. Pero venga… se que lo estáis pensando. A no ser que seáis muy apasionados del bajo nivel, o que tengáis mucho tiempo libre, os estaréis preguntando ¿Para que quiero yo saber todo esto? Pues allá van algunas razones que considero que pueden justificar el pelearse con el WinDbg:

  • Si nuestro sistema nos muestra una pantalla azul de la muerte, podemos tratar de analizar el minidump (volcado de memoria de pequeñas dimensiones) que nos genera con WinDbg para determinar que módulo fue el causante del error. Así podemos determinar si el problema se originó en el controlador de disco, de vídeo, en el propio kernel, etc.
  • Ciertas aplicaciones, como SQL Server, generan volcados de memoria cuando suceden eventos inesperados, errores, etc. Mediante WinDbg podemos intentar acercarnos al origen del problema, aunque sin los símbolos apropiados (y estos símbolos son, generalmente, privados) será muy dificil profundizar en la investigación. No obstante, al menos tendremos cierto conocimiento de como capturar volcados, que nos facilitará la tarea de colaborar con los servicios de soporte de Microsoft.
  • Jugando con WinDbg aumentamos notablemente nuestro conocimiento de la plataforma sobre la que trabajamos, lo cual siempre es positivo. De echo, esta es la razón que personalmente mas me motiva y por la que sigo jugando siempre que puedo con depuradores 🙂
  • Tu última sesión de depuración siempre es un buen tema de conversación para esos ratos de cervezas con los colegas… XD
Rock Tip:

Como el artículo de hoy es tan solo una pequeña introducción a lo que espero que sea una serie de artículos sobre WinDbg y depuración en general, el tema ‘Teaser‘, de Yngwie J. Malmsteen, me viene que ni pintado.

Para los que no le conozcáis, el señor Malmsteen es uno de los guitar heroes más conocidos, un virtuoso de corte neoclásico con igual número de seguidores que de detractores (los detractores son por pura envidia cochina xD). Si bien no es mi guitarrista favorito, he de admitir que sus discos mas ochenteros me llegan al alma. Dentro de este estilo os recomendaría especialmente el Eclipse (NOTA: Este link NO lleva a ningún IDE extraño… ¡¡siempre seré fiel a mi Visual Studio!!).

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 🙂

Love Lies: Bye, Bye, Notification Services

Creo que a veces todos nos hemos sentido atraídos o fascinados por una característica o producto que parece no levantar pasiones a nadie más. Intentamos convencer a nuestros amigos, compañeros y clientes de sus bondades, pero finalmente hemos de admitir que somos los únicos en comprenderlo o valorarlo (o en estar terriblemente ciegos y no ver que el producto apesta xD).

Eso es lo que me ha sucedido con SQL Server Notification Services. Lo he presentado en la práctica totalidad de las sesiones que he impartido sobre SQL Server 2005, he realizado las demos, y creía que los asistentes veían su utilidad… pero no debió ser así, ya que aparentemente no ha tenido muy buena acogida. Por ello, Microsoft ha anunciado su discontinuidad en SQL Server 2008.

Por supuesto, Microsoft seguirá soportando Notification Services de SQL Server 2005, al menos hasta que el soporte de SQL Server 2005 finalice, por lo que no debe alarmaros la noticia si sois alguno de los clientes que lo emplean actualmente en producción.

No es que fuera mi parte favorita del SQL Server, pero le tenía cariño 🙂 Pero, como dicen por ahí, a Rey muerto Rey puesto: tengo tantos ‘juguetes’ nuevos para jugar con SQL Server 2008 que en en breves me olvidaré del ya ol’ good NS 🙂

Rock Tip:

Para hoy, ‘Love Lies’, temazo del primer disco de los alemanes Casanova. La letra habla de cuando un amor se acaba por la ausencia de alguna de las partes, y como os digo, es un poco lo que sucede en este caso…

No os puedo poner esta vez un link a un vídeo, ni a la letra, ni a biografía del grupo… porque no los localizo! Como podéis ver, el disco es bastante complicado de conseguir, y ciertamente no se trata de un grupo muy conocido, pero si os gustan los medios tiempos en la onda de Europe, Bon Jovi y demás, no dejéis de buscarlo para pegarle un orejazo.