Hiểu đúng về mối quan hệ QoS giữa Publisher và Subscriber trong giao thức MQTT

Giao thức MQTT là một trong những giao thức phổ biến nhất hiện nay trong các ứng dụng và nền tảng IoT qua môi trường Internet. Mô hình của giao thức này giúp đáp ứng những yêu cầu quan trọng và đặc biệt phù hợp trong việc truyền nhận các gói tin IoT giữa các node (thiết bị, cảm biến,..) mà giao thức HTTP không thể có được, điển hình như:

  • MQTT là giao thức 2 chiều, các node không chỉ truyền mà còn có thể dễ dàng đăng ký nhận tin một cách thụ động theo cơ chế publish-subscribe (với HTTP thì node không thể nhận tin thụ động được mà luôn luôn phải khởi tạo kết nối trước với server)
  • MQTT hỗ trợ cơ chế 1-n, nghĩa là một node có khả năng gửi tin đến rất nhiều node khác chỉ trong một lần gửi hoặc ngược lại (HTTP chỉ hỗ trợ 1-1 giữa client và server theo cơ chế request-response)
  • MQTT là một “lightweight protocol”, với ưu điểm gói tin nhẹ, không chứa nhiều dữ liệu dư thừa nên có thể truyền nhận dữ liệu một cách mượt mà trong điều kiện bị giới hạn về băng thông đường truyền.
  • MQTT hỗ trợ cấu hình QoS còn HTTP thì không.
  • … và nhiều ưu điểm khác nữa

Trong các ưu điểm kể trên của giao thức MQTT, việc hỗ trợ QoS thường bị hiểu nhầm về mặt ý nghĩa dẫn đến bị bỏ qua hoặc sử dụng không đúng. Bài viết này nhằm mục đích giải thích QoS theo cách đơn giản nhất để người đọc không bị nhầm lẫn về thông số này, từ đó có thể hiểu và sử dụng được trong các trường hợp khác nhau.

QoS (viết tắt của Quality of Service) là thông số thể hiện mức độ đảm bảo việc truyền nhận các gói tin giữa bên gửi và bên nhận. Mức độ đảm bảo ở đây liên quan đến việc giải quyết hai vấn đề cơ bản khi truyền tin là: mất gói và lặp gói. Tùy vào nhu cầu của người phát triển và điều kiện sẵn có của hệ thống, mức QoS được lựa chọn có thể khác nhau. QoS càng cao thì mức độ đảm bảo khi truyền nhân các gói tin càng cao, nhưng đổi lại độ trễ khi truyền tin sẽ cao hơn.

QoS là một trường có giá trị 2 bit (bit 5 và bit 6) nằm bên trong trường fixed header của cả 2 gói publish và subscribe. Có 3 giá trị QoS có thể lựa chọn đối với cả 2 phía pub/sub là: 0, 1, 2.

MQTT publish packet fixed header

MQTT subscribe packet fixed header

Trước khi giải thích rõ mối quan hệ khi cấu hình QoS giữa publisher và subscriber mà bài viết này mình muốn nói đến, ta cần tìm hiểu trước về định nghĩa của các mức QoS:

  • QoS = 0 (at-most-once): mỗi gói tin được gửi đến đích tối đa một lần => như vậy gói tin truyền thành công tối thiểu sẽ là “0 lần” => nghĩa là đối với trường hợp này có thể xảy ra trường hợp mất gói tin và chỉ phù hợp với những ứng dụng gửi nhiều gói tin, trong đó có thể chấp nhận được khi mất đi một vài gói.
  • QoS = 1 (at-least-one): mỗi gói tin được gửi đến đích tối thiểu là một lần => như vậy một gói tin truyền đến đích tối đa có thể là “vô số lần” => nghĩa là có thể xảy ra trường hợp bị trùng lặp gói tin, về cơ bản QoS = 1 sẽ giải quyết được vấn đề mất gói của QoS = 0 nhưng phải chấp nhận việc có thể bị lặp gói.
  • QoS = 2 (Exactly-once): mỗi gói tin sẽ được gửi đến đích duy nhất là một lần => không bị mất gói cũng như bị lặp gói. Đây là mức độ đảm bảo nhất, dùng trong các hệ thống cần đảm bảo nghiêm ngặt về mức độ đảm bảo của mỗi gói tin khi truyền nhận.

