글 / MQTT 메시징

MQTT QoS 0·1·2 선택 기준

손실을 허용하면 0, 누락을 방지하려면 1, 중복도 방지하려면 2를 사용하며, 실제 전달은 구독 QoS와 비교해 낮은 값을 따른다.

작성일 · 읽는 시간 2분 · MQTT 5.0 기준

세 단계의 차이

QoS(전달 보장 수준)는 메시지 하나에 대해 송신 측과 수신 측이 어느 수준까지 확인할지를 결정한다. 숫자가 클수록 교환하는 패킷이 증가한다.

QoS 보장 확인 패킷
0 최대 한 번. 손실될 수 있음 없음
1 최소 한 번. 중복될 수 있음 PUBACK
2 정확히 한 번 PUBREC, PUBREL, PUBCOMP

QoS 0, 1, 2에서 송신 측과 수신 측이 교환하는 패킷 순서

QoS 1의 중복 가능성

QoS 1에서 송신 측은 PUBACK을 수신할 때까지 그 메시지를 미확인 상태로 유지한다. PUBACK을 수신하기 전에 연결이 단절되면, 세션을 재개하여 재연결했을 때 같은 PUBLISH를 한 번 더 전송한다. 수신 측이 이미 처리한 뒤였다면 같은 내용이 두 번 수신된다.

PUBACK 수신 전 단절로 같은 PUBLISH가 두 번 수신되는 순서

따라서 QoS 1로 수신하는 측은 두 번 수신해도 결과가 같도록 구현한다. 발행 측이 페이로드에 순번을 포함하고, 수신 측은 이미 처리한 번호를 무시한다.

pythonhandler.py
last_seq: dict[str, int] = {}


def handle(topic: str, seq: int, value: float) -> bool:
    # 이미 처리한 번호면 버린다
    if seq <= last_seq.get(topic, -1):
        return False
    last_seq[topic] = seq
    print(topic, value)
    return True

발행 QoS와 구독 QoS

QoS는 발행할 때와 구독할 때 각각 지정한다. 브로커는 구독자에게 전송할 때 발행 QoS와 구독에서 허용한 QoS 중 낮은 값을 사용한다.

bash
# 구독은 QoS 1, 발행은 QoS 2 → 구독자에게는 QoS 1로 간다
mosquitto_sub -t plant/line1/alarm -q 1
mosquitto_pub -t plant/line1/alarm -m '{"seq": 7}' -q 2

발행 QoS 2와 구독 QoS 1에서 브로커가 전달하는 QoS

QoS 2로 발행해도 구독이 QoS 1이면 중복이 발생할 수 있고, 구독이 QoS 0이면 메시지가 손실될 수 있다.

선택 기준

  • 0: 주기적으로 계속 발행되는 측정값. 하나가 손실되어도 다음 값이 곧 도착한다.
  • 1: 알람이나 명령처럼 누락되면 안 되는 메시지. 중복은 수신 측에서 제거한다.
  • 2: 두 번 처리되면 안 되지만 수신 측에서 중복을 제거하기 어려운 경우. 메시지 하나에 패킷 네 개가 교환된다.