Message Broker là gì? Vai trò của Message Broker trong Backend
1. Message Broker là gì?
Message Broker là phần mềm trung gian cho phép các thành phần trong hệ thống trao đổi thông điệp với nhau mà không cần giao tiếp trực tiếp. Nó tiếp nhận thông điệp từ bên gửi, sau đó định tuyến và phân phối thông điệp đến bên nhận theo cơ chế được cấu hình.
Trong Backend, Message Broker thường được sử dụng khi một service cần thông báo cho service khác thực hiện công việc hoặc khi nhiều thành phần cần trao đổi dữ liệu một cách bất đồng bộ.
Ví dụ, một hệ thống thương mại điện tử có thể gồm các service quản lý đơn hàng, thanh toán, kho hàng và thông báo. Khi khách hàng đặt hàng thành công, hệ thống có thể phát sinh thông điệp về đơn hàng để các service liên quan tiếp tục xử lý.
Thay vì để service quản lý đơn hàng gọi trực tiếp từng service, hệ thống có thể sử dụng Message Broker để phân phối thông điệp đến các thành phần cần nhận.
Có thể hiểu đơn giản:
- Message: thông tin được gửi giữa các thành phần.
- Message Broker: phần mềm trung gian tiếp nhận và điều phối việc trao đổi thông điệp.
- Producer: thành phần tạo và gửi thông điệp.
- Consumer: thành phần nhận và xử lý thông điệp.
Message Broker không trực tiếp thực hiện nghiệp vụ như thanh toán hoặc gửi email. Nó hỗ trợ việc chuyển thông điệp để các thành phần phù hợp thực hiện những công việc đó.
2. Tại sao hệ thống cần Message Broker?
Khi một ứng dụng còn nhỏ, các thành phần có thể gọi trực tiếp lẫn nhau thông qua HTTP API hoặc các phương thức trong chương trình. Tuy nhiên, khi hệ thống phát triển, cách giao tiếp này có thể tạo ra những vấn đề về sự phụ thuộc, hiệu năng và khả năng mở rộng.
2.1. Giảm sự phụ thuộc giữa các service
Giả sử khi tạo đơn hàng, Order Service cần thông báo cho Payment Service, Inventory Service và Notification Service.
Nếu giao tiếp trực tiếp, Order Service phải biết địa chỉ và cách gọi của từng service. Khi một service thay đổi hoặc tạm thời không hoạt động, quá trình xử lý có thể bị ảnh hưởng tùy theo cách triển khai.
Với Message Broker, Order Service có thể gửi một thông điệp như OrderCreated. Những service quan tâm đến sự kiện này sẽ nhận và xử lý thông điệp theo cơ chế đăng ký tương ứng.
Nhờ đó, Order Service không nhất thiết phải biết chi tiết triển khai của từng consumer.
2.2. Hỗ trợ xử lý bất đồng bộ
Một request HTTP có thể cần thực hiện nhiều công việc khác nhau. Một số công việc phải hoàn thành trước khi trả kết quả, nhưng một số khác có thể thực hiện sau.
Ví dụ, khi khách hàng đặt hàng, hệ thống có thể cần:
- Lưu đơn hàng.
- Xử lý thanh toán.
- Gửi email xác nhận.
- Gửi thông báo đến hệ thống chăm sóc khách hàng.
Tùy yêu cầu nghiệp vụ, việc gửi email hoặc gửi thông báo có thể được thực hiện bất đồng bộ thông qua Message Broker. Điều này giúp giảm lượng công việc cần thực hiện ngay trong luồng request chính.
Tuy nhiên, không phải mọi thao tác đều có thể chuyển sang xử lý bất đồng bộ. Những thao tác cần xác nhận kết quả ngay, chẳng hạn một bước thanh toán bắt buộc trước khi xác nhận đơn hàng, vẫn cần được thiết kế theo đúng yêu cầu nghiệp vụ.
2.3. Điều phối lượng công việc lớn
Khi có nhiều thông điệp được gửi đến, Message Broker có thể lưu trữ chúng trong queue và phân phối cho các consumer xử lý.
Nếu một consumer không xử lý kịp, thông điệp có thể chờ trong hàng đợi thay vì buộc producer phải chờ consumer hoàn thành từng công việc.
Hệ thống cũng có thể tăng số lượng consumer để xử lý nhiều thông điệp hơn, miễn là nghiệp vụ cho phép và tài nguyên đáp ứng được.
2.4. Tăng khả năng chịu lỗi
Một số Message Broker hỗ trợ lưu trữ thông điệp, xác nhận xử lý và phân phối lại thông điệp khi consumer gặp lỗi.
Nhờ đó, hệ thống có thể hạn chế mất thông điệp khi một thành phần tạm thời không hoạt động.
Tuy nhiên, khả năng này phụ thuộc vào loại broker, cấu hình lưu trữ, cơ chế xác nhận và cách consumer xử lý lỗi. Chỉ sử dụng Message Broker không đồng nghĩa với việc hệ thống chắc chắn không mất dữ liệu.
3. Message Broker hoạt động như thế nào?
Để hiểu cách hoạt động, hãy xét một hệ thống đăng ký tài khoản có chức năng gửi email xác minh.
Khi người dùng đăng ký, Backend tạo tài khoản và cần yêu cầu một thành phần khác gửi email. Quá trình trao đổi thông điệp có thể diễn ra như sau:
- Producer tạo thông điệp: Account Service tạo thông điệp yêu cầu gửi email xác minh.
- Gửi thông điệp đến Message Broker: thông điệp được gửi đến broker.
- Broker định tuyến thông điệp: broker chuyển thông điệp đến queue hoặc consumer phù hợp theo cấu hình.
- Consumer nhận thông điệp: Email Worker lấy thông điệp từ queue.
- Consumer thực hiện công việc: Email Worker sử dụng dịch vụ gửi email để gửi thư.
- Xác nhận xử lý: tùy cơ chế của broker, consumer xác nhận thông điệp đã được xử lý để broker có thể hoàn tất việc quản lý thông điệp đó.
Có thể hình dung luồng cơ bản như sau:
Account Service
|
| Gửi message
v
Message Broker
|
| Định tuyến
v
Email Queue
|
| Consumer nhận message
v
Email Worker
|
v
Gửi email xác minh
Trong mô hình này, Account Service và Email Worker không cần gọi trực tiếp nhau. Broker đóng vai trò trung gian trong việc trao đổi thông điệp.
Điều này cũng giúp tách biệt thời điểm gửi yêu cầu với thời điểm thực hiện công việc. Tuy nhiên, producer vẫn cần xử lý lỗi khi không thể gửi thông điệp đến broker, còn consumer cần có cơ chế xử lý khi công việc thất bại.
4. Các thành phần trong hệ thống Message Broker
4.1. Message
Message là thông điệp được truyền từ producer đến một hoặc nhiều consumer thông qua cơ chế trao đổi của hệ thống.
Thông điệp có thể chứa dữ liệu nghiệp vụ, thông tin định danh hoặc yêu cầu thực hiện một công việc.
Ví dụ, một thông điệp yêu cầu gửi email có thể được biểu diễn bằng JSON:
{
"type": "SendVerificationEmail",
"userId": 10,
"email": "[email protected]"
}
Trong ví dụ này:
typecho biết loại thông điệp.userIdxác định người dùng liên quan.emaillà địa chỉ nhận thư.
Đây chỉ là một cấu trúc minh họa. Trong hệ thống thực tế, thông điệp có thể cần thêm mã định danh, thời điểm tạo, phiên bản schema hoặc metadata phục vụ truy vết.
Message là dữ liệu được truyền đi; nó không nhất thiết chứa toàn bộ logic xử lý công việc.
4.2. Producer
Producer là thành phần tạo và gửi thông điệp đến Message Broker.
Ví dụ, sau khi tạo tài khoản, Account Service gửi thông điệp yêu cầu gửi email xác minh.
Producer không nhất thiết phải chờ consumer hoàn thành công việc. Trong mô hình bất đồng bộ, producer có thể tiếp tục xử lý sau khi gửi thông điệp thành công theo cơ chế của hệ thống.
Tuy nhiên, cần phân biệt việc broker đã nhận thông điệp với việc công việc nghiệp vụ đã hoàn thành. Một phản hồi xác nhận từ broker thường không có nghĩa là email đã được gửi thành công.
4.3. Consumer
Consumer là thành phần nhận và xử lý thông điệp.
Ví dụ, Email Worker nhận thông điệp SendVerificationEmail, sau đó gọi dịch vụ gửi email.
Consumer có thể là một worker chạy nền, một service độc lập hoặc một thành phần khác được thiết kế để nhận thông điệp.
Một queue có thể được xử lý bởi nhiều consumer nhằm tăng khả năng xử lý song song. Trong mô hình competing consumers, mỗi thông điệp thường được phân phối cho một consumer để xử lý, tùy cơ chế của broker.
Nếu nhiều hệ thống đều cần nhận một sự kiện, chẳng hạn OrderCreated, chúng có thể được cấu hình theo mô hình publish-subscribe để mỗi nhóm consumer nhận được bản thông điệp phù hợp.
4.4. Queue
Queue là hàng đợi dùng để lưu trữ hoặc giữ các thông điệp chờ được phân phối hay xử lý.
Ví dụ, khi hệ thống nhận nhiều yêu cầu gửi email cùng lúc, các thông điệp có thể được đưa vào queue. Email Worker sẽ nhận thông điệp theo cơ chế phân phối của broker.
Queue giúp producer không nhất thiết phải chờ consumer xử lý từng thông điệp ngay tại thời điểm gửi.
Cần lưu ý rằng queue không phải lúc nào cũng có đặc tính giống nhau. Thứ tự xử lý, thời gian lưu trữ, khả năng lưu bền vững và cách phân phối thông điệp phụ thuộc vào công nghệ và cấu hình được sử dụng.
4.5. Exchange và Routing Key
Trong RabbitMQ, Exchange là thành phần tiếp nhận thông điệp từ producer và định tuyến thông điệp đến các queue dựa trên loại exchange, binding và các quy tắc liên quan.
Routing Key là chuỗi được producer gửi kèm thông điệp để hỗ trợ việc định tuyến trong những loại exchange có sử dụng routing key.
Ví dụ, một hệ thống có thể dùng routing key order.created cho thông điệp về đơn hàng mới và payment.completed cho thông điệp thanh toán thành công.
Producer
|
v
Exchange
|
| Routing Key: order.created
v
Order Queue
|
v
Order Consumer
Đây là mô hình cụ thể của RabbitMQ, không phải cấu trúc bắt buộc của mọi Message Broker. Một số hệ thống sử dụng các khái niệm và cơ chế định tuyến khác.
5. Phân biệt Message Broker, Queue và Background Jobs
Ba khái niệm này có liên quan chặt chẽ nhưng đại diện cho những khía cạnh khác nhau của hệ thống.
Background Job là gì?
Background Job là công việc được thực hiện ở phía sau luồng xử lý chính, thường để tránh khiến người dùng phải chờ những thao tác không cần thiết.
Ví dụ: gửi email xác minh, tạo báo cáo hoặc xử lý hình ảnh.
Background Job có thể được triển khai bằng goroutine trong Go hoặc bằng hệ thống worker và queue chuyên dụng.
Queue là gì?
Queue là cơ chế hoặc cấu trúc hàng đợi dùng để giữ các công việc hay thông điệp đang chờ xử lý.
Trong Go, có thể sử dụng channel làm một hàng đợi đơn giản trong bộ nhớ. Với hệ thống phân tán, queue có thể được quản lý bởi một Message Broker.
Message Broker là gì?
Message Broker là phần mềm trung gian quản lý việc tiếp nhận, định tuyến và phân phối thông điệp giữa các thành phần.
Bảng so sánh:
| Khái niệm | Bản chất | Ví dụ |
|---|---|---|
| Background Job | Công việc cần thực hiện ở phía sau | Gửi email xác minh |
| Queue | Hàng đợi thông điệp hoặc công việc | Queue chứa các yêu cầu gửi email |
| Message Broker | Phần mềm trung gian trao đổi thông điệp | RabbitMQ |
| Worker | Thành phần thực hiện công việc | Email Worker |
Trong hệ thống thực tế, một Background Job có thể được biểu diễn thành message, đưa vào queue thông qua Message Broker và được Worker xử lý.
Tuy nhiên, không phải Background Job nào cũng cần Message Broker. Một goroutine đơn giản có thể đủ cho công việc nhỏ trong cùng tiến trình. Message Broker thường hữu ích hơn khi cần giao tiếp giữa các tiến trình, lưu trữ thông điệp, phân phối công việc hoặc tách biệt các service.
6. Message Broker trong kiến trúc Backend
Message Broker thường xuất hiện trong những kiến trúc cần giao tiếp bất đồng bộ giữa nhiều thành phần.
6.1. Giao tiếp giữa các service
Trong kiến trúc microservices, mỗi service thường chịu trách nhiệm cho một nhóm nghiệp vụ nhất định.
Ví dụ:
- Order Service quản lý đơn hàng.
- Payment Service xử lý thanh toán.
- Inventory Service quản lý tồn kho.
- Notification Service gửi thông báo.
Khi một sự kiện xảy ra, service phát sinh sự kiện có thể gửi message đến broker. Những service quan tâm sẽ nhận và xử lý thông điệp theo cơ chế đã cấu hình.
Cách này giúp giảm sự phụ thuộc trực tiếp giữa các service. Tuy nhiên, nó cũng làm tăng yêu cầu về theo dõi thông điệp, xử lý lỗi và đồng bộ trạng thái giữa các thành phần.
6.2. Xử lý tác vụ nền
Message Broker thường được sử dụng cùng với Background Jobs và Worker.
Ví dụ, sau khi người dùng đăng ký, Backend có thể tạo job gửi email và đưa job vào queue. Worker nhận job để gửi email trong khi API không cần chờ toàn bộ quá trình gửi thư hoàn thành.
Mô hình này phù hợp với các tác vụ có thể xử lý sau, đặc biệt khi hệ thống cần retry hoặc phân phối công việc cho nhiều worker.
6.3. Event-driven architecture
Event-driven architecture là kiến trúc trong đó các thành phần giao tiếp hoặc phản ứng với những sự kiện xảy ra trong hệ thống.
Ví dụ, sau khi một đơn hàng được tạo, Order Service phát sinh sự kiện OrderCreated. Những thành phần liên quan có thể phản ứng với sự kiện này:
- Inventory Service cập nhật hoặc giữ hàng.
- Notification Service gửi thông báo.
- Analytics Service ghi nhận dữ liệu phục vụ phân tích.
Message Broker có thể giúp phân phối các sự kiện đó đến những thành phần đăng ký nhận.
Cần phân biệt event và command:
- Event mô tả điều đã xảy ra, chẳng hạn
OrderCreated. - Command yêu cầu thực hiện một hành động, chẳng hạn
SendVerificationEmail.
Trong thực tế, cách đặt tên và thiết kế message cần phản ánh rõ ý nghĩa nghiệp vụ để tránh gây nhầm lẫn giữa thông báo sự kiện và yêu cầu thực hiện công việc.
7. Các Message Broker phổ biến
7.1. RabbitMQ
RabbitMQ là một message broker phổ biến, hỗ trợ giao thức AMQP 0-9-1 cùng nhiều tính năng định tuyến thông điệp.
RabbitMQ thường được sử dụng cho:
- Xử lý tác vụ nền.
- Giao tiếp bất đồng bộ giữa các service.
- Định tuyến message đến các queue.
- Phân phối công việc cho nhiều consumer.
- Quản lý xác nhận và xử lý lại thông điệp theo cấu hình.
RabbitMQ phù hợp khi hệ thống cần cơ chế queue và định tuyến thông điệp rõ ràng. Trong các ví dụ về Background Jobs & Queues, RabbitMQ là một lựa chọn thuận tiện để minh họa cách producer gửi message và worker xử lý message.
7.2. Apache Kafka
Apache Kafka là nền tảng phân tán dùng để lưu trữ và truyền các luồng sự kiện (event streams).
Kafka thường được sử dụng cho:
- Thu thập và phân phối sự kiện với lưu lượng lớn.
- Xử lý luồng dữ liệu.
- Tích hợp dữ liệu giữa các hệ thống.
- Lưu trữ và đọc lại sự kiện theo thời gian lưu giữ đã cấu hình.
Khác với mô hình queue truyền thống thường được minh họa bằng RabbitMQ, Kafka tổ chức dữ liệu thành các topic và partition. Consumer đọc các bản ghi theo offset, và nhiều consumer group có thể đọc cùng một topic độc lập với nhau.
Kafka không chỉ là một queue đơn giản. Mô hình lưu trữ log và khả năng đọc lại dữ liệu khiến nó phù hợp với những bài toán event streaming.
7.3. NATS
NATS là hệ thống nhắn tin nhẹ, được thiết kế để giao tiếp giữa các thành phần phân tán.
NATS hỗ trợ nhiều mô hình messaging, bao gồm publish-subscribe và request-reply. Khi sử dụng JetStream, hệ thống có thể bổ sung khả năng lưu trữ thông điệp, xác nhận và phát lại dữ liệu.
NATS có thể phù hợp với những hệ thống cần giao tiếp giữa các service với cách triển khai gọn nhẹ. Việc lựa chọn NATS hay công nghệ khác vẫn phụ thuộc vào yêu cầu về lưu trữ, độ tin cậy, thông lượng và cách tiêu thụ thông điệp.
Nên chọn công nghệ nào?
Không có một Message Broker phù hợp nhất cho mọi hệ thống. Việc lựa chọn cần dựa trên yêu cầu thực tế:
- Nếu cần queue và cơ chế định tuyến thông điệp rõ ràng, có thể xem xét RabbitMQ.
- Nếu cần lưu trữ và xử lý luồng sự kiện lớn, có thể xem xét Kafka.
- Nếu cần hệ thống messaging nhẹ với các mô hình giao tiếp linh hoạt, có thể xem xét NATS.
Ngoài tính năng, cần cân nhắc khả năng vận hành, giám sát, triển khai, chi phí và mức độ quen thuộc của đội ngũ.
8. Những vấn đề cần lưu ý khi sử dụng Message Broker
Message Broker giúp việc giao tiếp giữa các thành phần linh hoạt hơn, nhưng không tự giải quyết mọi vấn đề về độ tin cậy. Hệ thống vẫn cần thiết kế cách xử lý thông điệp cẩn thận.
8.1. Message acknowledgment
Acknowledgment (ack) là cơ chế xác nhận rằng consumer đã nhận hoặc xử lý thông điệp theo quy ước của hệ thống.
Trong những broker có hỗ trợ cơ chế này, consumer thường gửi xác nhận sau khi xử lý thành công. Nếu consumer thất bại trước khi xác nhận, broker có thể phân phối lại thông điệp tùy cấu hình.
Việc xác nhận quá sớm có thể khiến thông điệp bị coi là đã xử lý dù nghiệp vụ chưa hoàn thành. Ngược lại, nếu consumer hoàn thành công việc nhưng chưa gửi xác nhận rồi bị dừng, thông điệp có thể được xử lý lại.
Do đó, vị trí gửi acknowledgment cần được lựa chọn phù hợp với yêu cầu nghiệp vụ.
8.2. Retry và xử lý lỗi
Consumer có thể gặp lỗi khi xử lý thông điệp, chẳng hạn dịch vụ email tạm thời không hoạt động hoặc database không thể kết nối.
Một số hệ thống có thể thử xử lý lại thông điệp sau một khoảng thời gian. Tuy nhiên, retry vô hạn hoặc retry liên tục không có khoảng nghỉ có thể làm tăng tải cho hệ thống đang gặp sự cố.
Các chiến lược thường được sử dụng gồm:
- Giới hạn số lần retry.
- Tăng dần khoảng thời gian chờ giữa các lần retry (backoff).
- Chuyển những thông điệp thất bại nhiều lần sang dead-letter queue hoặc cơ chế xử lý lỗi tương đương.
- Ghi log và theo dõi các thông điệp không thể xử lý.
Cần phân biệt lỗi tạm thời với lỗi không thể khắc phục bằng retry. Ví dụ, lỗi kết nối có thể tạm thời, trong khi một thông điệp sai định dạng cần được kiểm tra hoặc xử lý riêng.
8.3. Duplicate messages và idempotency
Trong một số tình huống, cùng một thông điệp có thể được xử lý nhiều lần. Điều này có thể xảy ra khi consumer hoàn thành công việc nhưng không kịp xác nhận, khiến broker phân phối lại thông điệp.
Nếu xử lý lặp gây ra tác động ngoài ý muốn, chẳng hạn trừ tiền hai lần hoặc tạo nhiều bản ghi giống nhau, hệ thống có thể gặp lỗi nghiệp vụ nghiêm trọng.
Idempotency là tính chất cho phép một thao tác được thực hiện lặp lại mà không tạo thêm tác động ngoài ý muốn sau lần thực hiện đầu tiên, trong phạm vi được thiết kế.
Một số biện pháp thường dùng:
- Gắn mã định danh duy nhất cho thông điệp.
- Lưu trạng thái xử lý để nhận biết thông điệp đã hoàn thành.
- Sử dụng ràng buộc duy nhất hoặc transaction khi phù hợp.
- Thiết kế consumer để xử lý an toàn khi nhận lại cùng một thông điệp.
Không nên giả định rằng broker luôn bảo đảm mỗi thông điệp chỉ được xử lý đúng một lần. Mức bảo đảm thực tế phụ thuộc vào broker, cấu hình và cách thiết kế consumer.
8.4. Message persistence
Message persistence là khả năng lưu thông điệp theo cách giúp chúng tồn tại sau những sự cố nhất định, chẳng hạn khi tiến trình broker khởi động lại.
Tùy công nghệ, việc bảo vệ thông điệp có thể cần kết hợp nhiều cấu hình, chẳng hạn:
- Chế độ lưu trữ thông điệp bền vững.
- Queue hoặc topic có cấu hình lưu trữ phù hợp.
- Cơ chế xác nhận việc ghi dữ liệu.
- Sao chép dữ liệu và cấu hình phục hồi khi có sự cố.
Ví dụ, trong RabbitMQ, việc đánh dấu message là persistent không tự nó bảo đảm mọi thông điệp đều được bảo vệ trong mọi tình huống. Cần xem xét thêm cấu hình queue, xác nhận từ broker và các yêu cầu về tính sẵn sàng.
Trong Kafka, dữ liệu được lưu trong log theo thời gian hoặc chính sách lưu giữ đã cấu hình. Consumer có thể đọc lại dữ liệu còn được lưu trữ bằng cách quản lý offset phù hợp.
Vì vậy, khi đánh giá độ tin cậy của một Message Broker, cần xem xét toàn bộ cơ chế lưu trữ và phục hồi chứ không chỉ một tùy chọn riêng lẻ.
9. Kết luận
Message Broker là một thành phần quan trọng trong nhiều hệ thống Backend, đặc biệt khi cần giao tiếp bất đồng bộ, xử lý tác vụ nền hoặc trao đổi sự kiện giữa nhiều service.
Thông qua các thành phần như Producer, Message, Queue và Consumer, hệ thống có thể tách biệt bên gửi với bên nhận, phân phối công việc và hỗ trợ xử lý khi một thành phần gặp sự cố.
Tuy nhiên, sử dụng Message Broker cũng đặt ra những yêu cầu mới về xác nhận xử lý, retry, idempotency, lưu trữ và giám sát. Các vấn đề này cần được giải quyết trong thiết kế tổng thể thay vì mặc định rằng broker sẽ tự động bảo đảm mọi thông điệp được xử lý thành công.
Điều quan trọng nhất là hiểu Message Broker không thay thế logic nghiệp vụ của các service. Nó cung cấp cơ chế để các thành phần trao đổi thông điệp, còn việc xử lý thông điệp đúng cách vẫn phụ thuộc vào thiết kế và triển khai của hệ thống.








Khoá học lập trình game con rắn cho trẻ em




