인터넷에서 트래픽이 가장 많은 웹사이트 시장은 NGINX와 NGINX Plus가 장악하고 있습니다. 실제로 NGINX는 전 세계에서 트래픽이 가장 많은 100만 개 사이트 중 다른 어떤 웹 서버보다 더 많은 사이트를 지원합니다 단일 서버에서 100만 개가 넘는 동시 연결을 처리할 수 있는 성능 덕분에 Airbnb, Netflix, Uber와 같은 ‘하이퍼스케일’ 사이트와 앱에서 널리 채택되었습니다.
NGINX Plus는 일반적으로 웹 서버, HTTP 리버스 프록시 및 로드 밸런서로 가장 잘 알려져 있지만, TCP 및 UDP 애플리케이션을 지원하는 모든 기능을 갖춘 애플리케이션 전송 컨트롤러(ADC)이기도 합니다. NGINX Plus의 이벤트 기반 아키텍처를 비롯해 HTTP 사용 사례에서 성공을 이끈 다른 모든 특성은 사물 인터넷(IoT)에도 동일하게 적용됩니다.
이 글에서는 NGINX Plus를 사용하여 MQTT 트래픽의 부하를 분산하는 방법을 살펴봅니다. MQTT는 원래 원격 유전과의 통신을 위해 1999년에 발표되었습니다. 2013년에 IoT 사용 사례에 맞게 업데이트된 이후 많은 IoT 배포 환경에서 선호되는 프로토콜로 자리 잡았습니다. 수백만 대의 장치가 연결되는 프로덕션 IoT 배포 환경에서는 부하 분산기에 높은 성능과 고급 기능이 요구됩니다. 2부로 구성된 이 블로그 게시물 시리즈에서는 다음과 같은 고급 사용 사례를 살펴보겠습니다.
- MQTT 트래픽 부하 분산(이 게시물)
- MQTT 트래픽 암호화 및 인증
테스트 환경
NGINX Plus의 기능을 살펴보기 위해 MQTT 브로커 클러스터를 포함한 IoT 환경의 주요 구성 요소를 나타내는 간단한 테스트 환경을 사용합니다. 이 환경의 MQTT 브로커는 Docker 컨테이너 내부에서 실행되는 HiveMQ 인스턴스입니다.
MQTT 부하 분산 및 세션 지속성을 위한 테스트 환경
NGINX Plus는 MQTT 브로커의 리버스 프록시 및 로드 밸런서 역할을 하며 기본 MQTT 포트인 1883에서 수신 대기합니다. 이를 통해 클라이언트에 간단하고 일관된 인터페이스를 제공하는 동시에, 클라이언트에 아무런 영향을 주지 않고 백엔드 MQTT 노드를 확장하거나 오프라인으로 전환할 수도 있습니다. 테스트 환경에서는 IoT 기기를 나타내는 클라이언트로 Mosquitto 명령줄 도구를 사용합니다.
이 게시물과 2부의 모든 사용 사례에서는 이 테스트 환경을 사용하며, 모든 구성은 그림에 표시된 아키텍처에 그대로 적용됩니다. 테스트 환경을 구축하는 방법에 대한 전체 지침은 부록 1을 참조하세요.
고가용성을 위한 능동 상태 확인 기반 MQTT 부하 분산
A primary function of a 로드 밸런서의 주요 기능 중 하나는 클라이언트에 영향을 주지 않고 백엔드 서버를 추가하거나 제거하거나 오프라인으로 전환할 수 있도록 애플리케이션에 고가용성을 제공하는 것입니다. 이를 안정적으로 수행하려면 각 백엔드 서버의 가용성을 사전에 확인하는 상태 점검이 필수적입니다. 능동 상태 점검을 사용하면 실제 클라이언트 요청이 장애 서버에 도달하기 전에 NGINX Plus가 해당 서버를 로드 밸런싱 그룹에서 제거할 수 있습니다.
상태 확인의 유용성은 실제 애플리케이션 트래픽을 얼마나 정확하게 시뮬레이션하고 응답을 분석하는지에 따라 달라집니다. ping과 같은 단순한 서버 활성 상태 확인만으로는 백엔드 서비스가 실행 중인지 보장할 수 없습니다. TCP 포트 열림 확인만으로는 애플리케이션 자체가 정상인지 보장할 수 없습니다. 여기서는 각 백엔드 서버가 새로운 MQTT 연결을 수락할 수 있는지 확인하는 상태 확인과 함께 테스트 환경을 위한 기본 부하 분산을 구성합니다.
두 개의 구성 파일을 변경합니다.
기본 nginx.conf 파일에는 다음 stream 블록과 include 지시문을 추가하여 NGINX Plus가 stream_conf.d 하위 디렉터리에 있는 하나 이상의 파일에서 TCP 부하 분산 구성을 읽도록 합니다. 이 하위 디렉터리는 nginx.conf와 동일한 디렉터리에 있습니다. 실제 구성을 nginx.conf에 직접 포함하는 대신 이 방식을 사용합니다.
코드 예제를 로드하는 중…
그런 다음 nginx.conf와 동일한 디렉터리에 TCP 및 UDP 구성 파일을 저장할 stream_conf.d 디렉터리를 만듭니다. 기존 conf.d 디렉터리는 기본적으로 http 구성 컨텍스트용으로 예약되어 있으므로 사용하지 않습니다. 이 디렉터리에 stream 구성을 추가하면 오류가 발생합니다.
코드 예제를 로드하는 중…
In stream_mqtt_healthcheck.conf에서는 먼저 MQTT 트래픽의 액세스 로그 형식을 정의합니다(1~2행). 이 형식은 생성된 로그를 로그 분석 도구로 가져올 수 있도록 의도적으로 HTTP 공통 로그 형식과 유사하게 구성되었습니다.
다음으로 세 개의 MQTT 서버가 포함된 upstream 그룹인 hive_mq(4~9행)를 정의합니다. 테스트 환경에서는 각 서버에 localhost의 고유한 포트 번호를 통해 액세스할 수 있습니다. zone 지시문은 부하 분산 상태와 상태 정보를 유지하기 위해 모든 NGINX Plus 워커 프로세스가 공유하는 메모리의 크기를 정의합니다.
The match 블록(11~15행)은 MQTT 서버의 가용성을 테스트하는 데 사용되는 상태 확인을 정의합니다. send 지시문은 클라이언트 식별자(ClientId)가 CONNECT인 완전한 MQTT nginx health check 패킷을 16진수로 나타낸 것입니다. 이 패킷은 상태 확인이 실행될 때마다 업스트림 그룹에 정의된 각 서버로 전송됩니다. 이에 대응하는 expect 지시문은 NGINX Plus가 서버를 정상으로 판단하기 위해 서버가 반환해야 하는 응답을 설명합니다. 여기서 4바이트 16진수 문자열 20 02 00 00은 완전한 MQTT CONNACK 패킷입니다. 이 패킷이 수신되면 MQTT 서버가 새 클라이언트 연결을 수락할 수 있음을 알 수 있습니다.
The server 블록(17~25행)은 NGINX Plus가 클라이언트를 처리하는 방식을 구성합니다. NGINX Plus는 기본 MQTT 포트인 1883에서 수신 대기하고 모든 트래픽을 hive_mq 업스트림 그룹으로 전달합니다(19행). health_check 지시문은 업스트림 그룹에 대해 상태 확인을 수행하도록 지정하며(기본 주기: 5초), mqtt_conn match 블록에 정의된 검사를 사용합니다.
구성 확인
이 기본 구성이 제대로 작동하는지 확인하기 위해 Mosquitto 클라이언트를 사용하여 테스트 환경에 테스트 데이터를 게시할 수 있습니다.
$ mosquitto_pub -d -h mqtt.example.com -t "topic/test" -m "test123" -i "thing001"Client thing001 sending CONNECT
Client thing001 received CONNACK
Client thing001 sending PUBLISH (d0, q0, r0, m1, 'topic/test', ... (7 bytes))
Client thing001 sending DISCONNECT
$ tail --lines=1 /var/log/nginx/mqtt_access.log
192.168.91.1 [23/Mar/2017:11:41:56 +0000] TCP 200 23 4 127.0.0.1:18831액세스 로그의 이 줄을 보면 NGINX Plus가 총 23바이트를 수신했고 클라이언트로 4바이트(CONNACK 패킷)를 전송했음을 알 수 있습니다. 또한 MQTT node1이 선택되었음(포트 18831)을 확인할 수 있습니다. 액세스 로그의 다음 줄에서 볼 수 있듯이 테스트를 반복하면 기본 라운드 로빈 부하 분산 알고리즘이 node1, node2, node3을 차례로 선택합니다.
$ tail --lines=4 /var/log/nginx/mqtt_access.log192.168.91.1 [23/Mar/2017:11:41:56 +0000] TCP 200 23 4 127.0.0.1:18831
192.168.91.1 [23/Mar/2017:11:42:26 +0000] TCP 200 23 4 127.0.0.1:18832
192.168.91.1 [23/Mar/2017:11:42:27 +0000] TCP 200 23 4 127.0.0.1:18833
192.168.91.1 [23/Mar/2017:11:42:28 +0000] TCP 200 23 4 127.0.0.1:18831NGINX JavaScript 모듈을 사용한 세션 지속성 지원 MQTT 부하 분산
[편집자 – 다음 사용 사례는 NGINX JavaScript 모듈의 다양한 활용 사례 중 하나일 뿐입니다. 전체 목록은 NGINX JavaScript 모듈 활용 사례를 참조하세요.]
이 섹션의 코드는 블로그가 처음 게시된 이후 변경된 NGINX JavaScript 구현을 반영하기 위해 다음과 같이 업데이트되었습니다:
- To use the refactored session (
sNGINX JavaScript 0.2.4에서 도입된 Stream 모듈용으로 리팩터링된 세션() 객체를 사용하도록. - To use the
js_import지시어를 사용합니다. 이 지시어는js_include지시어를 NGINX Plus R23 이상에서 대체합니다. 자세한 내용은 NGINX JavaScript 모듈 참조 문서를 확인하세요. 구성 예제 섹션에서는 NGINX 구성 파일과 JavaScript 파일의 올바른 구문을 보여 줍니다.
라운드 로빈 부하 분산은 클라이언트 연결을 서버 그룹 전체에 분산하는 효과적인 메커니즘입니다. 하지만 MQTT 연결에는 적합하지 않은 몇 가지 이유가 있습니다.
MQTT 서버는 클라이언트와 서버 간의 연결이 장시간 유지되는 경우가 많으며, 서버에 상당한 양의 세션 상태가 축적될 수 있습니다. 하지만 IoT 장치와 이들이 사용하는 IP 네트워크의 특성상 연결이 끊어질 수 있어 일부 클라이언트는 자주 다시 연결해야 합니다. NGINX Plus는 해시 부하 분산 알고리즘을 사용하여 클라이언트 IP 주소를 기준으로 MQTT 서버를 선택할 수 있습니다. upstream 블록에 hash $remote_addr;를 추가하기만 하면 세션 지속성이 활성화되므로 특정 클라이언트 IP 주소에서 새 연결이 들어올 때마다 동일한 MQTT 서버가 선택됩니다.
하지만 IoT 디바이스가 동일한 IP 주소에서 다시 연결된다고 기대할 수는 없습니다. 특히 셀룰러 네트워크(예: GSM 또는 LTE)를 사용하는 경우에는 더욱 그렇습니다. 동일한 클라이언트가 동일한 MQTT 서버에 다시 연결되도록 하려면 MQTT 클라이언트 식별자를 해싱 알고리즘의 키로 사용해야 합니다.
MQTT ClientId 기반 세션 지속성
MQTT ClientId는 초기 CONNECT 패킷의 필수 요소이므로, 패킷이 업스트림 서버로 프록시되기 전에 NGINX Plus에서 사용할 수 있습니다. NGINX JavaScript를 사용하여 CONNECT 패킷을 구문 분석하고 ClientId를 변수로 추출한 다음, 이 변수를 hash 지시문에서 사용하여 MQTT 전용 세션 지속성을 구현할 수 있습니다.
NGINX JavaScript는 ‘NGINX 네이티브’ 프로그래밍 방식의 구성 언어입니다. NGINX 및 NGINX Plus를 위한 고유한 JavaScript 구현으로, 서버 측 사용 사례와 요청별 처리를 위해 특별히 설계되었습니다. MQTT의 세션 지속성을 구현하는 데 적합한 세 가지 주요 특성은 다음과 같습니다.
- NGINX JavaScript는 NGINX Plus의 처리 단계와 긴밀하게 통합되어 있어, 클라이언트 패킷이 업스트림 그룹으로 로드 밸런싱되기 전에 이를 검사할 수 있습니다.
- NGINX JavaScript는 문자열 및 숫자 처리를 위한 JavaScript 내장 메서드를 사용하므로 레이어 4 프로토콜을 효율적으로 파싱할 수 있습니다. 실제 MQTT
CONNECT패킷 파싱에는 20줄 미만의 코드만 필요합니다. - NGINX JavaScript는 NGINX Plus 구성에서 사용할 수 있는 변수를 생성할 수 있습니다.
NGINX JavaScript를 활성화하는 방법은 부록 2를 참조하세요.
세션 지속성을 위한 NGINX Plus 구성
이 사용 사례를 위한 NGINX Plus 구성은 비교적 간단합니다. 다음 구성은 활성 상태 확인을 사용한 부하 분산의 예제를 수정한 버전이며, 간결성을 위해 상태 확인은 생략했습니다.
코드 예제를 로드하는 중…
먼저 js_import 지시어를 사용하여 NGINX JavaScript 코드의 위치를 지정합니다. js_set 지시어는 $mqtt_client_id 변수를 평가해야 할 때 NGINX Plus가 setClientId 함수를 호출하도록 합니다. 이 변수를 5번째 줄의 mqtt 로그 형식에 추가하여 액세스 로그에 더 자세한 정보를 기록합니다.
12번째 줄에서 hash 지시어를 사용하고 $mqtt_client_id를 키로 지정하여 세션 지속성을 활성화합니다. 업스트림 서버에 장애가 발생할 경우 해당 서버가 처리하던 트래픽이 나머지 서버에 균등하게 분산되면서도 해당 서버들에 이미 설정된 세션에는 영향을 주지 않도록 consistent 매개변수를 사용한다는 점에 유의하세요. 일관된 해싱에 대한 자세한 내용은 웹 캐시 샤딩 관련 블로그 게시물에서 다룹니다. 이 원칙과 이점은 여기에도 동일하게 적용됩니다.
The js_preread 지시어(18행)는 요청 처리의 사전 읽기 단계에서 실행되는 NGINX JavaScript 함수를 지정합니다. 사전 읽기 단계는 모든 패킷(양방향)에 대해 트리거되며 프록시 처리 전에 수행되므로, $mqtt_client_id 값이 upstream 블록에서 필요할 때 사용 가능합니다.
세션 지속성을 위한 NGINX JavaScript 코드
MQTT ClientId를 추출하는 JavaScript는 mqtt.js 파일에 정의하며, 이 파일은 NGINX Plus 구성 파일의 js_import 지시어를 통해 로드됩니다(stream_mqtt_session_persistence.conf).
코드 예제를 로드하는 중…
기본 함수인 getClientId()는 4번째 줄에 선언되어 있습니다. 이 함수에는 현재 TCP 세션을 나타내는 s라는 객체가 전달됩니다. 세션 객체에는 수많은 속성이 있으며, 이 함수에서는 그중 몇 가지를 사용합니다.
5~9행에서는 현재 패킷이 클라이언트로부터 수신된 첫 번째 패킷인지 확인합니다. 이후의 클라이언트 메시지와 서버 응답은 무시되므로, 연결이 설정된 후에는 트래픽 흐름에 추가적인 오버헤드가 발생하지 않습니다.
코드 예제를 로드하는 중…
10~24행에서는 MQTT 헤더를 검사하여 패킷이 CONNECT 유형인지 확인하고 MQTT 페이로드가 시작되는 위치를 파악합니다.
코드 예제를 로드하는 중…
27~32행에서는 페이로드에서 ClientId를 추출하여 JavaScript 전역 변수 client_id_str에 값을 저장합니다. 그런 다음 이 변수는 setClientId 함수(43~45행)를 통해 NGINX 구성으로 내보내집니다.
세션 지속성 확인
이제 Mosquitto 클라이언트를 다시 사용하여 서로 다른 세 가지 ClientId 값(-i 옵션)을 지정해 일련의 MQTT 게시 요청을 전송함으로써 세션 지속성을 테스트할 수 있습니다.
$ mosquitto_pub -h mqtt.example.com -t "topic/test" -m "test123" -i "foo"$ mosquitto_pub -h mqtt.example.com -t "topic/test" -m "test123" -i "bar"
$ mosquitto_pub -h mqtt.example.com -t "topic/test" -m "test123" -i "baz"
$ mosquitto_pub -h mqtt.example.com -t "topic/test" -m "test123" -i "foo"
$ mosquitto_pub -h mqtt.example.com -t "topic/test" -m "test123" -i "foo"
$ mosquitto_pub -h mqtt.example.com -t "topic/test" -m "test123" -i "foo"
$ mosquitto_pub -h mqtt.example.com -t "topic/test" -m "test123" -i "bar"
$ mosquitto_pub -h mqtt.example.com -t "topic/test" -m "test123" -i "bar"
$ mosquitto_pub -h mqtt.example.com -t "topic/test" -m "test123" -i "baz"
$ mosquitto_pub -h mqtt.example.com -t "topic/test" -m "test123" -i "baz"액세스 로그를 살펴보면 ClientId foo는 항상 node1(포트 18831)에 연결되고, ClientId bar는 항상 node2(포트 18832)에 연결되며, ClientId baz는 항상 node3(포트 18833)에 연결됩니다.
$ tail /var/log/nginx/mqtt_access.log192.168.91.1 [23/Mar/2017:12:24:24 +0000] TCP 200 23 4 127.0.0.1:18831 foo
192.168.91.1 [23/Mar/2017:12:24:28 +0000] TCP 200 23 4 127.0.0.1:18832 bar
192.168.91.1 [23/Mar/2017:12:24:32 +0000] TCP 200 23 4 127.0.0.1:18833 baz
192.168.91.1 [23/Mar/2017:12:24:35 +0000] TCP 200 23 4 127.0.0.1:18831 foo
192.168.91.1 [23/Mar/2017:12:24:37 +0000] TCP 200 23 4 127.0.0.1:18831 foo
192.168.91.1 [23/Mar/2017:12:24:38 +0000] TCP 200 23 4 127.0.0.1:18831 foo
192.168.91.1 [23/Mar/2017:12:24:42 +0000] TCP 200 23 4 127.0.0.1:18832 bar
192.168.91.1 [23/Mar/2017:12:24:44 +0000] TCP 200 23 4 127.0.0.1:18832 bar
192.168.91.1 [23/Mar/2017:12:24:47 +0000] TCP 200 23 4 127.0.0.1:18833 baz
192.168.91.1 [23/Mar/2017:12:24:48 +0000] TCP 200 23 4 127.0.0.1:18833 baz세션 지속성이나 다른 어떤 부하 분산 알고리즘을 사용하든 관계없이 MQTT ClientId가 액세스 로그 줄에 표시된다는 이점도 있습니다.
결론
2부작 시리즈의 첫 번째 게시물인 이번 글에서는 NGINX Plus가 능동 상태 확인을 사용하여 IoT 애플리케이션의 가용성과 안정성을 개선하는 방법과 NGINX JavaScript가 TCP 트래픽의 세션 지속성과 같은 레이어 7 부하 분산 기능을 제공하여 NGINX Plus를 확장하는 방법을 살펴보았습니다. 두 번째 글에서는 NGINX Plus가 TLS 종료를 오프로드하고 클라이언트를 인증하여 IoT 애플리케이션의 보안을 강화하는 방법을 알아봅니다.
NGINX JavaScript와 함께 사용하든 단독으로 사용하든, NGINX Plus는 뛰어난 성능과 효율성을 기본적으로 갖추고 있어 IoT 인프라용 소프트웨어 로드 밸런서로 이상적입니다.
NGINX Plus에서 NGINX JavaScript를 사용해 보려면 30일 무료 평가판을 시작하거나 사용 사례에 대해 논의하려면 문의해 주세요.
부록
테스트 환경 만들기
테스트 환경을 격리하고 동일하게 재현할 수 있도록 가상 머신에 설치했습니다. 하지만 물리적인 ‘베어 메탈’ 서버에 설치하지 못할 이유는 없습니다.
NGINX Plus 설치
See the instructions in the NGINX Plus 관리 가이드의 지침을 참조하세요.
HiveMQ 설치
어떤 MQTT 서버든 사용할 수 있지만, 이 테스트 환경은 HiveMQ를 기반으로 합니다(여기에서 다운로드). 이 예제에서는 각 노드에 Docker 컨테이너를 사용하여 단일 호스트에 HiveMQ를 설치합니다. 다음 지침은 Docker를 사용한 HiveMQ 배포를 바탕으로 작성되었습니다.
- HiveMQ용 Dockerfile을 hivemq.zip과 동일한 디렉터리에 생성합니다.
코드 예제를 로드하는 중…
- Working in the directory that contains hivemq.zip 및 Dockerfile이 있는 디렉터리에서 Docker 이미지를 생성합니다.
$ docker build -t hivemq:latest .- 각각 서로 다른 포트로 노출되는 HiveMQ 노드 3개를 생성합니다.
$ docker run -p 18831:1883 -d --name node1 hivemq:latest
ff2c012c595a
$ docker run -p 18832:1883 -d --name node2 hivemq:latest
47992b1f4910
$ docker run -p 18833:1883 -d --name node3 hivemq:latest
17303b900b64- 세 개의 HiveMQ 노드가 모두 실행 중인지 확인합니다. (다음 샘플 출력에서는 읽기 쉽도록
COMMAND,CREATED,STATUS열을 생략했습니다.)
$ docker psCONTAINER ID IMAGE ... PORTS NAMES
17303b900b64 hivemq:latest ... 0.0.0.0:18833->1883/tcp node3
47992b1f4910 hivemq:latest ... 0.0.0.0:18832->1883/tcp node2
ff2c012c595a hivemq:latest ... 0.0.0.0:18831->1883/tcp node1Mosquitto 설치
Mosquitto 명령줄 클라이언트는 프로젝트 웹사이트에서 다운로드할 수 있습니다. Homebrew가 설치된 Mac 사용자는 다음 명령어를 실행할 수 있습니다.
$ brew install mosquittoDocker 이미지 중 하나에 간단한 게시 메시지를 전송하여 Mosquitto 클라이언트와 HiveMQ가 제대로 설치되었는지 테스트합니다.
$ mosquitto_pub -d -h mqtt.example.com -t "topic/test" -m "test123" -i "thing001" -p 18831
Client thing001 sending CONNECT
Client thing001 received CONNACK
Client thing001 sending PUBLISH (d0, q0, r0, m1, 'topic/test', ... (7 bytes))
Client thing001 sending DISCONNECT[ngx_snippet name=’njs-enable-instructions’]
작성자 소개

관련 블로그 게시물
시청하기: KubeCon North America 2023에서의 NGINX Gateway Fabric
이 영상에서는 KubeCon의 NGINX 부스를 찾아가, 저희가 공개한 Kubernetes Gateway API 구현을 살펴봅니다.
F5 NGINX로 대규모 WAF 플릿을 확인하고 관리하는 2가지 방법
앱 보안을 강화하는 두 가지 방법을 소개합니다. NGINX Management Suite를 통해 WAF 운영에 대한 가시성을 높이고, NGINX App Protect WAF를 활용해 코드형 보안을 구현하는 것입니다.
Ingress 컨트롤러 선택 가이드, 4부: NGINX Ingress Controller 옵션
개발 주체, 개발 철학, 프로덕션 환경 준비도, 보안 및 지원을 기준으로 어떤 NGINX Ingress 컨트롤러가 가장 적합한지 알아보세요.
진화하는 공격 환경에 NGINX App Protect Denial of Service가 적응하는 방법
NGINX App Protect Denial of Service(DoS)가 계층 7 DoS 공격을 방어하기 위해 완화 방법을 실시간으로 조정하는 방식을 설명합니다. 정상적인 사용자 행동과 서버 상태에 대한 모델을 생성하여 공격을 나타내는 이상 징후를 감지하고 맞춤형 완화 시그니처를 적용할 수 있습니다.
NGINX Instance Manager를 활용한 대규모 구성 업데이트 및 인증서 관리
NGINX Instance Manager 버전 1.0에는 두 가지 새로운 기능이 도입되었습니다. NGINX 인스턴스에 태그와 사용자 역할을 지정하면 전체 그룹에 구성을 한 번에 적용할 수 있습니다. 인증서 검사는 만료 예정인 인증서를 감지하여 서비스 중단을 방지할 수 있도록 인증서를 교체할 수 있게 해줍니다.
Netflix가 자사 CDN의 핵심으로 NGINX를 선택한 이유
Netflix가 글로벌 콘텐츠 전송 네트워크인 Open Connect의 스트리밍 미디어 기술로 NGINX를 선택한 이유를 NGINX 개발자 Gleb Smirnoff에게서 알아보세요.