MQTT QoS 0·1·2 선택 기준
손실을 허용하면 0, 누락을 방지하려면 1, 중복도 방지하려면 2를 사용하며, 실제 전달은 구독 QoS와 비교해 낮은 값을 따른다.
세 단계의 차이
QoS(전달 보장 수준)는 메시지 하나에 대해 송신 측과 수신 측이 어느 수준까지 확인할지를 결정한다. 숫자가 클수록 교환하는 패킷이 증가한다.
| QoS | 보장 | 확인 패킷 |
|---|---|---|
| 0 | 최대 한 번. 손실될 수 있음 | 없음 |
| 1 | 최소 한 번. 중복될 수 있음 | PUBACK |
| 2 | 정확히 한 번 | PUBREC, PUBREL, PUBCOMP |
QoS 1의 중복 가능성
QoS 1에서 송신 측은 PUBACK을 수신할 때까지 그 메시지를 미확인 상태로 유지한다. PUBACK을 수신하기 전에 연결이 단절되면, 세션을 재개하여 재연결했을 때 같은 PUBLISH를 한 번 더 전송한다. 수신 측이 이미 처리한 뒤였다면 같은 내용이 두 번 수신된다.
따라서 QoS 1로 수신하는 측은 두 번 수신해도 결과가 같도록 구현한다. 발행 측이 페이로드에 순번을 포함하고, 수신 측은 이미 처리한 번호를 무시한다.
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 중 낮은 값을 사용한다.
# 구독은 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 0이면 메시지가 손실될 수 있다.
선택 기준
0: 주기적으로 계속 발행되는 측정값. 하나가 손실되어도 다음 값이 곧 도착한다.1: 알람이나 명령처럼 누락되면 안 되는 메시지. 중복은 수신 측에서 제거한다.2: 두 번 처리되면 안 되지만 수신 측에서 중복을 제거하기 어려운 경우. 메시지 하나에 패킷 네 개가 교환된다.