2010-11-03 12 views
127

Me pregunto si hay una manera de hacer llamadas asíncronas a una base de datos?¿Es posible la llamada jdbc asincrónica?

Por ejemplo, imagine que tengo una gran solicitud que lleva mucho tiempo procesar, deseo enviar la solicitud y recibir una notificación cuando la solicitud devuelva un valor (pasando un Listener/callback o algo) No quiero bloquear esperando a que la base de datos responda.

No considero que el uso de un grupo de subprocesos sea una solución porque no se escala, en el caso de solicitudes simultáneas pesadas esto generará una gran cantidad de subprocesos.

Nos enfrentamos a este tipo de problema con los servidores de red y hemos encontrado soluciones utilizando la llamada al sistema select/poll/epoll para evitar tener un hilo por conexión. Me pregunto cómo tener una función similar con la solicitud de la base de datos.

Nota: Soy consciente de que usar FixedThreadPool puede ser una buena solución, pero me sorprende que nadie haya desarrollado un sistema realmente asincrónico (sin el uso de un hilo adicional).

** Actualización **
Debido a la falta de soluciones prácticas reales, decidí crear una biblioteca (parte de fingle) yo mismo: finagle-mysql. Básicamente decodifica/decodifica solicitud/respuesta de mysql y usa Finagle/Netty debajo del capó. Se escala extremadamente bien incluso con una gran cantidad de conexiones.

+0

Consulte http://code.google.com/p/async-mysql-connector/wiki/UsageExample –

+1

Vea también https://github.com/mauricio/postgresql-async –

+0

El problema es cómo podría notificar el db el cliente cuando termina la consulta. Uno sería (por ejemplo) que Oracle use la función "Notificación de cambio de resultado de consulta de base de datos" y se lo notifique cuando cambien los datos de db. Esto se aplica a las consultas SQL que modifican los datos de base de datos Para las consultas de solo lectura, esto no funcionaría. Por otro lado, no estoy seguro de que hacer conexiones asincrónicas sería una buena idea, ya que establecerlas es costoso. Por supuesto, esta no es una solución muy general. Solo comida para pensar ... –

Respuesta

137

No entiendo cómo alguno de los enfoques propuestos que envuelven las llamadas JDBC en Actores, ejecutores o cualquier otra cosa puede ayudar aquí. ¿Alguien puede aclararlo?

Seguramente el problema básico es que las operaciones JDBC bloquean en el socket IO. Cuando lo hace, bloquea el hilo que se ejecuta: el final de la historia. Cualquiera que sea el marco de ajuste que elijas usar, terminará con un hilo que se mantendrá ocupado/bloqueado por solicitud simultánea.

Si los controladores de base de datos subyacentes (MySql?) Ofrecen un medio para interceptar la creación del socket (ver SocketFactory) entonces imagino que sería posible construir una capa de base de datos accionada por evento asíncrono sobre la api JDBC pero tiene que encapsular todo el JDBC detrás de una fachada impulsada por un evento, y esa fachada no se vería como JDBC (después de que sería impulsada por un evento). El procesamiento de la base de datos se realizaría de manera asincrónica en un hilo diferente para la persona que llama, y ​​tendría que averiguar cómo crear un administrador de transacciones que no dependa de la afinidad de la secuencia de comandos.

Algo como el enfoque que menciono permitiría que incluso una sola hebra de fondo procesara una carga de ejecutables JDBC simultáneos. En la práctica, probablemente ejecute un conjunto de hilos para hacer uso de múltiples núcleos.

(Por supuesto, no estoy comentando la lógica de la pregunta original solo las respuestas que implican que la concurrencia en un escenario con bloqueo de IO es posible sin el usuario de un patrón de selector, más simple para resolver su típico Concurrencia JDBC y poner en un grupo de conexión del tamaño correcto).


Parece probable MySql hace algo en la línea que estoy sugiriendo --- http://code.google.com/p/async-mysql-connector/wiki/UsageExample

+2

Esto debe marcarse como la respuesta correcta. – stackoverflower

+0

El uso de Akka no hace que las llamadas a DB relacionales sean asíncronas. Le permite ejecutarlos fácilmente en un conjunto de subprocesos dedicados para el acceso a bases de datos. De esta forma, no se lleva todo el sitio cuando el sitio deja de responder porque siempre ha estado haciendo llamadas asincrónicas en la capa de servicio a la capa DAO con promesas y los hilos de su servidor web están separados del resto de su aplicación. – Onur

+0

