비동기 jdbc 호출이 가능합니까?


158

데이터베이스를 비동기식으로 호출하는 방법이 있는지 궁금합니다.

예를 들어, 처리하는 데 시간이 오래 걸리는 큰 요청이 있다고 가정합니다. 요청을 보내고 요청이 값을 반환 할 때 알림을 수신하려고합니다 (리스너 / 콜백 또는 기타를 전달하여). 데이터베이스가 응답하기를 기다리는 것을 차단하고 싶지 않습니다.

스레드 풀을 사용하는 것이 확장되지 않기 때문에 솔루션이라고 생각하지 않습니다. 동시 요청이 많은 경우에는 많은 수의 스레드가 생성됩니다.

우리는 네트워크 서버에서 이러한 종류의 문제에 직면하고 있으며 연결 당 하나의 스레드를 피하기 위해 select / poll / epoll 시스템 호출을 사용하여 솔루션을 찾았습니다. 데이터베이스 요청과 비슷한 기능을 갖는 방법이 궁금합니다.

참고 : FixedThreadPool을 사용하는 것이 좋은 해결 방법 일 수 있음을 알고 있지만 아무도 실제로 여분의 스레드를 사용하지 않고 비동기 시스템을 개발하지 않은 것에 놀랐습니다.

** 업데이트 **
실제 실제 솔루션이 없기 때문에 finagle-mysql 라이브러리 (finagle의 일부)를 직접 작성하기로 결정했습니다 . 기본적으로 mysql 요청 / 응답을 디코딩 / 디코딩하고 Finagle / Netty를 사용합니다. 많은 수의 연결로도 확장 성이 뛰어납니다.




문제는 쿼리가 완료 될 때 db가 어떻게 클라이언트에게 알릴 수 있는가입니다. 하나는 예를 들어 Oracle이 "데이터베이스 쿼리 결과 변경 알림"기능을 사용하고 db 데이터가 변경 될 때 알림을받는 것입니다. 이것은 db 데이터를 수정하는 SQL 쿼리에 적용됩니다. 읽기 전용 쿼리의 경우 작동하지 않습니다. 반면에 연결을 비동기로 만드는 것이 비용이 많이 들기 때문에 비동기식으로 만드는 것이 좋은 생각인지 확실하지 않습니다. 물론 이것은 매우 일반적인 해결책이 아닙니다. 그냥 생각을위한 음식 ...
Mike Argyriou

finagle-mysql은 JDBC를 사용합니까?
Saeed Zarinfam

답변:


164

Actors, executor 또는 다른 어떤 것에서 JDBC 호출을 래핑하는 제안 된 접근 방식이 어떻게 도움이 될 수 있는지 이해하지 못합니다.

분명히 기본적인 문제는 JDBC 작업이 소켓 IO에서 차단된다는 것입니다. 이 작업을 수행하면 스토리 종료시 스레드 실행이 차단됩니다. 어떤 래핑 프레임 워크를 사용하든간에 동시 요청 당 하나의 스레드가 사용 중 / 차단 상태로 유지됩니다.

기본 데이터베이스 드라이버 (MySql?)가 소켓 생성을 가로 채는 수단을 제공하는 경우 (SocketFactory 참조) JDBC API 위에 비동기 이벤트 기반 데이터베이스 계층을 구축하는 것이 가능할 것이라고 생각하지만 우리는 이벤트 주도 파사드 뒤의 전체 JDBC는 해당 파사드가 (이벤트 주도 후) JDBC처럼 보이지 않습니다. 데이터베이스 처리는 호출자와 다른 스레드에서 비동기 적으로 수행되므로 스레드 선호도에 의존하지 않는 트랜잭션 관리자를 빌드하는 방법을 연구해야합니다.

내가 언급 한 접근법과 같은 것은 단일 백그라운드 스레드조차도 동시 JDBC exec를로드 할 수있게합니다. 실제로 여러 코어를 사용하기 위해 스레드 풀을 실행할 수 있습니다.

(물론 나는 원래 질문의 논리에 대해서는 언급하지 않고 소켓 IO를 차단하는 시나리오에서 동시성이 선택기 패턴을 사용하지 않고도 가능하다는 암시 적 응답에 대해서는 언급하지 않습니다. 일반적인 JDBC 동시성을 해결하고 넣는 것이 더 간단합니다. 올바른 크기의 연결 풀에서).


MySql이 아마도 내가 제안하는 라인을 따라 뭔가를하는 것처럼 보입니다 --- http://code.google.com/p/async-mysql-connector/wiki/UsageExample


