<aside>
📒 1. 프로젝트 개요
- 프로젝트 소개
- 영화, 드라마, 스포츠 등 다양한 콘텐츠를 큐레이팅하고 공유하고 실시간 같이 보기 기능까지 제공하는 소셜 서비스로, 사용자들은 자신만의 플레이리스트를 만들고, 다른 사용자와 소통하며 콘텐츠 경험을 확장할 수 있는 서비스입니다.
- 핵심 기능
- 콘텐츠 관리/리뷰 기능
- 다른 유저 팔로우 기능
- 다른 유저와 DM(메시지) 기능
- 실시간 알림 기능 제공
- 플레이리스트 생성 및 구독 기능
- 자신의 플레이리스트를 생성해서 콘텐츠를 추가할 수 있는 기능
- 다른 사용자의 플레이리스트를 구독할 수 있는 기능
- 실시간 채팅 기능
- 동일한 콘텐츠를 보고있는 사용자끼리 실시간 채팅 기능
</aside>
<aside>
📝 2. 담당한 작업
- 실시간 채팅
- STOMP/WebSocket 기반으로 실시간으로 같은 콘텐츠를 보고 있는 유저화 채팅할 수 있는 기능 구현
- Redis의 Pub/Sub을 활용해 분산환경에서 작동될 수 있도록 구현
- 실시간 세션 관리
- 유저가 어느 콘텐츠를 시청하고 있는지에 대한 데이터 (실시간 세션) 관리
- OpenSearch (ElasticSearch)로 서치 고도화
- 기존 QueryDSL로 구현된 서치 기능을 OpenSearch로 고도화
- 데이터 동기화 작업 구현
- 데이터가 존재하지 않으면 PostgreSQL에서 데이터를 불러들임
- 배치 처리, 콘텐츠가 수동 등록/추가/삭제, 그리고 리뷰가 등록/삭제 될때 OpenSearch에도 콘텐츠 데이터 동기화 기능 구현
</aside>
<aside>
📈 3. 기술적 성과
- 실시간 채팅 / 실시간 시청
- 기술 스택
- 백엔드: Java 17, Spring Boot 3.x, Spring Security
- 데이터베이스: PostgreSQL, Spring Data JPA, QueryDSL
- WebSocket/STOMP, Redis (Pub/Sub)
- 테스팅**:** JUnit 5, Mockito (단위 테스트), Actuator (성능 측정)
- Docker compose
- 주요 기능
- 사용자가 콘텐츠 상세 페이지에 진입했을 때, 현재 같은 콘텐츠를 보고 있는 다른 사용자들의 목록과 입장/퇴장 상태를 실시간으로 동기화하는 기능을 구현
- 네트워크 지연으로 인해 HTTP 요청과 WebSocket 연결 순서가 뒤바뀌더라도 데이터가 꼬이지 않도록, 세션 생성 로직에 멱등성 보장
- 사용자가 비정상적으로 브라우저를 종료하거나 페이지를 이탈할 때(
Unsubscribe, Disconnect), Redis와 DB의 상태를 즉시 정리하여 실제 접속자와 표시되는 숫자 간의 오차를 최소화
- OpenSearch 도입 및 마이그레이션
- 기술 스택
- 백엔드: Java 17, Spring Boot 3.x
- 데이터베이스**:** PostgreSQL (QueryDSL, Spring Data JPA)
- 서치 엔진**:** OpenSearch (AWS OpenSearch Service, Local Docker)
- Text Analysis: Nori Analyzer (한국어 형태소 분석기 -
nori_tokenizer)
- 테스팅**:** JUnit 5, Mockito (단위 테스트), Actuator (성능 측정)
- Docker Compose
- 주요 기능
- QueryDSL과 Cursor Pagination을 활용한 레거시 조회 로직을 분석하고, 이를 OpenSearch의 searchAfter API로 마이그레이션하여 대용량 데이터 페이징 성능 확보
- 기존 SQL
LIKE 패턴 매칭(%keyword%)의 Full Table Scan으로 인한 성능 저하(약 1.8s)를 해결하기 위해 역색인(Inverted Index) 구조의 OpenSearch 도입.
- 검색 요청 응답 시간을 평균 1.8s에서 0.5s로 약 72% 단축 (3.5배 성능 향상).
</aside>
<aside>
🛠️ 4. 문제점 및 해결 과정
- 데이터 동기화 문제
- 발생한 문제
- 사용자가 컨텐츠 페이지에 진입했을 때 실제로 입장이 처리되었음에도 화면상 시청자 목록에는 본인이 포함되지 않거나 시청자 수가 잘못된 수로 표시되는 현상
- 특이사항 - DB를 확인해보면 정상적으로 데이터가 저장되어있는 데이터 불일치 상태
- 원인 분석
- 원인: 프로토콜 간 실행 속도 차이로 인한 레이스 컨디션
- 기존 로직은 웹소켓 연결(입장 처리/저장) → HTTP 요청(목록 조회) 순서를 가정하고 작성됨
- Cold Start (새로고침/첫 진입): 웹소켓은 핸드셰이크 과정 때문에 연결이 느려, HTTP 조회 요청이 먼저 실행되어버림 (저장 전이라 빈 목록 조회).
- 그 이후: 이미 연결된 웹소켓 이벤트가 HTTP 요청보다 더 빨리 실행됨 (반대 상황 발생).
- 결국, 두 요청 중 누가 먼저 도착할지 보장할 수 없는데 순서를 가정한 것이 원인이었음
- 해결책: 멱등성 보장 로직 도입
- 입장 처리의 책임을 한쪽(웹소켓)에만 두지 않고, 컨트롤러와 EventListener(WebSocket) 양쪽 모두에서 호출 가능한
joinSession() 메서드를 구현
- 배운 점
- 실행 순서를 가정하지 말 것 - HTTP 요청과 비동기 이벤트(WebSocket)가 병렬로 발생할 때, 네트워크 환경이나 브라우저 상태에 따라 실행 순서는 언제든 뒤바뀔 수 있음을 배웠습니다.
</aside>
<aside>
💡 5. 협업 및 피드백
- 이슈카드와 일정관리를 다들 너무 잘해주셔서 큰 문제 없이 협업이 수월했고 프로젝트를 마칠 수 있었다. 또한 할일을 명확히 분리를 해서 협업하는 동안 어디가 꼬이거나 문제가 생기는 일도 없었다. 이 덕분에 트러블슈팅과 브랜치 관리도 헷갈리지 않고 수월하게 할 수 있었다.
- 코드래빗을 적용한 이후 코드리뷰하는 시간을 아끼고, 사람이 쉽게 찾지 못하는 버그나 개선사항을 찾아줘서 팀의 생산성으로 크게 높힐 수 있었다고 생각한다.
</aside>
<aside>
💾 6. 코드 품질 및 최적화
- 변수/메서드 이름을 한눈에 알기 쉽게 썼고 반복적인 코드는 메서드로 따로 리팩토링하였다. 또한 이해하기 어려운 코드에는 읽는 사람을 배려해서 주석을 달았다.
- TDD를 적용하여 맡은 부분의 테스트 커버리지를 확보할 수 있었다.
- Opensearch를 도입해 검색 요청 응답 시간을 평균 1.8s에서 0.5s로 약 72% 단축 시킬 수 있었다 (3.5배 성능 향상).
</aside>
<aside>
</aside>