Optimizando el coste de nuestro Cosmos

Quizás uno de los servicios más caros que ofrece Azure sea Cosmos DB, un servicio que reúne diversas bases de datos no relacionales con una multitud de características que la convierten en una de las mejores del mercado. Sin embargo, ¿realmente es tan caro para implementarlo en todos los proyectos, o quizás no lo es tanto? En este artículo, intentaremos ofrecer una serie de consejos para comprender mejor todo lo que Azure nos ofrece y así poder pagar lo necesario en nuestro desarrollo.

¿Por qué se nos cobra en Cosmos DB?

Las Bases de Datos de Cosmos se facturan en función de lo que conocemos como Request Unit, o RU en adelante. Las RU representan el costo de los recursos de procesamiento necesarios para ejecutar operaciones en la base de datos, como leer, escribir y actualizar datos. Cada operación que se realiza consume una cierta cantidad de RU. Naturalmente, no todas las operaciones cuestan lo mismo; por ejemplo, una operación de lectura del primer elemento costará menos RU que una actualización de un registro completo. Estas RU son utilizadas para dimensionar y administrar la capacidad de rendimiento de nuestra base de datos. Por lo tanto, es crucial comprender su importancia al elegir el modo de capacidad de la base de datos, así como si deseamos ajustar el Throughput compartido entre todas las colecciones de la base de datos o si cada colección debe tener su provisión de forma independiente.

El primer paso y elección es indicar si vamos a tener un rendimiento aprovisionado o Serverless. Aunque la pregunta parece sencilla, no lo es tanto. Generalmente, todo lo que tenemos en la nube lo queremos en modo Serverless; no queremos administrar nada del servidor, ni preocuparnos por nada, y que nos cobren por lo que estamos utilizando. ¿No es ese el sueño perfecto? A nivel de marketing, suena muy bien, pero siempre conviene leer las características del servicio. El modo Serverless no asigna una capacidad de RU, lo que significa que si experimentamos una carga de trabajo imprevisible, nuestra base de datos puede quedarse sin recursos para ejecutarla. Además, el servicio está vinculado a una única región de Azure, lo que significa que si esa región falla, también quedaremos sin servicio. El rendimiento de la base de datos en este modo también tiene un valor más elevado en las escrituras que el modo normal. ¿Cuál es la conclusión? No deberíamos usar el modo Serverless. Ni siquiera en entornos no productivos. Puedo enumerar muchas razones:

  1. Desde un punto de vista técnico, la base de datos no se comporta igual que en un entorno productivo, por lo que asegurar su comportamiento en producción no es algo en lo que pueda confiarse.
  2. Desde un punto de vista del producto, no vamos a ahorrar costes. Basta con hacer bien el ejercicio siguiente para ajustar las RU y adaptarlas a nuestras necesidades, y aquí radica la clave del coste.

NOTA: Seguramente a muchos les haya pasado como a mí, que este modo les ha resultado una pequeña decepción. Pero hay que pensar que al final, Microsoft es una empresa que quiere ganar la mayor cantidad de dinero posible, y si hiciera este trabajo, probablemente los especialistas como tú y yo nos quedaríamos sin empleo. Así que tomémoslo como una oportunidad en lugar de una crítica.

¿Qué tipo de Throughput elegimos?

El tipo de escalado que elijamos dependerá principalmente de nuestro desarrollo. Dependiendo del mismo, elegir una opción u otra será la mejor alternativa. Es importante tener en cuenta que una vez elegido el nivel de RU, ya sea a nivel de Base de Datos o de colección, no se puede modificar, a menos que volvamos a crear la base de datos (con todo lo que ello implica, como migración de datos, posible parada del servicio, etc.).

Para ello, es importante tener en cuenta que el valor mínimo que podemos establecer para una colección son 400 RU. Esto es crucial porque, dependiendo de cómo se utilice esta colección, podemos estar pagando un importe que realmente no estemos consumiendo. Tomemos un ejemplo: imaginemos que tenemos una base de datos para un blog con la siguiente separación:

¿Cómo estableceríamos el Throughput? En primer lugar, está claro que los artículos y las RU que consumiremos dependerán de cuántos escribamos a lo largo del año y del número de visitas que pueda tener este post. Supongamos que esta colección tiene un tráfico “elevado” en el momento en que publicamos el artículo, mientras que el resto de días el tráfico es más bien bajo. Pensemos que, como máximo, tendremos 800 RU el día de más tráfico, mientras que el resto de días tendremos un tráfico de 400 RU.

