Là cuộc gọi jdbc không đồng bộ có thể?


158

Tôi tự hỏi nếu có một cách để thực hiện cuộc gọi không đồng bộ đến cơ sở dữ liệu?

Ví dụ, hãy tưởng tượng rằng tôi có một yêu cầu lớn mất nhiều thời gian để xử lý, tôi muốn gửi yêu cầu và nhận thông báo khi yêu cầu sẽ trả về một giá trị (bằng cách chuyển qua Listener / gọi lại hoặc một cái gì đó). Tôi không muốn chặn chờ cơ sở dữ liệu trả lời.

Tôi không nghĩ rằng việc sử dụng một nhóm các luồng là một giải pháp vì nó không mở rộng được, trong trường hợp các yêu cầu đồng thời nặng nề, điều này sẽ tạo ra một số lượng rất lớn các luồng.

Chúng tôi đang phải đối mặt với loại vấn đề này với các máy chủ mạng và chúng tôi đã tìm ra giải pháp bằng cách sử dụng lệnh gọi / poll / epoll để tránh có một luồng trên mỗi kết nối. Tôi chỉ tự hỏi làm thế nào để có một tính năng tương tự với yêu cầu cơ sở dữ liệu?

Lưu ý: Tôi biết rằng việc sử dụng FixedThreadPool có thể là một công việc tốt, nhưng tôi ngạc nhiên rằng không ai đã phát triển một hệ thống thực sự không đồng bộ (không sử dụng thêm luồng).

** Cập nhật **
Vì thiếu các giải pháp thực tế thực tế, tôi đã quyết định tự tạo một thư viện (một phần của finagle): finagle-mysql . Về cơ bản, nó giải mã / giải mã yêu cầu / phản hồi của mysql và sử dụng Finagle / Netty dưới mui xe. Nó quy mô cực kỳ tốt ngay cả với số lượng lớn các kết nối.




Vấn đề là làm thế nào db có thể thông báo cho khách hàng khi truy vấn kết thúc. Một người sẽ là (ví dụ) để Oracle sử dụng tính năng "Thông báo thay đổi kết quả truy vấn cơ sở dữ liệu" và được thông báo khi dữ liệu db thay đổi. Điều này áp dụng cho các truy vấn SQL sửa đổi dữ liệu db Đối với các truy vấn chỉ đọc, điều này sẽ không hoạt động. Mặt khác, tôi không chắc chắn rằng việc tạo kết nối không đồng bộ sẽ là một ý tưởng hay vì việc thiết lập chúng rất tốn kém. Tất nhiên, đây không phải là một giải pháp rất chung chung. Chỉ là thức ăn cho suy nghĩ ...
Mike Argyriou

Finagle-mysql có sử dụng JDBC không?
Saeed Zarinfam

Câu trả lời:


164

Tôi không hiểu làm thế nào bất kỳ cách tiếp cận được đề xuất nào bao trùm các cuộc gọi JDBC trong Diễn viên, người thực thi hoặc bất cứ điều gì khác có thể giúp đỡ ở đây - ai đó có thể làm rõ.

Chắc chắn vấn đề cơ bản là khối hoạt động JDBC trên socket IO. Khi thực hiện điều này, nó chặn Chủ đề đang chạy trên phần cuối của câu chuyện. Bất kỳ khung gói nào bạn chọn sử dụng sẽ kết thúc với một luồng được giữ bận / bị chặn theo yêu cầu đồng thời.

Nếu các trình điều khiển cơ sở dữ liệu cơ bản (MySql?) Cung cấp một phương tiện để chặn việc tạo ổ cắm (xem SocketFactory) thì tôi tưởng tượng rằng có thể xây dựng một lớp cơ sở dữ liệu điều khiển sự kiện không đồng bộ trên đỉnh api của JDBC nhưng chúng ta phải đóng gói toàn bộ JDBC đằng sau một mặt tiền hướng sự kiện và mặt tiền đó sẽ không giống như JDBC (sau khi nó được điều khiển theo sự kiện). Việc xử lý cơ sở dữ liệu sẽ xảy ra không đồng bộ trên một luồng khác với người gọi và bạn phải tìm ra cách xây dựng trình quản lý giao dịch không phụ thuộc vào mối quan hệ của luồng.

