최종대본

프로젝트, 팀 소개

안녕하세요

저희는 부스트캠퍼 300 분을 모시고 즐겁게 실시간으로 퀴즈를 진행할 수 있는 BooQuiz 프로젝트를 진행 중인 Web08 하하 팀입니다.

저는 이번주 발표를 맡은 J074 김현우입니다. 저희가 한번 씩 발표를 꼭 하자라는 그라운드룰이 있어서 이번주를 제가 맡게 되었습니다.

저희 기술 스택은 타입스크립트, WebSocket을 공통으로 사용하고 프론트는 리액트, vite, shadcn, tailwind를 사용 중이고 백엔드는 Nest.js를 사용하고 있습니다.

이번주 핵심 작업 내용

먼저 저희가 지난 주말을 포함해서 4주차에 진행한 주요 작업 내용에 대해서 공유드리겠습니다.

[공통] 모각글 활동

먼저 말씀드릴 내용은 정기적으로 진행하는 모각글입니다. 저희는 그라운드룰의 일환으로 매주 토요일 오전 10시에 온라인으로 가볍게 모여서 글을 작성하는 시간인 모각글 시간을 가졌습니다.

이번주는 프론트엔드에서도 테스트코드를 작성하기 시작해서 해당 부분과 관련된 내용, 그리고 도커를 통한 샌드박스 환경 구축 그리고 웹소켓을 사용하는 팀이다 보니 그와 관련된 고민에 대해서 글을 적어보게 되었습니다. 링크를 올려드리니 편하게 읽어보시면 좋을 거 같습니다.

