Чи можливий асинхронний виклик jdbc?


158

Цікаво, чи існує спосіб здійснення асинхронних дзвінків до бази даних?

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

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

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

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

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




Проблема полягає в тому, як може db повідомляти клієнта, коли запит закінчується. Для Oracle було б (наприклад) використовувати функцію "Повідомлення про зміну результатів запиту" та отримувати сповіщення при зміні даних db. Це стосується SQL-запитів, які змінюють дані db. Для запитів лише для читання це не працює. З іншого боку, я не впевнений, що підключення до асинхронізації з'єднань було б гарною ідеєю, оскільки встановити їх дорого. Звичайно, це не дуже загальне рішення. Просто їжа для роздумів ...
Майк Аргіріу

Чи використовує finagle-mysql JDBC?
Саїд Зарінфам

Відповіді:


164

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

Безумовно, основна проблема полягає в тому, що операції JDBC блокуються на IO сокета. Коли це робить, він блокує тему, яку він працює в кінці історії. Яку б рамку обгортання ви не використовували, вона буде в кінцевому підсумку, коли одна потока буде зайнята / заблокована за одночасним запитом

Якщо основні драйвери бази даних (MySql?) Пропонують засіб перехоплення створення сокету (див. SocketFactory), то я думаю, що можна було б створити шар бази даних, керований подіями асинхронізації, зверху до api JDBC, але нам доведеться інкапсулювати весь JDBC за фасадом, керованим подією, і цей фасад не буде схожий на JDBC (після того, як він буде керований подіями). Обробка бази даних буде асинхронізуватися в інший потік абоненту, і вам доведеться розробити, як створити менеджер транзакцій, який не покладається на спорідненість потоку.

Щось на кшталт підходу, про який я згадую, дозволив би навіть однієї фонової нитки обробити навантаження одночасних програм JDBC. На практиці ви, мабуть, запустили пул потоків, щоб використовувати кілька ядер.

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


Схоже, MySql, ймовірно, робить щось відповідно до запропонованих нами пропозицій --- http://code.google.com/p/async-mysql-connector/wiki/UsageExample


1
Використання Akka не робить виклики реляційних БД асинхронними. Це дозволяє легко запускати їх на купі виділених потоків для доступу до БД. Таким чином, ви не знімаєте весь сайт, коли сайт не реагує, оскільки ви завжди виконували виклики асинхронізації в сервісному шарі на рівень DAO з обіцянками, а потоки вашого веб-сервера відокремлені від решти вашої програми.
Онур

Актори - це не єдиний обхідний шлях (наприклад, мікро-сервіси та async http, яких ми масштабуємо до тисяч в секунду), і я би не настільки швидко відхилив їх, як несинхронний з точки зору клієнта. Якщо трафік потоків 1k UI входить у вашу систему, і лише 10 потоків заблоковано в БД, тоді як 990 'повідомлень' (або щось подібне) в черзі запам'ятовуються, не блокуючи жодного з потоків 1k UI (який, ймовірно, буде випущений). .. це не те, що потрібно? Я хотів би бачити справжній асинхронний JDBC, але це не означає, що в проміжку часу немає надзвичайно життєздатних обхідних шляхів.
Грег Пендлбері

42

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

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

Актори Scala за замовчуванням на основі подій (а не на основі потоку) - планування продовження дозволяє створювати мільйони акторів за стандартної установки JVM.

Якщо ви орієнтовані на Java, Akka Framework - це реалізація моделі Actor, яка має хороший API як для Java, так і для Scala.


Крім цього, синхронний характер JDBC має для мене ідеальний сенс. Вартість сеансу з базою даних набагато вище, ніж вартість блокованого потоку Java (або на передньому, або на задньому плані) і чекає відповіді. Якщо ваші запити працюють настільки довго, що можливостей служби виконавця (або обгортання фреймворків Actor / fork-join / обіцяють одночасність) вам недостатньо (і ви витрачаєте занадто багато ниток), перш за все, слід подумати про свою завантаження бази даних Зазвичай відповідь з бази даних повертається дуже швидко, і послуга виконавця, підтримувана фіксованим пулом потоків, є досить хорошим рішенням. Якщо у вас занадто багато тривалих запитів, слід розглянути можливість попередньої (попередньої) обробки - як нічний перерахунок даних чи щось подібне.


