발행/구독과 토픽
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).
같은 그룹의 구독자들은 메시지를 나누어 받습니다.
여러 소비자가 부하를 나누어 처리할 때 씁니다.
토픽 설계
섹션 제목: “토픽 설계”토픽은 한번 정하면 발행자, 구독자, 권한 설정이 모두 의존합니다. 다음 지침을 권장합니다.
- 일반에서 구체로 계층을 만듭니다. 예:
<사이트>/<라인>/<셀>/<데이터 종류>. 와일드카드로 원하는 범위를 쉽게 고를 수 있습니다. - 맨 앞에
/를 붙이지 않습니다. 의미 없는 빈 단계가 생깁니다. - ASCII 문자, 숫자,
-,_만 씁니다. 공백과 비ASCII 문자는 도구마다 다르게 다룹니다. - 값을 토픽에 넣지 않습니다. 시각이나 측정값은 페이로드에 넣습니다. 토픽이 계속 늘어나면 브로커 자원과 보존 메시지가 쌓입니다.
- 데이터, 명령, 상태를 다른 가지로 나눕니다. 권한 규칙(ACL)을 가지 단위로 줄 수 있습니다.
- 식별자는 바뀌지 않는 값으로 정합니다. 장비 이름보다 자산 번호처럼 고정된 값이 좋습니다.
OPC UA PubSub의 토픽 관례
섹션 제목: “OPC UA PubSub의 토픽 관례”OPC 10000-14 §7.3.4는 PubSub 메시지의 토픽 구조로 다음 관례를 정합니다.
opcua/<인코딩>/<메시지 종류>/<PublisherId>/<WriterGroup 이름>[/<DataSetWriter 이름>]예를 들어 PublisherId 100의 line1 WriterGroup이 UADP 데이터를 보내면 토픽은 opcua/uadp/data/100/line1입니다.
PDComm 튜토리얼은 이 관례를 따릅니다.