scala scalability websocket actor akka

scala - ¿Cómo funciona la E/S en Akka?



scalability websocket (3)

Las operaciones de bloqueo generalmente no generan excepciones, pero esperar en un futuro (por ejemplo, mediante el uso de métodos de envío !!! ) Puede provocar una excepción de tiempo de espera. Es por eso que debería seguir usando fuego y olvidarse tanto como sea posible, usar un valor significativo de tiempo de espera y preferir las devoluciones de llamada cuando sea posible.

  1. Un actor akka no puede procesar explícitamente varios mensajes seguidos, pero puede jugar con el valor de throughput través del archivo de configuración. El actor procesará varios mensajes (es decir, su método de recepción se llamará varias veces de forma secuencial) si su cola de mensajes no está vacía: http://akka.io/docs/akka/1.1.3/scala/dispatchers.html#id5

  2. Las operaciones de bloqueo dentro de un actor no "bloquearán" a todos los actores, pero si comparte subprocesos entre los actores (uso recomendado), se bloqueará uno de los subprocesos del despachador hasta que se reanuden las operaciones. Así que intente componer los futuros tanto como sea posible y tenga cuidado con el valor del tiempo de espera).

3 y 4. Estoy de acuerdo con las respuestas de Raymond.

¿Cómo funciona el modelo de actor (en Akka) cuando necesita realizar E / S (es decir, una operación de base de datos)?

Tengo entendido que una operación de bloqueo lanzará una excepción (y esencialmente arruinará toda concurrencia debido a la naturaleza de Netty, que Akka usa). Por lo tanto, tendría que usar un Future o algo similar; sin embargo, no entiendo el modelo de concurrencia.

  1. ¿Puede 1 actor procesar múltiples mensajes simultáneamente?
  2. Si un actor realiza una llamada de bloqueo en un future (es decir, future.get() ), solo bloquea la ejecución del actor actual; ¿O impedirá la ejecución en todos los actores hasta que se complete la llamada de bloqueo?
  3. Si bloquea toda la ejecución, ¿de qué manera el uso de una concurrencia de asistencia futura (es decir, no invocar llamadas de bloqueo en un futuro sería crear un actor y ejecutar la llamada de bloqueo)?
  4. ¿Cuál es la mejor manera de lidiar con un proceso de múltiples etapas (es decir, leer de la base de datos; llamar a un servicio web de bloqueo; leer de la base de datos; escribir en la base de datos) donde cada paso depende de la última?

El contexto básico es este:

  • Estoy usando un servidor Websocket que mantendrá miles de sesiones.
  • Cada sesión tiene algún estado (es decir, detalles de autenticación, etc.);
  • El cliente de Javascript enviará un mensaje JSON-RPC al servidor, que lo pasará al actor de sesión adecuado, que lo ejecutará y devolverá un resultado.
  • La ejecución de la llamada RPC implicará algunas llamadas de E / S y bloqueo.
  • Habrá una gran cantidad de solicitudes simultáneas (cada usuario realizará una cantidad significativa de solicitudes a través de la conexión WebSocket y habrá muchos usuarios).

¿Hay una mejor manera de lograr esto?


Las operaciones de bloqueo no lanzan excepciones en Akka. Puedes bloquear llamadas desde un Actor (lo que probablemente quieras minimizar, pero eso es otra historia).

  1. no, 1 instancia de actor no puede.
  2. No bloqueará a ningún otro actor. Puedes influir en esto usando un Dispatcher específico. Los futuros utilizan el despachador predeterminado (el evento global controlado normalmente) por lo que se ejecuta en un subproceso en un grupo. Puede elegir qué despachador desea usar para sus actores (por actor o para todos). Supongo que si realmente deseara crear un problema, podría pasar exactamente el mismo despachador (basado en subprocesos) a futuros y actores, pero eso tomaría cierta intención de su parte. Supongo que si tiene un gran número de futuros bloqueando indefinidamente y el servicio de ejecución se ha configurado para una cantidad fija de subprocesos, podría explotar el servicio de ejecución. Así que muchos ''ifs''. a f.get solo se bloquea si el futuro aún no se ha completado. Bloqueará el "hilo actual" del Actor desde el que lo llamas (si lo llamas desde un Actor, lo que no es necesario por cierto)
  3. No necesariamente tienes que bloquear. Puede utilizar una devolución de llamada en lugar de f.get. Incluso puedes componer futuros sin bloquear. consulte la charla de Viktor sobre ''el futuro prometedor de akka'' para obtener más detalles: http://skillsmatter.com/podcast/scala/talk-by-viktor-klang
  4. Yo usaría la comunicación asíncrona entre los pasos (si los pasos son procesos significativos por sí mismos), así que use un actor para cada paso, donde cada actor envía un mensaje de un lado a otro, posiblemente también mensajes de un solo camino a algún otro actor que no lo haga. Bloque que puede supervisar el proceso. De esta manera, podría crear cadenas de actores, de los cuales podría hacer muchos, y al frente podría poner un actor de equilibrio de carga, de modo que si un actor bloquea en una cadena, otro del mismo tipo podría no en la otra. Eso también funcionaría para su pregunta de ''contexto'', pasar la carga de trabajo a los actores locales, encadenarlos detrás de un actor de equilibrio de carga.

En cuanto a netty (y supongo que te refieres a Actores Remotos, porque esto es lo único para lo que Netty se usa en Akka), pasa tu trabajo lo antes posible a un actor local o un futuro (con devolución de llamada) si estás preocupado. sobre el tiempo o la prevención de Netty para hacer su trabajo de alguna manera.


Lo que dijo Raymond y paradigmático, pero también, si desea evitar que el grupo de subprocesos se scala.concurrent.blocking hambre, debe ajustar las operaciones de bloqueo en scala.concurrent.blocking .

Por supuesto, es mejor evitar las operaciones de bloqueo, pero a veces es necesario usar una biblioteca que bloquee. Si envuelve dicho código en el blocking , permitirá que el contexto de ejecución sepa que puede estar bloqueando este hilo para que pueda asignar otro si es necesario.

El problema es peor que lo que describe paradigmáticamente, ya que si tiene varias operaciones de bloqueo, puede terminar bloqueando todos los subprocesos en el grupo de subprocesos y no tener subprocesos libres. Podría terminar con un punto muerto si todos sus hilos están bloqueados en algo que no sucederá hasta que se programe otro actor / futuro.

Aquí hay un ejemplo:

import scala.concurrent.blocking ... Future { val image = blocking { load_image_from_potentially_slow_media() } val enhanced = image.enhance() blocking { if (oracle.queryBetter(image, enhanced)) { write_new_image(enhanced) } } enhanced }

La documentación está here .