Me pregunto si hay una manera de hacer llamadas asincrónicas a una base de datos.
Por ejemplo, imagine que tengo una gran solicitud que toma mucho tiempo procesar, quiero enviar la solicitud y recibir una notificación cuando la solicitud devuelva un valor (al pasar un Listener / callback o algo así). No quiero bloquear la espera de 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 concurrentes pesadas esto generará una gran cantidad de subprocesos.
Estamos enfrentando este tipo de problema con los servidores de red y hemos encontrado soluciones al usar 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 base de datos.
Nota: Soy consciente de que usar un FixedThreadPool puede ser una buena solución, pero me sorprende que nadie haya desarrollado un sistema realmente asíncrono (sin el uso de hilo adicional).
** Actualización **
Debido a la falta de soluciones prácticas reales, decidí crear una biblioteca (parte de finagle): finagle-mysql . Básicamente decodifica / decodifica la solicitud / respuesta mysql, y usa Finagle / Netty debajo del capó. Se escala extremadamente bien incluso con una gran cantidad de conexiones.
fuente
Respuestas:
No entiendo cómo cualquiera 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 se bloquean en el socket IO. Cuando hace esto, bloquea el hilo en ejecución - final de la historia. Cualquiera que sea el marco de envoltura que elija utilizar, terminará con un subproceso ocupado / bloqueado por solicitud simultánea.
Si los controladores de la base de datos subyacentes (MySql?) Ofrecen un medio para interceptar la creación del socket (vea SocketFactory), entonces imagino que sería posible construir una capa de base de datos controlada por eventos asíncronos en la parte superior de la API JDBC, pero tendríamos que encapsular el JDBC completo detrás de una fachada impulsada por eventos, y esa fachada no se vería como JDBC (después de que sería impulsada por eventos). El procesamiento de la base de datos sucedería de forma asíncrona en un subproceso diferente al que realiza la llamada, y tendría que averiguar cómo construir un administrador de transacciones que no dependa de la afinidad del subproceso.
Algo así como el enfoque que menciono permitiría que incluso un solo subproceso en segundo plano procese una carga de ejecutivos JDBC concurrentes. En la práctica, probablemente ejecute un grupo de subprocesos para utilizar múltiples núcleos.
(Por supuesto, no estoy comentando sobre la lógica de la pregunta original, solo las respuestas que implican que la concurrencia en un escenario con bloqueo de socket IO es posible sin el usuario de un patrón selector, más simple solo para resolver su concurrencia JDBC típica y poner en un grupo de conexiones del tamaño correcto).
Parece que MySql probablemente hace algo similar a lo que sugiero --- http://code.google.com/p/async-mysql-connector/wiki/UsageExample
fuente
Es imposible realizar una llamada asincrónica a la base de datos a través de JDBC, pero puede realizar llamadas asincrónicas 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 terceros, cuando las llamadas terminan), o, si le gusta CPS, con futuros canalizados (promesas) (una buena implementación es Scalaz Promises )
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 JVM estándar.
Si está apuntando a Java, Akka Framework es una implementación de modelo de actor que tiene una buena API tanto para Java como para Scala.
Aparte de eso, la naturaleza sincrónica de JDBC tiene mucho sentido para mí. El costo de una sesión de base de datos es mucho mayor que el costo del bloqueo del hilo de Java (ya sea en primer o 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 regresa muy rápido, y un servicio ejecutor respaldado con un grupo de subprocesos fijos es una solución lo suficientemente buena. Si tiene demasiadas consultas de larga duración, debe considerar el procesamiento previo (previo), como el recálculo nocturno de los datos o algo así.
fuente
Tal vez podría usar un sistema de mensajería asíncrona JMS, que escala bastante bien, en mi humilde opinión:
Envíe un mensaje a una cola, donde los suscriptores aceptarán el mensaje y ejecutarán el proceso SQL. Su proceso principal continuará ejecutándose y aceptando o enviando nuevas solicitudes.
Cuando finaliza el proceso SQL, puede ejecutarlo de la manera opuesta: envíe un mensaje a ResponseQueue con el resultado del proceso, y un escucha del lado del cliente lo acepta y ejecuta el código de devolución de llamada.
fuente
No hay soporte directo en JDBC pero tiene múltiples opciones como MDB, Executors from Java 5.
"No considero que el uso de un grupo de subprocesos sea una solución porque no se escala, en el caso de solicitudes concurrentes pesadas esto generará una gran cantidad de subprocesos".
Tengo curiosidad por qué un grupo limitado de hilos no se escalará. Es un grupo no hilo por solicitud para generar un hilo por cada solicitud. He estado usando esto durante bastante tiempo en una aplicación web de carga pesada y hasta ahora no hemos visto ningún problema.
fuente
Parece que una nueva API asíncrona jdbc "JDBC next" está en proceso.
Ver presentación aquí
Puedes descargar la API desde aquí
fuente
Como se menciona en otras respuestas, la API JDBC no es asíncrona por su naturaleza.
Sin embargo, si puede vivir con un subconjunto de operaciones y una API diferente, existen soluciones. Un ejemplo es https://github.com/jasync-sql/jasync-sql que funciona para MySQL y PostgreSQL.
fuente
El proyecto Ajdbc parece responder a este problema http://code.google.com/p/adbcj/
Actualmente hay 2 controladores asíncronos nativos experimentales para mysql y postgresql.
fuente
Una vieja pregunta, pero algo más de información. No es posible 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 envolver JDBC con una cola de procesamiento e implementar una lógica que pueda procesar fuera de 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á bajo una carga lo suficientemente pesada, 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 llamadas donde se están insertando datos, y el resultado real solo necesita registrarse si hay un error. Un gran ejemplo de esto es si se realizan inserciones para registrar la actividad del usuario. La aplicación ganó '
Como nota al margen, un producto en el mercado proporciona un enfoque basado en políticas para permitir que las llamadas asincrónicas como las que describí se realicen de forma asincrónica ( http://www.heimdalldata.com/ ). Descargo de responsabilidad: soy cofundador de esta empresa. Permite que se apliquen 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 y JDBC con rewriteBatchedStatements = true ), esto puede reducir significativamente la carga general en la base de datos.
fuente
Tienes tres opciones en mi opinión:
Diclaimer: Soy uno de los desarrolladores de CoralMQ.
fuente
Se está desarrollando una solución para hacer posible la conectividad reactiva con bases de datos relacionales estándar.
Sitio web de R2DBC
GitHub de R2DBC
Matriz de funciones
fuente
Los ejecutores de Java 5.0 pueden ser útiles.
Puede tener un número fijo de subprocesos para manejar operaciones de larga duración. Y en lugar de
Runnable
que pueda usarCallable
, que devuelven un resultado. El resultado se encapsula en unFuture<ReturnType>
objeto, por lo que puede obtenerlo cuando regrese.fuente
Aquí hay un resumen sobre cómo podría ser una API jdbc sin bloqueo de Oracle presentada en JavaOne: https://static.rainfocus.com/oracle/oow16/sess/1461693351182001EmRq/ppt/CONF1578%2020160916.pdf
Por lo tanto, parece que al final, las llamadas JDBC verdaderamente asincrónicas serán posibles.
fuente
Solo una idea loca: podría usar un patrón Iteratee sobre el resultado de JBDC Conjunto envuelto en algún Futuro / Promesa
Hammersmith hace eso por MongoDB .
fuente
Solo estoy pensando ideas aquí. ¿Por qué no podría tener un grupo de conexiones de bases de datos con cada una que tenga un hilo? Cada hilo tiene acceso a una cola. Cuando desee hacer una consulta que lleve mucho tiempo, puede ponerla en la cola y luego uno de los hilos la recogerá y la manejará. Nunca tendrás demasiados hilos porque el número de tus hilos está limitado.
Editar: O mejor aún, solo una serie de hilos. Cuando un hilo ve algo en una cola, solicita una conexión del grupo y lo maneja.
fuente
La biblioteca commons-dbutils tiene soporte para una a la
AsyncQueryRunner
que proporciona un ayExecutorService
devuelve unFuture
. Vale la pena echarle un vistazo, ya que es fácil de usar y garantiza que no perderá recursos.fuente
Si está interesado en las API de base de datos asíncronas para Java, debe saber que existe una nueva iniciativa para crear un conjunto de API estándar basadas en CompletableFuture y lambdas. También hay una implementación de estas API sobre JDBC que se puede usar para practicar estas API: https://github.com/oracle/oracle-db-examples/tree/master/java/AoJ El JavaDoc se menciona en el archivo README de El proyecto Github.
fuente