Skip to content

Hàng đợi tin nhắn và Kiến trúc hướng sự kiện

🎯 Câu hỏi cốt lõi

Khi hệ thống bị ghép nối chặt chẽ và lưu lượng tăng đột biến, làm thế nào để đảm bảo luồng chính ổn định? Hàng đợi tin nhắn là "bộ đệm" và "bộ giải ghép" của hệ thống phân tán hiện đại. Bài viết này sử dụng các tình huống thực tế (hệ thống gọi số nhà hàng, phân loại chuyển phát nhanh, hệ thống flash sale) để hiểu sâu về triết lý thiết kế và thực tiễn kỹ thuật của hàng đợi tin nhắn.


1. Tại sao cần "Hàng đợi tin nhắn"?

1.1 Bắt đầu từ một case study thực tế: Sự phát triển của hệ thống đơn hàng Taobao

Năm 2012, hệ thống đơn hàng của Taobao gặp một sự cố nghiêm trọng. Vào lúc 0 giờ ngày 11/11, lưu lượng truy cập đổ vào ồ ạt, dịch vụ đơn hàng gọi trực tiếp đến dịch vụ kho hàng, dịch vụ thanh toán, dịch vụ logistics... toàn bộ chuỗi liên kết sụp đổ như hiệu ứng domino.

Kiến trúc lúc đó (ghép nối chặt chẽ):

Người dùng đặt hàng → Dịch vụ đơn hàng → Gọi đồng bộ dịch vụ kho → Gọi đồng bộ dịch vụ thanh toán → Gọi đồng bộ dịch vụ logistics
                              ↓                    ↓                    ↓
                         Phản hồi 200ms        Phản hồi 500ms        Phản hồi 300ms

⚠️ Vấn đề chết người của ghép nối chặt chẽ

  • Tổng thời gian phản hồi = 200 + 500 + 300 = 1000ms (người dùng chờ 1 giây)
  • Dịch vụ kho gặp sự cố → Dịch vụ đơn hàng cũng gặp sự cố (cạn kiệt thread pool)
  • Dịch vụ thanh toán chậm → Toàn bộ chuỗi bị kéo chậm
  • Không thể mở rộng ngang → Chỉ có thể mở rộng dọc (thêm máy, đắt và có giới hạn)

Kiến trúc cải tiến (giới thiệu hàng đợi tin nhắn):

Người dùng đặt hàng → Dịch vụ đơn hàng → Gửi tin nhắn "Đơn hàng đã tạo" → Phản hồi ngay (50ms)

                                    Hàng đợi tin nhắn (Kafka)

                ┌─────────────┬─────────────┬─────────────┬─────────────┐
                ▼             ▼             ▼             ▼             ▼
        Dịch vụ kho    Dịch vụ thanh toán  Dịch vụ logistics  Dịch vụ thông báo
        (trừ kho bất   (xử lý bất đồng     (tạo bất đồng      (gửi bất đồng
        đồng bộ)        bộ)                  bộ)                 bộ)

✨ Hiệu quả sau cải tiến

  • Thời gian phản hồi người dùng = 50ms (trải nghiệm cải thiện gấp 20 lần)
  • Dịch vụ kho gặp sự cố → Tin nhắn được lưu tạm trong hàng đợi, xử lý tiếp sau khi khôi phục
  • Dịch vụ thanh toán chậm → Không ảnh hưởng đến việc tạo đơn hàng
  • Có thể mở rộng ngang → Chỉ cần tăng số lượng consumer instance

1.2 Phép so sánh đời thường về hàng đợi tin nhắn

Hệ thống gọi số nhà hàng

Hãy tưởng tượng bạn đến một nhà hàng nổi tiếng:

  • Không có hệ thống gọi số: Khách hàng phải đứng chờ ở quầy, quầy có hạn, người phía sau xếp hàng dài, nhà hàng chịu áp lực lớn
  • Có hệ thống gọi số: Sau khi gọi món, bạn nhận một số, có thể ngồi xuống trước, khi được gọi số thì đến lấy món

