Una pieza clave de SharePoint son los Timer Jobs, existiendo por defecto gran cantidad de ellos (ej: Immediate Alerts, Profile Sync, Variations, Workflows, etc) que se ejecutan cada pocos minutos sobre cada una de las Bases de Datos, lo cual puede provocar que nuestros servidores SharePoint puedan alcanzar el máximo número de puertos TCP dinámicos que pueden abrir: Port Exhaustion
Cada vez que un servidor SharePoint se conecta a SQL Server establece una conexión (socket TCP), desde un puerto dinámico en el servidor SharePoint (proceso cliente) al puerto de la instancia SQL Server (proceso servidor). Lo mismo ocurre cuando un servidor SharePoint necesita invocar a un Web Service, y así en muchos otros casos.
Existe un rango por defecto para los puertos TCP dinámicos que pueden ser utilizados para iniciar un Socket TCP desde un proceso cliente a un proceso servidor. Este rango por defecto depende de cada Sistema Operativo, y en caso de agotarse, si no quedan puertos libres no podremos establecer ningún nuevo Socket TCP (como si el servidor se hubiese quedado aislado en la red), una situación conocida como Port Exhaustion, que ya nos encontramos hace un tiempo (Data Collector, SQL Server 2008 R2, FileServer, Cluster, errores de conexión, y Sockets en TIME_WAIT).
Describiendo un Escenario de Ejemplo
Hace poco me encontré con un caso muy sospechoso de estar sufriendo Port Exhaustion, como consecuencia de un alto número de Bases de Datos de Contenido: un servidor SharePoint Server 2007 x64 sobre Windows Server 2003 junto con otro servidor SQL Server 2005 sobre Windows Server 2003 x64, con aproximadamente 450 Bases de Datos de Contenido (la mayoría de un tamaño bastante pequeño).
Lo primero que deberemos tener en cuenta, es que el rango por defecto para puertos TCP dinámicos en Windows Server 2003 es desde el 1025 al 5000, por lo tanto, estamos hablando de aproximadamente 4000 sockets.
Este comportamiento por defecto se puede cambiar a través de la clave de registro MaxUserPort en la rama HKLM\CurrentControlSet\Services\Tcpip\Parameters, que podemos establecer a un valor superior de 5000 para así ampliar el rango por defecto de puertos TCP dinámicos. Sin embargo, esta clave de registro no estaba establecida.
Al ejecutar el comando NETSTAT -ano en el servidor SharePoint, en muchas ocasiones había casi 4000 sockets establecidos, y además:
- La mayoría de los sockets correspondían a conexiones a SQL Server.
- La mayoría de los sockets estaban en estado TIME_WAIT.
- En la mayoría de los sockets en estado TIME_WAIT, el proceso origen era el Windows SharePoint Services Timer.
Otro detalle que pude observar, es que había muchas conexiones concurrentes a SQL Server desde el proceso Windows SharePoint Services Timer, que estaban en estado SLEEPING y eran bastante antiguas, ya no sólo por la fecha de conexión, sino porque la fecha del último Batch era de hace semanas o incluso meses, algo que se puede consultar fácilmente con un SELECT * FROM SYSPROCESSES. Sockets TCP abiertos que parecía que no se estaban utilizando para absolutame
nte nada.
Cómo reproducir este escenario
Una forma de reproducir este escenario, en cierto modo, podría ser la siguiente:
- Reiniciar el servicio Windows SharePoint Services Timer, esperar unos 10 minutos, y comprobar las conexiones concurrentes a SQL Server existentes desde este servicio.
- Crear 400 Colecciones de Sitios, cada una en su propia Base de Datos de Contenido, por ejemplo, utilizando el comando STSADM -createsiteinnewdb
- Reiniciar el servicio Windows SharePoint Services Timer, esperar unos 10 minutos, y comprobar las conexiones concurrentes a SQL Server existentes desde este servicio. Podremos observar que hay muchas más conexiones que antes.
- Quitar de SharePoint las Bases de Datos de Contenido que hemos creado (y en consecuencia, las Colecciones de Sitios existentes en su interior).
- Crear 4 Bases de Datos de Contenido (ej: utilizando el comando STSADM addcontentdb), y seguidamente crear 400 Colecciones de Sitios (ej: utilizando el comando STSADM createsite) repartidas entre estas 4 Bases de Datos.
- Reiniciar el servicio Windows SharePoint Services Timer, esperar unos 10 minutos, y comprobar las conexiones concurrentes a SQL Server existentes desde este servicio. Podremos observar que hay muchas menos conexiones a SQL Server que teniendo las mismas Colecciones de Sitios utilizando más Bases de Datos.
- Quitar de SharePoint las Bases de Datos de Contenido que hemos creado (y en consecuencia, las Colecciones de Sitios existentes en su interior), para dejar el entorno limpio.
Esta es una forma de ver las conexiones a SQL Server que creará el Windows SharePoint Services Timer para la ejecución de los Timer Jobs de SharePoint, y de este modo, comprobar que con el mismo número de Colecciones de Sitios, al utilizar menos Bases de Datos de Contenido minimizaremos el número de conexiones concurrentes a SQL Server.
Hay que tener en cuenta, que en un entorno real (Producción) existirán más conexiones, como es el caso de las peticiones de los usuarios, etc., que no estamos modelando como parte de esta prueba.
Plan de Acción
Ante esta situación había que preparar un Plan de Acción, que solucionase los problemas que se estaban produciendo, o en todo caso, que al menos minimizasen su impacto. Dicho Plan de Acción consistía en:
- Cambiar la Planificación de algunos Timer Jobs. Es posible cambiar la Planificación de algunos Timer Jobs, de tal modo que en lugar de ejecutarse cada 5 minutos, se ejecuten cada 10 minutos (por poner un ejemplo), o en lugar de ejecutarse cada minuto se ejecuten cada 5 minutos. Muchos de estos Timer Jobs se ejecutarán para cada Base de Datos de Contenido, por lo tanto, al cambiar su Planificación, minimizaremos el número de conexiones a SQL Server que se realizan a lo largo del día.
- Matar (Kill) las conexiones antiguas a SQL Server que no están siendo utilizadas (último Batch de hace varios días). Debido a que detectamos 800 conexiones antiguas no utilizadas, preparamos un Job en SQL Server con un cursor sobre SYSPROCESSES que utilizaba SQL Server Dinámico para hacer un Kill a las conexiones SQL Server antiguas desde SharePoint que estén en estado SLEEPING con fecha de último Batch de hace varios días. Este Job lo planificamos para su ejecución diaria, fuera del horario de negocio.
- Minimizar el número de Bases de Datos de Contenido, almacenando en cada base de datos varias Colecciones de Sitios. Y por último, la principal medida: reducir el número de Bases de Datos de Contenido. Dado que muchas Colecciones de Sitios eran muy pequeñas y estaban utilizando una Base de Datos de Contenido en exclusiva para ellas, decidimos estudiar la mejor forma de agruparlas, de tal modo que en lugar de tener varios cientos de Bases de Datos de Contenido muy pequeñas, tuviésemos unas pocas Bases de Datos de Contenido, en las cuales se almacenasen varias Colecciones de Sitio, minimizando así el número de Bases de Datos de Contenido, el número de conexiones a SQL Server, y en general el rendimiento de la plataforma.
Realizado esto, se minimizaron el número de conexiones concurrentes a SQL Server, y desaparecieron los problemas que se estaban sufriendo sobre esta plataforma.
Despedida y Cierre
Los Problemas de Rendimiento en SharePoint no son siempre tan obvios. Hace poco comentamos algunos temas de Rendimiento y Theading en SharePoint (IIS Deadlocks, Rendimiento, Threads y SharePoint), y en esta ocasión hemos querido mostrar otra de las caras que puede tener este tipo problemas de Rendimiento en SharePoint, en el caso de trabajar con muchas Bases de Datos de Contenido.
Por último, aprovecho parar incluir algunos enlaces de interés:
Poco más por hoy. Como siempre, confío que la lectura resulte de interés.