Zaman uyumsuz jdbc araması mümkün mü?


158

Bir veritabanına eşzamansız arama yapmanın bir yolu var mı acaba?

Örneğin, işlemek için çok uzun zaman alan büyük bir isteğim olduğunu düşünün, istek göndermek ve istek bir değer döndürdüğünde bir bildirim almak istiyorum (bir Dinleyici / geri arama veya bir şey ileterek). Ben veritabanı cevap beklemek engellemek istemiyorum.

Bir iş parçacığı havuzu kullanmanın bir çözüm olduğunu düşünmüyorum çünkü ölçeklenmiyor, ağır eşzamanlı istekler durumunda bu çok fazla iş parçacığı oluşturacak.

Ağ sunucuları ile bu tür bir sorunla karşı karşıyayız ve bağlantı başına bir iş parçacığına sahip olmaktan kaçınmak için select / poll / epoll sistem çağrısı kullanarak çözümler bulduk. Ben sadece veritabanı isteği ile benzer bir özellik var merak ediyorum?

Not: FixedThreadPool kullanmanın iyi bir çözüm olabileceğinin farkındayım, ancak hiç kimsenin (asgari iş parçacığı kullanmadan) gerçekten eşzamansız bir sistem geliştirmediğine şaşırdım.

** Güncelleme **
Gerçek pratik çözümlerin olmaması nedeniyle kendim bir kütüphane (finagle'ın bir parçası) oluşturmaya karar verdim: finagle-mysql . Temelde mysql isteğini / yanıtını çözer / çözer ve başlık altında Finagle / Netty kullanır. Çok sayıda bağlantıyla bile son derece iyi ölçeklenir.




Sorun sorgu bittiğinde db istemciye nasıl bildirebilir. Biri (örneğin) Oracle'ın "Veritabanı Sorgusu Sonuç Değişikliği Bildirimi" özelliğini kullanması ve db verileri değiştiğinde bildirim alması olacaktır. Bu, db verilerini değiştiren SQL sorguları için geçerlidir. Salt okunur sorgular için bu işe yaramaz. Öte yandan, bağlantılarını async yapmanın iyi bir fikir olacağından emin değilim çünkü bunları kurmak pahalı. Tabii ki bu çok genel bir çözüm değil. Düşünce için sadece yiyecek ...
Mike Argyriou

Finagle-mysql JDBC kullanıyor mu?
Saeed Zarinfam

Yanıtlar:


164

JDBC çağrılarını Aktörlere, uygulayıcılara veya başka bir şeye sarmalayan önerilen yaklaşımlardan herhangi birinin burada nasıl yardımcı olabileceğini anlamıyorum - biri açıklığa kavuşturabilir.

Elbette temel sorun JDBC işlemlerinin soket IO'sunda engellenmesidir. Bunu yaptığında, hikayenin sonunda iş parçacığının çalışmasını engeller. Hangi sarma çerçevesini seçerseniz seçin, bir iş parçacığı aynı anda istek başına meşgul / engellenir.

Temel veritabanı sürücüleri (MySql?) Soket oluşturma (bkz. SocketFactory) durdurmak için bir araç sunuyorsa o zaman JDBC api üstüne bir async olay tahrikli veritabanı katmanı oluşturmak mümkün olacağını hayal ama biz kapsüllemek zorundayız olay odaklı bir cephenin arkasındaki tüm JDBC ve o cephe JDBC gibi görünmeyecekti (olay güdümlendikten sonra). Veritabanı işleme arayan farklı bir iş parçacığında zaman uyumsuz olur ve iş parçacığı yakınlığına dayanmayan bir işlem yöneticisi oluşturmak için nasıl çalışmanız gerekir.

Bahsettiğim yaklaşım gibi bir şey, tek bir arka plan iş parçacığının bile eşzamanlı JDBC exec'in bir yükünü işlemesine izin verir. Pratikte, birden fazla çekirdeği kullanmak için muhtemelen bir iş parçacığı havuzu çalıştırırsınız.

(Tabii ki orijinal sorunun mantığı hakkında, sadece soket IO'yu engelleyen bir senaryoda eşzamanlılığın bir seçici desen kullanıcısı olmadan mümkün olduğunu ima eden cevaplar hakkında yorum yapmıyorum - sadece tipik JDBC eşzamanlılığınızı çözmek ve koymak daha basit doğru boyutta bir bağlantı havuzunda).


Görünüşe göre MySql muhtemelen önerdiğim satırlarda bir şeyler yapıyor --- http://code.google.com/p/async-mysql-connector/wiki/UsageExample


1
Akka kullanmak ilişkisel DB'leri zaman uyumsuz olarak çağırmaz. Kolayca DB erişimi için bir dizi özel iş parçacığında çalıştırmanıza izin verir. Bu şekilde, site yanıt vermediğinde sitenin tamamını almazsınız, çünkü DAO katmanına hizmet katmanında her zaman zaman uyumsuz çağrılar yaptığınız ve web sunucusu iş parçacıklarınız uygulamanızın geri kalanından ayrıdır.
Onur

Aktörler tek çözüm değildir (örneğin saniyede binlerce olarak ölçeklendirdiğimiz mikro hizmetler ve zaman uyumsuz http) ve bunları müşterinin bakış açısından eşzamansız olmadığı için reddetmek o kadar hızlı olmaz. Bellekte queue'd edilir 1k UI iş parçacığı trafik sistemine girmek ve sadece 10 ipler 990 'mesajları' (ya da benzer bir şey) iken, DB üzerinde engellenirse olmadan engelleme herhangi (muhtemelen çıkacak) 1 k UI iş parçacığı. .. gerekli olan bu değil mi? Gerçek asenkron JDBC'yi görmek isterim, ancak bu geçici olarak son derece uygulanabilir geçici çözümlerin olmadığı anlamına gelmez.
Greg Pendlebury

42

Bu bir asenkron arama yapmak imkansız veritabanına JDBC üzerinden, ancak asenkron arama yapabilirsiniz JDBC için birlikte Aktörler (örneğin, aktör JDBC üzerinden DB çağrıda bulunur ve aramalar bitti üçüncü şahıslara, mesaj gönderir), veya CPS'den hoşlanıyorsanız , pipeline edilmiş vadeli işlemler (vaatler) (iyi bir uygulama Skallaz Vaatleridir )

Bir iş parçacığı havuzu kullanmanın bir çözüm olduğunu düşünmüyorum çünkü ölçeklenmiyor, ağır eşzamanlı istekler durumunda bu çok fazla iş parçacığı oluşturacak.

Scala aktörleri varsayılan olarak olaya dayalıdır (iş parçacığı tabanlı değil) - devam zamanlaması, standart bir JVM kurulumunda milyonlarca aktör oluşturmanıza olanak tanır.

Java'yı hedefliyorsanız, Akka Framework , hem Java hem de Scala için iyi bir API'ye sahip bir Aktör modeli uygulamasıdır.


Bunun dışında, JDBC'nin eşzamanlı doğası benim için çok mantıklı. Bir veritabanı oturumunun maliyeti, engellenen (iş parçacığı veya arka planda) ve bir yanıt bekleyen Java iş parçacığının maliyetinden çok daha yüksektir. Sorgularınız bir yürütücü hizmetinin (veya Actor / fork-join / promise eşzamanlılık çerçevelerini sarma) yetenekleri sizin için yeterli değilse (ve çok fazla iş parçacığı tüketiyorsanız) öncelikle veritabanı yükü. Normalde bir veritabanından gelen yanıt çok hızlı bir şekilde geri döner ve sabit bir iş parçacığı havuzu ile desteklenen bir yürütme hizmeti yeterince iyi bir çözümdür. Çok fazla uzun süredir çalışan sorgunuz varsa, verilerin (her zaman) işlemeyi düşünmelisiniz - verilerin gece yeniden hesaplanması veya bunun gibi bir şey.


2
@Victor, engelleme operasyonunda (JDBC) paralel çalışan her aktör, Steve'in kaçınmaya çalıştığı ayrı bir iş parçacığında çalışacak
Vasil Remeniuk

36
Aktör yaklaşımı, işlem devam ederken her etkin veritabanı işlemi için bir iş parçacığı gerektirir, bu nedenle paralel veritabanı işlemlerinin sayısını sınırlamak istemiyorsanız ve bazı "eşzamansız" veritabanı işlemlerini beklemediğiniz sürece bu OP'nin sorununa gerçekten bir çözüm değildir. zaten iş parçacıkları bitirmek ve serbest bırakmak için. Yine de bu kötü bir fikir değil - çok fazla bağlantı açarsanız veritabanı aşırı yüklenebilir - bu nedenle veritabanı işleminizi http istek işleme iş parçacığınızı engellemek yerine işlemek için bir sıraya koymak yardımcı olacaktır.
Dobes Vandermeer

8
Aktör tabanlı çözüm hala ipliği engelliyor. Async jdbc çağrısını yürütmenin mümkün olmadığını söyleme, async jdbc'yi uygulamaya çalışan deneysel açık kaynak kütüphaneleri var.

6
+1 "Bir veritabanı oturumunun maliyeti, engellenen Java iş parçacığının maliyetinden çok daha yüksek"
Paul Draper

1
Pahalı DB çağrıları için genellikle böyle büyük bir sorun yoktur. Çağrı önemsiz olduğunda, ağ ek yükü bir sorun haline gelir. Her biri DB'de 1 ms süren 100 sorgu yapmak istiyorsanız, ancak ağ yükü 200 msyse, senkronize olarak 20 saniyeden fazla sürecek, ancak asenkron olarak 300 ms sürecektir.
morten

12

Belki de oldukça iyi ölçeklenen bir JMS asenkron mesajlaşma sistemi kullanabilirsiniz, IMHO:

  • Abonelerin mesajı kabul edeceği ve SQL sürecini çalıştıracağı bir Kuyruğa mesaj gönderin. Ana işleminiz çalışmaya ve yeni istekleri kabul etmeye veya göndermeye devam edecektir.

  • SQL işlemi sona erdiğinde, tersi şekilde çalıştırabilirsiniz: işlemin sonucuyla birlikte ResponseQueue'ya bir ileti gönderin ve istemci tarafındaki bir dinleyici bunu kabul edip geri arama kodunu yürütün.


7

JDBC'de doğrudan destek yoktur ancak Java 5'ten MDB, Executor gibi birden çok seçeneğiniz vardır.

Diyerek şöyle devam etti: "Bir iş parçacığı havuzu kullanmanın bir çözüm olduğunu düşünmüyorum çünkü ölçeklenmiyor, aynı anda yoğun isteklerde bu çok fazla iş parçacığı oluşturacak."

Sınırlı bir iş parçacığı havuzu neden ölçeklenmeyecek merak ediyorum? Her istek için bir iş parçacığı oluşturmak için istek başına iş parçacığı olmayan bir havuzdur. Ben ağır yük webapp üzerinde oldukça bir süredir bu ve şimdiye kadar herhangi bir sorun görmedim.


Ben iş parçacıkları karşı ana argüman temelde daha sonra herhangi bir standart Java kapsayıcı kısıtlamaları dışında olduğunu düşünüyorum, böylece kendi yönetebilir veya Terracotta gibi bir şey kullanabilirsiniz, ancak konteyner yönetilen kümeleme kaybetmek ve yeteneklerini başarısız.
mezmo

3
iş yöneticilerini kullanarak uygulama sunucusu tarafından yönetilen iş parçacığı anketlerine başvurabiliriz. websphere, weblogic ve glassfish destekliyor
Aravind Yarram


4

Diğer cevaplarda belirtildiği gibi JDBC API, doğası gereği Async değildir.
Ancak, işlemlerin bir alt kümesiyle ve farklı bir API ile yaşayabiliyorsanız, çözümler vardır. Bir örnek, MySQL ve PostgreSQL için çalışan https://github.com/jasync-sql/jasync-sql'dir .


3

Ajdbc projesi bu soruna cevap veriyor gibi görünüyor http://code.google.com/p/adbcj/

Şu anda mysql ve postgresql için 2 deneysel yerel async sürücüsü vardır.


Bu yaklaşımı hazırlatmak istiyorum. JDBC en başından beri çok gelişti (yineleyiciler, şablonlar, hazırlanmış prosedürler), ancak bu asenkron yaklaşım hiçbir zaman uygulanmadı. Yazma işlemleri (Ekle, Güncelle, Sil) ve özellikle hepimizin karşılaştığı ağır toplu TX için özellikle ilginç olurdu. Bana göre, her türlü müşteri tabanlı yaklaşım (Havuzlama, Aktör, Programlama, Mesajlaşma ...) kaynak kullanımı açısından küçük ödüllere yol açacaktır (muhtemelen bazı verim veya gecikme kazançları).
Jaime Casero

Eski ve terk edilmiş, yalnızca iki veri türü desteklenir ve üretime hazır bile değildir. Ne yazık ki :(
Aaron Zinman

Bu kütüphanenin 1 numaralı sayısı, web sitesinin mevcut olmamasıyla ilgilidir . Bir yıldan daha eski. Bu kütüphanenin oldukça öldüğünden şüpheleniyorum.
Lukas Eder

3

Eski bir soru, ama biraz daha bilgi. Bir satıcı JDBC'ye bir uzantı ve JDBC'yi işlemek için bir sarıcı sağlamadığı sürece, JDBC'nin veritabanının kendisiyle eşzamansız istekleri yayınlaması mümkün değildir. Bununla birlikte, JDBC'nin kendisini bir işleme kuyruğuyla sarmak ve bir veya daha fazla ayrı bağlantıda kuyruğu işleyebilen mantık uygulamak mümkündür. Bazı çağrı türleri için bunun bir avantajı, mantığın, eğer yeterince ağırsa, çağrıları işleme için JDBC gruplarına dönüştürebilmesidir, bu da mantığı önemli ölçüde hızlandırabilir. Bu, en çok verinin eklendiği aramalar için kullanışlıdır ve gerçek sonucun yalnızca bir hata olması durumunda günlüğe kaydedilmesi gerekir. Bunun harika bir örneği, kullanıcı etkinliğini günlüğe kaydetmek için ekler yapılıyor olmasıdır. Uygulama kazandı '

Bir yan not olarak, piyasadaki bir ürün, tarif ettiğim gibi eşzamansız çağrıların eşzamansız olarak yapılmasına izin vermek için politikaya dayalı bir yaklaşım sağlar ( http://www.heimdalldata.com/ ). Feragatname: Bu şirketin kurucu ortağıyım. Herhangi bir JDBC veri kaynağı için ekleme / güncelleme / silme gibi veri dönüştürme isteklerine düzenli ifadelerin uygulanmasına izin verir ve bunları işlenmek üzere otomatik olarak toplu olarak işler. MySQL ve rewriteBatchedStatements seçeneği ( rewriteBatchedStatements = true ile MySQL ve JDBC) ile kullanıldığında , bu veritabanı üzerindeki genel yükü önemli ölçüde düşürebilir.


Ancak bu, JDBC'nin en az bir ayrı iş parçacığına sahip olması gerektiği anlamına gelir. Tek iş parçacıklı ancak yine de geri arama tabanlı çerçeveler ve yığınlar ne olacak (nodejs akla geliyor)? JDBC çağrılarını nasıl yönettiklerini biliyor musunuz?
yuranos

3

Bence üç seçeneğiniz var:

  1. İletileri küçük ve sabit sayıda iş parçacığına dağıtmak için eşzamanlı bir kuyruk kullanın . Yani 1000 bağlantınız varsa 1000 iş parçacığı değil 4 iş parçacığınız olur.
  2. Başka bir düğümde (yani başka bir işlem veya makinede) veritabanı erişimini yapın ve veritabanı istemcinizin bu düğüme eşzamansız ağ aramaları yapmasını sağlayın .
  3. Eşzamansız iletiler aracılığıyla gerçek bir dağıtılmış sistem uygulayın. Bunun için CoralMQ veya Tibco gibi bir mesaj kuyruğuna ihtiyacınız olacak.

Dikte: CoralMQ'nun geliştiricilerinden biriyim.


3

Standart ilişkisel veritabanlarıyla reaktif bağlantıyı mümkün kılmak için bir çözüm geliştirilmektedir.

İlişkisel veritabanlarının kullanımını korurken ölçeklemek isteyen kişiler, G / Ç'yi engellemeye dayalı mevcut standartlar nedeniyle reaktif programlamadan kesilir. R2DBC, ilişkisel veritabanlarıyla verimli çalışan reaktif koda izin veren yeni bir API belirtir.

R2DBC, veritabanı sürücüsü uygulayıcıları ve istemci kitaplığı yazarları için engellenmeyen bir SPI tanımlayan SQL veritabanlarıyla reaktif programlama için sıfırdan tasarlanmış bir özelliktir. R2DBC sürücüleri, veritabanı teli protokolünü, engellenmeyen bir G / Ç katmanının üzerine tam olarak uygular.

R2DBC'nin Web Sitesi

R2DBC'den GitHub

Özellik Matrisi

resim açıklamasını buraya girin


2

Java 5.0 executors kullanışlı gelebilir.

Uzun süren işlemleri gerçekleştirmek için sabit sayıda iş parçacığına sahip olabilirsiniz. Ve bunun yerine, sonuç döndüren Runnablekullanabilirsiniz Callable. Sonuç bir Future<ReturnType>nesnede kapsüllenir , böylece geri döndüğünde alabilirsiniz.



2

Sadece çılgın bir fikir: JBDC sonucu üzerinde bir Yineleme paterni kullanabilirsiniz.

Hammersmith bunu MongoDB için yapar .


1

Ben sadece burada fikir düşünüyorum. Neden her biri bir iş parçacığı olan bir veritabanı bağlantıları havuzunuz olamazdı. Her iş parçacığının bir kuyruğa erişimi vardır. Uzun süren bir sorgu yapmak istediğinizde, kuyruğa girebilir ve iş parçacıklarından biri onu alıp işleyebilir. Asla çok fazla konuya sahip olmayacaksınız çünkü konularınızın sayısı sınırlıdır.

Düzenleme: Ya da daha iyisi, sadece bir dizi iş parçacığı. Bir iş parçacığı bir kuyrukta bir şey gördüğünde, havuzdan bir bağlantı ister ve onu işler.


1

Commons-dbutils kitaplığı, AsyncQueryRunnersağladığınız bir desteği destekler ExecutorServiceve a değerini döndürür Future. Kullanımı basit ve kaynak sızıntısı yapmayacağınızdan emin olmaya değer.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.