1
Akka를 사용하면 관계형 DB를 비동기 적으로 호출하지 않습니다. DB 액세스를 위해 여러 전용 스레드에서 쉽게 실행할 수 있습니다. 이렇게하면 서비스 계층에서 DAO 계층에 대한 비동기 호출을 약속하고 웹 서버 스레드가 나머지 응용 프로그램과 분리되므로 사이트가 응답하지 않을 때 전체 사이트를 중단하지 않습니다.
Onur

액터가 유일한 해결 방법 (예 : 마이크로 서비스 및 비동기 http, 초당 수천으로 확장)이 아니며 클라이언트의 관점에서 비동기 인 것처럼 무시하지 않습니다. 1k UI 스레드 트래픽이 시스템에 유입되고 DB에서 10 개의 스레드 만 차단되는 경우 1k UI 스레드 (아마도 해제 될 것임) 차단 하지 않고 990 개의 '메시지'(또는 이와 유사한 것)가 메모리에 대기됩니다 . .. 필요한 것이 아닌가? 나는 진정한 비동기 JDBC를보고 싶지만 그 중간에 극히 실용적인 해결책이 없다는 것을 의미하지는 않습니다.
그렉 펜들 버리

42

JDBC를 통해 데이터베이스 를 비동기식으로 호출하는 것은 불가능 하지만 액터 를 사용하여 JDBC 를 비동기식으로 호출 할 수 있습니다 (예 : 액터 가 JDBC 를 통해 DB를 호출하고 호출이 끝나면 제 3 자에게 메시지를 보냅니다). 또는 파이프 라인 선물 (약속) 과 함께 CPS 를 선호 하는 경우 ( Scalaz Promises 구현 )

스레드 풀을 사용하는 것이 확장되지 않기 때문에 솔루션이라고 생각하지 않습니다. 동시 요청이 많은 경우에는 많은 수의 스레드가 생성됩니다.

스칼라 액터는 기본적으로 이벤트 기반 (스레드 기반이 아님)입니다. 연속 스케줄링을 통해 표준 JVM 설정에서 수백만 액터를 생성 할 수 있습니다.

Java를 대상으로하는 경우 Akka Framework 는 Java 및 Scala 모두에 적합한 API를 가진 Actor 모델 구현입니다.


그 외에도 JDBC의 동기 특성은 나에게 완벽합니다. 데이터베이스 세션 비용은 Java 스레드가 차단되기 전 (또는 백그라운드에서) 응답을 기다리는 것보다 훨씬 높습니다. 실행기 서비스의 기능 (또는 Actor / fork-join / promise 동시성 프레임 워크 래핑)이 충분하지 않아 쿼리가 충분하지 않은 경우 (그리고 너무 많은 스레드를 소비하는 경우) 먼저 데이터베이스로드. 일반적으로 데이터베이스의 응답은 매우 빠르게 되돌아오고 고정 스레드 풀로 백업 된 실행기 서비스는 충분한 솔루션입니다. 오래 실행되는 쿼리가 너무 많으면 야간에 데이터를 다시 계산하는 것과 같은 선행 처리 (사전 처리)를 고려해야합니다.


2
@Victor, 차단 작업 (JDBC)에서 병렬로 작업하는 모든 행위자는 Steve가 피하려고하는 별도의 스레드에서 실행됩니다.
Vasil Remeniuk

36
액터 접근에는 여전히 활성 데이터베이스 트랜잭션 당 하나의 스레드가 필요하지만 트랜잭션이 진행되는 동안 병렬 데이터베이스 트랜잭션의 수를 제한하고 "비동기적인"데이터베이스 작업이 대기하지 않는 한 실제로는 OP 문제에 대한 솔루션이 아닙니다. 이미 실행중인 일부 스레드를 완료하고 비우기 위해. 연결을 너무 많이 열면 데이터베이스가 오버로드 될 수 있으므로 http 요청 처리 스레드를 차단하는 대신 데이터베이스 트랜잭션을 큐에 넣는 것이 좋습니다.
Dobes Vandermeer

8
액터 기반 솔루션이 여전히 스레드를 차단하고 있습니다. 비동기 jdbc 호출을 실행할 수 없다고 말하지 말고, 비동기 jdbc를 구현하려는 실험적인 오픈 소스 라이브러리가 있습니다.

6
+1 "데이터베이스 세션 비용은 차단되는 Java 스레드 비용보다 훨씬 높습니다"
Paul Draper

