Akka antipatterns: demasiados actores

imagen

Por akka hay pocos materiales sobre Habré. Decidí traducir algunos de los antipatrones descritos por Manuel en su blog. Realmente pueden no ser obvios para las personas que se encontraron por primera vez con el marco.

Se me ocurrió que todavía no había escrito sobre este antipatrón muy frecuente. A menudo se puede encontrar en el código de los desarrolladores que recién comienzan a trabajar con el modelo de actor.

Hay dos formas de obtener demasiados actores:

- haber desarrollado un sistema con demasiados tipos diferentes de actores, muchos de los cuales no son necesarios
- crear una gran cantidad de actores en tiempo de ejecución cuando no es necesario e ineficiente

Veamos estas opciones en detalle.

Demasiados tipos de actores


La idea general es algo como esto: "tenemos actores, por lo que todo debería ser un actor".

El modelo de actor simplifica la escritura de aplicaciones asincrónicas. Lo hace al proporcionar la ilusión de ejecución de código síncrono dentro de un actor: no hay necesidad de preocuparse por el acceso concurrente al estado de un actor, porque solo un actor puede acceder a su estado y los mensajes se procesan uno a la vez.

Pero, de hecho, no todo debe hacerse de forma asincrónica. Las llamadas a métodos que están asociadas exclusivamente con la CPU (y no están "bloqueadas" en el sentido de que no sobrecargan completamente la CPU, por ejemplo, al calcular el valor de Pi), no deben realizarse de forma asíncrona.

A menudo veo código con una gran cantidad de actores diferentes que interactúan entre sí y no hacen nada, lo que tiene una gran ventaja en la ejecución asíncrona o simultánea. En estos proyectos, cada uno de estos actores debe almacenar el mismo estado o transmitirlo en cada mensaje.

Este enfoque tiene dos inconvenientes:

"No se obtiene nada en términos de rendimiento". Por el contrario, existe una sobrecarga asociada con la creación de mensajes y su transmisión.
- Con cada tipo de actor y mensajes relacionados, el sistema se vuelve más difícil de entender y mantener.

Por lo tanto, al diseñar sistemas de actores, debe pensar en lo que debería ser realmente asíncrono, básicamente esto:

- llamadas a sistemas externos (fuera de su jvm)
- llamadas a operaciones de bloqueo (API desactualizadas, computación pesada, ...)

Demasiados actores en tiempo de ejecución


La idea general es algo como esto: "cuantos más actores tengamos, más rápido irá todo".

En realidad, los actores son livianos y puedes ejecutar millones de ellos en una máquina virtual . Si puedes. ¿Pero es necesario?

imagen

Si puedes, no significa que debas

Respuesta corta: no siempre, depende de lo que hagas con los actores.

Si su sistema tiene muchos actores de larga vida, cada uno de los cuales contiene un pequeño estado e interactúa entre sí de vez en cuando, es muy posible que esté con un millón de actores, y este es un caso de uso legítimo, muy bien respaldado por Akka. Por ejemplo, puede crear un sistema con una gran cantidad de usuarios, donde cada usuario está representado por un actor. Un actor puro de Akka ocupa solo 300 bytes de memoria, por lo que es muy posible crear millones en una máquina y dejarlos trabajando sin preocuparse por nada. Y si al final crea una gran cantidad de actores o actores con una gran fortuna que ya no encajarán en la memoria de una máquina, el fragment de clúster simplificará la distribución de actores en varias máquinas.

Sin embargo, si tiene varios tipos de actores que participan en el cálculo de algo, por ejemplo, analizar un documento XML, es dudoso crear millones de dichos actores (no importa directamente o a través de un enrutador).

El procesador tiene un número fijo de núcleos (hilos de hardware) a su disposición, y los actores de Akka procesan los mensajes en un ExecutionContext basado en un grupo de hilos. Por defecto, este es fork-join-ejecutor basado en ForkJoinPool agregado en Java 7.

Pero, a pesar de su ventaja técnica, forkjoinpool no es magia que deroga las leyes de la física. Si tiene un millón de actores, cada uno de los cuales analiza un documento XML (ya cargado en la memoria) y 4 subprocesos de hardware, el sistema no funcionará mucho mejor que si solo tuviera 4 actores que analicen estos documentos XML (cuando condición de carga homogénea). De hecho, su sistema funcionará mucho mejor con 4 actores porque solo habrá una sobrecarga mínima en términos de planificación y gestión de memoria. Por cierto, si su sistema tiene solo unos pocos actores, verifique su grupo de subprocesos, que probablemente esté tratando de reutilizar el mismo subproceso para el mismo actor.

En general, el sistema no funcionará más rápido si crea muchos actores.

Actores apátridas


Los actores están orientados a objetos correctamente (a diferencia de, por ejemplo, los objetos en Java): su estado no es visible desde el exterior y se comunican a través de mensajes. Es imposible romper la encapsulación, porque no puedes mirar el estado del actor durante su trabajo. Este es el objetivo de los actores: le brindan la ilusión de un espacio seguro en el que los mensajes se ejecutan secuencialmente, uno tras otro, lo que le permite usar un estado mutable dentro de su actor sin preocuparse por las condiciones de la carrera (condiciones de la carrera - aprox. Por.) (Bueno, casi sin preocuparse: lo principal es no dejar que el estado se filtre).

Es por eso que el uso de actores que no tienen estado es algo extraño, por decir lo menos. Con la excepción de los actores que controlan la observación de grandes partes de la jerarquía del sistema de actores (por ejemplo, la creación de supervisores de respaldo), los actores están realmente diseñados para trabajar con cálculos largos que tienen estado. Hablando mucho, quiero decir que el actor procesará varios mensajes a lo largo de su vida, produciendo diferentes resultados dependiendo de su condición, a diferencia de los cálculos únicos. Para ellos, los futuros son una gran abstracción: permiten la ejecución de código asíncrono, ideal para casos de trabajo con una red o informática relacionada con el disco (o tareas de procesador realmente intensas), pueden estar compuestos y tener un mecanismo de procesamiento de fallas. También se integran bien con los actores Akka (usando el patrón de tubería).

En general: no use actores si no tiene un estado, no están destinados a esto.

Source: https://habr.com/ru/post/es420639/


All Articles