2
@Victor, кожен актор, що працює паралельно над блокувальною операцією (JDBC), буде працювати на окремій темі, якої намагається уникнути Стів
Василь Ременюк

36
Акторський підхід все ще вимагає одного потоку на активну транзакцію бази даних, тоді як транзакція триває, тому це насправді не вирішення проблеми ОП, якщо ви не готові обмежувати кількість паралельних транзакцій із базою даних та зачекати деякі операції з базою даних "асинхронізувати". деякі вже виконують, щоб закінчити та звільнити нитку. Це не погана ідея - база даних може перевантажуватися, якщо ви відкриваєте занадто багато з'єднань - тому розміщення транзакції вашої бази даних у черзі на обробку замість блокування потоку обробки запиту http допоможе.
Dobes Vandermeer

8
Рішення на основі актора все ще блокує нитку. Не кажіть, що неможливо виконати виклик async jdbc, є експериментальні бібліотеки з відкритим кодом, які намагаються реалізувати async jdbc.

6
+1 "Вартість сеансу з базою даних набагато вища, ніж вартість заблокованого потоку Java"
Пол Драпер

1
Для дорогих дзвінків DB зазвичай не така велика проблема. Саме тоді, коли виклик є тривіальним, мережа накладних витрат стає проблемою. Якщо ви хочете зробити 100 запитів, що займають 1 мс в БД, але мережеві накладні витрати - 200 мс, то це триватиме 20 секунд синхронно, але триватиме 300 мс асинхронно.
ранок

12

Можливо, ви могли б використовувати асинхронну систему обміну повідомленнями JMS, яка масштабує досить добре, IMHO:

  • Надішліть повідомлення до черги, де підписники приймуть повідомлення та запустить процес SQL. Ваш основний процес буде продовжувати працювати та приймати чи надсилати нові запити.

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


7

У JDBC немає прямої підтримки, але у вас є кілька варіантів, таких як MDB, Виконавці з Java 5.

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

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


Я думаю, що головний аргумент проти потоків полягає в тому, що ви в основному знаходяться поза будь-якими стандартними обмеженнями контейнерів Java, тож ви втрачаєте кластеризацію керованих контейнерів і не спрацьовуєте над можливостями, хоча ви можете згорнути свій власний або використовувати щось на зразок Terracotta.
mezmo

3
ми можемо скористатись потоковими опитуваннями, керованими сервером додатків, використовуючи менеджерів роботи. websphere, weblogic та glassfish підтримують це
Aravind Yarram


4

Як вже згадувалося в інших відповідях, API JDBC за своєю природою не є Асинхронним.
Однак якщо ви можете жити з підмножиною операцій та іншим API, є рішення. Один з прикладів - https://github.com/jasync-sql/jasync-sql, який працює для MySQL та PostgreSQL.


3

Проект Ajdbc, здається, відповідає на цю проблему http://code.google.com/p/adbcj/

В даний час є два експериментальних асинхронних драйвера для mysql та postgresql.


Я хотів би, щоб цей підхід був готовий. JDBC сильно розвивався з самого початку (ітератори, шаблони, підготовлені процедури), але цей підхід до асинхронізації ніколи не був реалізований. Це було б особливо цікаво для операцій запису (Вставка, оновлення, видалення), а також особливо важких пакетних TX, з якими ми стикаємося. На мою думку, будь-який підхід, орієнтований на клієнта (Пул, Актор, Планування, Повідомлення ...) призведе до невеликих винагород у плані використання ресурсів (можливо, певний приріст у пропускній спроможності чи затримці).
Хайме Казеро

