0️⃣ 서비스 소개
화상 홈 트레이닝 서비스 ChatPT는 webRTC & webSocket 을 통해 실시간 화상채팅 서비스를 제공합니다.
⚡ Github_ChatPT | 💿 시연영상
1️⃣ 기술 스택 및 서비스 아키텍쳐
Nest.js
React
MySQL
GitActions
WebRTC
WebSocket
Socket.io
RabbitMQ
ElasticSearch
PortOne
TossAPI
WinstonErrorBot
2️⃣ 핵심 기능

Num | 기능 | 기술 | 비고 |
1 | 백엔드 | Nest.js | 서버 개발을 위한 효율적이고 확장 가능한 구조 제공 |
2 | 프론트 | React.js | 사용자 인터페이스 개발 |
3 | 데이터 | MySQL | 데이터베이스로 사용자 정보 및 대화기록 저장 |
4 | 영상 및 음성 | webRTC | 브라우저 간 실시간 음성 및 영상 통신 기능 구현 |
5 | 통신 | WebSocket, Socket.io | 실시간 이벤트 처리 및 양방향 실시간 통신 구현 |
6 | 메시지 | RabbitMQ | 이벤트 기반의 메시지 브로커로 비동기 통신 구현 |
7 | 검색 기능 | ElasticSearch | 검색 기능을 위한 데이터 색인 및 검색 엔진 |
8 | 강의 결제 테스트 | PortOne, TossAPI | 결제 테스 기능을 위한 API 호출 및 연동 |
9 | 배포 | GitActions | CI/CD 파이프라인 구축 |
10 | 에러 알림 | WinstonErrorBot | 로그 수집 및 에러 알림 도구 |
3️⃣ 개발 내용
webRTC Peer-to-Peer 방식 선택
WebRTC를 Peer-to-Peer (P2P) 방식으로 선택한 주요 이유는 사용자 간 직접적인 연결을 통해 데이터를 주고받는 이점이 있습니다.
- 간단한 시작점: WebRTC는 초기 학습자에게 친숙한 API와 풍부한 자료로 쉬운 시작을 제공합니다.
RTCPeerConnection
을 생성하는 것만으로도 P2P 통신을 시작할 수 있습니다.
javascriptCopy code const peerConnection = new RTCPeerConnection();
- 대역폭 효율성: P2P 방식은 서버를 경유하지 않고 직접 연결을 통해 데이터를 주고받습니다. 이로써 대역폭 사용을 최소화하면서 효율적인 통신을 구현할 수 있습니다.
javascriptCopy code peerConnection.onicecandidate = (event) => { if (event.candidate) { sendIceCandidateToOtherUser(event.candidate); } };
- 빠른 화상 통화: 서버를 경유하지 않아 데이터 전송이 빠르게 이뤄지므로 실시간 화상 통화를 구현하면서 높은 성능을 제공합니다.
javascriptCopy code navigator.mediaDevices.getUserMedia({ video: true, audio: true }) .then((stream) => { peerConnection.addStream(stream); });
- 가독성과 직관성: P2P 방식은 직접적인 데이터 흐름을 갖기 때문에 코드가 간결하고 가독성이 뛰어납니다. 서버 중심의 아키텍처를 이해하고 적용하는 과정에서도 코드의 직관성이 도움이 됩니다.
javascriptCopy code socket.on('message', (data) => { handleMessage(data); });
이러한 이유로 P2P 방식을 선택하면서 더 효율적이고 직관적인 웹 실시간 통신을 구현할 수 있는 경험을 쌓고자 했습니다.
하나의 인스턴스에 Frontend와 Backend를 동시에 사용하여 배포
- 프로젝트를 단일 인스턴스에 프론트엔드와 백엔드를 함께 배포했습니다. 이로써 코드 관리와 배포가 효율적으로 이루어질 뿐만 아니라, 동일한 도메인에서 서비스를 제공함으로써 CORS 관련 문제도 우회했습니다. 프론트엔드와 백엔드가 함께 실행되는 구조는 애플리케이션의 간단한 구조를 제공하여 전체적인 유지보수 및 운영을 간편하게 만들었습니다.
deploy.yaml
name: Deploy to Amazon EC2 on: push: branches: - master # 본인이 설정한 값을 여기서 채워넣습니다. # 리전, 버킷 이름, CodeDeploy 앱 이름, CodeDeploy 배포 그룹 이름 env: AWS_REGION: ap-northeast-2 S3_BUCKET_NAME: chatpt-githubaction-s3-bucket CODE_DEPLOY_APPLICATION_NAME: chatpt-codedeploy-app CODE_DEPLOY_DEPLOYMENT_GROUP_NAME: chatpt-codedeploy-deployment-group permissions: contents: read jobs: deploy: name: Deploy runs-on: ubuntu-latest environment: production steps: - name: Enable Debug Logging for the runner run: echo "ACTIONS_RUNNER_DEBUG=true" >> $GITHUB_ENV - name: Enable Debug Logging for each step run: echo "ACTIONS_STEP_DEBUG=true" >> $GITHUB_ENV # (1) 기본 체크아웃 - name: Checkout uses: actions/checkout@v3 # (2) Node.js 세팅 - name: Set up Node.js uses: actions/setup-node@v2 with: node-version: '18.x' # (3) build (Test 제외) - name: Install dependencies run: | cd backend npm install cd ../frontend npm install cd ../room npm install - name: Build test run: | cd backend npm run build cd ../frontend npm run build env: CI: '' # (4) AWS 인증 (IAM 사용자 Access Key, Secret Key 활용) - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v1 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: ${{ env.AWS_REGION }} # (5) 빌드 결과물을 S3 버킷에 업로드 - name: Upload to AWS S3 run: | aws deploy push \ --application-name ${{ env.CODE_DEPLOY_APPLICATION_NAME }} \ --ignore-hidden-files \ --s3-location s3://$S3_BUCKET_NAME/$GITHUB_SHA.zip \ --source . # (6) S3 버킷에 있는 파일을 대상으로 CodeDeploy 실행 - name: Deploy to AWS EC2 from S3 run: | aws deploy create-deployment \ --application-name ${{ env.CODE_DEPLOY_APPLICATION_NAME }} \ --deployment-config-name CodeDeployDefault.AllAtOnce \ --deployment-group-name ${{ env.CODE_DEPLOY_DEPLOYMENT_GROUP_NAME }} \ --s3-location bucket=$S3_BUCKET_NAME,key=$GITHUB_SHA.zip,bundleType=zip
HTTPS 적용
- 화상 공유 서비스에서는 사용자들의 개인정보 및 영상 컨텐츠를 안전하게 보호하기 위해 HTTPS 프로토콜을 적용하였습니다. Amazon Certificate Manager(ACM)를 사용하여 SSL/TLS 인증서를 획득하고 웹 서버에 적용함으로써, 데이터 전송 중에 암호화된 연결을 제공하여 중간자 공격 등의 보안 이슈를 방지하고 있습니다. 이를 통해 사용자들은 안전하게 화상 공유 서비스를 이용할 수 있습니다.
4️⃣ 성장 경험
메모리 부족 문제 대응과 스와핑 도입
문제 상황
- 프리티어 사용 중 메모리 부족으로 서버 다운 발생
- 클라이언트 및 서버를 하나로 묶어 배포 시 인스턴스 부하 증가
- T2 마이크로에서 스몰로 변경하여도 서버 지속 다운 문제 발생
대응 방안
- 스왑 메모리 도입
- 스왑 메모리를 통해 물리적 메모리 부족 시 하드 디스크 등을 활용하여 확장
- 필요한 페이지만 물리적 메모리에 유지, 필요하지 않은 페이지는 하드 디스크에 저장하여 메모리 부족 현상 완화
- 가격 대비 메모리 용량을 효과적으로 확장
- 서버 캐싱 및 최적화
- 불필요한 리소스 및 서비스를 식별하여 비활성화
- 캐싱을 통한 불필요한 계산 회피 및 성능 최적화
- 클라이언트와 서버 간 효율적인 통신을 위한 최적화 작업 수행
- 비동기 처리 및 멀티 프로세스 관리
- 비동기 프로그래밍을 통한 효율적인 리소스 활용
- 멀티 프로세스 관리를 통한 부하 분산 및 안정성 향상
- 스레드 또는 프로세스 간 효율적인 작업 분배
- 인프라스트럭처 리뷰 및 확장
- 현재 인프라스트럭처의 한계를 검토하여 필요한 경우 업그레이드 또는 추가 확장
- 클라우드 서비스의 경우, 인스턴스 유형 및 사양 조정
- 로그 및 성능 모니터링 도구 활용
- 로그를 통한 메모리 사용 추적 및 문제점 파악
- 성능 모니터링 도구를 활용하여 시스템 상태 실시간 감시
- 문제 발생 시 빠르게 대응 가능한 환경 조성
문제 해결
- 메모리 부족 문제 해결을 위해 스왑 메모리 도입 및 다양한 최적화 방안을 적극적으로 활용하여 안정적이고 효율적인 서버 운영을 보장하고자 함.
WebRTC 연결 문제 해결과 로드밸런싱 주소 일치 문제
문제 상황
- WebRTC 연결 문제 발생
- 로드밸런서의 주소가 두 개로 나뉘어져 클라이언트 연결이 일관되지 않음
- 서버 연결 시 중복된 주소 등록으로 트래픽 처리에 문제 발생
해결 방안
- 로드밸런서 설정 확인
- 로드밸런서의 설정을 통해 트래픽이 균등하게 분산되도록 조정
- 로드밸런서의 주소가 하나로 일치하도록 설정 확인
- 라우터에 등록된 인스턴스 관리
- 중복된 주소 등록 방지를 위해 라우터에 등록된 서버 인스턴스를 하나로 유지
- 로드밸런서가 클라이언트 요청을 일관된 방식으로 분배할 수 있도록 관리
- 서버 연결 아이피 충돌 해결
- 서버 간 아이피 충돌로 발생한 통신 에러 해결을 위해 하나의 인스턴스만 사용
- 도메인 구매 및 적용으로 서버 간 아이피 충돌 방지
- 도메인을 통한 트래픽 관리 및 서버 연결 성공적으로 처리
문제 해결
- 로드밸런서 설정 조정 및 라우터에 등록된 인스턴스 관리로 주소 일치 및 트래픽 균형 조절
- 서버 연결 아이피 충돌 문제 해결을 통해 WebRTC 연결 문제 완화
- 도메인을 활용하여 트래픽을 효과적으로 관리하고 안정적인 서버 운영
WebSocket 관리 어려움과 데이터 소실 위험 대응을 위한 RabbitMQ 메시지 브로커 도입
문제 상황
- WebSocket 사용 시 발생하는 어려움과 위험
- 메시지 추적 어려움
- 데이터 소실의 위험
- 관리적인 측면에서의 어려움
해결 방안
- RabbitMQ 메시지 브로커의 도입
- 메시지 추적과 관리 간편화
- RabbitMQ를 활용하여 메시지 전송 및 수신 추적 용이화
- RabbitMQ의 큐 및 익스체인지를 활용하여 데이터 흐름을 투명하게 관리
- 데이터 소실 위험 완화
- RabbitMQ의 메시지 큐를 통해 안정적인 메시지 전달 보장
- 데이터 소실 가능성을 최소화하며 안정성 향상
- 메시지 포맷 표준화 및 인코딩
- JSON 또는 Protocol Buffers와 같은 표준화된 메시지 포맷 도입
- RabbitMQ를 통해 전송되는 메시지의 일관성 유지
- 서비스 간의 호환성 향상
- 실시간 로깅 및 모니터링 시스템 도입
- WebSocket 통신 내역 실시간 로깅 및 모니터링 시스템 구축
- 문제 발생 시 신속한 대응을 위해 로깅을 통한 실시간 모니터링
- 서비스 운영 효율성 향상
문제 해결
- RabbitMQ 메시지 브로커의 도입으로 WebSocket 관리 어려움과 데이터 소실 위험 완화
- 표준화된 메시지 포맷 및 실시간 모니터링 시스템 도입으로 관리적인 어려움을 극복하고 안정적인 서비스 운영을 목표로 함