Los actores no son las únicas soluciones (p. Ej.micro-servicios y asincronización http, que escalamos a miles por segundo), y no sería tan rápido descartarlos como no asincrónicos desde la perspectiva del cliente. Si 1k UI intercepta el tráfico ingrese a su sistema y solo 10 subprocesos están bloqueados en la base de datos, mientras que 990 'mensajes' (o algo similar) se almacenan en la memoria _sin_ bloqueo _grandes_ de los subprocesos de la interfaz de usuario 1k (que probablemente se liberarán). .. no es eso lo que se requiere? Me encantaría ver una verdadera asincrónica JDBC, pero eso no significa que no haya soluciones alternativas extremadamente viables en el ínterin. –

7

no hay apoyo directo en JDBC pero tienes múltiples opciones como MDB, ejecutores de Java 5.

"No considero que el uso de un grupo de subprocesos es una solución, ya que no escala, en el caso de solicitudes concurrentes pesadas esto generará una gran cantidad de hilos ".

Tengo curiosidad ¿por qué un conjunto de hilos limitados no va a escalar? Es un grupo, no thread-per-request, para engendrar un hilo por cada solicitud. He estado usando esto durante bastante tiempo en una aplicación de carga pesada y hasta ahora no hemos visto ningún problema.

+0

Creo que el principal argumento en contra de los hilos es que usted está básicamente fuera de cualquier restricción estándar de contenedores de Java, por lo que pierde las capacidades de agrupamiento administrado y conmutación por error del contenedor, aunque puede ejecutar el propio, o usar algo como Terracotta. – mezmo

+3

podemos acceder a las encuestas de hilos gestionados por el servidor de aplicaciones utilizando gestores de trabajo. websphere, weblogic y glassfish lo admiten –

1

Solo estoy pensando ideas aquí. ¿Por qué no podrías tener un conjunto de conexiones de bases de datos con cada una de ellas teniendo un hilo? Cada hilo tiene acceso a una cola. Cuando quiere hacer una consulta que lleva mucho tiempo, puede poner la cola y luego uno de los hilos la recogerá y manejará. Nunca tendrás demasiados hilos porque el número de tus hilos está limitado.

Editar: O mejor aún, solo una cantidad de hilos. Cuando un hilo ve algo en una cola, solicita una conexión del grupo y lo maneja.

9

Tal vez usted podría utilizar un sistema de mensajería asíncrona JMS, que escala muy bien, en mi humilde opinión:

  • Enviar un mensaje a una cola, donde los suscriptores aceptar el mensaje, y ejecutar el proceso de SQL. Su proceso principal continuará ejecutándose y aceptando o enviando nuevas solicitudes.

  • Cuando finaliza el proceso de SQL, puede ejecutar la ruta opuesta: enviar un mensaje a una ResponseQueue con el resultado del proceso, y un oyente del lado del cliente lo acepta y ejecuta el código de devolución de llamada.

37

Es imposible hacer una llamada asincrónica a la base de datos través de JDBC, pero se puede hacer llamadas asíncronas a JDBC con Actores (por ejemplo, el actor realiza llamadas a la base de datos a través de JDBC, y envía mensajes a los terceros, cuando las llamadas son más), o bien, si te gusta CPS, con pipelined futures (promises) (una buena aplicación es ScalazPromises)

no considero que el uso de un grupo de subprocesos es una solución beca usarlo no escala, en el caso de solicitudes concurrentes pesadas esto generará una gran cantidad de hilos.

Los actores de Scala por defecto están basados ​​en eventos (no basados ​​en hilos) - la programación de continuación permite crear millones de actores en una configuración de JVM estándar.

Si se orienta a Java, Akka Framework es una implementación de modelo Actor que tiene una buena API tanto para Java como para Scala.


Aparte de eso, la naturaleza síncrona de JDBC tiene mucho sentido para mí. El costo de una sesión de base de datos es mucho más alto que el costo de la cadena Java que se está bloqueando (ya sea en primer plano o en segundo plano) y esperando una respuesta. Si sus consultas se ejecutan durante tanto tiempo que las capacidades de un servicio de ejecutor (o envolviendo los marcos de concurrencia Actor/fork-join/promise) no son suficientes para usted (y está consumiendo demasiados hilos) primero debe pensar en su carga de la base de datos Normalmente, la respuesta de una base de datos vuelve muy rápido, y un servicio ejecutor respaldado con un grupo de subprocesos fijo es una solución lo suficientemente buena. Si tiene demasiadas consultas de larga ejecución, debe considerar el procesamiento previo (pre), como el recálculo nocturno de los datos o algo así.

+0

+1. Envolví costosas llamadas JDBC (técnicamente, Querulous) en actores y nunca miré hacia atrás. –

+0

Me estoy orientando a scala, y estoy muy familiarizado con el patrón Promise/Actor. En realidad, no consideré el modelo de actor porque todavía quiero ejecutar solicitudes en paralelo, no quiero tener un gran actor que ejecute todas mis solicitudes secuencialmente. Mi primera idea fue utilizar Promises respaldado por FixedThreadPool con el mismo tamaño que el número de conexión a la base de datos, en caso de un uso intensivo, cada subproceso del grupo de subprocesos está bloqueado esperando por la base de datos. Lo que me molesta es que no hay necesidad de todos esos hilos. Sería completamente factible tener un sistema equivalente con solo un hilo. –

