Apakah panggilan jdbc asinkron dimungkinkan?

158

Saya ingin tahu apakah ada cara untuk melakukan panggilan asinkron ke database?

Misalnya, bayangkan saya memiliki permintaan besar yang membutuhkan waktu sangat lama untuk diproses, saya ingin mengirim permintaan dan menerima pemberitahuan ketika permintaan akan mengembalikan nilai (dengan melewati Pendengar / panggilan balik atau sesuatu). Saya tidak ingin memblokir menunggu database untuk menjawab.

Saya tidak menganggap bahwa menggunakan kumpulan thread adalah solusi karena tidak skala, dalam kasus permintaan bersamaan yang berat ini akan menelurkan sejumlah besar thread.

Kami menghadapi masalah semacam ini dengan server jaringan dan kami telah menemukan solusi dengan menggunakan panggilan sistem select / poll / epoll untuk menghindari satu utas per koneksi. Saya hanya ingin tahu bagaimana caranya memiliki fitur yang mirip dengan permintaan basis data?

Catatan: Saya sadar bahwa menggunakan FixedThreadPool mungkin merupakan solusi yang baik, tetapi saya terkejut bahwa tidak ada yang mengembangkan sistem yang benar-benar tidak sinkron (tanpa menggunakan utas tambahan).

Pembaruan ** **
Karena kurangnya solusi praktis nyata, saya memutuskan untuk membuat perpustakaan (bagian dari finagle) sendiri: finagle-mysql . Ini pada dasarnya menerjemahkan / menerjemahkan permintaan / respons mysql, dan menggunakan Finagle / Netty di bawah tenda. Ini berskala sangat baik bahkan dengan sejumlah besar koneksi.

Steve Gury
sumber
1
Lihat juga github.com/mauricio/postgresql-async
Daniel Worthington-Bodart
Masalahnya adalah bagaimana db dapat memberi tahu klien ketika permintaan selesai. Satu akan menjadi (misalnya) untuk Oracle untuk menggunakan fitur "Notifikasi Perubahan Hasil Permintaan Database" dan mendapatkan pemberitahuan ketika perubahan data db. Ini berlaku untuk kueri SQL yang mengubah data db Untuk kueri hanya-baca, ini tidak akan berfungsi. Di sisi lain saya tidak yakin membuat koneksi async akan menjadi ide yang bagus karena membangun koneksi itu mahal. Tentu saja ini bukan solusi yang sangat umum. Hanya makanan untuk dipikirkan ...
Mike Argyriou
Apakah finagle-mysql menggunakan JDBC?
Saeed Zarinfam

Jawaban:

164

Saya tidak mengerti bagaimana salah satu pendekatan yang diusulkan yang membungkus panggilan JDBC di Aktor, pelaksana atau apa pun dapat membantu di sini - dapat seseorang mengklarifikasi.

Tentunya masalah dasarnya adalah bahwa operasi JDBC memblokir IO pada soket. Ketika hal ini terjadi, ia memblokir Thread yang berjalan di akhir cerita. Apapun kerangka pembungkus yang Anda pilih akan berakhir dengan satu utas tetap sibuk / diblokir per permintaan bersamaan.

Jika driver basis data yang mendasarinya (MySql?) Menawarkan cara untuk mencegat pembuatan soket (lihat SocketFactory) maka saya membayangkan akan mungkin untuk membangun lapisan basis data yang didorong oleh peristiwa async di atas api JDBC tetapi kita harus merangkum seluruh JDBC di belakang fasad yang digerakkan oleh acara, dan fasad yang tidak akan terlihat seperti JDBC (setelah itu akan digerakkan oleh acara). Pemrosesan basis data akan terjadi secara async pada utas yang berbeda dengan penelepon, dan Anda harus mengetahui cara membangun manajer transaksi yang tidak bergantung pada afinitas utas.

Sesuatu seperti pendekatan yang saya sebutkan akan memungkinkan bahkan utas latar belakang tunggal untuk memproses beban bersamaan JDBC exec. Dalam praktiknya, Anda mungkin akan menjalankan kumpulan utas untuk memanfaatkan beberapa inti.

(Tentu saja saya tidak mengomentari logika pertanyaan asli hanya tanggapan yang menyiratkan bahwa konkurensi dalam skenario dengan memblokir soket IO dimungkinkan tanpa pengguna pola pemilih - lebih sederhana hanya untuk bekerja di luar konkurensi JDBC khas Anda dan menempatkan di kolam koneksi dengan ukuran yang tepat).


Sepertinya MySql mungkin melakukan sesuatu yang saya sarankan --- http://code.google.com/p/async-mysql-connector/wiki/UsageExample

