경력기술서 · 2023.04 – 2024.01 · ECS / 퓨렌스
KB증권 AI기반 금융상담 시스템 구축
실시간 TTS 음성 스트리밍 · MediaMTX · gRPC · Nginx
화상채팅 세션에 TTS 음성을 함께 들려 주는 금융상담 시스템입니다.
중계망 RTSP 송출, TTS 파일용 gRPC, WebSocket·API의 Nginx 분산을 구성했습니다.
MediaMTX
RTSP
RTP
WebSocket
gRPC
Spring Boot
Python
Nginx
L4 VIP
00
제어는 Nginx, 음성은 RTSP
화상 솔루션 → 중계망 → 내부망
Nginx · MediaMTX 같은 서버
화상 솔루션
중계망
내부망
제어
WebSocket
WebSocket
중계 서버L4 VIP · Nginx
MediaMTX와 같은 서버
WebSocket
음성
RTSP
RTSP
중계 서버MediaMTX · Nginx
runOnDemand가 Nginx로 요청
HTTP
SpringgRPC · TTS 파일
proto는 전달받아 호출
담당한 구성
MediaMTXPython 훅Spring gRPCHTTPNginx
01
규모와 역할
KB증권 금융상담규모 · ECS 연계
화상 상담 세션규모 · 세션에 TTS 송출
전송 서버 개발역할 · RTSP · WebSocket · gRPC
중계 인프라 구성역할 · Nginx · L4 VIP
02
한 음원을 여러 세션이 구독
화상채팅 서버는 먼저 WebSocket으로 송출 시작·종료와 채팅 세션을 보냅니다.
음원은 중계망 MediaMTX의 RTSP path 하나로 받습니다. MediaMTX와 중계 Nginx는 같은 서버이고, 음원 요청은 그 Nginx가 내부 Spring으로 프록시합니다.
화상채팅 서버
중계 Nginx
WebSocket
1. 어떤 세션에 넣을지
① start · 세션
② 내부로 프록시
화상채팅 서버
MediaMTX
같은 서버
중계 Nginx
같은 서버
Spring
TTS
2. 같은 서버의 Nginx로 음원 요청
③ 같은 path 구독
④ runOnDemand
⑤ API 프록시
⑥ gRPC 파일
⑦ HTTP 스트림
⑧ RTP
① ② WebSocket
송출 시작·종료와 채팅 세션은 WebSocket으로만 오갑니다. 중계망 L4 VIP 뒤 Nginx가 이 연결을 내부 WebSocket 서버로 넘깁니다. end도 같은 경로로 그 세션만 끊습니다.
③ ⑧ 같은 path
세션마다 RTSP 주소를 만들지 않습니다. 화상채팅 서버가 음원 path 하나를 구독해 start로 들어온 세션에 나눕니다. end가 온 세션만 빼고, 다른 세션이 남아 있으면 path는 유지됩니다.
④ ⑦ runOnDemand
구독이 생기면 MediaMTX가 파이썬을 실행합니다. 파이썬은 같은 서버의 중계 Nginx로 HTTP 요청을 보내고, 그 Nginx가 내부 Spring으로 프록시합니다. 돌아온 스트림이 RTP로 나갑니다.
⑥ gRPC 한 번
TTS는 음원 파일을 gRPC로만 줍니다. 전달받은 proto로 Spring이 파일 전체를 받은 다음 HTTP 송출을 시작합니다. 같은 path 구독이 유지되는 동안 이 파일 수신은 한 번입니다. 세션이 추가될 때 TTS를 다시 부르지 않습니다.
안내
중계 서버의 Nginx가 프록시하는 요청과, MediaMTX가 직접 받는 음성입니다.
Step 01 / 제어 · 담당
WebSocket은 중계 VIP 뒤 Nginx
화상채팅 서버의 start · end · 세션은 중계 L4 VIP로 들어갑니다. 중계 Nginx가 내부 WebSocket 서버로 프록시하며, 이 Nginx는 MediaMTX와 한 서버입니다.
Step 02 / 파일 · 담당
API는 같은 서버의 중계 Nginx
runOnDemand 파이썬이 같은 서버의 Nginx로 HTTP 요청을 보내면, 그 Nginx가 내부 Spring으로 프록시합니다.
Step 03 / 음성 · 담당
RTP는 화상 서버와 MediaMTX가 직접
음성은 중계망 MediaMTX와 화상채팅 서버 사이 RTSP · RTP로 오갑니다.
03
음성은 MediaMTX가 직접 송출
01RTP를 리버스 프록시에 실을 수 없음
음성을 Nginx에 싣는 경우
RTP · UDP
TTS 음성
리버스 프록시 upstream으로 나가지 못함
TCP · HTTP만
Nginx
WebSocket과 API 요청만 전달
음성 UDP는 이 경로에 실리지 않습니다.
구성한 경로
TCP · HTTP
WebSocket · API
중계 서버 Nginx가 내부로 프록시
UDP
MediaMTX ↔ 화상채팅 서버
RTSP path 하나를 구독
파일 1회
Spring gRPC
받은 파일을 HTTP로 송출
문제여러 화상 세션에 TTS 음성을 보내야 하는데, 중계 Nginx로는 그 음성을 넘길 수 없었습니다.
원인Nginx 리버스 프록시는 TCP와 HTTP를 처리합니다. RTSP 미디어인 RTP는 UDP입니다.
해결중계망 MediaMTX가 RTSP로 송출하게 했습니다. runOnDemand 파이썬은 같은 서버의 중계 Nginx로 HTTP 요청을 보내고, Nginx가 내부 Spring으로 프록시합니다.
결과신호와 파일 조회는 중계 Nginx가 프록시하고, 음성은 화상채팅 서버가 같은 path로 받아 세션에 나눕니다.
04
핵심성과
속도
세션 수와 gRPC 횟수를 분리
한 일
TTS 파일을 gRPC로 한 번 받아 HTTP로 바꾸고, 화상채팅 서버가 RTSP path 하나를 구독해 여러 세션에 나누게 했습니다.
개선
송출 시작은 파일 전체를 받은 뒤에 시작됩니다. 이미 열린 path에 세션이 더해질 때는 TTS를 다시 호출하지 않습니다.
망분리
중계망에는 음원 바이트만
한 일
RTSP 서버를 중계망에 두고, 세션을 처리하는 WebSocket 서버와 TTS에 붙는 Spring은 내부망에 두었습니다.
개선
MediaMTX가 다루는 것은 음원 스트림뿐입니다. 상담 세션과 TTS 원본은 내부망에 있습니다.
분산
신호와 파일은 중계 Nginx 하나
한 일
WebSocket과 API 프록시를 중계 서버의 Nginx에 모았습니다. MediaMTX는 그 서버에서 runOnDemand로 Nginx에 요청합니다.
개선
신호와 파일 조회는 그 Nginx가 내부로 나눕니다. 음성은 MediaMTX가 화상채팅 서버에 직접 송출합니다.