Hàng đợi tin nhắn chính là "hệ thống gọi số" của hệ thống phần mềm:

  • Producer (người gọi món) → Đưa tin nhắn (đơn hàng) vào hàng đợi
  • Queue (máy gọi số) → Lưu tạm tin nhắn
  • Consumer (đầu bếp) → Xử lý tin nhắn theo nhịp độ của riêng mình
Peak Shaving: flatten traffic spikes
Simulate a burst and see how a queue protects backend systems
Processing capacity (Consumer)200 req/s
Maximum backend processing speed
Queue capacity (Queue Size)2000
Maximum requests the message queue can buffer
Current inbound traffic
100 req/s
Queue backlog
0 msgs
Actual processing rate
0 req/s
Rejected requests (rate limited)
0 req
Inbound traffic (user requests)Processed traffic (system load)Queue backlog
💡
Core principle: When inbound traffic (blue) exceeds processing capacity (green line), extra requests are stored in the message queue (orange area).
After the traffic peak passes, the system keeps processing the backlog at full speed until the queue is empty. This is peak shaving.

2. Hàng đợi tin nhắn là gì? (Định nghĩa + Ba yếu tố cốt lõi)

2.1 "Hàng đợi tin nhắn" là gì?

🤔 Giải thích thuật ngữ

Hàng đợi tin nhắn (Message Queue, MQ) là một container lưu trữ tin nhắn, producer đưa tin nhắn vào, consumer lấy tin nhắn ra để xử lý. Nó thực hiện "giao tiếp bất đồng bộ" — bên gửi không cần chờ bên nhận xử lý xong.

Đồng bộ vs Bất đồng bộ:

  • Đồng bộ: Giống như gọi điện thoại, đối phương phải bắt máy mới có thể giao tiếp
  • Bất đồng bộ: Giống như gửi tin nhắn, gửi đi là xong, đối phương có thời gian rảnh thì xem

Điều này giống như bạn gọi điện cho bạn bè (đồng bộ) vs gửi tin nhắn WeChat (bất đồng bộ).

2.2 Ba yếu tố cốt lõi của hàng đợi tin nhắn

Yếu tố thứ nhất: Producer (Nhà sản xuất)

Trách nhiệm: Tạo và gửi tin nhắn vào hàng đợi.

Phép so sánh đời thường: Producer giống như "người gửi", đưa thư (tin nhắn) đến bưu điện (hàng đợi).

Các điểm thiết kế chính
  • Cách gửi: Gửi đồng bộ (tin cậy nhưng chặn) vs Gửi bất đồng bộ (hiệu suất cao nhưng cần xử lý callback)
  • Xác nhận tin nhắn: Chờ Broker xác nhận (At Least Once) vs Gửi rồi quên (At Most Once)
  • Xử lý thất bại: Chiến lược thử lại, sao lưu log cục bộ, hàng đợi tin chết

Yếu tố thứ hai: Consumer (Người tiêu dùng)

Trách nhiệm: Lấy tin nhắn từ hàng đợi và xử lý.

Phép so sánh đời thường: Consumer giống như "người nhận", lấy thư (tin nhắn) từ hộp thư (hàng đợi) và xử lý.

Các điểm thiết kế chính
  • Mô hình tiêu thụ: Chế độ đẩy (Push, Broker chủ động đẩy) vs Chế độ kéo (Pull, consumer chủ động kéo)
  • Xác nhận tiêu thụ: Tự động ACK (hiệu quả nhưng có thể mất tin nhắn) vs Thủ công ACK (tin cậy nhưng cần xử lý timeout)
  • Kiểm soát đồng thời: Tiêu thụ tuần tự đơn luồng vs Tiêu thụ song song đa luồng
  • Xử lý thất bại: Chiến lược thử lại, hàng đợi tin chết, cơ chế bù trừ

Yếu tố thứ ba: Broker (Môi giới tin nhắn)