Johnlon
sumber
1
Menggunakan Akka tidak membuat panggilan ke DB relasional asinkron. Ini memungkinkan Anda menjalankannya pada sekelompok utas khusus untuk akses DB dengan mudah. Dengan cara ini Anda tidak mengambil seluruh situs ketika situs menjadi tidak responsif karena Anda selalu membuat panggilan async di lapisan layanan ke lapisan DAO dengan janji dan utas server web Anda terpisah dari sisa aplikasi Anda.
Onur
Aktor bukan satu-satunya solusi (mis. Layanan mikro dan http async, yang kami skala hingga ribuan per detik), dan saya tidak akan begitu cepat menganggapnya sebagai tidak sinkron dari perspektif klien. Jika lalu lintas 1k UI masuk ke sistem Anda dan hanya 10 utas yang diblokir pada DB, sementara 990 'pesan' (atau yang serupa) dimasukkan dalam memori tanpa memblokir salah satu utas UI 1k (yang mungkin akan dirilis). .. bukankah itu yang dibutuhkan? Saya ingin melihat JDBC async yang sebenarnya, tetapi itu tidak berarti tidak ada solusi yang sangat layak untuk sementara.
Greg Pendlebury
42

Tidak mungkin membuat panggilan asinkron ke database melalui JDBC, tetapi Anda dapat membuat panggilan asinkron ke JDBC dengan Aktor (mis. Aktor membuat panggilan ke DB melalui JDBC, dan mengirim pesan ke pihak ketiga, saat panggilan selesai), atau, jika Anda menyukai CPS, dengan futures pipelined (janji) (implementasi yang baik adalah Scalaz Promises )

Saya tidak menganggap bahwa menggunakan kumpulan thread adalah solusi karena tidak skala, dalam kasus permintaan bersamaan yang berat ini akan menelurkan sejumlah besar thread.

Aktor scala secara default berbasis pada peristiwa (bukan berdasarkan thread) - penjadwalan lanjutan memungkinkan pembuatan jutaan aktor pada pengaturan JVM standar.

Jika Anda menargetkan Java, Akka Framework adalah implementasi model Aktor yang memiliki API yang baik untuk Java dan Scala.


Selain itu, sifat sinkron JDBC sangat masuk akal bagi saya. Biaya sesi basis data jauh lebih tinggi daripada biaya utas Java yang diblokir (baik di latar depan atau di belakang) dan menunggu tanggapan. Jika pertanyaan Anda berjalan begitu lama sehingga kemampuan layanan pelaksana (atau membungkus kerangka kerja konkurensi Actor / fork-join / janji) tidak cukup untuk Anda (dan Anda menggunakan terlalu banyak utas), pertama-tama Anda harus memikirkan tentang beban basis data. Biasanya respons dari basis data kembali sangat cepat, dan layanan pelaksana yang didukung dengan kumpulan utas tetap merupakan solusi yang cukup baik. Jika Anda memiliki terlalu banyak pertanyaan yang berjalan lama, Anda harus mempertimbangkan pemrosesan di muka (pra-) - seperti perhitungan ulang malam hari dari data atau sesuatu seperti itu.

Vasil Remeniuk
sumber
2
@ Viktor, setiap aktor yang bekerja secara paralel pada operasi pemblokiran (JDBC) akan berjalan pada utas terpisah yang coba dihindarkan Steve
Vasil Remeniuk
36
Pendekatan aktor masih memerlukan satu utas per transaksi basis data aktif, sementara transaksi sedang berlangsung, jadi itu bukan solusi untuk masalah OP kecuali Anda bersedia membatasi jumlah transaksi basis data paralel dan memiliki beberapa operasi basis data "async" tunggu untuk beberapa yang sudah dieksekusi untuk menyelesaikan dan membebaskan utas. Namun, ini bukan ide yang buruk - database mungkin kelebihan beban jika Anda membuka terlalu banyak koneksi - jadi menempatkan transaksi database Anda dalam antrian untuk diproses alih-alih memblokir utas pemrosesan permintaan http Anda akan membantu.
Dobes Vandermeer
8
Solusi berbasis aktor masih memblokir utas. Jangan katakan itu tidak mungkin untuk mengeksekusi panggilan jdbc async, ada pustaka sumber terbuka eksperimental yang mencoba mengimplementasikan async jdbc.
6
+1 "Biaya sesi basis data jauh lebih tinggi daripada biaya utas Java yang diblokir"
Paul Draper
1
Untuk panggilan DB mahal biasanya tidak ada masalah besar. Saat panggilan sepele, overhead jaringan menjadi masalah. Jika Anda ingin membuat 100 kueri, yang masing-masing mengambil 1 ms pada DB, tetapi overhead jaringan adalah 200 ms, maka itu akan memakan waktu lebih dari 20 detik secara serempak, tetapi akan mengambil 300 ms secara tidak sinkron.
morten
12