Một cái gì đó giống như cách tiếp cận mà tôi đề cập sẽ cho phép ngay cả một luồng nền duy nhất xử lý tải của trình thực thi JDBC đồng thời. Trong thực tế, bạn có thể chạy một nhóm các luồng để sử dụng nhiều lõi.

(Tất nhiên tôi không bình luận về logic của câu hỏi ban đầu chỉ là các câu trả lời ngụ ý rằng đồng thời trong kịch bản với việc chặn socket IO là có thể mà không cần sử dụng mẫu chọn - đơn giản hơn là xử lý đồng thời JDBC điển hình của bạn và đặt trong một nhóm kết nối có kích thước phù hợp).


Có vẻ như MySql có thể thực hiện điều gì đó dọc theo dòng tôi đang đề xuất --- http://code.google.com.vn/p/async-mysql-connector/wiki/UsageExample


1
Sử dụng Akka không thực hiện các cuộc gọi đến các DB quan hệ không đồng bộ. Nó cho phép bạn chạy chúng trên một loạt các luồng chuyên dụng để truy cập DB dễ dàng. Bằng cách này, bạn sẽ không gỡ toàn bộ trang web xuống khi trang web không phản hồi vì bạn luôn thực hiện các cuộc gọi không đồng bộ trong lớp dịch vụ với lớp DAO với các lời hứa và các luồng máy chủ web của bạn tách biệt với phần còn lại của ứng dụng.
Onur

Các diễn viên không phải là cách giải quyết duy nhất (ví dụ: dịch vụ vi mô và http không đồng bộ, chúng tôi mở rộng đến hàng nghìn mỗi giây) và tôi sẽ không nhanh chóng loại bỏ chúng là không đồng bộ theo quan điểm của khách hàng. Nếu lưu lượng luồng 1k UI vào hệ thống của bạn và chỉ có 10 luồng bị chặn trên DB, trong khi 990 'tin nhắn' (hoặc một cái gì đó tương tự) được xếp hàng trong bộ nhớ mà không chặn bất kỳ luồng UI 1k nào (có thể sẽ được phát hành). .. đó không phải là những gì được yêu cầu? Tôi rất thích xem JDBC async thực sự, nhưng điều đó không có nghĩa là không có cách giải quyết cực kỳ khả thi trong thời gian tạm thời.
Greg Pendlebury

42

Không thể thực hiện cuộc gọi không đồng bộ đến cơ sở dữ liệu qua JDBC, nhưng bạn có thể thực hiện các cuộc gọi không đồng bộ tới JDBC bằng Actors (ví dụ: diễn viên thực hiện cuộc gọi tới DB qua JDBC và gửi tin nhắn cho bên thứ ba, khi cuộc gọi kết thúc), hoặc, nếu bạn thích CPS, với tương lai theo đường ống (lời hứa) (một triển khai tốt là Lời hứa của Scalaz )

Tôi không nghĩ rằng việc sử dụng một nhóm các luồng là một giải pháp vì nó không mở rộng được, trong trường hợp các yêu cầu đồng thời nặng nề, điều này sẽ tạo ra một số lượng rất lớn các luồng.

Các tác nhân Scala theo mặc định là dựa trên sự kiện (không dựa trên luồng) - lập lịch tiếp tục cho phép tạo ra hàng triệu diễn viên trên một thiết lập JVM tiêu chuẩn.

Nếu bạn đang nhắm mục tiêu Java, Akka Framework là một triển khai mô hình Actor có API tốt cho cả Java và Scala.


Bên cạnh đó, bản chất đồng bộ của JDBC có ý nghĩa hoàn hảo với tôi. Chi phí của một phiên cơ sở dữ liệu cao hơn nhiều so với chi phí của luồng Java bị chặn (ở phía trước hoặc nền) và chờ phản hồi. Nếu các truy vấn của bạn chạy quá lâu đến nỗi các khả năng của một dịch vụ thực thi (hoặc bao bọc các khung đồng thời Actor / fork-tham gia / lời hứa) không đủ cho bạn (và bạn đang tiêu thụ quá nhiều luồng), trước hết bạn nên nghĩ về tải cơ sở dữ liệu. Thông thường, phản hồi từ cơ sở dữ liệu trở lại rất nhanh và dịch vụ thực thi được hỗ trợ với nhóm luồng cố định là một giải pháp đủ tốt. Nếu bạn có quá nhiều truy vấn chạy dài, bạn nên xem xét xử lý trả trước (trước) - như tính toán lại dữ liệu hàng đêm hoặc một cái gì đó tương tự.