1
비싼 DB 호출의 경우 일반적으로 큰 문제는 없습니다. 호출이 사소한 경우 네트워크 오버 헤드가 문제가됩니다. DB에서 각각 1ms가 걸리지 만 네트워크 오버 헤드가 200ms 인 100 개의 쿼리를 만들려면 동 기적으로 20 초 이상 걸리지 만 비동기 적으로 300ms가 걸립니다.
morten

12

아마도 IMHO 확장 성이 뛰어난 JMS 비동기 메시징 시스템을 사용할 수있을 것입니다.

  • 가입자가 메시지를 수락하고 SQL 프로세스를 실행할 큐에 메시지를 보냅니다. 기본 프로세스는 계속 실행되어 새 요청을 수락 또는 전송합니다.

  • SQL 프로세스가 끝나면 반대 방식으로 실행할 수 있습니다. 프로세스 결과와 함께 ResponseQueue에 메시지를 보내면 클라이언트 측의 리스너가이를 승인하고 콜백 코드를 실행합니다.


7

JDBC에는 직접적인 지원이 없지만 Java 5의 MDB, MDB와 같은 여러 옵션이 있습니다.

"나는 스레드 풀을 사용하는 것이 확장되지 않기 때문에 솔루션이라고 생각하지 않는다. 동시 요청이 많은 경우에는 매우 많은 수의 스레드가 생성 될 것이다."

제한된 스레드 풀이 확장되지 않는 이유가 궁금합니다. 요청마다 스레드를 생성하는 것은 요청 당 스레드가 아닌 풀입니다. 나는 이것을 막대한로드 웹 애플리케이션에서 꽤 오랫동안 사용 해 왔으며 지금까지 아무런 문제도 보지 못했습니다.


스레드에 대한 주요 주장은 기본적으로 표준 Java 컨테이너 제약 조건을 벗어난 것이므로 컨테이너 관리 클러스터링을 잃고 페일 오버 기능을 잃을 수는 있지만 자신 만 롤링하거나 Terracotta와 같은 것을 사용할 수 있다고 생각합니다.
mezmo

3
작업 관리자를 사용하여 앱 서버 관리 스레드 폴링을 활용할 수 있습니다. 웹 스피어, 웹 로직 및 글래스 피쉬 지원이
아 라빈 Yarram


4

다른 답변에서 언급했듯이 JDBC API는 본질적으로 비동기가 아닙니다.
그러나 작업의 하위 집합과 다른 API를 사용할 수 있다면 솔루션이 있습니다. 한 가지 예는 MySQL 및 PostgreSQL에서 작동하는 https://github.com/jasync-sql/jasync-sql 입니다.


3

Ajdbc 프로젝트가 http://code.google.com/p/adbcj/ 이 문제에 답하는 것 같습니다

현재 mysql 및 postgresql에 대해 기본적으로 2 개의 실험용 비동기 드라이버가 있습니다.


이 접근법을 준비하고 싶습니다. JDBC는 처음부터 반복적으로 발전했지만 (반복자, 템플릿, 준비된 절차)이 비동기 방식은 구현 된 적이 없습니다. 쓰기 작업 (삽입, 업데이트, 삭제), 특히 우리 모두가 직면 한 대량 배치 TX에 특히 흥미로울 것입니다. 내 의견으로는, 모든 종류의 클라이언트 기반 접근 방식 (Pooling, Actor, Scheduling, Messaging ...)은 리소스 사용 측면에서 약간의 보상을 가져올 것입니다 (아마도 처리량 또는 대기 시간의 일부 향상).
Jaime Casero

