Возможен ли асинхронный вызов jdbc?

122

Интересно, есть ли способ сделать асинхронные вызовы в базе данных?

Например, представьте, что у меня большой запрос, который занимает очень много времени для обработки, я хочу отправить запрос и получить уведомление, когда запрос вернет значение (передав Listener/callback или что-то еще), Я не хочу блокировать ожидание ответа базы данных.

Я не считаю, что использование пула потоков является решением, потому что оно не масштабируется, в случае тяжелых параллельных запросов это порождает очень большое количество потоков.

Мы сталкиваемся с такой проблемой с сетевыми серверами, и мы нашли решения, используя системный вызов select/poll/epoll, чтобы избежать использования одного потока для каждого соединения. Мне просто интересно, как иметь подобную функцию с запросом базы данных?

Примечание: Я знаю, что использование FixedThreadPool может быть хорошей практикой, но я удивлен, что никто не разработал систему, которая действительно асинхронна (без использования дополнительного потока).

** Обновление **
Из-за отсутствия реальных практических решений я решил сам создать библиотеку (часть finagle): finagle-mysql. Он в основном декодирует/декодирует запрос/ответ mysql и использует Finagle/Netty под капотом. Он очень хорошо масштабируется даже при большом количестве подключений.

  • 0
    См. Code.google.com/p/async-mysql-connector/wiki/UsageExample
  • 1
    Смотрите также github.com/mauricio/postgresql-async
Показать ещё 2 комментария
Теги:
asynchronous
jdbc
nonblocking

13 ответов

137
Лучший ответ

Я не понимаю, как какой-либо из предложенных подходов, которые обертывают вызовы JDBC в Актеры, исполнители или что-то еще, может помочь здесь - может кто-то уточнить.

Несомненно, основная проблема заключается в том, что блок операций JDBC в сокете IO. Когда он делает это, он блокирует поток, который работает на конце истории. Какую бы фреймворческую оболочку вы не решили использовать, чтобы в конечном итоге один поток был занят/заблокирован на один параллельный запрос.

Если базовые драйверы базы данных (MySql?) предлагают средство для перехвата создания сокета (см. SocketFactory), то я предполагаю, что можно было бы создать слой базы данных, основанный на async-событий, поверх api JDBC, но мы бы чтобы инкапсулировать весь JDBC за фасад, управляемый событиями, и этот фасад не будет похож на JDBC (после того, как он будет управляться событиями). Обработка базы данных будет происходить как асинхронный для другого потока для вызывающего, и вам нужно будет разработать, как создать диспетчер транзакций, который не полагается на сходство потоков.

Что-то вроде подхода, о котором я упоминал, позволит даже одному фоновому потоку обрабатывать нагрузку параллельных JDBC-exec. На практике вы, вероятно, запускаете пул потоков, чтобы использовать несколько ядер.

(Конечно, я не комментирую логику исходного вопроса только ответы, которые подразумевают, что concurrency в сценарии с блокирующим сокером IO возможен без пользователя шаблона селектора - проще просто выработать свой типичный JDBC concurrency и добавьте пул соединений нужного размера).


Похоже, что MySql, вероятно, делает что-то по строкам, которые я предлагаю --- http://code.google.com/p/async-mysql-connector/wiki/UsageExample

  • 2
    Это должно быть помечено как правильный ответ.
  • 0
    Использование Akka не делает вызовы реляционных БД асинхронными. Это позволяет вам легко запускать их на нескольких выделенных потоках для доступа к БД. Таким образом, вы не отключаете весь сайт, когда он перестает отвечать на запросы, потому что вы всегда выполняли асинхронные вызовы на уровне обслуживания для уровня DAO с обещаниями, а потоки вашего веб-сервера отделены от остальной части вашего приложения.
Показать ещё 1 комментарий
38

Невозможно выполнить асинхронный вызов базы данных через JDBC, но вы можете сделать асинхронные вызовы в JDBC с помощью Актеров (например, актер совершает вызовы в БД через JDBC и отправляет сообщения в третьи стороны, когда вызовы закончены), или, если вам нравится CPS, конвейерные фьючерсы (promises) (хорошая реализация Scalaz Promises)