2
@Victor, mọi diễn viên làm việc song song trong hoạt động chặn (JDBC) sẽ chạy trên một luồng riêng biệt mà Steve đang cố tránh
Vasil Remeniuk

36
Cách tiếp cận tác nhân vẫn yêu cầu một luồng cho mỗi giao dịch cơ sở dữ liệu đang hoạt động, trong khi giao dịch đang diễn ra, vì vậy đó không thực sự là giải pháp cho vấn đề của OP trừ khi bạn sẵn sàng hạn chế số lượng giao dịch cơ sở dữ liệu song song và chờ một số hoạt động cơ sở dữ liệu "không đồng bộ" đối với một số người đã thực hiện để hoàn thành và giải phóng một chuỗi. Tuy nhiên, đây không phải là ý tưởng tồi - cơ sở dữ liệu có thể bị quá tải nếu bạn mở quá nhiều kết nối - vì vậy việc đặt giao dịch cơ sở dữ liệu của bạn vào hàng đợi để xử lý thay vì chặn luồng xử lý yêu cầu http của bạn sẽ giúp ích.
Dobes Vandermeer

8
Diễn viên dựa trên giải pháp vẫn đang chặn các chủ đề. Đừng nói rằng không thể thực hiện cuộc gọi jdbc async, có những thư viện mã nguồn mở thử nghiệm cố gắng thực hiện async jdbc.

6
+1 "Chi phí của phiên cơ sở dữ liệu cao hơn nhiều so với chi phí của luồng Java bị chặn"
Paul Draper

1
Đối với các cuộc gọi DB đắt tiền thường không phải là một vấn đề lớn. Đó là khi cuộc gọi là tầm thường mà chi phí mạng trở thành một vấn đề. Nếu bạn muốn thực hiện 100 truy vấn, mỗi lần mất 1 ms trên DB, nhưng tổng phí mạng là 200 ms, thì sẽ mất hơn 20 giây đồng bộ, nhưng sẽ mất không đồng bộ 300 ms.
chấp

12

Có lẽ bạn có thể sử dụng hệ thống nhắn tin không đồng bộ JMS, có quy mô khá tốt, IMHO:

  • Gửi tin nhắn đến Hàng đợi, nơi người đăng ký sẽ chấp nhận tin nhắn và chạy quy trình SQL. Quá trình chính của bạn sẽ tiếp tục chạy và chấp nhận hoặc gửi yêu cầu mới.

  • Khi quá trình SQL kết thúc, bạn có thể chạy theo cách ngược lại: gửi tin nhắn đến FeedbackQueue với kết quả của quá trình và một người nghe ở phía máy khách chấp nhận nó và thực thi mã gọi lại.


7

Không có hỗ trợ trực tiếp trong JDBC nhưng bạn có nhiều tùy chọn như MDB, Executors từ Java 5.

"Tôi không coi việc sử dụng một nhóm các luồng là một giải pháp vì nó không có quy mô, trong trường hợp các yêu cầu đồng thời nặng nề, điều này sẽ sinh ra một số lượng rất lớn các luồng."

Tôi tò mò tại sao một nhóm các chủ đề giới hạn sẽ không mở rộng? Đó là một nhóm không phải luồng trên mỗi yêu cầu để sinh ra một luồng cho mỗi yêu cầu. Tôi đã sử dụng điều này khá lâu trên một ứng dụng web tải nặng và chúng tôi chưa thấy có vấn đề gì cho đến nay.


Tôi nghĩ rằng đối số chính chống lại các luồng là về cơ bản bạn đang ở bên ngoài bất kỳ ràng buộc vùng chứa Java tiêu chuẩn nào, do đó bạn mất phân cụm được quản lý vùng chứa và thất bại đối với các khả năng, mặc dù bạn có thể tự cuộn hoặc sử dụng thứ gì đó như Terracotta.
mezmo

3
chúng ta có thể truy cập vào các cuộc thăm dò chủ đề do máy chủ ứng dụng quản lý bằng cách sử dụng trình quản lý công việc. websphere, weblogic và cá thủy tinh hỗ trợ nó
Aravind Yarram


4