Mungkin Anda bisa menggunakan sistem pesan asinkron JMS, yang berskala cukup baik, IMHO:

  • Kirim pesan ke Antrian, di mana pelanggan akan menerima pesan, dan jalankan proses SQL. Proses utama Anda akan terus berjalan dan menerima atau mengirim permintaan baru.

  • Ketika proses SQL berakhir, Anda dapat menjalankan sebaliknya: mengirim pesan ke ResponseQueue dengan hasil dari proses, dan pendengar di sisi klien menerimanya dan menjalankan kode panggilan balik.

Tomas Narros
sumber
7

Tidak ada dukungan langsung di JDBC tetapi Anda memiliki beberapa opsi seperti MDB, Pelaksana dari Java 5.

"Saya tidak menganggap bahwa menggunakan kumpulan utas adalah solusi karena tidak menskalakan, dalam kasus permintaan serentak yang besar ini akan menelurkan sejumlah besar utas."

Saya ingin tahu mengapa kumpulan benang yang dibatasi tidak akan bertambah? Ini bukan kumpulan utas per permintaan untuk menelurkan utas per setiap permintaan. Saya telah menggunakan ini selama beberapa waktu di webapp beban berat dan kami belum melihat masalah sejauh ini.

Aravind Yarram
sumber
Saya berpikir bahwa argumen utama terhadap utas adalah bahwa Anda pada dasarnya berada di luar batasan kontainer Java standar, sehingga Anda kehilangan pengelompokan yang dikelola kontainer dan gagal karena kemampuan, meskipun Anda dapat menggulirkan milik Anda sendiri, atau menggunakan sesuatu seperti Terracotta.
mezmo
3
kita dapat memanfaatkan polling yang dikelola server aplikasi dengan menggunakan manajer kerja. websphere, weblogic, dan glassfish mendukungnya
Aravind Yarram
4

Seperti yang disebutkan dalam jawaban lain, JDBC API pada dasarnya bukan Async.
Namun, jika Anda dapat hidup dengan subset operasi dan API yang berbeda ada solusinya. Salah satu contohnya adalah https://github.com/jasync-sql/jasync-sql yang berfungsi untuk MySQL dan PostgreSQL.

oshai
sumber
3

Proyek Ajdbc tampaknya menjawab masalah ini http://code.google.com/p/adbcj/

Saat ini ada 2 driver async asli eksperimental untuk mysql dan postgresql.