Trách nhiệm: Nhận, lưu trữ, chuyển tiếp tin nhắn.

Phép so sánh đời thường: Broker giống như "bưu điện" hoặc "trạm trung chuyển chuyển phát nhanh", chịu trách nhiệm nhận, phân loại, phân phát thư.

Các điểm thiết kế chính
  • Mô hình lưu trữ: Lưu trữ bộ nhớ (độ trễ thấp) vs Lưu trữ đĩa (độ tin cậy cao)
  • Chiến lược sao chép: Sao chép chủ-tớ, đồng bộ đa bản sao
  • Cơ chế sẵn sàng cao: Triển khai cụm, chuyển đổi dự phòng tự động
  • Khả năng mở rộng: Phân vùng (Partition), Phân mảnh (Sharding)

3. Vấn đề cốt lõi thứ nhất: Làm thế nào để giải ghép hệ thống, tránh "động một chỗ ảnh hưởng toàn bộ"?

3.1 Bi kịch của ghép nối chặt chẽ: Một dịch vụ gặp sự cố, toàn bộ thất bại

Tái hiện tình huống: Kiến trúc ban đầu của một nền tảng thương mại điện tử

Dịch vụ đơn hàng gọi trực tiếp các dịch vụ hạ nguồn:
┌─────────────┐
│ Dịch vụ đơn hàng │
└──────┬──────┘

       ├───────────┬───────────┬───────────┬───────────┐
       ▼           ▼           ▼           ▼           ▼
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│Dịch vụ kho│ │Dịch vụ TT│ │Dịch vụ LH│ │Dịch vụ TN│ │Dịch vụ SMS│
│  200ms   │ │  500ms   │ │  300ms   │ │  100ms   │ │  100ms   │
└──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘

📊 Bảng phân tích điểm đau

Điểm đauBiểu hiện cụ thểHậu quả
Lỗi lan truyềnDịch vụ kho gặp sự cố, dịch vụ đơn hàng gọi đồng bộ timeoutThread pool dịch vụ đơn hàng cạn kiệt, không thể xử lý yêu cầu mới
Độ trễ phản hồiPhải chờ tất cả dịch vụ hạ nguồn phản hồiNgười dùng chờ hơn 1 giây, trải nghiệm cực kém
Khó mở rộngThêm dịch vụ điểm thưởng, cần sửa code dịch vụ đơn hàngChu kỳ phát hành dài hơn, rủi ro tăng
Lãng phí tài nguyênDịch vụ đơn hàng phải chờ dịch vụ SMSKết nối cơ sở dữ liệu bị chiếm dụng lâu

3.2 Giải pháp giải ghép: Giới thiệu hàng đợi tin nhắn làm "lớp trung gian"

Kiến trúc sau khi giải ghép:

Dịch vụ đơn hàng chỉ chịu trách nhiệm gửi tin nhắn, không quan tâm ai tiêu thụ:

┌─────────────┐
│ Dịch vụ đơn hàng │ ──Gửi tin nhắn "Đơn hàng đã tạo"──┐
└─────────────┘                                         │

                                              ┌───────────────────┐
                                              │   Hàng đợi tin nhắn│
                                              │  (Kafka/RabbitMQ) │
                                              │   - Lưu trữ tin cậy│
                                              │   - Đa bản sao     │
                                              │   - Đảm bảo thứ tự │
                                              └─────────┬─────────┘

                        ┌───────────────────────────────┼───────────────────────────────┐
                        │                               │                               │
                        ▼                               ▼                               ▼
                 ┌──────────────┐              ┌──────────────┐              ┌──────────────┐
                 │ Dịch vụ kho  │              │Dịch vụ thanh │              │Dịch vụ logis │
                 │ Đăng ký sự    │              │toán Đăng ký  │              │tics Đăng ký  │
                 │ kiện đơn hàng │              │sự kiện đơn   │              │sự kiện đơn   │
                 └──────────────┘              │hàng          │              │hàng          │
                                               └──────────────┘              └──────────────┘