Yếu tố gây nhầm lẫn: Việc truyền nhận dữ liệu trong giao thức MQTT được thực hiện giữa publisher và subscriber nên ngữ nghĩa về “đảm bảo gói tin” trong bài viết này được xét đến khi truyền một gói tin từ publisher đến subscriber. Nhưng có một yếu tố quan trọng là 2 đối tượng client này không hề giao tiếp trực tiếp với nhau mà lại thông qua một broker trung tâm. Vì thế QoS được cấu hình bởi client chính xác phải là QoS của publisher đối với broker và QoS của subscriber đối với broker chứ không phải giữa 2 client với nhau, mỗi client đều có quyền lựa chọn QoS của mình để giao tiếp với broker, nhưng mức độ đảm bảo của gói tin để truyền thành công từ publisher->subscriber thì chỉ có 1 mà thôi.
Xét một ví dụ cụ thể: khi một publisher A gửi một gói tin có QoS gọi là QA đến một subscriber có QoS là QB , vậy thì sự khác nhau giữa 2 giá trị QA và QB sẽ dẫn đến mức độ đảm bảo gói tin khi truyền từ A->B sẽ có QoS là bao nhiêu?

Trường hợp 1: QA>QB (vd: QA=1, QB=0): kết quả gói có QoS =QB = 0

Trường hợp 2: QA<QB (vd: QA=1, QB=2): kết quả gói tin có QoS = QA = 1

Giải thích:

Trong trường hợp 1, A khi gửi tin đã cấu hình QoS = 1 với mong muốn gói tin của mình khi gửi đến B không bị mất, tuy nhiên điều này chỉ đúng trong quá trình gửi từ A đến Broker, trong khi đó B chỉ sử dụng QoS = 0 (có thể để ưu tiên tốc độ truyền nhận) nên Broker sẽ chuyển tiếp gói tin đến B với QoS=0, nghĩa là gói tin đó hoàn toàn có thể bị mất trong quá trình chuyển tiếp này

=> Gói tin gửi từ A->B có QoS=0

Trong trường hợp 2, B khi đăng ký nhận tin đã cấu hình QoS=2 với mong muốn là tất cả gói tin khi truyền từ A đến topic chung đều có thể nhận được một lần duy nhất (không mất , không lặp). Tuy nhiên nếu xét cả quá trình từ A->B, vì A truyền  gói tin đến broker với QoS=1 thì có thể bị lỗi lặp gói tin, nên chắc chắn gói tin lặp này cũng sẽ được chuyển tiếp đến B đẫn đến B cũng sẽ bị lặp gói tin dù QoS =2.

=> Gói tin gửi từ A->B có QoS=1

Kết luận: QoS có tính chất Downgrade, nghĩa là QoS tổng hợp sẽ có giá trị bằng với QoS nhỏ nhất được cấu hình giữa A và B.

QoS (A->B) = min (QA,QB)

Như vậy ở bài viết này mình đã chia sẻ với các bạn cách hiểu về QoS trong giao thức MQTT khi truyền nhận dữ liệu từ publisher->subscriber, và cho thấy tính chất Downgrade của thông số này. Tuy nhiên có một lưu ý nhỏ rằng tính chất này sẽ khả dụng khi chúng ta xét cả một chặng gửi tin từ publisher dến subscriber (không tính đến broker), còn QoS bản chất vẫn là giữa client với broker nên trong một số trường hợp thiết kế hệ thống, mỗi client có thể chỉ quan tâm đến QoS của bản thân đối với broker mà thôi. Hy vọng với bài viết này sẽ giúp cho các bạn hiểu thêm về giá trị QoS trong giao thức MQTT và có thể ứng dụng sau này.

Nhóm TAPIT IoTs