Sebastien
sumber
Saya ingin pendekatan ini siap. JDBC telah banyak berkembang sejak awal (iterator, templat, prosedur yang disiapkan), tetapi pendekatan async ini tidak pernah diterapkan. Ini akan sangat menarik untuk operasi penulisan (Sisipkan, Perbarui, Hapus), dan khususnya TX banyak yang kita hadapi. Menurut pendapat saya, segala jenis pendekatan berbasis klien (Pooling, Aktor, Penjadwalan, Pesan ...) akan mengarah pada sedikit penghargaan dalam hal penggunaan sumber daya (mungkin beberapa peningkatan dalam throughput atau latensi).
Jaime Casero
Tua dan ditinggalkan, hanya dua tipe data yang didukung & bahkan tidak dekat dengan produksi siap. Sayangnya :(
Aaron Zinman
Masalah # 1 dari perpustakaan ini adalah tentang situs web yang tidak tersedia . Umurnya lebih dari satu tahun. Saya menduga perpustakaan ini sudah mati.
Lukas Eder
3

Sebuah pertanyaan lama, tetapi beberapa informasi lebih lanjut. Tidak mungkin memiliki JDBC mengeluarkan permintaan asinkron ke database itu sendiri, kecuali jika vendor memberikan ekstensi ke JDBC dan pembungkus untuk menangani JDBC. Yang mengatakan, adalah mungkin untuk membungkus JDBC itu sendiri dengan antrian pemrosesan, dan untuk mengimplementasikan logika yang dapat memproses dari antrian pada satu atau lebih koneksi terpisah. Satu keuntungan dari ini untuk beberapa jenis panggilan adalah bahwa logika, jika di bawah beban yang cukup berat, dapat mengubah panggilan menjadi batch JDBC untuk diproses, yang dapat mempercepat logika secara signifikan. Ini paling berguna untuk panggilan di mana data dimasukkan, dan hasil aktual hanya perlu dicatat jika ada kesalahan. Contoh yang bagus tentang ini adalah jika memasukkan dilakukan untuk mencatat aktivitas pengguna. Aplikasi menang '

Sebagai catatan tambahan, satu produk di pasar menyediakan pendekatan yang didorong oleh kebijakan untuk memungkinkan panggilan asinkron seperti yang saya jelaskan dibuat secara tidak sinkron ( http://www.heimdalldata.com/ ). Penafian: Saya adalah salah satu pendiri perusahaan ini. Ini memungkinkan ekspresi reguler untuk diterapkan pada permintaan transformasi data seperti memasukkan / memperbarui / menghapus sumber data JDBC, dan secara otomatis akan mengumpulkannya bersama untuk diproses. Ketika digunakan dengan MySQL dan opsi rewriteBatchedStatements ( MySQL dan JDBC dengan rewriteBatchedStatements = true ) ini dapat secara signifikan menurunkan keseluruhan beban pada database.

Erik Brandsberg
sumber
Tetapi ini masih berarti bahwa JDBC harus memiliki setidaknya satu utas terpisah. Bagaimana dengan kerangka kerja dan tumpukan yang single-threaded tetapi masih berbasis callback (nodejs datang ke pikiran)? Apakah Anda tahu bagaimana mereka mengatur panggilan JDBC?
yuranos
3

Anda memiliki tiga opsi menurut saya:

  1. Gunakan antrian serentak untuk mendistribusikan pesan di sejumlah kecil utas. Jadi, jika Anda memiliki 1000 koneksi, Anda akan memiliki 4 utas, bukan 1000 utas.
  2. Lakukan akses basis data pada simpul lain (yaitu proses atau mesin lain) dan minta klien basis data Anda membuat panggilan jaringan tidak sinkron ke simpul itu.
  3. Menerapkan sistem terdistribusi benar melalui pesan asinkron. Untuk itu Anda perlu antrian pengiriman pesan seperti CoralMQ atau Tibco.

Diclaimer: Saya adalah salah satu pengembang CoralMQ.

rdalmeida
sumber
3

Sebuah solusi sedang dikembangkan untuk memungkinkan konektivitas reaktif dengan database relasional standar.

Orang yang ingin meningkatkan skala sambil tetap mempertahankan penggunaan basis data relasional terputus dari pemrograman reaktif karena standar yang ada berdasarkan pemblokiran I / O. R2DBC menentukan API baru yang memungkinkan kode reaktif yang bekerja secara efisien dengan basis data relasional.

R2DBC adalah spesifikasi yang dirancang dari bawah ke atas untuk pemrograman reaktif dengan database SQL yang mendefinisikan SPI non-pemblokiran untuk pengandar driver database dan penulis pustaka klien. Driver R2DBC mengimplementasikan sepenuhnya protokol kawat basis data di atas lapisan I / O yang tidak menghalangi.

WebDite R2DBC

GitHub R2DBC

Matriks Fitur

masukkan deskripsi gambar di sini

Yassin Hajaj
sumber
2

Para pelaksana Java 5.0 mungkin berguna.

Anda dapat memiliki sejumlah utas untuk menangani operasi yang sudah berjalan lama. Dan alih-alih RunnableAnda dapat menggunakan Callable, yang mengembalikan hasil. Hasilnya diringkas dalam suatu Future<ReturnType>objek, sehingga Anda bisa mendapatkannya ketika itu kembali.

Bozho
sumber
2

Hanya ide gila: Anda bisa menggunakan pola Iteratee di atas hasil JBDC. Setel dalam beberapa Future / Promise

Hammersmith melakukan itu untuk MongoDB .

jwinandy
sumber
1

Saya hanya memikirkan ide di sini. Mengapa Anda tidak dapat memiliki kumpulan koneksi database dengan masing-masing memiliki utas. Setiap utas memiliki akses ke antrian. Saat Anda ingin melakukan kueri yang membutuhkan waktu lama, Anda dapat memasukkan antrian dan kemudian salah satu utas akan mengambilnya dan menanganinya. Anda tidak akan pernah memiliki terlalu banyak utas karena jumlah utas Anda dibatasi.

Sunting: Atau lebih baik lagi, hanya sejumlah utas. Ketika utas melihat sesuatu dalam antrian, ia meminta koneksi dari kolam dan menanganinya.

Amir Raminfar
sumber
1

Pustaka commons-dbutils memiliki dukungan untuk AsyncQueryRunnermana Anda memberikan ExecutorServicedan mengembalikan a Future. Layak dicoba karena mudah digunakan dan memastikan Anda tidak akan membocorkan sumber daya.

William Speirs
sumber
1

Jika Anda tertarik pada API database asinkron untuk Java, Anda harus tahu bahwa ada inisiatif baru untuk menghasilkan seperangkat API standar berdasarkan CompletableFuture dan lambdas. Ada juga implementasi API ini di atas JDBC yang dapat digunakan untuk mempraktekkan API ini: https://github.com/oracle/oracle-db-examples/tree/master/java/AoJ JavaDoc disebutkan dalam README of proyek github.

Jean de Lavarene
sumber