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

발행/구독과 토픽

MQTT에서는 메시지를 보내는 쪽과 받는 쪽이 서로 직접 연결하지 않습니다. 모든 참여자는 브로커(broker)에 연결하는 클라이언트(client)입니다. 이 문서는 MQTT 5.0 §4.7(토픽 이름과 토픽 필터)과 §4.8(구독)을 바탕으로 설명합니다.

발행자(publisher)는 메시지에 토픽(topic)을 붙여 브로커로 보냅니다. 구독자(subscriber)는 받고 싶은 토픽을 토픽 필터(topic filter)로 브로커에 등록합니다. 브로커는 받은 메시지의 토픽과 각 구독의 필터를 비교해 일치하는 구독자에게 메시지를 전달합니다.

Publisher Broker Subscribers
┌──────────────┐ PUBLISH ┌──────────────────┐ PUBLISH ┌─────────────────────────┐
│ line 1 cell 2│ ───────▶ │ match topic │ ───────▶ │ factory/+/temperature │
└──────────────┘ │ against filters │ └─────────────────────────┘
topic: │ │ PUBLISH ┌─────────────────────────┐
factory/line1/temperature│ │ ───────▶ │ factory/# │
└──────────────────┘ └─────────────────────────┘

그림의 Publisher는 발행자, Broker는 브로커, Subscribers는 구독자입니다.

이 구조에는 다음 특징이 있습니다.

  • 공간 분리: 발행자와 구독자는 서로의 주소를 모릅니다. 둘 다 브로커 주소만 알면 됩니다.
  • 수의 분리: 한 메시지가 구독자 0개에서 여러 개까지 전달됩니다. 발행자는 구독자 수와 관계없이 한 번만 보냅니다.
  • 시간 분리: 세션과 보존 메시지를 쓰면 구독자가 연결되어 있지 않은 동안의 메시지도 받을 수 있습니다. 자세한 내용은 세션, Keep Alive, Will과 QoS와 보존 메시지에서 설명합니다.

클라이언트는 브로커와 TCP 연결 하나를 맺고 CONNECT 패킷으로 세션을 시작합니다. 같은 연결로 발행과 구독을 모두 할 수 있습니다.

  • 클라이언트 식별자(Client Identifier): 브로커 안에서 세션을 구분하는 문자열입니다(§3.1.3.1). 같은 식별자로 다른 클라이언트가 연결하면 브로커는 기존 연결을 끊습니다(§3.1.4).
  • 포트: IANA가 MQTT에 등록한 TCP 포트는 1883(평문)과 8883(TLS)입니다(§4.2).
  • 브로커의 역할: 연결과 세션 관리, 필터 비교, QoS에 따른 전달 보장, 보존 메시지 저장, 인증과 권한 확인을 맡습니다.

토픽 이름(topic name)은 PUBLISH 패킷에 들어가는 UTF-8 문자열입니다.

  • /로 단계(level)를 나눕니다. 예: factory/line1/temperature
  • 대소문자를 구분합니다. Factory와 factory는 다른 토픽입니다.
  • 빈 단계도 하나의 단계입니다. /factory는 빈 단계와 factory 두 단계로 이루어집니다.
  • 와일드카드 문자 +, #과 널 문자(U+0000)를 쓸 수 없습니다.
  • 최대 길이는 65,535바이트입니다.
  • $로 시작하는 토픽은 브로커용입니다(§4.7.2). Mosquitto는 $SYS/ 아래에 브로커 상태를 발행합니다.

토픽 필터는 SUBSCRIBE 패킷에 들어갑니다. 필터에는 와일드카드(wildcard)를 쓸 수 있습니다(§4.7.1).

와일드카드 뜻 규칙
+ 한 단계 단계 전체를 차지해야 합니다. line+는 잘못된 필터입니다.
# 0개 이상의 단계 필터의 마지막 단계여야 합니다. factory/#은 factory 자신과도 일치합니다.
필터 factory/line1/temperature factory/line1/cell2/temperature factory
factory/+/temperature 일치 불일치 불일치
factory/# 일치 일치 일치
factory/+/+/temperature 불일치 일치 불일치
+/line1/# 일치 일치 불일치

#과 +로 시작하는 필터는 $로 시작하는 토픽과 일치하지 않습니다. $SYS 토픽을 보려면 $SYS/#처럼 명시적으로 구독합니다.

MQTT 5.0의 공유 구독(shared subscription)은 $share/<그룹 이름>/<필터> 형식입니다(§4.8.2). 같은 그룹의 구독자들은 메시지를 나누어 받습니다. 여러 소비자가 부하를 나누어 처리할 때 씁니다.

토픽은 한번 정하면 발행자, 구독자, 권한 설정이 모두 의존합니다. 다음 지침을 권장합니다.

  1. 일반에서 구체로 계층을 만듭니다. 예: <사이트>/<라인>/<셀>/<데이터 종류>. 와일드카드로 원하는 범위를 쉽게 고를 수 있습니다.
  2. 맨 앞에 /를 붙이지 않습니다. 의미 없는 빈 단계가 생깁니다.
  3. ASCII 문자, 숫자, -, _만 씁니다. 공백과 비ASCII 문자는 도구마다 다르게 다룹니다.
  4. 값을 토픽에 넣지 않습니다. 시각이나 측정값은 페이로드에 넣습니다. 토픽이 계속 늘어나면 브로커 자원과 보존 메시지가 쌓입니다.
  5. 데이터, 명령, 상태를 다른 가지로 나눕니다. 권한 규칙(ACL)을 가지 단위로 줄 수 있습니다.
  6. 식별자는 바뀌지 않는 값으로 정합니다. 장비 이름보다 자산 번호처럼 고정된 값이 좋습니다.

OPC 10000-14 §7.3.4는 PubSub 메시지의 토픽 구조로 다음 관례를 정합니다.

opcua/<인코딩>/<메시지 종류>/<PublisherId>/<WriterGroup 이름>[/<DataSetWriter 이름>]

예를 들어 PublisherId 100의 line1 WriterGroup이 UADP 데이터를 보내면 토픽은 opcua/uadp/data/100/line1입니다. PDComm 튜토리얼은 이 관례를 따릅니다.