🔗System Decoupling DemoFrom tight coupling to loose coupling
❌ The fatal problem of tight coupling
Order service
Create order
Call inventory service
Call points service
Call notification service
Notification service
Send SMS/email
⚠️Strong dependency: notification failure blocks order creation
⚠️Slow response: total time = 300ms + 500ms + 400ms = 1200ms
⚠️Hard to extend: adding a service requires changing order code
💡Core idea:Synchronous calls create strong dependencies and slow responses; asynchronous messaging decouples systems, improves response speed, and scales more easily.

✨ Lợi ích của giải ghép

Khía cạnhTrước khi giải ghépSau khi giải ghép
Cô lập lỗiKho gặp sự cố = Đơn hàng gặp sự cốKho gặp sự cố, tin nhắn lưu tạm hàng đợi, tiêu thụ sau khi khôi phục
Thời gian phản hồi1000ms (chờ đồng bộ)50ms (gửi tin nhắn xong trả về ngay)
Khả năng mở rộngThêm dịch vụ cần sửa code đơn hàngThêm dịch vụ chỉ cần đăng ký topic
Độ phức tạp hệ thốngDịch vụ đơn hàng phụ thuộc mạnh vào hạ nguồnDịch vụ đơn hàng chỉ phụ thuộc hàng đợi tin nhắn

3.3 Bản chất của giải ghép: Từ "gọi trực tiếp" đến "hướng sự kiện"

Sự thay đổi mô hình tư duy:

Tư duy truyền thống (Mệnh lệnh):
"Dịch vụ đơn hàng ra lệnh cho dịch vụ kho: trừ kho cho tôi!"
  ↓ Gọi trực tiếp
  ↓ Độ ghép nối cao, bên được gọi phải online
  ↓ Bên gọi cần biết interface của bên được gọi

Tư duy hướng sự kiện (Khai báo):
"Dịch vụ đơn hàng tuyên bố: Đơn hàng đã được tạo, ai quan tâm thì đến xử lý."
  ↓ Gửi sự kiện đến hàng đợi tin nhắn
  ↓ Giải ghép, consumer có thể offline
  ↓ Producer không cần biết sự tồn tại của consumer

4. Vấn đề cốt lõi thứ hai: Làm thế nào để cắt đỉnh lấp thung lũng, đối phó với lưu lượng tăng đột biến?

4.1 Kịch bản flash sale: Làm thế nào để xử lý ổn định 10 vạn QPS?

Tái hiện tình huống: Sự kiện flash sale 11/11 của một nền tảng thương mại điện tử, dự kiến đỉnh 10 vạn QPS, nhưng cơ sở dữ liệu chỉ chịu được 1000 QPS.

Hậu quả của việc tấn công trực tiếp:

Yêu cầu người dùng ──→ Máy chủ ứng dụng ──→ Cơ sở dữ liệu
   10 vạn/s              10 vạn/s              1000/s (giới hạn)

                                             Cạn kiệt connection pool
                                             Timeout phản hồi
                                             Cơ sở dữ liệu sụp đổ

                                             Hiệu ứng tuyết lở (tất cả dịch vụ phụ thuộc CSDL đều gặp sự cố)

🌊 Giải thích thuật ngữ

QPS (Queries Per Second): Số lượng truy vấn mỗi giây, chỉ số đo lường thông lượng hệ thống.

10 vạn QPS có nghĩa là mỗi giây có 100.000 yêu cầu, giống như 100.000 người cùng lúc xông vào cửa hàng.

4.2 Giải pháp cắt đỉnh lấp thung lũng: Hàng đợi tin nhắn làm "bể chứa"

Thiết kế kiến trúc:

┌───────────────────────────────────────────────────────────────────────────────────────┐
│                        Kiến trúc hệ thống flash sale                                    │
├───────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                         │
│  Tầng 1: Tầng Gateway (Giới hạn cứng)                                                    │
│  ┌───────────────────────────────────────────────────────────────────────────────────┐  │
│  │  - Token bucket rate limiting: 10 vạn/s → 1 vạn/s (loại bỏ 90% yêu cầu)            │  │
│  │  - CDN cache tài nguyên tĩnh (trang chi tiết sản phẩm)                               │  │
│  │  - Mã xác minh / Trang xếp hàng (tầng cắt đỉnh thứ nhất)                             │  │
│  └───────────────────────────────────────────────────────────────────────────────────┘  │
│                            │                                                             │
│                            ▼                                                             │
│  Tầng 2: Tầng dịch vụ (Giới hạn mềm)                                                    │
│  ┌───────────────────────────────────────────────────────────────────────────────────┐  │
│  │  - Nginx rate limiting: 1 vạn/s → 5000/s                                            │  │
│  │  - Redis trừ kho trước (thao tác nguyên tử):                                          │  │
│  │    * Sử dụng Lua script đảm bảo tính nguyên tử                                       │  │
│  │    * Hết kho trả về ngay "Đã bán hết"                                                 │  │
│  │  - Tạo token đơn hàng (chứng từ xếp hàng)                                             │  │
│  └───────────────────────────────────────────────────────────────────────────────────┘  │
│                            │                                                             │
│                            ▼                                                             │
│  Tầng 3: Tầng hàng đợi tin nhắn (Cắt đỉnh cốt lõi)                                       │
│  ┌───────────────────────────────────────────────────────────────────────────────────┐  │
│  │  Kafka/RocketMQ:                                                                   │  │
│  │  - Ghi theo lô: 5000/s → 1000/s (khả năng chịu đựng của CSDL)                       │  │
│  │  - Tin nhắn bền vững: Ghi xuống đĩa đảm bảo không mất tin nhắn                        │  │
│  │  - Tiêu thụ song song đa partition: Tăng thông lượng                                   │  │
│  │  - Quản lý offset tiêu thụ: Hỗ trợ khôi phục sự cố                                    │  │
│  │                                                                                     │  │
│  │  Giám sát chỉ số chính:                                                               │  │
│  │  - Tốc độ sản xuất (Produce Rate)                                                     │  │
│  │  - Tốc độ tiêu thụ (Consume Rate)                                                     │  │
│  │  - Tồn đọng tin nhắn (Lag)                                                            │  │
│  └───────────────────────────────────────────────────────────────────────────────────┘  │
│                            │                                                             │
│                            ▼                                                             │
│  Tầng 4: Tầng tiêu thụ (Xử lý bất đồng bộ)                                               │
│  ┌───────────────────────────────────────────────────────────────────────────────────┐  │
│  │  Consumer xử lý đơn hàng (đa instance):                                               │  │
│  │  - Kéo tin nhắn từ Kafka (1000/s, phù hợp khả năng CSDL)                              │  │
│  │  - Transaction CSDL: Tạo đơn hàng + Trừ kho                                           │  │
│  │  - Cập nhật trạng thái đơn hàng thành "Đã tạo"                                         │  │
│  │  - Gửi thông báo tạo đơn hàng thành công (Email/SMS/Push)                              │  │
│  │  - Xác nhận đã tiêu thụ tin nhắn (ACK)                                                 │  │
│  │                                                                                       │  │
│  │  Chiến lược mở rộng consumer:                                                          │  │
│  │  - Khi Lag > 10000, tự động tăng số lượng consumer instance                              │  │
│  │  - Khi Lag < 1000, giảm số lượng consumer instance (tiết kiệm chi phí)                  │  │
│  └───────────────────────────────────────────────────────────────────────────────────┘  │
│                                                                                         │
└───────────────────────────────────────────────────────────────────────────────────────┘
Peak Shaving: flatten traffic spikes
Simulate a burst and see how a queue protects backend systems
Processing capacity (Consumer)200 req/s
Maximum backend processing speed
Queue capacity (Queue Size)2000
Maximum requests the message queue can buffer
Current inbound traffic
100 req/s
Queue backlog
0 msgs
Actual processing rate
0 req/s
Rejected requests (rate limited)
0 req
Inbound traffic (user requests)Processed traffic (system load)Queue backlog
💡
Core principle: When inbound traffic (blue) exceeds processing capacity (green line), extra requests are stored in the message queue (orange area).
After the traffic peak passes, the system keeps processing the backlog at full speed until the queue is empty. This is peak shaving.

4.3 Nguyên lý toán học của cắt đỉnh lấp thung lũng

Hiệu quả làm mịn lưu lượng:

Lưu lượng gốc (đỉnh nhọn):                 Lưu lượng sau khi làm mịn:

10 vạn/s │    ╱╲                             1000/s │████████████████
         │   ╱  ╲                                   │
         │  ╱    ╲                                  │
  1000/s │╱        ╲                            0/s │
         └───────────────                          └────────────────
         0s   1s   2s                              0s              20s

Gốc: Đỉnh 10 vạn/s, kéo dài 1 giây
Làm mịn: Tốc độ không đổi 1000/s, kéo dài 100 giây

Công thức chính:

Độ dài hàng đợi = Tốc độ producer × Thời gian - Tốc độ consumer × Thời gian
                 = 100.000 × 1 - 1.000 × 1
                 = 99.000 tin nhắn (tồn đọng hàng đợi tại đỉnh)

Thời gian tiêu thụ hết tất cả tin nhắn = Độ dài hàng đợi / Tốc độ consumer
                                        = 99.000 / 1.000
                                        = 99 giây

5. Vấn đề cốt lõi thứ ba: Làm thế nào để đảm bảo tin nhắn không bị mất, không trùng lặp, có thứ tự?

5.1 Độ tin cậy của tin nhắn: Ba tuyến phòng thủ

Tin nhắn có thể bị mất ở ba khâu: khi producer gửi, khi Broker lưu trữ, khi consumer xử lý.

🛡️ Ba tuyến phòng thủ

Tuyến phòng thủ 1: Producer xác nhận (Producer ACK)

  • Khi gửi tin nhắn, chờ Broker xác nhận đã nhận được
  • Nếu không nhận được xác nhận, thử lại hoặc ghi log cục bộ

Tuyến phòng thủ 2: Broker bền vững hóa

  • Tin nhắn ghi vào đĩa, không chỉ ở bộ nhớ
  • Đồng bộ đa bản sao, đảm bảo không mất dữ liệu

Tuyến phòng thủ 3: Consumer xác nhận (Consumer ACK)

  • Sau khi xử lý xong tin nhắn, xác nhận thủ công (ACK)
  • Nếu xử lý thất bại, không xác nhận, Broker gửi lại
🛡️Message Reliability DemoThree defense lines keep messages from being lost
Line 1
Producer ACK
📤
Producer
Send message
📨
Message
ACK confirmation
📦
Broker
Receive and store
💡 If no ACK is received, the producer retries or records a local log.
Line 2
Broker persistence
Memory storage
Fast, but lost on restart
❌ High risk
vs
🔄 Multi-replica sync
Messages are synced to 3 nodes, so data is not lost even if 1 node fails.
Message persisted and safe
Line 3
Consumer ACK
1
Pull message
Fetch message from Broker
2
Process message
Run business logic
3
Manual ACK
Confirm after processing
Auto ACK
Efficient but can lose messages
⚠️ Not recommended
💡 If processing fails, no ACK is sent and the Broker redelivers.
🎯
All three defense lines are required:Producer ACK → Broker persistence → Consumer ACK

5.2 Làm thế nào để xử lý tin nhắn bị tiêu thụ trùng lặp?

Tin nhắn trùng lặp có thể xảy ra trong các tình huống sau:

  1. Producer thử lại: Producer gửi tin nhắn nhưng không nhận được ACK, thử lại gửi cùng một tin nhắn
  2. Consumer ACK timeout: Consumer xử lý xong nhưng ACK timeout, Broker gửi lại
  3. Network jitter: ACK của consumer không đến được Broker, Broker cho rằng chưa được tiêu thụ
  4. Consumer khởi động lại: Consumer khởi động lại và tiêu thụ lại cùng một lô tin nhắn

💡 Tính lũy đẳng (Idempotence)

Tính lũy đẳng: Cùng một thao tác thực hiện nhiều lần có hiệu quả giống như thực hiện một lần.

Tính lũy đẳng trong đời sống:

  • Lũy đẳng: Nhấn nút thang máy (nhấn 10 lần và nhấn 1 lần, thang máy đều đến)
  • Không lũy đẳng: Chuyển khoản (chuyển 10 tệ, thực hiện hai lần sẽ chuyển 20 tệ)

Giải pháp kỹ thuật: Tạo ID duy nhất cho mỗi tin nhắn, kiểm tra xem đã xử lý chưa trước khi xử lý.

🔄Idempotence DemoRepeated consumption does not create side effects
❌ Non-idempotent operation: bank transfer
Repeated consumption can debit multiple times
Disabled
Processing log
No logs yet. Click the button to start.
❌ No idempotence protection
Debit ¥100
Duplicate consumption causes multiple debits
✅ With idempotence protection
Debit ¥100
Duplicate requests are filtered, so debit happens once
🎯
Core idempotence principle: Generate a unique ID for each message and check whether it was processed before doing the operation.

6. Thực hành: Làm thế nào để chọn hàng đợi tin nhắn?

6.1 So sánh bốn hàng đợi tin nhắn chính

Đặc tínhRabbitMQKafkaRocketMQRedis Stream
Định vịHàng đợi truyền thốngLog stream phân tánHàng đợi cấp TMĐTHàng đợi nhẹ
Thông lượng~1 vạn/s~100 vạn/s~10 vạn/s~5 vạn/s
Độ trễMicro giâyMilli giâyMilli giâyMilli giây
Độ tin cậyCao (bền vững)Cao (đa bản sao)Cao (đồng bộ ghi đĩa)Trung bình (AOF)
Phát lại tin nhắnKhông hỗ trợHỗ trợHỗ trợHỗ trợ
Transaction messageHỗ trợ (yếu)Không hỗ trợHỗ trợ (mạnh)Không hỗ trợ
Tin nhắn trễHỗ trợKhông hỗ trợHỗ trợKhông hỗ trợ
Kịch bản phù hợpỨng dụng doanh nghiệp truyền thốngLog, dữ liệu lớnTMĐT, tài chínhỨng dụng quy mô nhỏ

💡 Gợi ý lựa chọn

Cây quyết định:

Chọn hàng đợi tin nhắn:

├─ Cần transaction message (giao dịch phân tán)?
│  ├─ Có → RocketMQ (ưu tiên) hoặc RabbitMQ
│  └─ Không → Tiếp tục

├─ Cần xử lý lượng lớn log/real-time stream?
│  ├─ Có → Kafka (ưu tiên)
│  └─ Không → Tiếp tục

├─ QPS > 1 vạn/s?
│  ├─ Có → RocketMQ hoặc Kafka
│  └─ Không → Tiếp tục

├─ Cần định tuyến phức tạp (như khớp headers)?
│  ├─ Có → RabbitMQ
│  └─ Không → Tiếp tục

├─ Đã có hạ tầng Redis?
│  ├─ Có → Redis Stream (bắt đầu nhanh)
│  └─ Không → RabbitMQ (chức năng đầy đủ, đường cong học tập vừa phải)

7. Tổng kết: Tâm pháp thiết kế hàng đợi tin nhắn

7.1 Ôn tập nguyên tắc cốt lõi

