NGINX Plus를 통한 엔터프라이즈 환경에서의 MQTT 배포 최적화

관리자
조회수 190

NGINX Plus의 R29 릴리스를 발표할 때 MQTT 메시지 구문에 대한 새로운 기본 지원에 대해 간략하게 다루었습니다. 이 글에서는 이를 기반으로 엔터프라이즈 환경에서 MQTT 배포를 최적화하기 위해 NGINX Plus를 구성하는 방법에 대해 설명합니다.


MQTT란 무엇인가요?

MQTT는 메시지 큐 텔레메트리 전송의 약자입니다. 매우 인기 있는 경량 게시-구독 메시징 프로토콜로, 인터넷을 통해 사물 인터넷(IoT) 또는 M2M(기계 간) 디바이스 및 애플리케이션을 연결하는 데 이상적입니다. MQTT는 저대역폭 또는 저전력 환경에서 효율적으로 작동하도록 설계되어 원격 클라이언트가 많은 애플리케이션에 이상적인 선택입니다. 소비자 가전, 자동차, 운송, 제조, 의료 등 다양한 산업에서 사용됩니다.


NGINX Plus MQTT 메시지 처리

NGINX Plus R29는 MQTT 3.1.1 및 MQTT 5.0를 지원합니다. 클라이언트와 브로커 사이의 프록시 역할을 하여 핵심 시스템에서 작업을 오프로드하고 확장성을 간소화하며 컴퓨팅 비용을 절감합니다. 특히 NGINX Plus는 MQTT CONNECT 메시지의 일부를 파싱하고 다시 작성하여 다음과 같은 기능을 활성화합니다:

  • MQTT 브로커 부하 분산  
  • 세션 지속성(클라이언트를 동일한 브로커에 재연결) 
  • SSL/TLS 종료
  • 클라이언트 인증서 인증

MQTT 메시지 처리 지시어는 NGINX 구성 파일의 stream 컨텍스트에 정의해야 하며, ngx_stream_mqtt_preread_module
및 ngx_stream_mqtt_filter_module에 의해 제공됩니다.

preread 모듈은 NGINX의 내부 프록시에 앞서 MQTT 데이터를 처리하여 파싱된 메시지 데이터를 기반으로 부하 분산 및 업스트림 라우팅을 결정할 수 있도록 합니다.

필터 모듈을 사용하면 수신된 CONNECT 메시지 내의 clientid, username, password 필드에 다시 쓰기를 수행할 수 있습니다. 이러한 필드를 변수 및 복합 값으로 설정하는 기능은 구성 옵션을 크게 확장하여 NGINX Plus에서 민감한 기기 정보를 마스킹하거나 TLS 인증서 고유 이름과 같은 데이터를 삽입할 수 있게 해줍니다.


MQTT 지시어 및 변수

이제 몇 가지 새로운 지시어와 임베디드 변수를 사용하여 MQTT 배포를 최적화하고 특정 요구 사항을 충족하도록 NGINX 구성을 조정할 수 있습니다.


모듈 지시어 및 임베디드 변수 미리 읽기

  • mqtt_preread - 클라이언트 디바이스에서 보낸 CONNECT 메시지에서 clientid 및 username 필드를 추출하여 MQTT 파싱을 사용하도록 설정합니다. 이러한 값은 임베디드 변수와 도움말 해시 세션을 통해 로드 밸런싱된 업스트림 서버에 사용할 수 있습니다(아래 예시).
  • $mqtt_preread_clientid - 디바이스에서 전송한 MQTT 클라이언트 식별자를 나타냅니다.
  • $mqtt_preread_username - 인증 목적으로 클라이언트가 전송한 사용자 이름을 나타냅니다.