Я не считаю, что использование пула потоков является решением, потому что оно не масштабируется, в случае тяжелых параллельных запросов это порождает очень большое количество потоков.

Scala субъекты по умолчанию основаны на событиях (не на основе потоков) - планирование продолжения позволяет создавать миллионы участников на стандартной установке JVM.

Если вы ориентируетесь на Java, Akka Framework является реализацией модели Actor, которая имеет хороший API как для Java, так и для Scala.


Кроме того, синхронный характер JDBC имеет для меня прекрасный смысл. Стоимость сеанса базы данных намного выше, чем затраты на поток Java, который блокируется (как на переднем, так и на заднем плане) и ожидает ответа. Если ваши запросы выполняются так долго, что возможности службы-исполнителя (или обертывания фреймворков Actor/fork-join/prom

  • 0
    +1. Я обернул дорогие вызовы JDBC (технически, Querulous) в актеров и никогда не оглядывался назад.
  • 0
    Я нацеливаюсь на scala, и я очень хорошо знаком с паттерном Promise / Actor. На самом деле я не рассматривал модель актера, потому что я все еще хочу выполнять запросы параллельно, я не хочу иметь большого актера, который выполняет все мои запросы последовательно. Моя первая идея состояла в том, чтобы использовать Promises, поддерживаемые FixedThreadPool с тем же размером, что и количество подключений к БД. В случае интенсивного использования каждый поток пула потоков блокируется в ожидании БД. Меня раздражает то, что все эти потоки не нужны, вполне возможно иметь эквивалентную систему с одним потоком.
Показать ещё 7 комментариев
10

Возможно, вы могли бы использовать систему асинхронных сообщений JMS, которая очень хорошо масштабируется, ИМХО:

  • Отправить сообщение в очередь, где подписчики будут принимать это сообщение и запустить SQL-процесс. Ваш основной процесс продолжит выполнение и принятие или отправку новых запросов.

  • Когда процесс SQL заканчивается, вы можете запустить обратный путь: отправить сообщение ResponseQueue с результатом процесса, а слушатель на стороне клиента принять его и выполнить код обратного вызова.

7

В JDBC нет прямой поддержки, но у вас есть несколько параметров, таких как MDB, Executors из Java 5.

"Я не считаю, что использование пула потоков является решением, потому что оно не масштабируется, в случае тяжелых одновременных запросов это порождает очень большое количество потоков".

Мне любопытно, почему ограниченный пул потоков не будет масштабироваться? Это пул, а не поток на запрос, чтобы порождать поток за каждый запрос. Я использую это довольно часто в режиме большой загрузки webapp, и мы пока не видели никаких проблем.

  • 0
    Я думаю, что основной аргумент против потоков заключается в том, что вы в основном находитесь за пределами каких-либо стандартных ограничений контейнеров Java, поэтому вы теряете управляемую контейнером кластеризацию и отказоустойчивые возможности, хотя вы можете свернуть свои собственные или использовать что-то вроде терракоты.
  • 3
    мы можем подключиться к опросам управляемых потоков сервера приложений с помощью рабочих менеджеров. websphere, weblogic и glassfish поддерживают его
3

Старый вопрос, но еще немного информации. Невозможно, чтобы JDBC выдавал асинхронные запросы самой базе данных, если поставщик не предоставляет расширение JDBC и оболочку для обработки JDBC. Тем не менее, можно обернуть сам JDBC очереди обработки и реализовать логику, которая может обрабатывать очередь на одном или нескольких отдельных соединениях. Одним из преимуществ этого для некоторых типов вызовов является то, что логика, если она находится при достаточно большой нагрузке, может преобразовывать вызовы в пакеты JDBC для обработки, что значительно ускорит логику. Это наиболее полезно для вызовов, где данные вставляются, и фактический результат нужно регистрировать только в случае возникновения ошибки. Хорошим примером этого является то, что для регистрации активности пользователя выполняются вставки. Приложение не заботится, будет ли вызов завершен немедленно или через несколько секунд.

В качестве побочного примечания один продукт на рынке обеспечивает политический подход к разрешению асинхронных вызовов, подобных тем, которые я описал, асинхронно (http://www.heimdalldata.com/). Отказ от ответственности: Я являюсь соучредителем этой компании. Это позволяет использовать регулярные выражения для запросов преобразования данных, таких как вставка/обновление/удаление для любого источника данных JDBC, и будет автоматически их совместно обрабатывать для обработки. При использовании с MySQL и параметром rewriteBatchedStatements (MySQL и JDBC с rewriteBatchedStatements = true) это может значительно снизить общую нагрузку на базу данных.

  • 0
    Но это все еще означает, что JDBC должен иметь хотя бы один отдельный поток. Как насчет каркасов и стеков, которые являются однопоточными, но все еще основаны на обратном вызове (на ум приходит nodejs)? Вы знаете, как они управляют вызовами JDBC?
3

Проект Ajdbc, кажется, отвечает на эту проблему http://code.google.com/p/adbcj/

В настоящее время существует 2 экспериментальных асинхронных драйвера для mysql и postgresql.

  • 0
    Я хотел бы, чтобы этот подход был готов. JDBC с самого начала сильно развивался (итераторы, шаблоны, подготовленные процедуры), но этот асинхронный подход никогда не был реализован. Это было бы особенно интересно для операций записи (Вставка, Обновление, Удаление), и особенно тех тяжелых TX, с которыми мы все сталкиваемся. По моему мнению, любой вид клиентского подхода (объединение в пул, актер, планирование, обмен сообщениями ...) приведет к небольшому вознаграждению с точки зрения использования ресурсов (возможно, некоторый выигрыш в пропускной способности или задержке).
  • 0
    Старые и заброшенные, поддерживаются только два типа данных и даже не готовы к работе. К несчастью :(
Показать ещё 1 комментарий
3

Java 5.0-исполнители могут пригодиться.

У вас может быть фиксированное количество потоков для обработки длительных операций. Вместо Runnable вы можете использовать Callable, которые возвращают результат. Результат заключен в объект Future<ReturnType>, поэтому вы можете получить его, когда он вернется.

2

У меня есть три варианта:

  • Используйте параллельную очередь для распространения сообщений через небольшое и фиксированное количество потоков. Так что если у вас 1000 соединений, у вас будет 4 потока, а не 1000 потоков.
  • Доступ к базе данных на другом node (т.е. другой процесс или машина) и клиент базы данных асинхронные сетевые вызовы, чтобы node.
  • Реализовать истинную распределенную систему через асинхронные сообщения. Для этого вам понадобится очередь сообщений, такая как CoralMQ или Tibco.

Diclaimer: Я один из разработчиков CoralMQ.

2

Просто сумасшедшая идея: вы можете использовать шаблон Iteratee по результирующему набору JBDC, заключенному в Future/Promise

Хаммерсмит делает это для MongoBd.

  • 1
    Не исправляет, что он все еще где-то блокирует поток.
1

Похоже, что новый асинхронный jdbc API "JDBC следующий" находится в работе.

См. презентация здесь

Вы можете загрузить API из здесь

  • 1
    перенаправленная ссылка, которая указывает на более свежую реализацию, находится здесь: oracle.com/goto/java-async-db
1

Ниже приведен пример того, что неблокирующий jdbc api может выглядеть как Oracle, представленный на JavaOne: https://static.rainfocus.com/oracle/oow16/sess/1461693351182001EmRq/ppt/CONF1578%2020160916.pdf

Итак, похоже, что в конечном итоге действительно будут асинхронные вызовы JDBC.

  • 0
    Это не JDBC, а дополнительный API
1

Библиотека commons-dbutils поддерживает AsyncQueryRunner, который вы предоставляете ExecutorService, и возвращает Future. Стоит проверить, как это просто использовать и гарантировать, что вы не будете утечки ресурсов.

1

Я просто думаю об этом здесь. Почему у вас не было пула соединений с базой данных, каждый из которых имеет поток. Каждый поток имеет доступ к очереди. Когда вы хотите выполнить запрос, который занимает много времени, вы можете поставить очередь, а затем один из потоков подберет его и обработает. У вас никогда не будет слишком много потоков, потому что количество ваших потоков ограничено.

Изменить: Или еще лучше, просто несколько потоков. Когда поток видит что-то в очереди, он запрашивает соединение из пула и обрабатывает его.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню