TL;DR
- Bản chất: MQTT QoS (Quality of Service) là một hợp đồng thỏa thuận mức độ tin cậy trong việc chuyển phát gói tin giữa Client và Broker trên một kênh truyền vật lý không ổn định.
- Mục đích: Cân bằng có chủ đích giữa thông lượng mạng (Throughput), độ trễ (Latency) và tính toàn vẹn dữ liệu (Data Integrity) nhằm hóa giải giới hạn phân tán của The Two Generals’ Problem.
- Điểm mấu chốt: QoS 0 là Best-Effort không lưu trạng thái (Zero ACK); QoS 1 đảm bảo không mất tin bằng cơ chế ACK-Retransmission nhưng có thể gây Duplicate tin (bắt buộc Backend phải Idempotent); QoS 2 sử dụng quy trình bắt tay 4 bước (4-Way Handshake / Two-Phase Commit thu nhỏ) triệt tiêu hoàn toàn mất mát và trùng lặp với cái giá là Latency cao nhất.
Core Mechanics
1. The Two Generals’ Problem & Đường biên Đánh đổi Tin cậy
Trong lý thuyết mạng máy tính phân tán, The Two Generals’ Problem chứng minh rằng: Trên một môi trường mạng có độ trễ biến thiên và nguy cơ rớt gói tin (Packet Loss), hai nút tính toán không bao giờ có thể đạt được sự đồng thuận tuyệt đối về trạng thái chỉ bằng một số lượng hữu hạn các thông điệp xác nhận (Acknowledge).
Mọi giao thức chuyển phát đều phải chấp nhận đánh đổi:
- Liveness: Đảm bảo gói tin luôn đến được đích.
- Safety: Đảm bảo gói tin không bao giờ bị thực thi thừa hoặc trùng lặp.
- Overhead: Giảm thiểu số vòng lặp mạng (Round-Trip Time - RTT) và mức tiêu thụ RAM lưu trữ trạng thái đệm.
MQTT QoS giải quyết bài toán này bằng cách phân tầng thành 3 cấp độ cam kết rõ rệt.
2. Giải phẫu Ba Cấp độ QoS State Machine
Mọi gói tin có QoS bắt buộc phải mang một trường nhị phân 16-bit gọi là Packet Identifier (Packet ID) có giá trị từ 1 đến 65.535 để định danh phiên trao đổi.
QoS 0: [PUBLISH] ───────────────────────────────────────────────► (Stateless)
QoS 1: [PUBLISH (PacketID=N)] ──────────────────────────────────►
◄─────────────────────────── [PUBACK (PacketID=N)] ─────── (Retransmit nếu Timeout)
QoS 2: [PUBLISH (PacketID=N)] ──────────────────────────────────► (Phase 1: Lock Message)
◄─────────────────────────── [PUBREC (PacketID=N)] ───────
[PUBREL (PacketID=N)] ───────────────────────────────────► (Phase 2: Commit & Release)
◄─────────────────────────── [PUBCOMP (PacketID=N)] ──────
A. QoS 0: At Most Once (Best-Effort / Fire-and-Forget)
- Cơ chế: Bên gửi đẩy gói tin
PUBLISHtrực tiếp vào Socket Buffer của OS Kernel và giải phóng ngay lập tức khỏi bộ nhớ ứng dụng. - Trạng thái bộ nhớ: Hoàn toàn không lưu trạng thái (Stateless). Không sử dụng
Packet ID. Không có đồng hồ đếm ngược (Retry Timer). - Rủi ro: Nếu kết nối mạng bị ngắt đúng thời điểm gói tin đang truyền, gói tin bị hủy hoàn toàn mà cả bên gửi lẫn bên nhận đều không hề hay biết.
B. QoS 1: At Least Once (ACK-Retransmission & Nguy cơ Duplicate)
- Cơ chế:
- Bên gửi gán
Packet ID = N, ghi gói tin vào Retransmission Queue (Inflight Table) trong RAM, sau đó truyền góiPUBLISH. - Bên nhận đón nhận gói tin, đẩy lên tầng ứng dụng xử lý, đồng thời gửi trả gói
PUBACK(N). - Bên gửi chỉ xóa gói tin khỏi Retransmission Queue khi nhận được đúng gói
PUBACK(N)tương ứng. - Nếu Retry Timer hết hạn mà chưa thấy
PUBACK, bên gửi bật cờDUP = 1và gửi lại nguyên vẹn gói tin vớiPacket ID = N.
- Bên gửi gán
- Cơ chế phát sinh trùng lặp (Duplicate Message Trap):
- Nếu bên nhận đã nhận thành công
PUBLISH(N)và đẩy vào database, nhưng gói phản hồiPUBACK(N)trên đường về bị đứt mạng hoặc quá hạn Timeout → Bên gửi kết luận sai rằng bên nhận chưa có dữ liệu → Bên gửi thực hiện Retransmit → Bên nhận bị nhận gói tin đó lần thứ hai.
- Nếu bên nhận đã nhận thành công
C. QoS 2: Exactly Once (Two-Phase Commit 4-Way Handshake)
QoS 2 triệt tiêu hoàn toàn khả năng mất tin và trùng lặp thông qua quy trình hai pha (Two-Phase Commit) với 4 bước bắt tay:
- Pha 1: Vận chuyển và Khóa dữ liệu (Transfer & Deduplication Lock):
- Bên gửi truyền
PUBLISH(N). Trạng thái chuyển thànhAWAIT_PUBREC. - Bên nhận nhận dữ liệu, ghi nhận
Packet ID = Nvào Deduplication State Cache để khóa lại. Bên nhận chưa giải phóng bản tin cho tầng ứng dụng tiêu thụ cuối cùng. Bên nhận gửi phản hồiPUBREC(N)(Publish Received). - Khi bên gửi nhận được
PUBREC(N), nó chắc chắn bên nhận đã cất giữ an toàn bản tin. Lúc này bên gửi xóa payload thực tế khỏi RAM để giải phóng bộ nhớ, chỉ giữ lại mã số định danhN.
- Bên gửi truyền
- Pha 2: Giải phóng và Hoàn tất (Commit & Complete):
- Bên gửi truyền tiếp gói tin điều khiển
PUBREL(N)(Publish Release). Trạng thái chuyển thànhAWAIT_PUBCOMP. - Bên nhận nhận được
PUBREL(N)→ Đây là lệnh kích hoạt cho phép bên nhận chuyển tiếp payload lên tầng ứng dụng, đồng thời xóaPacket ID = Nkhỏi Deduplication State Cache → Bên nhận phản hồiPUBCOMP(N)(Publish Complete). - Bên gửi nhận
PUBCOMP(N)→ Thu hồi hoàn toànPacket ID = Nvề bể ID rảnh rỗi (Free ID Pool).
- Bên gửi truyền tiếp gói tin điều khiển
3. Inflight Window, Packet ID Lifecycle & Backpressure
- Inflight Window (Hạn ngạch gói tin đang bay):
- Vì
Packet IDchỉ có 16-bit (tối đa 65.535 ID khả dụng) và bộ nhớ RAM của thiết bị là hữu hạn, hệ thống không thể gửi đi vô hạn các gói tin chưa có xác nhận. - Chuẩn MQTT quy định một hạn mức cửa sổ (Inflight Window, thường cấu hình từ 10 đến 100). Khi số lượng gói tin QoS 1 và QoS 2 chưa nhận được
PUBACKhoặcPUBCOMPchạm ngưỡng này, bên gửi phải tạm dừng gửi gói tin mới.
- Vì
- Hiện tượng Backpressure (Áp lực ngược):
- Khi mạng bị nghẽn (Latency tăng cao, tỷ lệ rớt gói tin lớn), hàng đợi Inflight Window bị lấp đầy.
- Tầng gửi (Publisher) bị nghẽn bộ đệm, buộc phải áp dụng chính sách chặn (Block Publisher Thread), đệm vào đĩa cứng (Disk Spooling), hoặc chủ động ngắt kết nối để bảo toàn bộ nhớ RAM.
4. Yêu cầu Bắt buộc tại Tầng Ứng dụng: Idempotency Pattern
Một ngộ nhận tai hại trong kiến trúc phần mềm là cho rằng: “Chỉ cần chọn QoS 1 ở tầng mạng là dữ liệu của hệ thống sẽ an toàn tuyệt đối”.
Thực tế, QoS 1 chỉ bảo vệ gói tin ở tầng truyền thông (Transport Level). Để xử lý triệt để nguy cơ trùng lặp bản tin do Retransmission gây ra, tầng ứng dụng Backend bắt buộc phải hiện thực hóa Idempotent Consumer Pattern:
- Mỗi bản tin nghiệp vụ phải chứa một mã định danh duy nhất sinh ra từ nguồn (ví dụ:
UUIDhoặctimestamp + device_id). - Backend (Go Service) khi nhận bản tin từ MQTT Broker phải kiểm tra trạng thái khóa này (thông qua Redis
SET NXhoặc PostgreSQL Unique Constraint) trước khi thực hiện ghi nhận dữ liệu hoặc kích hoạt cảnh báo.
Comparative Decision Matrix
Áp dụng trong Hệ thống Giám sát & Điều khiển Máy phát điện Công nghiệp (Industrial Generator Management):
| Cấp độ QoS | Độ tin cậy | Chi phí RTT mạng | Tác động bộ nhớ RAM | Kịch bản ứng dụng chuẩn xác |
|---|---|---|---|---|
| QoS 0 | Có thể mất tin, không bao giờ trùng | (Không chờ ACK) | Tối thiểu (Không lưu Inflight) | Đo đạc Telemetry định kỳ: Điện áp, nhiệt độ, mức dầu gửi mỗi 1 giây/lần. Bản tin sau tự động bù đắp bản tin trước. |
| QoS 1 | Không mất tin, có thể nhận trùng | RTT (PUBACK) | Trung bình (Lưu Inflight Queue) | Cảnh báo bất thường (Alerts): Máy quá nhiệt , mất điện lưới, mức dầu cạn . Thà nhận 2 lần cảnh báo còn hơn bị thất lạc. |
| QoS 2 | Không mất tin, không trùng lặp | RTT (4-Way Handshake) | Cao (Lưu Inflight + Deduplication Cache) | Lệnh điều khiển nhạy cảm (Critical Control): Lệnh tắt máy khẩn cấp từ xa, lệnh kích hoạt nổ máy chạy tải bệnh viện, lệnh thanh toán nạp nhiên liệu. |
Related Notes
- MQTT_Broker_Architecture: Tổng quan kiến trúc định tuyến Trie và cơ chế Decoupling của MQTT Broker.
- Process_vs_Thread_and_Context_Switching: Cấu trúc luồng và chi phí chuyển đổi ngữ cảnh trong xử lý Concurrency.
- 000_Concepts_MOC: Danh mục lý thuyết nền tảng Khoa học Máy tính.