+0

Steve, solo crea un nuevo actor para cada llamada? –

3

El Java 5.0 executors puede ser útil.

Puede tener un número fijo de hilos para manejar operaciones de larga ejecución. Y en lugar de Runnable puede usar Callable, que devuelve un resultado. El resultado se encapsula en un objeto Future<ReturnType>, por lo que puede obtenerlo cuando vuelva.

2

Sólo una idea loca: Se podría utilizar un patrón de Iteratee sobre JBDC conjuntoResultados envuelto en algún futuro/Promise

Hammersmith lo hace por MongoBd.

+0

No soluciona que todavía esté bloqueando un hilo en alguna parte. –

1

La biblioteca Commons-dbUtils tiene soporte para un AsyncQueryRunner que usted proporciona una ExecutorService a y devuelve una Future . Vale la pena echarle un vistazo ya que es fácil de usar y garantiza que no se perderán recursos.

3

proyecto Ajdbc parece responder a este problema http://code.google.com/p/adbcj/

existe en la actualidad 2 experimentales conductores nativa asincrónicos para MySQL y PostgreSQL.

+0

Me gustaría tener este enfoque listo. JDBC ha evolucionado mucho desde el principio (iteradores, plantillas, procedimientos preparados), pero este enfoque asincrónico nunca se ha implementado. Sería particularmente interesante para las operaciones de escritura (Insertar, Actualizar, Eliminar), y especialmente aquellas TX de lote pesado que todos enfrentamos. En mi opinión, cualquier tipo de enfoque basado en el cliente (Pooling, Actor, Scheduling, Messaging ...) daría lugar a pequeñas recompensas en términos de uso de recursos (probablemente algunas mejoras en el rendimiento o la latencia). –

+0

Antiguo y abandonado, solo dos tipos de datos compatibles y ni siquiera cerca de la producción. Desafortunadamente :( –

+0

[El número 1 de esta biblioteca es sobre el sitio web que no está disponible] (https://github.com/mheath/adbcj/issues/1). Tiene más de un año. Sospecho que esta biblioteca es bonita –

3

Una vieja pregunta, pero algo más de información. No es posible hacer que JDBC emita solicitudes asincrónicas a la base de datos, a menos que un proveedor proporcione una extensión a JDBC y un contenedor para manejar JDBC. Dicho esto, es posible ajustar JDBC con una cola de procesamiento e implementar una lógica que pueda procesar la cola en una o más conexiones separadas. Una ventaja de esto para algunos tipos de llamadas es que la lógica, si está suficientemente cargada, podría convertir las llamadas en lotes JDBC para su procesamiento, lo que puede acelerar la lógica significativamente. Esto es más útil para las llamadas donde se están insertando datos, y el resultado real solo se debe registrar si hay un error. Un buen ejemplo de esto es si se realizan inserciones para registrar la actividad del usuario. A la aplicación no le importará si la llamada finaliza inmediatamente o dentro de unos segundos.

Como nota al margen, un producto en el mercado proporciona un enfoque basado en políticas para permitir que las llamadas asíncronas como las que describí se hagan de forma asíncrona (http://www.heimdalldata.com/). Descargo de responsabilidad: soy cofundador de esta empresa. Permite aplicar expresiones regulares a las solicitudes de transformación de datos, como insertar/actualizar/eliminar para cualquier fuente de datos JDBC, y las agrupará automáticamente para su procesamiento. Cuando se usa con MySQL y la opción rewriteBatchedStatements (MySQL and JDBC with rewriteBatchedStatements=true), esto puede reducir significativamente la carga general en la base de datos.

+0

Pero esto todavía significa que JDBC debería tener al menos un hilo separado. ¿Qué hay de los frameworks y stacks que son de un solo subproceso pero aún están basados ​​en la devolución de llamada (se me ocurren nodejs)? ¿Sabes cómo gestionan las llamadas JDBC? – yuranos87

2

tiene tres opciones en mi opinión:

  1. utilizar un concurrent queue para distribuir mensajes a través de una pequeña y fija el número de hilos. Entonces, si tiene 1000 conexiones, tendrá 4 hilos, no 1000 hilos.
  2. Haga el acceso a la base de datos en otro nodo (es decir, otro proceso o máquina) y haga que su cliente de base de datos haga asynchronous network calls a ese nodo.
  3. Implemente un verdadero sistema distribuido a través de mensajes asíncronos. Para eso necesitarás una cola de mensajes como CoralMQ o Tibco.

Diclaimer: Soy uno de los desarrolladores de CoralMQ.

Cuestiones relacionadas