RabbitMQ và mối quan hệ giữa kênh và kết nối


176

Máy khách Java RabbitMQ có các khái niệm sau:

  • Connection - kết nối đến phiên bản máy chủ RabbitMQ
  • Channel - ???
  • Nhóm luồng tiêu dùng - nhóm luồng tiêu thụ các tin nhắn khỏi hàng đợi máy chủ RabbitMQ
  • Hàng đợi - một cấu trúc chứa các thông điệp theo thứ tự FIFO

Tôi đang cố gắng để hiểu mối quan hệ, và quan trọng hơn , mối liên hệ giữa chúng.

  1. Tôi vẫn không hoàn toàn chắc chắn a Channellà gì , ngoài thực tế rằng đây là cấu trúc mà bạn xuất bản và sử dụng và nó được tạo từ một kết nối mở. Nếu ai đó có thể giải thích cho tôi "Kênh" đại diện cho điều gì, nó có thể giúp xóa một vài điều.
  2. Mối quan hệ giữa Kênh và Hàng đợi là gì? Có thể sử dụng cùng một Kênh để liên lạc với nhiều Hàng đợi hay không, phải là 1: 1?
  3. Mối quan hệ giữa Hàng đợi và Nhóm người tiêu dùng là gì? Nhiều người tiêu dùng có thể đăng ký vào cùng một hàng đợi không? Nhiều hàng đợi có thể được tiêu thụ bởi cùng một người tiêu dùng? Hay là mối quan hệ 1: 1?

Cảm ơn trước sự giúp đỡ ở đây!


Các câu trả lời cho câu hỏi này đã dẫn đến việc tôi báo cáo vấn đề này với khách hàng của golang thay vì đặt câu hỏi ở đây.
Bruce Adams

Kênh là một khái niệm logic được sử dụng để ghép một kết nối TCP vật lý duy nhất giữa máy khách và nút. Số kênh được bao gồm trong tiêu đề thư của khung AMQP.
ymas

Câu trả lời:


196
  1. A Connectionđại diện cho một kết nối TCP thực sự với nhà môi giới tin nhắn, trong khi đó Channellà một kết nối ảo (kết nối AMQP) bên trong nó. Bằng cách này, bạn có thể sử dụng nhiều kết nối (ảo) như bạn muốn trong ứng dụng của mình mà không làm quá tải nhà môi giới với các kết nối TCP.

  2. Bạn có thể sử dụng một Channelcho tất cả mọi thứ. Tuy nhiên, nếu bạn có nhiều chủ đề, nó đề nghị sử dụng một khác nhau Channelđối với từng chủ đề.

    An toàn luồng kênh trong Hướng dẫn API máy khách Java :

    Trường hợp kênh là an toàn để sử dụng bởi nhiều chủ đề. Các yêu cầu vào Kênh được tuần tự hóa, mỗi lần chỉ có một luồng có thể chạy lệnh trên Kênh. Mặc dù vậy, các ứng dụng nên ưu tiên sử dụng Kênh trên mỗi luồng thay vì chia sẻ cùng một Kênh trên nhiều luồng.

    Không có mối quan hệ trực tiếp giữa ChannelQueue. A Channelđược sử dụng để gửi các lệnh AMQP cho người môi giới. Đây có thể là việc tạo ra một hàng đợi hoặc tương tự, nhưng các khái niệm này không được gắn với nhau.

  3. Mỗi Consumerlần chạy trong luồng riêng được phân bổ từ nhóm luồng tiêu dùng. Nếu nhiều Người tiêu dùng được đăng ký vào cùng một Hàng đợi, nhà môi giới sẽ sử dụng vòng tròn để phân phối các thông điệp giữa họ như nhau. Xem Hướng dẫn hai: "Hàng đợi làm việc" .

    Cũng có thể đính kèm giống nhau Consumercho nhiều Hàng đợi. Bạn có thể hiểu Người tiêu dùng là cuộc gọi lại. Chúng được gọi mỗi khi có tin nhắn đến Hàng đợi mà Người tiêu dùng bị ràng buộc. Đối với trường hợp Máy khách Java, mỗi Người tiêu dùng có một phương thức handleDelivery(...), đại diện cho phương thức gọi lại. Những gì bạn thường làm là, phân lớp DefaultConsumervà ghi đè handleDelivery(...). Lưu ý: Nếu bạn đính kèm cùng một đối tượng Người tiêu dùng vào nhiều hàng đợi, phương thức này sẽ được gọi bởi các luồng khác nhau. Vì vậy, hãy chăm sóc đồng bộ nếu cần thiết.


