Criterios para elegir un stack tecnológico

Comparando Elixir, Reactor, Akka y Node.js

Daniel Estiven Rico Posada
Bancolombia Tech
6 min readNov 9, 2020

--

Es común encontrarse en una situación en la que, elegir el stack para un nuevo proyecto, se convierte en todo un reto. Las búsquedas en google o stack overflow suelen ser los primeros recursos que usamos, escribiendo frases como: ¿es mejor Spring o Node.js?. La realidad y la respuesta a ese tipo de preguntas es: depende.

Lo más importante ante este tipo de situaciones es tener unos criterios claros para evaluar una u otra opción, dependiendo del escenario y seguir siempre esta regla o recomendación: la mejor herramienta para cada caso de uso. Por tanto, es fundamental no dejarse llevar solo por gustos, ni tampoco hacer una elección de manera apresurada.

En Bancolombia nos hemos encontrado ante esta situación en varias oportunidades, por eso decidimos hacer una comparación formal, con unos criterios que consideramos útiles, y que puede ser de gran utilidad para tomar este tipo de decisiones.

En esta ocasión, queremos presentar el resultado de un trabajo comparativo entre herramientas de diferentes ecosistemas: Elixir, Java (Reactor), Node.js, Java (Akka).

Criterio 1: Concurrencia vs Throughtput

La capacidad para soportar usuarios concurrentes es un criterio importante. Si necesitas que una aplicación se mantenga responsiva ante miles o cientos de miles de usuarios concurrentes, debes considerar una plataforma que en un escenario de alta concurrencia, garantice el mejor throughput y con la menor cantidad de infraestructura posible.

Para este escenario desarrollamos, en cada una de las plataformas, una aplicación que expone servicios REST y permite hacer validaciones sobre una base de datos MongoDB.

El eje X en la gráfica anterior representa el nivel de concurrencia que lanzamos a estas aplicaciones y que fue variado cada 5 segundos (llegando hasta 2.500 usuarios concurrentes), y el eje Y representa el throughtput (TPS — transactions per second) que puede lograrse bajo una concurrencia específica.

El top 3 en este criterio es:

  1. Elixir (hasta 39.000 TPS)
  2. Akka (hasta 35.000 TPS)
  3. Reactor (hasta 31.000 TPS)

Estas tres plataformas — que permiten la construcción de flujos reactivos — arrojaron muy buenos resultados, con algunas pequeñas diferencias en cuanto a su estabilidad.

Criterio 2: Latencia

La latencia es un criterio de suma importancia en cualquier sistema, pero cuando hablamos de sistemas distribuidos juega un papel más importante aún, ¿por qué?, esto se debe a que los tiempos que un usuario final va a percibir al realizar alguna transacción, corresponden a la latencia acumulada de los diferentes componentes que hagan parte del sistema.

En las gráficas anteriores, el eje X tiene que ver con la cantidad de usuarios concurrentes y el eje Y representa la latencia media para cada prueba específica.

Las pruebas que realizamos sobre latencia nos indican que las aplicaciones Node.js, aunque suelen tener buenos resultados a nivel de throughtput, cuando la concurrencia es demasiado alta y el trabajo que debe realizar no corresponde a I/O, tienen tendencia a arrojar tiempos de respuesta altos.

Para este segundo criterio buscamos tener la menor latencia posible, para generar mejores experiencias durante la interacción de un usuario con una aplicación.

El top 3 en cuanto a menor latencia:

  1. Elixir
  2. Reactor
  3. Node Cluster

Nota: La prueba anterior considera un escenario con carga constante y una afectación incremental (uso abusivo de la capacidad de la CPU por un porcentaje de las peticiones) para, además de la latencia, medir la capacidad de los sistemas para mantenerse responsivos.

Criterio 3: Estilo de programación

Las decisiones que se tomen alrededor del estilo de programación, tendrán un impacto directo sobre la mantenibilidad y extensibilidad de un sistema. Una adecuada elección en este punto puede evitar asumir complejidades innecesarias en el código, y ayudar a lograr, además, un alto nivel de reúso, eficiencia y expresividad en un caso de uso específico.

En nuestro caso estamos considerando, para algunos proyectos nuevos, el uso de programación reactiva y funcional con una alta orientación a eventos, debido a que aporta al uso eficiente de los recursos computacionales, y permite tener soluciones más elegantes y mantenibles, que garantizan la responsividad de los sistemas.