필터 모듈 지시어

  • mqtt - MQTT 재작성 활성화 여부를 정의합니다.
  • mqtt_buffers - 연결당 할당할 수 있는 MQTT 처리 버퍼의 최대 수와 각 버퍼의 크기를 재정의합니다. 기본적으로 NGINX는 연결당 100개의 버퍼(각 버퍼의 길이는 1k)로 제한합니다. 일반적으로 이는 성능에 최적이지만 특수한 상황에서는 튜닝이 필요할 수 있습니다. 예를 들어, MQTT 메시지가 길수록 더 큰 버퍼 크기가 필요합니다. 단시간 내에 특정 연결에 대해 더 많은 양의 MQTT 메시지를 처리하는 시스템은 버퍼 수를 늘리면 이점을 얻을 수 있습니다. 대부분의 경우 버퍼 매개변수 조정은 기본 시스템 성능에 거의 영향을 미치지 않는데, 이는 NGINX가 내부 메모리 풀에서 버퍼를 구성하기 때문입니다.
  • mqtt_rewrite_buffer_size - MQTT 메시지를 구성하는 데 사용되는 버퍼의 크기를 지정합니다. 이 지시어는 더 이상 사용되지 않으며 NGINX Plus R30부터 더 이상 사용되지 않습니다.
  • mqtt_set_connect - 클라이언트에서 보낸 CONNECT 메시지의 파라미터를 다시 씁니다. 지원되는 매개변수는 다음과 같습니다: clientid, 사용자 이름, 비밀번호.


MQTT 예제

NGINX Plus로 MQTT 메시지를 처리할 때의 장점과 관련 모범 사례에 대해 자세히 살펴보겠습니다. 아래 예제에서는 포트 1883과 8883을 사용합니다. 포트 1883은 기본 비보안 MQTT 포트이며, 포트 8883은 기본 SSL/TLS 암호화 포트입니다.


MQTT 브로커 부하 분산

MQTT 디바이스의 임시적인 특성으로 인해 클라이언트 IP가 예기치 않게 변경될 수 있습니다. 이로 인해 디바이스 연결을 올바른 업스트림 브로커로 라우팅할 때 문제가 발생할 수 있습니다. 한 업스트림 브로커에서 다른 업스트림 브로커로 디바이스 연결을 이동하면 브로커 간 동기화 작업에 많은 비용이 발생하여 지연 시간과 비용이 추가될 수 있습니다.

MQTT CONNECT 메시지의 clientid 필드를 파싱하여 NGINX는 업스트림 서비스 브로커에 대한 스티키 세션을 설정할 수 있습니다. 이는 백엔드에서 브로커 서비스에 대한 연결을 유지하기 위한 해시 키로 clientid를 사용하여 수행됩니다.

이 예시에서는 3개의 업스트림 브로커에 대한 스티키 세션을 설정하기 위한 토큰으로 clientid를 사용하여 MQTT 디바이스 데이터를 프록시합니다. 일관된 매개변수를 사용하여 업스트림 서버에 장애가 발생하더라도 해당 서버에 이미 설정된 세션에 영향을 주지 않고 나머지 서버에 트래픽이 균등하게 분산되도록 합니다.

stream {      mqtt_preread on; 
     
      upstream backend {
          zone tcp_mem 64k;
          hash $mqtt_preread_clientid consistent;
    
          server 10.0.0.7:1883; # upstream mqtt broker 1
          server 10.0.0.8:1883; # upstream mqtt broker 2
          server 10.0.0.9:1883; # upstream mqtt broker 3 
      }
    
      server {
          listen 1883;
          proxy_pass backend;
          proxy_connect_timeout 1s;
      }
  }

NGINX Plus는 MQTT CONNECT 메시지의 사용자 이름 필드도 파싱할 수 있습니다. 자세한 내용은 ngx_stream_mqtt_preread_module 사양을 참조하세요;


SSL/TLS Termination

디바이스 통신을 암호화하는 것은 데이터 기밀성을 보장하고 중간자 공격으로부터 보호하는 데 있어 핵심입니다. 하지만 TLS 핸드셰이킹, 암호화, 복호화는 MQTT 브로커에 리소스 부담이 될 수 있습니다. 이 문제를 해결하기 위해 NGINX Plus는 브로커(또는 브로커 클러스터)에서 데이터 암호화를 오프로드하여 보안 규칙을 간소화하고 브로커가 디바이스 메시지 처리에 집중할 수 있도록 지원합니다. 

이 예제에서는 NGINX를 사용하여 디바이스에서 백엔드 브로커로 TLS 암호화 MQTT 트래픽을 프록시하는 방법을 보여줍니다. ssl_session_cache 지시어는 약 20,000개의 SSL 세션을 저장하기에 충분한 5메가바이트의 캐시를 정의합니다. NGINX는 proxy_connect_timeout 지시문에 정의된 대로 5초 동안 프록시 브로커에 접속을 시도한 후 시간 초과를 시도합니다.

stream {      server {
          listen 8883 ssl;
          ssl_certificate /etc/nginx/certs/tls-cert.crt;
          ssl_certificate_key /etc/nginx/certs/tls-key.key;
          ssl_session_cache shared:SSL:5m;
          proxy_pass 10.0.0.8:1883;
          proxy_connect_timeout 5s;
      }
  } 


클라이언트 ID 대체

보안상의 이유로 클라이언트 식별 정보를 MQTT 브로커의 데이터베이스에 저장하지 않도록 선택할 수 있습니다. 예를 들어, 디바이스에서 일련번호나 기타 민감한 데이터를 MQTT CONNECT 메시지의 일부로 전송할 수 있습니다. 디바이스의 식별자를 클라이언트로부터 받은 다른 알려진 정적 값으로 대체함으로써, NGINX Plus 프록시 브로커에 접속하려는 모든 디바이스에 대해 대체 고유 키를 설정할 수 있습니다.

이 예에서는 디바이스의 클라이언트 SSL 인증서에서 고유 식별자를 추출하고 이를 사용하여 MQTT 클라이언트 ID를 마스킹합니다. 클라이언트 인증서 인증(상호 TLS)은 ssl_verify_client 지시어로 제어합니다. on 매개 변수로 설정하면 NGINX는 클라이언트 인증서가 신뢰할 수 있는 CA(인증 기관)에 의해 서명되도록 합니다. 신뢰할 수 있는 CA 인증서 목록은 ssl_client_certificate 디렉티브에 정의되어 있습니다;

stream {      mqtt on; 
    
      server {
          listen 8883 ssl;
          ssl_certificate /etc/nginx/certs/tls-cert.crt;
          ssl_certificate_key /etc/nginx/certs/tls-key.key;
          ssl_client_certificate /etc/nginx/certs/client-ca.crt;
          ssl_session_cache shared:SSL:10m;
          ssl_verify_client on;
          proxy_pass 10.0.0.8:1883;
          proxy_connect_timeout 1s;
          
          mqtt_set_connect clientid $ssl_client_serial;
      }
  } 


인증 자격 증명으로서의 클라이언트 인증서

MQTT 클라이언트를 인증하는 일반적인 접근 방식 중 하나는 클라이언트 인증서에 저장된 데이터를 사용자 이름으로 사용하는 것입니다. NGINX Plus는 클라이언트 인증서를 파싱하고 MQTT 사용자 이름 필드를 다시 작성하여 백엔드 브로커에서 이 작업을 오프로드할 수 있습니다. 다음 예에서는 클라이언트 인증서의 주체 고유 이름(Subject DN)을 추출하여 MQTT CONNECT 메시지의 사용자 이름 부분에 복사합니다.

stream {      mqtt on; 
     
      server {
          listen 8883 ssl;
          ssl_certificate /etc/nginx/certs/tls-cert.crt;
          ssl_certificate_key /etc/nginx/certs/tls-key.key;
          ssl_client_certificate /etc/nginx/certs/client-ca.crt;
          ssl_session_cache shared:SSL:10m;
          ssl_verify_client on;
          proxy_pass 10.0.0.8:1883;
          proxy_connect_timeout 1s;
          
          mqtt_set_connect username $ssl_client_s_dn;
      }
  }  

NGINX 플러스 MQTT 연결 메시지 재작성에 대한 전체 사양은 ngx_stream_mqtt_filter_module 사양을 참조하세요.


지금 바로 시작하기

향후에는 다른 MQTT 메시지 유형에 대한 구문 분석과 CONNECT 메시지의 심층 구문 분석을 통해 다음과 같은 기능을 사용할 수 있도록 NGINX Plus에서 MQTT를 개발할 예정입니다:

  • 추가 인증 및 액세스 제어 메커니즘
  • "채팅이 많은" 클라이언트의 속도를 제한하여 브로커 보호하기
  • 메시지 텔레메트리 및 연결 메트릭



위 내용과 같이 NGINX Plus를 활용하여 Demo 가 필요하시면 하단의 전문가에게 상담받기 버튼을 클릭해주세요

 

전문가에게 상담받기 




0 0