Poco a poco va siendo más habitual encontrarse SQL Server ejecutando en contenedores sobre Linux. Aunque sigue siendo mayoritario su uso en entornos de desarrollo y pruebas no es raro también encontrarnos con ciertos problemas en dichos entornos y la tendencia, como ya pasó en su día con la virtualización, es culpar “al nuevo”.

Cuando nos planteamos el uso de Kubernetes y sus container runtime (containerd, Docker, etc.) es muy importante realizar una buena gestión de expectativas. Cuando hablamos de Kubernetes, no vienen naturalmente asociadas palabras como “performance” o “fast” asociadas a dicho término. Tampoco parecen ser conceptos que se promocionen como características de Kubernetes en su página principal:

uso de kubernetes

Sin embargo sí vemos presentes otros conceptos como “horizontal scaling” o “self-healing” que sí me vienen naturalmente a la cabeza cuando pienso en Kubernetes.

Con esto no quiero decir que un SQL Server dentro de Kubernetes no pueda tener un buen rendimiento y ser rápido, simplemente que son factores que quizás no vamos a obtener “por defecto” en configuraciones estándar. En definitiva cuando nos movemos en este tipo de entornos es necesario entender bien cómo funcionan, que recursos tenemos realmente “por debajo” para poder así poder analizar los problemas de rendimiento cuando aparezcan y, especialmente, transmitir tanto a desarrolladores, arquitectos, managers, etc. unas expectativas realistas sobre qué esperar de SQL Server en Kubernetes.

En la mayoría de entornos lo que tenemos es algo parecido a esto:

Matar al mensajero – SQL Server en Kubernetes (Parte 1)

Básicamente tenemos definida una aplicación, con un servicio que es el que nos permitirá conectarnos a nuestro SQL Server y un conjunto de nodos que nos darán la alta disponibilidad básica que esperaríamos en estos entornos. Nuestra instancia de SQL Server vivirá dentro de un pod el cual podrá “levantar” en cualquiera de los nodos. Por hacer una analogía, nuestro pod sería el equivalente a una máquina virtual y nuestros nodos serían como los hosts dentro de un cluster de virtualización Hyper-V, VMware, Xen, etc.

Si tenemos un fallo en el nodo donde ejecuta nuestro pod, Kubernetes lo detectará como “no sano” y lo levantará en otro nodo disponible:

fallo en el nodo

Una forma rápida de poder ver algunos de los escenarios habituales es creando un cluster de Kubernetes manejado en Azure. El servicio Azures Kubernetes Service (AKS) nos ofrece una forma sencilla de crear un cluster Kubernetes. Una vez tenemos el cluster creado, podremos desplegar nuestro SQL Server en un pod y acceder a él:

properties
Matar al mensajero – SQL Server en Kubernetes (Parte 1)
nodepool

Los requisitos y enlaces a las instrucciones para montar un entorno como este las tenéis muy bien detalladas aquí.

Una vez tenemos el entorno anterior montado, podemos conectar a él mediante una IP pública en el 1433:

ip publica

A continuación vamos a lanzar unas operaciones T-SQL que testeen el rendimiento de CPU en modo single thread, en paralelo, hagan algunas escrituras en serie, etc.

Comenzando por el rendimiento de CPU en single thread, podemos lanzar una consulta similar a la siguiente, que nos devolverá el tiempo necesario para hacer un conteo de un cross join con bastantes filas ejecutando sin paralelismo:

DECLARE @time datetime=getdate()
DECLARE @count bigint
select @count=COUNT_BIG(*) from (select top 50 * from sys.objects) s1,(select top 50 * from sys.objects) s2,(select top 50 * from sys.objects) s3, (select top 50 * from sys.objects) s4, (select top 50 * from sys.objects) s5, (select top 50 * from sys.objects) s6, (select top 5 * from sys.objects) s7 OPTION (MAXDOP 1)
select datediff(ms, @time,getdate()),@count
 