Nguyên tắcÝ nghĩaĐiểm thực hành
Giải ghépCác dịch vụ không phụ thuộc trực tiếpGiao tiếp qua hàng đợi tin nhắn, lỗi consumer không ảnh hưởng producer
Cắt đỉnhLàm mịn biến động lưu lượngHàng đợi tin nhắn làm bể chứa, consumer xử lý với tốc độ không đổi
Tin cậyTin nhắn không bị mấtProducer xác nhận + Broker bền vững + Consumer xác nhận
Lũy đẳngTiêu thụ trùng lặp không ảnh hưởngĐảm bảo tính lũy đẳng ở tầng nghiệp vụ (khóa duy nhất, state machine)
Có thứ tựĐảm bảo thứ tự tin nhắnCó thứ tự trong một partition hoặc sắp xếp ở phía consumer

7.2 Danh sách kiểm tra thiết kế

Trước khi giới thiệu hàng đợi tin nhắn, hãy tự hỏi những câu hỏi sau:

  • [ ] Có thực sự cần hàng đợi tin nhắn không? (Bất đồng bộ đơn giản có thể dùng thread pool)
  • [ ] Mất tin nhắn có thể chấp nhận được không? (Quyết định mức độ tin cậy)
  • [ ] Tin nhắn trùng lặp có ảnh hưởng đến nghiệp vụ không? (Quyết định đầu tư tính lũy đẳng)
  • [ ] Thứ tự tin nhắn có quan trọng không? (Quyết định chiến lược partition)
  • [ ] Khả năng xử lý của consumer như thế nào? (Quyết định kích thước hàng đợi và ngưỡng cảnh báo)
  • [ ] Làm thế nào để xử lý khi tiêu thụ thất bại? (Quyết định chiến lược thử lại và hàng đợi tin chết)

8. Bảng tra cứu thuật ngữ

Thuật ngữTên đầy đủGiải thích
MQMessage QueueHàng đợi tin nhắn. Middleware dùng cho giao tiếp bất đồng bộ, thực hiện giải ghép giữa producer và consumer.
Producer-Nhà sản xuất. Bên gửi tin nhắn.
Consumer-Người tiêu dùng. Bên nhận và xử lý tin nhắn.
Broker-Môi giới tin nhắn. Chương trình máy chủ lưu trữ và chuyển tiếp tin nhắn.
Topic-Chủ đề. Phân loại logic của tin nhắn (ví dụ: "orders").
Queue-Hàng đợi. Container vật lý lưu trữ tin nhắn.
Partition-Phân vùng. Khái niệm của Kafka, một Topic có thể chia thành nhiều Partition, tăng khả năng đồng thời.
ACKAcknowledgmentXác nhận. Sau khi consumer xử lý xong tin nhắn, xác nhận với Broker.
Pub/SubPublish/SubscribeXuất bản/Đăng ký. Một mô hình tin nhắn, một tin nhắn có thể được nhiều consumer nhận.
P2PPoint-to-PointĐiểm-đến-điểm. Một mô hình tin nhắn, một tin nhắn chỉ có thể được một consumer nhận.
DLQDead Letter QueueHàng đợi tin chết. Lưu trữ những tin nhắn không thể tiêu thụ.
Idempotence-Tính lũy đẳng. Nhiều lần thực hiện cho cùng một kết quả.
Throughput-Thông lượng. Số lượng tin nhắn được xử lý trong một đơn vị thời gian.
Latency-Độ trễ. Khoảng thời gian từ khi tin nhắn được gửi đến khi được nhận.
Persistence-Tính bền vững. Tin nhắn được ghi vào đĩa, không chỉ tồn tại trong bộ nhớ.
Replication-Bản sao. Để đảm bảo tính sẵn sàng cao, tin nhắn được sao chép sang nhiều node.
Transaction Message-Transaction message. Đảm bảo tính nhất quán giữa giao dịch cục bộ và việc gửi tin nhắn.
Backpressure-Áp lực ngược. Khi consumer không xử lý kịp, thông báo cho producer giảm tốc độ.
Offset-Offset. Vị trí tiêu thụ của consumer trong partition.
Rebalance-Tái cân bằng. Khi thành viên consumer group thay đổi, phân phối lại partition.