오래되고 포기 된 두 가지 데이터 유형 만 지원되며 프로덕션 준비에 가깝지 않습니다. 불행히도 :(
Aaron Zinman

이 라이브러리의 # 1 문제는 웹 사이트를 사용할 수 없다는 것 입니다. 1 년 이상되었습니다. 이 도서관이 죽었다고 생각합니다.
Lukas Eder

3

오래된 질문이지만 더 많은 정보가 있습니다. 벤더가 JDBC를 확장하고 JDBC를 처리 할 랩퍼를 제공하지 않으면 데이터베이스 자체에 JDBC가 비동기 요청을 발행 할 수 없습니다. 즉, JDBC 자체를 처리 큐로 랩핑하고 하나 이상의 개별 연결에서 큐를 처리 할 수있는 논리를 구현할 수 있습니다. 일부 유형의 호출에 대한 이것의 한 가지 장점은로드가 충분할 경우 로직이 처리를 위해 호출을 JDBC 배치로 변환하여 로직 속도를 크게 높일 수 있다는 것입니다. 이것은 데이터가 삽입되는 호출에 가장 유용하며 오류가있는 경우 실제 결과 만 기록하면됩니다. 이에 대한 좋은 예는 사용자 활동을 기록하기 위해 삽입이 수행되는 경우입니다. 응용 프로그램은

부수적으로, 시장에 나와있는 하나의 제품은 내가 설명한 것과 같은 비동기식 호출을 비동기식으로 할 수 있도록 정책 중심의 접근 방식을 제공합니다 ( http://www.heimdalldata.com/ ). 면책 조항 : 나는이 회사의 공동 설립자입니다. JDBC 데이터 소스의 삽입 / 업데이트 / 삭제와 같은 데이터 변환 요청에 정규식을 적용 할 수 있으며 처리를 위해 자동으로 일괄 처리합니다. MySQL 및 rewriteBatchedStatements 옵션 ( rewriteBatchedStatements = true 인 MySQL 및 JDBC)과 함께 사용 하면 데이터베이스의 전체로드가 현저하게 낮아질 수 있습니다.


그러나 이것은 여전히 ​​JDBC에 적어도 하나의 별도 스레드가 있어야 함을 의미합니다. 단일 스레드이지만 여전히 콜백 기반 (nodejs가 떠오름) 인 프레임 워크 및 스택은 어떻습니까? 이들이 JDBC 호출을 관리하는 방법을 알고 있습니까?
yuranos

3

내 의견으로는 세 가지 옵션이 있습니다.

  1. 동시 큐 를 사용하여 적은 수의 스레드에 메시지를 분배 하십시오 . 따라서 1000 개의 연결이 있으면 1000 개의 스레드가 아닌 4 개의 스레드가 있습니다.
  2. 다른 노드 (예 : 다른 프로세스 또는 시스템)에서 데이터베이스 액세스를 수행하고 데이터베이스 클라이언트 가 해당 노드에 대한 비동기 네트워크 호출 을 수행하도록하십시오.
  3. 비동기 메시지를 통해 진정한 분산 시스템을 구현하십시오. 이를 위해서는 CoralMQ 또는 Tibco와 같은 메시징 큐가 필요합니다.

면책 조항 : 저는 CoralMQ 개발자 중 한 명입니다.


3

표준 관계형 데이터베이스와의 반응성 연결을 가능하게하는 솔루션이 개발되고 있습니다.

I / O 차단에 기반한 기존 표준으로 인해 관계형 데이터베이스의 사용을 유지하면서 확장하려는 사용자는 반응 형 프로그래밍에서 차단됩니다. R2DBC는 관계형 데이터베이스와 효율적으로 작동하는 반응 코드를 허용하는 새로운 API를 지정합니다.

R2DBC는 데이터베이스 드라이버 구현 자 및 클라이언트 라이브러리 작성자를위한 비 차단 SPI를 정의하는 SQL 데이터베이스를 사용한 반응성 프로그래밍을 위해 처음부터 설계된 사양입니다. R2DBC 드라이버는 비 차단 I / O 계층 위에 데이터베이스 와이어 프로토콜을 완벽하게 구현합니다.

R2DBC의 웹 사이트

R2DBC의 GitHub

기능 매트릭스

여기에 이미지 설명을 입력하십시오


2

자바 5.0 집행은 편리하게 올 수 있습니다.

장기 실행 조작을 처리하기 위해 고정 된 수의 스레드를 가질 수 있습니다. 그리고 대신에 결과를 반환하는을 Runnable사용할 수 Callable있습니다. 결과는 객체에 캡슐화되어 Future<ReturnType>있으므로 다시 얻을 수 있습니다.



2

미친 아이디어 : JBDC 결과 세트에 Iteratee 패턴을 사용할 수 있습니다.

Hammersmith는 MongoDB 를 위해 그렇게합니다 .


1

나는 단지 여기에서 아이디어를 생각하고 있습니다. 각각 스레드가있는 데이터베이스 연결 풀을 가질 수없는 이유는 무엇입니까? 각 스레드는 대기열에 액세스 할 수 있습니다. 시간이 오래 걸리는 쿼리를 수행하려는 경우 큐에 넣을 수 있으며 스레드 중 하나가이를 처리하여 처리합니다. 스레드 수가 제한되어 있으므로 스레드가 너무 많지 않습니다.

편집 : 또는 더 나은 아직 많은 스레드. 스레드가 대기열에서 무언가를 발견하면 풀에서 연결을 요청하고 처리합니다.


1

commons-dbutils 라이브러리는 AsyncQueryRunner사용자에게 제공하는 기능 ExecutorService을 지원하며를 반환합니다 Future. 사용이 간편하고 리소스가 유출되지 않도록 체크 아웃 할 가치가 있습니다.


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.