Como entorno con el que comparar, utilizaré una máquina virtual local donde tengo un SQL Server 2019. Estos son los resultados obtenidos:

Matar al mensajero – SQL Server en Kubernetes (Parte 1)

A continuación vamos a probar con una consulta que se ejecutará en paralelo y consumirá una buena cantidad de CPU:

SELECT s1.name into #temp FROM (select top 50 * from sys.objects) s1,(select top 50 * from sys.objects) s2, (select top 50 * from sys.objects) s3
DECLARE @time datetime=getdate()
DECLARE @count bigint
select @count=COUNT_BIG(*) from #temp t1
inner loop join (select top 10000 * from #temp) t2 on t2.name=t1.name
select datediff(ms, @time,getdate()),@count
 

Estos son los resultados con esta consulta que depende del rendimiento de CPU paralelo principalmente:

Matar al mensajero – SQL Server en Kubernetes (Parte 1)

Podemos ver que en ambos casos el tiempo es aproximadamente 2.5 veces mayor en AKS. Los nodos del cluster de Kubernetes son máquinas virtuales E8s v3 contando por tanto con 8 cores y 64 GB de RAM cada uno. En la documentación podemos ver que por debajo podemos tener una variedad de procesadores pero que se caracterizan por un ACU entre 160 y 190:

Matar al mensajero – SQL Server en Kubernetes (Parte 1)

Esta medida ACU (Azure Compute Units) intenta darnos una idea del rendimiento aproximado por core que podemos obtener. Por ejemplo para SQL Server resulta muy interesante una de las últimas series añadidas, las FX-series. Estas máquinas FX tienen un rendimiento por core prácticamente el doble que las anteriores gracias a su frecuencia de trabajo es de 4 GHz. Esto va a beneficiar mucho a las cargas que dependan de un buen rendimiento por core. Si además añadimos que tenemos además 21 GB de RAM por core las hace una excelente opción para entornos exigentes SQL Server:

fx series

Pero, ¿Realmente es tan importante esta diferencia?

Debemos tener claro que tipos de máquinas decidimos utilizar para nuestro cluster de AKS ya que las diferencias de rendimiento “por core” pueden  ser muy importantes. En este caso concreto de la diferencia total de 2.5 veces podríamos justificar hasta 2 veces únicamente por el procesador y su frecuencia de trabajo. Por tanto es importante que cuando comparemos estos escenarios intentemos igualar el hardware en rendimiento por core ya que si igualamos hardware las diferencias serán mucho menores. Si no deseamos utilizar este tipo de máquinas deberemos intentar utilizar esta medida ACU para calcular si, proporcionalmente, el rendimiento de CPU está en línea de lo esperado.

No olvidemos que el rendimiento de SQL Server en muchas operaciones depende de dicho rendimiento “por core” y, aunque no sea así en todos los casos, debemos tener en cuenta que el coste de SQL Server es “por core” por lo que cuantos menos cores utilicemos, menor será el coste total. Este argumento suele entenderse por la parte de negocio bastante mejor que las diferencias de frecuencia o de microarquitectura ya que nos afectará directamente al coste de la solución.

Conclusión

En esta primera parte hemos explicado en qué consiste un SQL Server en contenedores y hemos mostrado una forma sencilla de crear un entorno Kubernetes manejado donde ejecutar nuestro SQL Server dentro de un contenedor. En la siguiente parte vamos a enfocarnos en los escenarios más críticos donde el uso de contenedores puede añadirnos latencias y esperas extras que acaben impactando en el rendimiento percibido por nuestros usuarios tras una migración de SQL Server a contenedores.

¡Sigue Aprendiendo!

Si quieres que te ayudemos a poner en marcha este tipo de proyecto, no dudes en contactar con nosotros. También puedes aprovechar las formaciones existentes para ampliar tus conocimientos 👇🏼

>> Más info
0 Shares:
Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

You May Also Like