Như đã đề cập trong các câu trả lời khác, API JDBC không phải là Async.
Tuy nhiên, nếu bạn có thể sống với một tập hợp con của các hoạt động và một API khác thì có các giải pháp. Một ví dụ là https://github.com/jasync-sql/jasync-sql hoạt động cho MySQL và PostgreQuery.


3

Dự án Ajdbc dường như trả lời vấn đề này http://code.google.com.vn/p/adbcj/

Hiện tại có 2 trình điều khiển async tự nhiên thử nghiệm cho mysql và postgresql.


Tôi muốn có sẵn phương pháp này. JDBC đã phát triển rất nhiều từ đầu (iterators, mẫu, thủ tục chuẩn bị), nhưng cách tiếp cận không đồng bộ này chưa bao giờ được thực hiện. Nó sẽ đặc biệt thú vị đối với các thao tác ghi (Chèn, Cập nhật, Xóa) và đặc biệt là các lô TX nặng mà chúng ta đều phải đối mặt. Theo tôi, bất kỳ cách tiếp cận dựa trên khách hàng nào (Pooling, Actor, Lập kế hoạch, Nhắn tin ...) sẽ dẫn đến những phần thưởng nhỏ về việc sử dụng tài nguyên (có thể là một số lợi ích trong thông lượng hoặc độ trễ).
Jaime Casero

