Pasar al contenido principal
En Inspiring Technology by Hunters: Hoy os hablamos de Virtual Threads, hebras virtuales ligeras.
27/08/2024
virtual-threads-altia-inspiring-tech

Una hebra o proceso ligero en computación es básicamente un conjunto mínimo de tareas que puede ser ejecutada por el sistema operativo y se ejecutan en el contexto de un proceso. Dependiendo del número de Cores del CPU, se podrán ejecutar simultáneamente múltiples tareas (paralelismo). Si hay más hebras que Cores de CPU entonces habrá que establecer una planificación (Scheduling) consistente en que las hebras toman un CPU por un tiempo determinado y luego lo suelta para que otra hebra pueda cogerlo, dando la sensación de paralelismo.

La máquina virtual Java (JVM) en sí funciona en base a hebras habiendo una equivalencia de 1 a 1 con las hebras del sistema operativo subyacente.

Ahora bien, en un sistema Web, cada petición de Usuario es atendida por una hebra creada a tal efecto (modelo Thread per request), entonces... ¿Qué pasa cuando 1000 usuarios hacen una invocación al mencionado sistema Web?

virtual-threads

Modelo Thread per request

Como su nombre indica, cada petición que llega es atendida por un thread. Cuando se alcanza el número máximo de threads corriendo simultáneamente, el resto de peticiones deben ser encoladas a la espera de algún thread disponible.

Cuando se está programando hay fundamentalmente dos estilos, Síncrono y Asíncrono.

 

Imagen
virtual-threads

En programación síncrona, una hebra realiza una petición a un servicio externo (Base de datos, otro servicio…) y espera la respuesta sin hacer nada. Por el contrario, en Asíncrono, cuando se hace dicha petición, la hebra no se bloquea y puede seguir haciendo cosas mientras recibe la respuesta.

La programación síncrona es una programación más sencilla ya que las respuestas se tienen en el contexto en el que se hizo la petición. Por el contrario, es más ineficiente, pues hay muchos tiempos de espera a que se resuelvan las llamadas.

Imagen
virtual-threads-sincrono-asincrono

En el caso asíncrono es todo lo contrario, resulta más complejo pues hay que programar sabiendo que la respuesta puede llegar en un contexto de ejecución distinto al que se hizo la petición, lo que complica la programación. Sin embargo, dado que las hebras nunca paran, resulta más eficiente.

Virtual Threads

Las hebras virtuales son hebras ligeras pensadas para reducir el esfuerzo de escribir y mantener aplicaciones concurrentes de alto rendimiento. Para más información revisar la JEP 444.

Las hebras virtuales NO son gestionadas por el sistema operativo sino por la propia JVM. Se ha visto antes que cada hebra de la JVM tiene su correspondiente hebra del SO (Platform Thread).

La idea ahora es que estas hebras de la JVM llamadas carrier threads, sean asignadas a las hebras virtuales cuando les llega el momento de ejecutarse, con lo cual se consigue tener multitud de hebras virtuales con pocas hebras portadoras y, por tanto, pocas hebras del sistema operativo, ganando así en eficiencia y mejor gestión de recursos.

Ejecuciones de ejemplo

El escenario que se plantea es la invocación simple a un servicio rest que devuelve un string. Se utiliza como framework base Spring Boot 3.2.3 y el servidor web por defecto: Tomcat. Para la ejecución de hebras tradicionales no se modificará la configuración del servidor, pero para la ejecución de hebras virtuales, se obligará a Tomcat a utilizar el un Executor que utiliza hebras virtuales para atender peticiones (Executors.newVirtualThreadPerTaskExecutor).

Ejecuciones con hebras tradicionales

Estadísticas con 100 usuarios concurrentes:
 

inspiring

Recursos con 100 usuarios concurrentes:

inspiring

Estadísticas con 1000 usuarios concurrentes:
 

inspiring

Recursos usados con 1000 usuarios concurrentes:

inspiring

Ejecución con hebras virtuales

Estadísticas con 100 usuarios concurrentes:

inspiring

Recursos con 100 usuarios concurrentes:

inspiring

Estadísticas con 1000 usuarios concurrentes:

inspiring

Recursos con 1000 usuarios concurrentes:
 

inspiring

Conclusiones

Como puede verse, el uso de hebras virtuales no solo reduce la consumición de recursos, sino que, además, ante el incremento de cargas de trabajo, mantiene constante la consumición de los mismos.

Nótese que el número de hebras (carrier threads) creadas en el escenario de hebras virtuales se ha mantenido más o menos constante (28-30) aun cuando el incremento de la carga ha aumentado un orden de magnitud (de 100 a 1000 usuarios).

En el caso de las hebras tradicionales no ha sido así, viéndose un incremento de casi 100 hebras (125 a 222) cuando se ha incrementado la carga en los mismos términos que en el escenario de hebras virtuales.

En cuanto a las estadísticas, puede observarse que tanto a baja carga (100 usuarios) como a alta (1000), el comportamiento de las hebras virtuales es mucho mejor.

¿Conoces ya el programa Hunters?

Ser un hunter es aceptar el reto de probar nuevas soluciones que aporten resultados diferenciales. Únete al programa Hunters y forma parte de un grupo transversal con capacidad de generar y transferir conocimiento.

Anticípate a las soluciones digitales que nos harán crecer. Consulta más información sobre Hunters en la web.