**[WebSocket 통신 난독화](<https://www.notion.so/WebSocket-72c27e4fb24f4473be05cc2238b1781a?pvs=21>)**  

[[FE] Vitest 테스트 코드 작성하기](<https://www.notion.so/FE-Vitest-140f1897cdf5801587c5cb35829becda?pvs=21>) 

[프론트엔드에서 테스트 코드를 작성해야 되는 이유](<https://www.notion.so/a0aaa7cc860445a49e000a58f4c11e57?pvs=21>) 

[도커를 이용한 테스트 환경 구축](<https://www.notion.so/a4e628e3a2664f10bc5ccd3915e02436?pvs=21>) 

[웹소켓 + 리버스 프록시(엔진엑스)](<https://www.notion.so/2325bd00d5b04718b295857ff2dbfcef?pvs=21>) 

[WsAdapter 커스터마이징](<https://www.notion.so/WsAdapter-b702ace55d4c46be9c9bb97df1c50652?pvs=21>)

[인프라] 테스트 서버 환경 세팅

Docker 기반 테스트 환경 구축에 대해 발표드리겠습니다. 먼저 테스트 환경을 구축하게 된 배경을 말씀드리겠습니다. CI/CD 환경을 구축한 이후, 실제 배포 과정에서 여러 이슈들이 발생했습니다. 특히 데모데이 준비 과정에서, 변경사항을 실제 운영 환경에 적용하기 전에 안전하게 검증할 수 있는 환경이 필요했습니다. 이러한 문제를 해결하기 위해 저희는 Docker 기반의 테스트 환경을 구축했습니다. 구축한 테스트 환경은 실제 운영 환경과 동일한 구성으로 테스트가 가능하며, 변경사항 브랜치에서 develop을 거쳐 main으로 이어지는 과정에서 안전한 검증이 가능합니다. 또한 운영 서비스에 전혀 영향을 주지 않는 완전한 격리 환경을 제공합니다. Docker를 선택한 주된 이유는 리소스 효율성과 경제성입니다. 현재 저희 프로젝트는 한정된 자원과 작은 서비스 규모를 가지고 있어, 단일 공인 IP와 서브도메인을 활용하면서 최소한의 비용으로 운영 환경과 테스트 환경을 분리할 수 있는 솔루션이 필요했습니다. 물론 Docker 외에도 여러 대안을 검토했습니다. 첫 번째로 TestContainers라는 NestJS의 E2E 테스트용 라이브러리를 고려했는데, 이는 동적으로 테스트 환경을 생성하고 삭제할 수 있지만 실제 배포 환경을 정확하게 검증하기는 어렵다는 한계가 있었습니다. 두 번째로 별도의 스테이징 환경 구축을 고려했지만, 현재 프로젝트 규모에서는 비용 부담이 너무 컸습니다. 결국 저희는 샌드박스와 스테이징 환경의 장점을 모두 가진 Docker 기반 통합 환경을 선택하게 되었습니다. 구현 과정에서 발견한 장단점도 말씀드리겠습니다. 장점으로는 운영 환경과 완전히 동일한 구성으로 정확한 테스트가 가능하다는 점과, Public Subnet의 nginx 서버를 재활용하여 비용을 절감할 수 있다는 점이 있습니다. 또한 단일 IP와 서브도메인을 활용해 효과적으로 환경을 분리할 수 있었습니다. 반면 단점으로는 Docker 리소스를 추가로 관리해야 하고 nginx 프록시 설정의 복잡도가 증가한다는 점이 있었습니다. 기술적인 측면에서는 성능과 확장성을 중점적으로 고려했습니다. Docker 컨테이너의 리소스 제한을 적절히 설정하고 nginx 프록시 설정을 최적화했습니다. Public Subnet의 nginx 서버가 테스트 서버로 요청을 프록시하는 방식을 채택하여 효율적인 요청 처리가 가능하도록 구성했으며, 서브도메인을 통한 환경 분리로 향후 확장 가능성도 고려했습니다. 특히 이 테스트 환경의 실효성은 어제 진행된 4주차 배포 목표를 위한 프론트엔드와 백엔드 통합 과정에서 잘 입증되었습니다. 프론트엔드 팀에서 개발한 새로운 기능들과 백엔드의 API 변경사항을 실제 운영 환경에 배포하기 전에 Docker 테스트 환경에서 먼저 검증할 수 있었습니다. 이를 통해 실제 배포 과정에서 발생할 수 있는 여러 이슈들을 사전에 발견하고 해결할 수 있었으며, 특히 WebSocket 연결과 관련된 문제들을 안전하게 테스트할 수 있었습니다. 결과적으로 실제 운영 환경 배포 시에는 훨씬 더 안정적이고 신속하게 진행할 수 있었습니다. 결과적으로 이러한 Docker 기반 테스트 환경 구축을 통해 안전하고 효율적인 배포 프로세스를 확립할 수 있었습니다. 향후에도 지속적인 모니터링과 개선을 통해 더 나은 개발 환경을 만들어나갈 계획입니다.

[BE] ws에서의 사용자 식별 문제 처리

300명 이상의 대규모 동시 접속 환경에서 웹소켓 연결이 예상보다 자주 끊기는 현상이 발생했습니다. .

가장 큰 문제는 웹소켓이 재연결될 때마다 소켓 정보가 변경되면서 동일한 사용자를 식별할 수 없게 되는 상황이었습니다. 예를 들어, 퀴즈를 진행하는 중에 사용자의 연결이 잠시 끊겼다가 복구되면, 시스템은 이전 사용자와 새로 연결된 사용자를 다른 사람으로 인식하게 되는 거죠.

기본적으로 ws 모듈은 방 관리나 브로드캐스팅 같은 기능을 지원하지 않기 때문에, 저희가 직접 사용자 식별 방법을 구현해야 했습니다. 여러 방안을 검토한 끝에, 세션 기반의 사용자 식별 방식을 채택했습니다.

구체적인 구현은 이렇게 진행했습니다.

handleConnection(client: WebSocket) {
    const cookies = parse(request.headers.cookie);
    const sessionId = cookies['connect.sid'].split('.').at(0).slice(2);
    client['sessionId'] = sessionId;
}