콘텐츠로 이동
무료 평가 시작

QoS와 보존 메시지

QoS(Quality of Service)는 한 메시지를 얼마나 확실하게 전달할지 정하는 수준입니다. MQTT는 QoS 0, 1, 2 세 단계를 정의합니다(MQTT 5.0 §4.3, MQTT 3.1.1 §4.3).

QoS는 구간마다 따로 적용됩니다

섹션 제목: “QoS는 구간마다 따로 적용됩니다”

QoS는 종단 간 보장이 아닙니다. 두 구간에 따로 적용됩니다.

  1. 발행자 → 브로커: 발행자가 PUBLISH 패킷에 넣은 QoS로 전달합니다.
  2. 브로커 → 구독자: 메시지 QoS와 구독에 허용된 QoS(granted QoS) 중 낮은 값으로 전달합니다(§3.8.4).

예를 들어 QoS 1로 발행한 메시지라도 QoS 0으로 구독한 클라이언트에게는 QoS 0으로 전달됩니다. mosquitto_sub는 -q를 주지 않으면 QoS 0으로 구독합니다.

PUBLISH 패킷 하나만 보냅니다. 응답이 없고 재전송도 없습니다. 연결이 끊기면 메시지가 사라질 수 있습니다.

Sender Receiver
│ ── PUBLISH (QoS 0) ──────▶ │ deliver

송신자는 패킷 식별자(Packet Identifier)를 붙여 PUBLISH를 보내고 PUBACK을 기다립니다. PUBACK을 받기 전까지 그 메시지를 미확인 상태로 보관합니다.

Sender Receiver
│ ── PUBLISH (QoS 1, id 1) ─▶ │ deliver
│ ◀─────────── PUBACK (id 1) ─ │
  • 같은 세션으로 다시 연결하면 미확인 메시지를 DUP 플래그와 함께 다시 보냅니다(§4.4). MQTT 5.0에서는 다시 연결할 때만 재전송합니다.
  • 그래서 수신자는 같은 메시지를 두 번 이상 받을 수 있습니다. 응용 프로그램이 중복을 걸러야 합니다.

네 개의 패킷으로 중복 없는 전달을 보장합니다.

Sender Receiver
│ ── PUBLISH (QoS 2, id 1) ─▶ │ store id 1
│ ◀─────────── PUBREC (id 1) ─ │
│ ── PUBREL (id 1) ─────────▶ │ deliver once, forget id 1
│ ◀────────── PUBCOMP (id 1) ─ │

수신자는 PUBREL을 받을 때까지 패킷 식별자를 기억해 같은 메시지를 두 번 전달하지 않습니다. 대신 왕복이 두 번 필요하므로 지연과 브로커 부하가 큽니다.

mosquitto_pub -d로 실제 흐름을 볼 수 있습니다. 다음은 QoS 2로 한 번 발행한 출력입니다.

Client auto-DB1B2CB5-… sending PUBLISH (d0, q2, r0, m1, 'factory/line1/temperature', ... (4 bytes))
Client auto-DB1B2CB5-… received PUBREC (Mid: 1)
Client auto-DB1B2CB5-… sending PUBREL (m1)
Client auto-DB1B2CB5-… received PUBCOMP (Mid: 1, RC:0)
QoS 맞는 데이터 주의할 점
0 자주 갱신되어 하나쯤 잃어도 되는 측정값 연결이 끊기면 유실
1 대부분의 설비 데이터와 이벤트 중복 수신 가능. 순번이나 식별자로 중복 제거
2 중복되면 안 되는 명령, 계수 지연과 부하가 가장 큼

브로커는 한 클라이언트가 같은 토픽에 같은 QoS로 보낸 메시지를 받은 순서대로 구독자에게 보냅니다(§4.6). 서로 다른 발행자의 메시지 사이 순서나 서로 다른 토픽 사이 순서는 정해져 있지 않습니다.

PUBLISH의 RETAIN 플래그가 1이면 브로커는 그 메시지를 토픽의 보존 메시지(retained message)로 저장합니다(§3.3.1.3).

  • 토픽마다 마지막 보존 메시지 하나만 남습니다.
  • 새 구독이 생기면 브로커가 일치하는 보존 메시지를 바로 보냅니다. 이때 RETAIN 플래그는 1입니다.
  • 페이로드가 비어 있는 보존 메시지를 발행하면 그 토픽의 보존 메시지가 지워집니다.
  • 보존 메시지는 이력이 아닙니다. 마지막 값 하나만 알려 줍니다.

MQTT 5.0은 구독 옵션으로 보존 메시지 처리를 조절합니다(§3.8.3.1).

옵션 값 동작
Retain Handling 0 구독할 때마다 보존 메시지를 보냅니다(기본값).
1 새로 생긴 구독에만 보냅니다.
2 보내지 않습니다.
Retain As Published 0 일반 전달에서는 RETAIN을 0으로 바꿉니다(기본값).
1 발행자가 보낸 RETAIN 값을 그대로 둡니다.

브로커가 보존 메시지를 지원하지 않으면 CONNACK의 Retain Available 속성이 0입니다(§3.2.2.3.5).

  • 시뮬레이터는 데이터를 QoS 1, RETAIN 0으로 발행하고 QoS 1로 구독합니다.
  • 보존 메시지를 쓰지 않으므로 시뮬레이터 구독자는 구독하기 전에 발행된 데이터를 받지 않습니다.
  • QoS 1이므로 같은 DataSetMessage를 두 번 받을 수 있습니다. 받은 메시지의 Sequence(순번)로 중복을 확인합니다.