Para conocer con un mayor detalle todos los principios que estamos utilizando en la construcción de sistemas reactivos, puedes leer el siguiente artículo:

https://medium.com/bancolombia-tech/potenciando-la-arquitectura-de-microservicios-reactivos-88fc84ae0b7d

Criterio 4: Popularidad y programación políglota

Tal como lo plantea Thoughtworks en su último radar (2020), la popularidad en las tecnologías muchas veces lleva a elegirlas de manera indiscriminada o por las razones incorrectas; de ahí la importancia de elegir la herramienta adecuada para el caso de uso correcto.

En el caso de Node.js, que tradicionalmente ha sido elegido porque permite construir una aplicación completa en el mismo lenguaje (back y front), es importante considerar que en muchos escenarios no es la mejor opción; a veces es mejor esforzarse en construir un sistema en diferentes lenguajes para sacar el mayor provecho de cada herramienta, en cada parte del sistema.

Por otro lado, Node.js ha sido utilizado porque fue de los primeros en ofrecer un modelo de programación no bloqueante, muy útil y eficiente para trabajos relacionados a I/O, pero que por su naturaleza single-thread claramente no es una buena opción para cargas pesadas de cómputo.

Ten en cuenta que los modelos de programación no bloqueantes ya no solo existen en Node.js, sino también en otras opciones que pueden tener API’s más elegantes para el manejo de flujos asíncronos, y que pueden tener un rendimiento bastante bueno para cargas pesadas de computo, como es el caso del proyecto Reactor(Java) y de Elixir (Erlang VM).

Criterio 5: Sistemas de alta concurrencia y tolerantes a fallos

Actualmente existe bastante diversidad de herramientas para el desarrollo de aplicaciones, pero es importante conocer que algunas de ellas han sido creadas con propósitos muy específicos.

Cuando hablamos de herramientas para construir sistemas distribuidos de alta concurrencia, tolerantes a fallos y que tengan como principio fundamental la disponibilidad, Elixir (Erlang VM) es una opción muy apropiada.

Erlang — un lenguaje construido por Joe Amstrong y su equipo en el laboratorio de ciencias de la computación de Ericsson — ha sido utilizado tradicionalmente en el mundo de las telecomunicaciones, pero desde hace un tiempo ha tomado bastante fuerza para la construcción de sistemas distribuidos en otros ámbitos, siendo una de las razones principales la evolución en la sintaxis a través de la propuesta de Elixir. Uno de los casos más conocidos es Whatsapp, quien tiene construido su backend de enrutamiento de mensajes en Erlang y soporta el procesamiento de alrededor de 2.6 billones de mensajes por hora.

Criterio 6: Compatibilidad

Considerar los componentes externos con los que un microservicio debe comunicarse, además de los protocolos, drivers y servicios que van a ser usados, es fundamental a la hora de elegir la herramienta con la cual se va a desarrollar.

Uno de los ejemplos claros es Elixir, un lenguaje con una comunidad open source sólida pero con algunos retos importantes en cuanto algunas librerías externas o drivers. Estos retos están relacionados con que algunas de estas librerías requeridas no existen, no cuentan con buena documentación, tienen versiones muy iniciales o no cuentan con una comunidad open source muy amplia. Por lo tanto, elegir este stack, en algunos casos, puede no ser la mejor opción.

Conclusión

La tecnología para el desarrollo de aplicaciones es muy diversa y es recomendable aprovechar esa diversidad para elegir las herramientas más adecuadas para lo que requerimos.

Node.js, Elixir y Java(Reactor, Akka) son alternativas bastante buenas para iniciar un proyecto de software, pero conocer sus fortalezas y debilidades puede ahorrarnos muchos dolores de cabeza, especialmente a la hora de mantener una aplicación funcionando adecuadamente en producción.

¡Elige la opción que más se acomode al caso de uso que buscas resolver!

Nota: Ten en cuenta que los resultados presentados anteriormente no son una comparación exhaustiva de herramientas, sino una serie de criterios que, desde nuestra experiencia, han sido útiles a la hora de elegir un stack tecnológico.

Tenemos claro que existen muchas más tecnologías válidas e interesantes que no abordamos en la comparación — sería imposible hacerlo en un sólo artículo — , así que priorizamos algunas de las que le apuntan a las necesidades particulares de Bancolombia.

--

--