4
Chỉ cần thêm từ tài liệu: Cuộc gọi lại cho người tiêu dùng được gửi trên một luồng riêng biệt với luồng được kết nối bởi Kết nối. Điều này có nghĩa là Người tiêu dùng có thể gọi các phương thức chặn một cách an toàn trên Kết nối hoặc Kênh, chẳng hạn như queueDeclare, txCommit, basic Hủy hoặc basicPublish. Mỗi kênh có chủ đề công văn riêng. Đối với trường hợp sử dụng phổ biến nhất của một Người tiêu dùng trên mỗi Kênh, điều này có nghĩa là Người tiêu dùng không giữ người tiêu dùng khác. Nếu bạn có nhiều Người tiêu dùng trên mỗi Kênh, hãy lưu ý rằng Người tiêu dùng lâu năm có thể tiếp tục gửi các cuộc gọi lại cho Người tiêu dùng khác trên Kênh đó.
filip

1
Nếu bạn đính kèm cùng một đối tượng Người tiêu dùng vào nhiều Hàng đợi từ cùng một Kênh, điều đó có nghĩa là các cuộc gọi lại được gửi trên cùng một chuỗi. Trong trường hợp đó, bạn sẽ không cần đồng bộ hóa, phải không?
filip

Tôi có thể chỉ sử dụng một kết nối và sử dụng nhóm kênh thay vì nhóm kết nối không? Điều này sẽ ảnh hưởng đến thông lượng xuất bản tin nhắn?
qeek

4
Tôi nghĩ rằng tài liệu tham khảo này về API máy khách Java hiện đã lỗi thời và trên thực tế, tài liệu tham khảo ngày nay mâu thuẫn trực tiếp với trích dẫn trong câu trả lời này. Tài liệu tham khảo hôm nay cho biết "Các trường hợp kênh không được chia sẻ giữa các luồng".
Edwin Dalorzo

1
@EdwinDalorzo - có vẻ như bất cứ ai ban đầu đã viết tài liệu không hiểu đầy đủ về sự phân đôi kết nối kênh. Kiến trúc cơ bản của AMQP 0.9.1 thực sự coi một kênh là một phiên, vì vậy các luồng khác nhau chia sẻ một phiên thực sự là vô nghĩa. Tôi đoán đó là lý do cho sự thay đổi.
Người chơi

53

Một sự hiểu biết khái niệm tốt về những gì giao thức AMQP thực hiện "dưới mui xe" là hữu ích ở đây. Tôi sẽ cung cấp rằng tài liệu và API mà AMQP 0.9.1 đã chọn để triển khai làm cho điều này đặc biệt khó hiểu, vì vậy câu hỏi này là một câu hỏi mà nhiều người phải vật lộn với.

TL; DR

Một kết nối là ổ cắm TCP được thương lượng vật lý với máy chủ AMQP. Các máy khách được triển khai đúng cách sẽ có một trong số các ứng dụng này, an toàn theo luồng, có thể chia sẻ giữa các luồng.

Một kênh là một phiên ứng dụng duy nhất trên kết nối. Một chủ đề sẽ có một hoặc nhiều trong số các phiên này. Kiến trúc AMQP 0.9.1 là những thứ này không được chia sẻ giữa các luồng và nên được đóng / hủy khi luồng tạo ra nó kết thúc với nó. Chúng cũng bị đóng bởi máy chủ khi xảy ra các vi phạm giao thức khác nhau.

Khách hàng là một cấu trúc ảo đại diện cho sự hiện diện của "hộp thư" trên một kênh cụ thể. Việc sử dụng của người tiêu dùng nói với người môi giới để đẩy các thông điệp từ một hàng đợi cụ thể đến điểm cuối kênh đó.

Sự kiện kết nối