Por otro lado, la colección de preguntas es algo que no podemos prever de antemano. ¿Cuánta gente la va a utilizar? Por lo general, recibimos mucho feedback, pero pensemos en un escenario conservador donde no lo recibamos tanto. Así que podríamos tener un tráfico de inserción en la colección de preguntas de una vez a la semana, lo que se traduciría en 50 RU.

Dicho esto, si hacemos los cálculos y distribuimos las RU por colección, dado que el mínimo son 400, estaríamos pagando por dos colecciones: una con un aprovisionamiento autoescalado con un máximo de 1000 RU y otra con un escalado manual de 400 RU. Con esto, estaríamos pagando aproximadamente 850 RU al mes. Ahora bien, ¿cuánto nos costaría si lo hiciéramos a nivel de Base de Datos? En este escenario, pondríamos un autoescalado con un máximo de 1000 RU, que es el mínimo que podemos establecer. Pero esto, al igual que a nivel de colección, implica que tiene un mínimo del 10% de lo que estamos consumiendo. Dado que no podemos establecer 100 RU, estaríamos pagando continuamente 400 RU, y cuando hubiera un pico, escalaría hasta un máximo de 1000 RU, que es el valor que hemos estimado. Por lo tanto, ¿cuál sería el máximo que pagaríamos? Pagaríamos un máximo de 450 RU.

Con este ejemplo, hemos visto que una buena elección en la distribución de las RU puede provocar un ahorro cercano al 50% en nuestra factura.

¿Es oro todo lo que reluce?

He presentado un ejemplo y un escenario bastante sencillo y favorable donde la elección es clara. Pero vamos a complicar un poco el ejemplo. Supongamos que nuestro blog está triunfando y aumentamos nuestro tráfico, duplicando la cantidad de visitas, lo que también provoca un aumento en el uso de la funcionalidad de preguntas. ¿Qué puede ocurrir en nuestro desarrollo según lo que hayamos elegido?

En el caso de la separación del Throughput por Base de Datos, en la colección de artículos no sería necesario aumentar nada, ya que tenemos el autoescalado activo, lo que significa que al usar más RU, es posible que se nos facture más. Ahora, pensemos en la colección de preguntas. En este caso, al usarse más, es probable que ya esté utilizando adecuadamente los RU y que ambas colecciones estén adaptadas a su uso y proporcionando un servicio justo.

Sin embargo, en el segundo escenario, al poner el autoescalado manual, si el tráfico aumenta en ambas colecciones, el autoescalado aumentaría hasta el máximo que hemos establecido. Sin embargo, ahora es posible que tengamos puntos en los que los RU máximos que tenemos compartidos entre ambas colecciones sean superiores a los que hemos contratado. Esto puede provocar errores en el cliente dependiendo de cómo se comporte.

¿Esto significa que siempre deberíamos decantarnos por el escalado por colección? La respuesta obvia es que no. Para solucionar este caso, “fácilmente” podemos aumentar el rango del autoescalado en la Base de Datos para poder digerir esta carga de tráfico. Pero claro, ¿nos costará más dinero, no? No necesariamente. Al tener un autoescalado, es posible que durante algunos momentos estemos un poco por encima de esos 800 RU, pero también tendremos muchos momentos en los que estaremos por debajo de eso, por lo que prácticamente el importe será el mismo en uno u otro escenario.

Entonces, ¿siempre elegimos el escalado por Base de Datos? Los que me conocen ya saben la respuesta, y es que no. Es la opción más probable y que mejor se adapta a todos los escenarios, pero eso no implica que no puedas encontrarte en situaciones en las que una colección siempre demande un cierto número de RU de forma constante, lo que implica que cualquier cambio en el tráfico en el resto de colecciones pueda afectar negativamente a tu aplicación. ¿Cuándo puede ocurrir esto? Imaginemos que tenemos un producto con 100 millones de clientes. Así que piensa que puede ser un escenario algo diferente y en el que se presentan muchas casuísticas, y donde cualquier decisión que se tome tendrá un impacto en el producto, ya sea en su coste o en la experiencia del cliente.

Resumen

Cosmos DB es uno de los servicios más potentes de Azure, quizás el más caro, pero ofrece características que ningún otro servicio tiene. A menudo, incorporamos muchas funcionalidades que no necesitamos sin pensar por qué hacemos una cosa u otra. El coste que tenemos en nuestro producto es algo que siempre debemos mirar y adecuar a las necesidades que tiene nuestro producto en cada momento. Tenerlo siempre dimensionado según lo que estamos usando es algo que debemos tener en cuenta.

Este artículo no habría sido posible sin el conocimiento de Fernando Escolar y Almudena Vivanco para llevarlo a la práctica.