Si no considero las 3 horas que dormí del viernes al sábado, podría decir que llevo casi 48 horas despierto, o que llevaba hasta hoy en la mañana ya que pude dormir 5 horas más de 6 a 11 am (hoy es domingo en la tarde). ¿Cómo tanto?. La primera trasnochada fue por una fiesta de la oficina. La segunda, por un visita fugaz a un cliente en apuros. Mi día sábado fue extenuante y estresante para mi familia, cumpleaños, visitas, compra de pasajes, arreglo de taxis, reservas hoteleras, información adicional, ajustar otros viajes, una locura.
Menos detalles aburridos y vamos al caso
El escenario era similar al descrito a continuación:
Aplicaciones COM+ configuradas por defecto, salvo que algunas de ellas estaban configuradas con diferentes identidades (usuario que será utilizado para ejecutar la aplicación Com+). Las opciones disponibles para identidad son Interactive, Local Service, Network Service o uno específico.
Después de un par de días funcionando, cualquier aplicación COM+ que no estuviese funcionando y era requerida, fallaría al levantarse
Si la aplicación no había sido detenida durante todo el período de tiempo, seguiría funcionando sin problemas, aún cuando otras aplicaciones no pudiesen levantarse.
Si esta aplicación dejaba de ser requerida por más de 3 minutos (valor por defecto) y era bajada, un nuevo requerimiento trataría de levantarla y fallaría.
Claramente no estábamos en presencia de algún problema de código ya que en ese caso, habría fallado siempre. Y más aún, nadie había hecho ningún cambio en los componentes en bastante tiempo.
Investigación del problema
Como en cualquier actividad de resolución de problemas, lo PRIMERO que hay que mirar es el event viewer o visor de sucesos (en español).
Dos tipos de eventos llamaban la atención sutilmente. No habían muchos registros de ellos, pero estaban en el momento adecuado, en el lugar adecuado.
Uno de los eventos estaba en el mismo momento cuando empezaban los problemas. El mensaje era el siguiente.
Failed to create a desktop due to desktop heap exhaustion
Adicionalmente, otros tres eventos habían ocurrido uno de estos días, los que terminaron de aclarar la situación. Este evento el 2019:
Event ID 2019: “The server was unable to allocate from the system nonpaged pool because the pool was empty.”
Serie de preguntas y respuestas
Ingeniero, es decir, yo [:)]: ¿Configuraron /3GB en boot.ini?
Contraparte: Si
Ingeniero: ¿y configuraron userva?
Contraparte: No
Ingeniero: mmm…interesante
…
Ingeniero: ¿Cómo andan las PTEs?
Ingeniero: perfmon -> Memory -> Free System Page Table Entries (PTEs) –> cercano a 2.000 … ouch
Conclusión
El Kernel se quedó sin memoria.
¿Ahh?…bajémoslo a la tierra.
En una arquitectura de 32 bits, la memoria virtual es un recurso medianamente escaso. No vamos a hablar de la cantidad memoria física del servidor. Si bien, mientras más memoria mejor, el problema a describir ahora no depende totalmente de la cantidad de memoria del servidor, ya que o bien tengas 2 o 20 GB, se presentará igual.
Con 32 bits, la memoria virtual, que tampoco tiene que ver con la memoria paginada en disco, está restringida a 4GB por aplicación. El valor 4GB se obtiene al elevar 2 a 32, o 2^32.
De esos 4 GB virtuales, 2 GB son usados por un proceso y los otros 2 por el kernel. Cada aplicación tendrá sus 2 GB virtuales y compartirán los 2 GB de kernel. Debido a esto último, algunos de ustedes recordarán haber visto en Task manager que un proceso nunca pasa de 1,7 o 1,8 GB. Bueno, la explicación es esa. Una aplicación no puede usar más de 2 GB de memoria virtual.
Existe un switch para que sí lo haga, pero con su consecuencia. Este switch se configura en el archivo boot.ini, y corresponde a la opción /3GB.
El impacto de la aplicación de éste es que del espacio virtual de 4 GB, 1 GB pasa de memoria de kernel a memoria de proceso de usuario. Entonces ahora un proceso de usuario puede llegar a usar 3 GB y el kernel queda drásticamente reducido a 1 GB.
SQL Server, Exchange, COM+ y los Application pool de IIS son algunos de los procesos que tomarán ventaja de este cambio y podrán llegar a 2,7 u 2,8 GB de memoria usada, lo que representa un incremento del 50%, y que tiende a ayudar bastante en algunos casos, pero en otros, produce problemas si no se usa adecuadamente (como éste).
¿El problema?
El kernel necesita memoria para poder funcionar, y 1 GB virtual no es suficiente en algunos casos. En el kernel se cargan drivers, el manejador de memoria, de procesos, controladores gráficos, el HAL, manejo de plug & play y otras tareas.
Además, el kernel maneja dos pool de memoria, uno llamado paginable y el otros no paginable. En ingles, paged pool y nonpaged pool respectivamente. ¿Recuerdan el evento 2019? Vuelvan a leer la descripción.
Al aplicar el switch /3GB, el tamaño de estos pools se reduce a la mitad, pudiendo entonces en determinados casos agotarse y poner en riesgo el servidor. Si el kernel no es capaz de obtener memoria de estos pools, varios problemas pueden ocurrir, a saber:
Problemas de interfaz grafica, en donde ésta no responde adecuadamente
Problemas de funcionamiento de algunos procesos, para nuestro caso, las aplicaciones COM+ no levantan.
Falla en procesar requerimientos vía red
Al aplicar /3GB se reduce también la cantidad de PTEs disponibles, lo que generará problemas con los requerimientos de IO, entre otros.
Identidades de aplicaciones
Complementando lo anterior, si recuerdan, en un inicio hablamos de las identidades de las aplicaciones COM+.
Este tópico no lo comprendo a cabalidad, pero puedo decir (con temor a equivocarme) que cada aplicación que es iniciada con un usuario diferente, requerirá que el sistema operativo cargue ciertos componentes para el usuario (desktop). Estos componentes incluyen:
Menús del sistema
Ventanas
Otra información.
Entonces, si tengo aplicaciones COM+ configuradas con X usuarios, podría llegar a cargar X desktops. ¿De donde se obtiene la memoria para cargar estos desktops? De la memoria del kernel.
Como sé que la información que acabo de entregar del tópico de Desktops es bastante limitada, prefiero incluir un link donde esta MUCHO mejor descrita. Aunque está en inglés, no está difícil. El link es http://blogs.msdn.com/ntdebugging/archive/2007/01/04/desktop-heap-overview.aspx.
Solución
Si tu aplicación no hará uso de 3GB, no incluyas la opción. No será necesaria.
Si tienes alguno de los servicios que mencioné antes y necesitas usarlo, deberás entonces usar además la opción userva en el archivo boot.ini.
Userva se utiliza para “mover” un poco de memoria de proceso de usuario a kernel. Realmente no mueve nada, pero el efecto final es que en vez de tener 3GB de usuario y 1GB de kernel, puedes configurar 2,7 GB y 1,3GB respectivamente, lo que ayudará a mitigar el problema, y en la gran mayoría de los casos, desaparecerá totalmente.
El KB referenciado al final muestra como configurarlo. Si bien dice que se deberá probar entre 2900 y 3030, si es necesario para tu sistema, podrás llegar a un valor menor. Mayores valores no tienen sentido.
Si estas usando SQL Server, utiliza mejor AWE por sobre 3GB. No expondrás el kernel a estos problemas.
Adicionalmente, estos links te podrán proveer mas información:
http://technet.microsoft.com/en-us/library/7a44b064-8872-4edf-aac7-36b2a17f662a.aspx
http://support.microsoft.com/kb/316739
Este otro está curioso: http://xentelworker.blogspot.com/2005/10/i-open-100-explorer-windows-and-my.html
Saludos,
Patrick.