Đầu tiên, như những người khác đã chỉ ra một cách chính xác, một kết nối là đối tượng đại diện cho kết nối TCP thực sự đến máy chủ. Các kết nối được chỉ định ở cấp giao thức trong AMQP và tất cả giao tiếp với nhà môi giới xảy ra qua một hoặc nhiều kết nối.

  • Vì là kết nối TCP thực tế, nó có Địa chỉ IP và Cổng #.
  • Các tham số giao thức được đàm phán trên cơ sở mỗi khách hàng như là một phần của việc thiết lập kết nối (một quá trình được gọi là bắt tay .
  • Nó được thiết kế để tồn tại lâu dài ; có vài trường hợp đóng kết nối là một phần của thiết kế giao thức.
  • Từ góc độ OSI, nó có thể nằm ở đâu đó xung quanh Lớp 6
  • Nhịp tim có thể được thiết lập để theo dõi trạng thái kết nối, vì TCP không chứa bất cứ thứ gì trong chính nó để làm điều này.
  • Tốt nhất là có một luồng quản lý chuyên dụng đọc và ghi vào ổ cắm TCP bên dưới. Hầu hết, nếu không phải tất cả, khách hàng của RabbitMQ làm điều này. Về vấn đề đó, chúng thường an toàn cho chủ đề.
  • Nói một cách tương đối, các kết nối là "tốn kém" để tạo ra (do bắt tay), nhưng thực tế mà nói, điều này thực sự không quan trọng. Hầu hết các quá trình thực sự sẽ chỉ cần một đối tượng kết nối. Nhưng, bạn có thể duy trì các kết nối trong một nhóm, nếu bạn thấy bạn cần nhiều thông lượng hơn một luồng / ổ cắm duy nhất có thể cung cấp (không thể với công nghệ điện toán hiện tại).

Sự kiện kênh

Một kênh là phiên ứng dụng được mở ra cho mỗi phần của ứng dụng của bạn để liên lạc với người môi giới RabbitMQ. Nó hoạt động trên một kết nối duy nhất và đại diện cho một phiên với nhà môi giới.

  • Vì nó đại diện cho một phần logic của logic ứng dụng, mỗi kênh thường tồn tại trên luồng riêng của nó.
  • Thông thường, tất cả các kênh được mở bởi ứng dụng của bạn sẽ chia sẻ một kết nối (chúng là các phiên nhẹ hoạt động trên đầu kết nối). Các kết nối là an toàn chủ đề, vì vậy điều này là OK.
  • Hầu hết các hoạt động AMQP diễn ra trên các kênh.
  • Từ phối cảnh Lớp OSI, các kênh có thể nằm xung quanh Lớp 7 .
  • Các kênh được thiết kế tạm thời ; một phần của thiết kế AMQP là kênh thường bị đóng để phản hồi lỗi (ví dụ: khai báo lại một hàng đợi với các tham số khác nhau trước khi xóa hàng đợi hiện có).
  • Vì chúng là nhất thời, các kênh không nên được tổng hợp bởi ứng dụng của bạn.
  • Máy chủ sử dụng một số nguyên để xác định một kênh. Khi luồng quản lý kết nối nhận được một gói cho một kênh cụ thể, nó sử dụng số này để báo cho người môi giới biết gói / phiên thuộc về kênh nào.
  • Các kênh nói chung không an toàn cho luồng vì sẽ không có ý nghĩa khi chia sẻ chúng giữa các luồng. Nếu bạn có một chủ đề khác cần sử dụng nhà môi giới, một kênh mới là cần thiết.

Thông tin người tiêu dùng

Một người tiêu dùng là một đối tượng được xác định bởi giao thức AMQP. Nó không phải là kênh cũng không phải là kết nối, thay vào đó là thứ mà ứng dụng cụ thể của bạn sử dụng làm "hộp thư" sắp xếp để gửi tin nhắn.

  • "Tạo người tiêu dùng" có nghĩa là bạn thông báo cho nhà môi giới (sử dụng kênh thông qua kết nối ) rằng bạn muốn tin nhắn được gửi đến bạn qua kênh đó. Đáp lại, nhà môi giới sẽ đăng ký rằng bạn có một người tiêu dùng trên kênh và bắt đầu đẩy tin nhắn cho bạn.
  • Mỗi thông báo được đẩy qua kết nối sẽ tham chiếu cả số kênhsố người tiêu dùng . Theo cách đó, luồng quản lý kết nối (trong trường hợp này, trong API Java) biết phải làm gì với thông báo; sau đó, luồng xử lý kênh cũng biết phải làm gì với thông báo.
  • Việc triển khai của người tiêu dùng có số lượng biến thể lớn nhất, bởi vì nó thực sự là ứng dụng cụ thể. Trong quá trình thực hiện, tôi đã chọn loại bỏ một nhiệm vụ mỗi khi có tin nhắn đến người tiêu dùng; do đó, tôi có một luồng quản lý kết nối, một luồng quản lý kênh (và theo phần mở rộng, người tiêu dùng) và một hoặc nhiều luồng tác vụ cho mỗi thông báo được gửi qua người tiêu dùng.
  • Đóng kết nối sẽ đóng tất cả các kênh trên kết nối. Đóng một kênh sẽ đóng tất cả người tiêu dùng trên kênh. Cũng có thể hủy một người tiêu dùng (mà không đóng kênh). Có nhiều trường hợp khác nhau khi thực hiện bất kỳ điều gì trong ba điều này.
  • Thông thường, việc triển khai người tiêu dùng trong ứng dụng khách AMQP sẽ phân bổ một kênh dành riêng cho người tiêu dùng để tránh xung đột với các hoạt động của các luồng hoặc mã khác (bao gồm xuất bản).

Xét về ý nghĩa của nhóm chủ đề người tiêu dùng, tôi nghi ngờ rằng máy khách Java đang làm một cái gì đó tương tự như những gì tôi đã lập trình cho máy khách của mình (tôi đã dựa trên máy khách .Net, nhưng đã được sửa đổi rất nhiều).


1
"các kênh không nên được gộp", đó là những gì tôi đang tìm kiếm
ospider

"Vì chúng là nhất thời, các kênh không nên được tổng hợp bởi ứng dụng của bạn." - bạn có thể làm rõ làm thế nào bạn đi đến kết luận này xin vui lòng. Các tài liệu khuyến nghị tổng hợp kênh nếu việc triển khai "một kênh trên mỗi luồng" đang sử dụng quá nhiều tài nguyên, xem tại đây: rabbitmq.com/channels.html#resource-usage
ymas

@ymas - Tài liệu bạn đang đề cập là đầu cơ, và theo tôi, hướng dẫn kém. Tôi đang đọc mã nguồn và thông số giao thức. Các kênh không được gộp, thời gian. Hơn nữa, một kênh trên mỗi luồng là hướng dẫn dựa trên cùng nguyên tắc này. Nếu bạn thấy rằng bạn có quá nhiều kênh mở mà máy chủ bị hạn chế về tài nguyên, bạn cần đánh giá lại kiến ​​trúc của mình (nghĩa là chuyển sang sơ đồ có tính sẵn sàng cao và / hoặc giảm đồng thời).
Người chơi

21

Tôi tìm thấy bài viết này giải thích tất cả các khía cạnh của mô hình AMQP, trong đó, kênh là một. Tôi thấy nó rất hữu ích trong việc làm tròn sự hiểu biết của tôi

https://www.rabbitmq.com/tutorials/amqp-con accept.html

Một số ứng dụng cần nhiều kết nối với nhà môi giới AMQP. Tuy nhiên, việc giữ nhiều kết nối TCP mở cùng một lúc là điều không mong muốn vì làm như vậy sẽ tiêu tốn tài nguyên hệ thống và khiến việc cấu hình tường lửa trở nên khó khăn hơn. Các kết nối AMQP 0-9-1 được ghép kênh với các kênh có thể được coi là "các kết nối nhẹ chia sẻ một kết nối TCP".

Đối với các ứng dụng sử dụng nhiều luồng / tiến trình để xử lý, việc mở một kênh mới trên mỗi luồng / tiến trình và không chia sẻ các kênh giữa chúng là điều rất phổ biến.

Giao tiếp trên một kênh cụ thể hoàn toàn tách biệt với giao tiếp trên một kênh khác, do đó, mọi phương thức AMQP cũng mang một số kênh mà khách hàng sử dụng để tìm ra phương thức nào cho phương thức (và do đó, cần xử lý sự kiện nào để xử lý sự kiện) .


4

Có một mối quan hệ giữa như Một kết nối TCP có thể có nhiều Kênh .

Kênh : Đó là một kết nối ảo bên trong một kết nối. Khi xuất bản hoặc tiêu thụ thư từ hàng đợi - tất cả đều được thực hiện qua kênh Kết nối trong đó : Đó là kết nối TCP giữa ứng dụng của bạn và nhà môi giới RabbitMQ.

Trong kiến ​​trúc đa luồng, bạn có thể cần một kết nối riêng cho mỗi luồng. Điều đó có thể dẫn đến việc sử dụng không đúng cách kết nối TCP, ngoài ra, nó còn bổ sung thêm chi phí cho hệ điều hành để thiết lập bao nhiêu kết nối TCP mà nó yêu cầu trong thời gian cao điểm của mạng. Hiệu suất của hệ thống có thể bị giảm mạnh. Đây là nơi kênh trở nên tiện dụng, nó tạo ra các kết nối ảo bên trong kết nối TCP. Nó ngay lập tức làm giảm chi phí hoạt động của HĐH, đồng thời cho phép chúng tôi thực hiện các hoạt động không đồng bộ theo cách nhanh hơn, đáng tin cậy hơn và đồng thời. nhập mô tả hình ảnh ở đây

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.