Cũ và bị bỏ rơi, chỉ có hai loại dữ liệu được hỗ trợ và thậm chí không gần với sản xuất. Thật không may :(
Aaron Zinman

Vấn đề # 1 của thư viện này là về trang web không có sẵn . Nó hơn một tuổi rồi. Tôi nghi ngờ thư viện này là khá chết.
Lukas Eder

3

Một câu hỏi cũ, nhưng một số thông tin thêm. Không thể có JDBC đưa ra các yêu cầu không đồng bộ cho cơ sở dữ liệu, trừ khi nhà cung cấp cung cấp phần mở rộng cho JDBC và trình bao bọc để xử lý JDBC. Điều đó nói rằng, có thể bao bọc chính JDBC bằng một hàng đợi xử lý và thực hiện logic có thể xử lý hàng đợi trên một hoặc nhiều kết nối riêng biệt. Một lợi thế của điều này đối với một số loại cuộc gọi là logic, nếu dưới tải đủ lớn, có thể chuyển đổi các cuộc gọi thành các lô JDBC để xử lý, có thể tăng tốc đáng kể logic. Điều này hữu ích nhất cho các cuộc gọi nơi dữ liệu được chèn và kết quả thực tế chỉ cần được ghi lại nếu có lỗi. Một ví dụ tuyệt vời về điều này là nếu các phần chèn đang được thực hiện để ghi nhật ký hoạt động của người dùng. Ứng dụng đã thắng '

Một lưu ý phụ, một sản phẩm trên thị trường cung cấp cách tiếp cận theo chính sách để cho phép các cuộc gọi không đồng bộ giống như các cuộc gọi mà tôi mô tả được thực hiện không đồng bộ ( http://www.heimdalldata.com/ ). Tuyên bố miễn trừ trách nhiệm: Tôi là đồng sáng lập của công ty này. Nó cho phép các biểu thức thông thường được áp dụng cho các yêu cầu chuyển đổi dữ liệu như chèn / cập nhật / xóa đối với bất kỳ nguồn dữ liệu JDBC nào và sẽ tự động gộp chúng lại với nhau để xử lý. Khi được sử dụng với MySQL và tùy chọn RewriteBatchedStatements ( MySQL và JDBC với RewriteBatchedStatements = true ), điều này có thể làm giảm đáng kể tải tổng thể trên cơ sở dữ liệu.


Nhưng điều này vẫn có nghĩa là JDBC nên có ít nhất một luồng riêng biệt. Điều gì về các khung và ngăn xếp là luồng đơn nhưng vẫn dựa trên cuộc gọi lại (nodejs đến với tâm trí)? Bạn có biết làm thế nào họ quản lý các cuộc gọi JDBC?
yuranos

3

Bạn có ba lựa chọn theo ý kiến ​​của tôi:

  1. Sử dụng hàng đợi đồng thời để phân phối tin nhắn qua một số lượng nhỏ các chủ đề cố định. Vì vậy, nếu bạn có 1000 kết nối, bạn sẽ có 4 luồng chứ không phải 1000 luồng.
  2. Thực hiện truy cập cơ sở dữ liệu trên một nút khác (tức là một quy trình hoặc máy khác) và để máy khách cơ sở dữ liệu của bạn thực hiện các cuộc gọi mạng không đồng bộ đến nút đó.
  3. Thực hiện một hệ thống phân tán thực sự thông qua các tin nhắn không đồng bộ. Cho rằng bạn sẽ cần một hàng đợi nhắn tin như CoralMQ hoặc Tibco.

Diclaimer: Tôi là một trong những nhà phát triển của CoralMQ.


3

Một giải pháp đang được phát triển để làm cho kết nối phản ứng có thể với cơ sở dữ liệu quan hệ tiêu chuẩn.

Những người muốn mở rộng quy mô trong khi vẫn duy trì việc sử dụng cơ sở dữ liệu quan hệ bị cắt khỏi chương trình phản ứng do các tiêu chuẩn hiện có dựa trên việc chặn I / O. R2DBC chỉ định API mới cho phép mã phản ứng hoạt động hiệu quả với cơ sở dữ liệu quan hệ.

R2DBC là một đặc tả được thiết kế từ đầu để lập trình phản ứng với cơ sở dữ liệu SQL xác định SPI không chặn cho người triển khai trình điều khiển cơ sở dữ liệu và tác giả thư viện khách. Trình điều khiển R2DBC thực hiện đầy đủ giao thức dây cơ sở dữ liệu trên lớp I / O không chặn.

Trang web của R2DBC

GitHub của R2DBC

Ma trận tính năng

nhập mô tả hình ảnh ở đây


2

Các trình thực thi Java 5.0 có thể có ích.

Bạn có thể có một số luồng cố định để xử lý các hoạt động chạy dài. Và thay vì Runnablebạn có thể sử dụng Callable, trả về một kết quả. Kết quả được gói gọn trong một Future<ReturnType>đối tượng, vì vậy bạn có thể lấy nó khi nó quay lại.


2

Dưới đây là một phác thảo về một api jdbc không chặn có thể trông như thế nào từ Oracle được trình bày tại JavaOne: https : //static.rainf Focus.com/oracle/oow16/sess/1461693351182001EmRq/ppt/CONF1578%2020160916.pdf

Vì vậy, có vẻ như cuối cùng, các cuộc gọi JDBC không đồng bộ thực sự sẽ thực sự có thể.


Đó không phải là JDBC mà là một API bổ sung
yaccob

2

Chỉ là một ý tưởng điên rồ: bạn có thể sử dụng mô hình Iteratee trên kết quả JBDC được gói trong một số Tương lai / Lời hứa

Hammersmith làm điều đó cho MongoDB .


1

Tôi chỉ đang nghĩ ý tưởng ở đây. Tại sao bạn không thể có một nhóm các kết nối cơ sở dữ liệu với mỗi người có một luồng. Mỗi luồng có quyền truy cập vào một hàng đợi. Khi bạn muốn thực hiện một truy vấn mất nhiều thời gian, bạn có thể đặt vào hàng đợi và sau đó một trong các luồng sẽ chọn nó và xử lý nó. Bạn sẽ không bao giờ có quá nhiều chủ đề vì số lượng chủ đề của bạn bị giới hạn.

Chỉnh sửa: Hoặc tốt hơn nữa, chỉ là một số chủ đề. Khi một chủ đề nhìn thấy một cái gì đó trong hàng đợi, nó yêu cầu một kết nối từ nhóm và xử lý nó.


1

Thư viện commons-dbutils có hỗ trợ cho cái AsyncQueryRunnermà bạn cung cấp ExecutorServicevà nó trả về a Future. Đáng để kiểm tra vì nó đơn giản để sử dụng và đảm bảo bạn sẽ không bị rò rỉ tài nguyên.


1

Nếu bạn quan tâm đến các API cơ sở dữ liệu không đồng bộ cho Java, bạn nên biết rằng có một sáng kiến ​​mới để đưa ra một bộ API tiêu chuẩn dựa trên CompleteableFuture và lambdas. Ngoài ra còn có việc triển khai các API này trên JDBC, có thể được sử dụng để thực hành các API này: https://github.com/oracle/oracle-db-examples/tree/master/java/AoJ JavaDoc được đề cập trong README của dự án github.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.