Старі та покинуті, підтримуються лише два типи даних, навіть не готові до виробництва. На жаль :(
Аарон Зінман

Випуск №1 цієї бібліотеки стосується недоступності веб-сайту . Це вже більше року. Я підозрюю, що ця бібліотека досить мертва.
Лукас Едер

3

Старе запитання, але трохи більше інформації. Неможливо, щоб JDBC видавав асинхронні запити до самої бази даних, якщо тільки постачальник не надає розширення на JDBC та обгортку, з якою обробляє JDBC. З огляду на це, можна обернути JDBC з чергою на обробку та реалізувати логіку, яка може вимикати чергу з одного або декількох окремих з'єднань. Однією з переваг цього для деяких типів дзвінків є те, що логіка, за умови достатнього великого навантаження, може перетворити виклики в пакети JDBC для обробки, що може значно прискорити логіку. Це найбільш корисно для дзвінків, де вставляються дані, а фактичний результат потрібно реєструвати лише у випадку помилки. Прекрасним прикладом цього є те, якщо виконуються вставки для реєстрації активності користувачів. Додаток переміг "

Як зауваження, один продукт на ринку пропонує підхід, орієнтований на політику, щоб дозволити асинхронні дзвінки, як ті, які я описав, робити асинхронно ( http://www.heimdalldata.com/ ). Відмова: Я є співзасновником цієї компанії. Це дозволяє застосовувати регулярні вирази до запитів на перетворення даних, таких як вставка / оновлення / видалення для будь-якого джерела даних JDBC, і автоматично збирає їх разом для обробки. Якщо використовується з MySQL та параметром rewriteBatchedStatements ( MySQL та JDBC з rewriteBatchedStatements = вірно ), це може значно знизити загальне навантаження на базу даних.


Але це все ще означає, що JDBC повинен мати хоча б одну окрему нитку. Що з фреймворками та стеками, які є однопотоковими, але все ще засновані на зворотному дзвінку (nodejs спадає на думку)? Чи знаєте ви, як вони управляють дзвінками JDBC?
yuranos

3

На ваш погляд, у вас є три варіанти:

  1. Використовуйте паралельну чергу для поширення повідомлень по невеликій та фіксованій кількості потоків. Тож якщо у вас 1000 підключень, у вас буде 4 потоки, а не 1000 потоків.
  2. Зробіть доступ до бази даних на іншому вузлі (тобто іншому процесі чи машині), і ваш клієнт бази даних здійснює асинхронні мережеві дзвінки до цього вузла.
  3. Реалізуйте справжню розподілену систему за допомогою асинхронних повідомлень. Для цього вам знадобиться черга повідомлень, таких як CoralMQ або Tibco.

Діклаймер: Я один із розробників CoralMQ.


3

Розробляється рішення, щоб зробити можливим реактивне з'єднання за допомогою стандартних реляційних баз даних.

Люди, які бажають масштабувати, зберігаючи використання реляційних баз даних, відключаються від реактивного програмування завдяки існуючим стандартам, заснованим на блокуванні вводу-виводу. R2DBC задає новий API, який дозволяє реагувати код, які ефективно працюють з реляційними базами даних.

R2DBC - це специфікація, розроблена з нуля для реактивного програмування з базами даних SQL, що визначає неблокуючий SPI для виконавців драйверів баз даних та авторів бібліотеки клієнтів. Драйвери R2DBC повністю реалізують протокол проводу бази даних поверх неблокуючого рівня вводу / виводу.

Веб-сайт R2DBC

GitHub R2DBC

Матриця функцій

введіть тут опис зображення


2

В Java 5.0 виконавці можуть стати в нагоді.

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



2

Просто божевільна ідея: ви можете використовувати шаблон Iteratee над результатом JBDCSet, загорнутий у якесь майбутнє / обіцянку

Hammersmith робить це для MongoDB .


1

Я просто думаю ідеї тут. Чому ви не могли мати пул з'єднань із базою даних, кожен з яких має потік. Кожен потік має доступ до черги. Коли ви хочете зробити запит, який займає тривалий час, ви можете поставити його в чергу, і тоді одна з ниток підбере її і обробить її. У вас ніколи не буде занадто багато ниток, оскільки кількість ваших потоків обмежена.

Редагувати: Або ще краще, лише кількість ниток. Коли нитка бачить щось у черзі, вона запитує з'єднання з пулу та обробляє його.


1

Бібліотека commons-dbutils має підтримку, AsyncQueryRunnerяку ви надаєте, ExecutorServiceі вона повертає a Future. Варто перевірити, як це просто у використанні та гарантуйте, що ви не просочите ресурси.


1

Якщо ви зацікавлені в API асинхронних баз даних для Java, ви повинні знати, що існує нова ініціатива щодо створення набору стандартних API, заснованих на CompletableFuture та лямбдах. Існує також реалізація цих API через JDBC, які можна використовувати для використання цих API: https://github.com/oracle/oracle-db-examples/tree/master/java/AoJ JavaDoc згадується в README від проект github.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.