안녕하세요, 백앤드 개발자 김원석입니다

사용자에게는 안정적인 서비스 경험을,
팀에는 신뢰할 수 있는 코드를 제공하고 싶은 백엔드 개발자 김원석입니다.

기능 구현에 그치지 않고 문제의 원인을 측정하고 분석한 뒤,
서비스의 안정성과 유지보수성을 고려한 해결책을 선택하고자 합니다.

소개

경험

2018.03~2024.02
아주대학교 수학과(주) 소프트웨어(복수)
2025.01~2025.08
LG U+ 유레카 백엔드 과정 수료
2026.07~
삼성청년SW·AI아카데미(SSAFY) 자바 Track 진행 중

수상

2025.06
LG U+ 유레카 종합 프로젝트(U-fit) 우수상 수상

U-FIT: 통신성향 파악 및 요금제 추천 챗봇 서비스 (WEB)

팀원: BE 7명

프로젝트 개요

‘U-fit’은 사용자의 통신 이용 패턴과 요구사항을 분석하여 적합한 요금제를 추천하고, AI 챗봇을 통해 통신 관련 정보와 상담을 제공하는 서비스입니다.

U-FIT 기술 구성: Vue.js, Spring Boot·Security, FastAPI·LangGraph, PostgreSQL·pgvector, Redis와 AWS
U-FIT 요금제 추천 챗봇 대화창과 요금제 대시보드를 포함한 서비스 화면

역할

  • 인증·인가: Spring Security와 JWT를 이용한 인증·인가 및 토큰 재발급 구현
  • AI 챗봇: LangChain·LangGraph 기반 질문 분류, 멀티턴 처리 및 RAG 파이프라인 설계·구현

U-FIT: 통신성향 파악 및 요금제 추천 챗봇 서비스 (WEB)

시스템 아키텍처

U-FIT 시스템 구성도: Vue.js 프런트엔드, Spring Boot API 서버, FastAPI 챗봇 서버, PostgreSQL pgvector 및 외부 LLM

API서버와 챗봇 서버를 분리하고, API 서버에서 사용자 인증과 서비스 데이터를 관리했습니다.

챗봇 서버는 대화 이력과 질문 의도를 바탕으로 처리 경로를 결정하고, 요금제 정보가 필요한 경우에만 pgvector 검색을 수행하도록 구성했습니다.

U-FIT: 1. 인증/인가

문제

  • API 서버와 챗봇 서버가 분리된 환경에서 세션 인증을 사용하려면 두 서버가 인증 상태를 공유해야 했습니다.
  • 이는 별도의 세션 저장소와 동기화 구조를 필요로 하며, 서버 간 의존성과 운영 복잡도를 높일 수 있었습니다.

전략

  • 두 서버가 공통 저장소 없이 사용자 인증 정보를 검증할 수 있도록 JWT 기반 Stateless 인증을 선택했습니다. API 요청은 Spring Security Filter Chain에서 일관되게 검증하고, 사용자 권한에 따라 접근 가능한 API를 구분했습니다.

결과

  • API 서버와 챗봇 서버가 별도의 세션 상태를 공유하지 않고도 동일한 인증 정보를 검증할 수 있게 됐습니다.
  • 인증과 권한 검사를 Security Filter Chain에 집중시켜 컨트롤러의 중복 검증 코드도 줄였습니다.

U-FIT: 2. RAG, LLM 설계

U-FIT 챗봇 처리 흐름도: 질문 필터링과 문맥 재작성, 요금제 추천 분기, 벡터 DB 검색 및 LLM 답변
  1. 1. 질문 재작성

    최근 대화와 현재 질문을 함께 분석해, 문맥에 의존하는 후속 질문을 독립적으로 이해할 수 있는 문장으로 재작성했습니다.

  2. 2. 처리 경로 분기

    안전성 검사와 서비스 관련성 판별 결과를 바탕으로 일반 대화, 통신 정보 검색, 요금제 추천 경로로 분기했습니다.

  3. 3. 관련 정보 검색

    통신 정보 또는 요금제 추천에 검색 근거가 필요한 경우에만 질문을 임베딩하고 pgvector에서 관련 문서를 조회했습니다.

설계 의도

  • 불필요한 검색을 줄이면서도 요금제 안내와 추천 답변은 최신 서비스 데이터를 근거로 생성하도록 품질과 비용 사이의 균형을 고려했습니다.

U-FIT: 2. RAG, LLM 설계

문제

  • 초기에는 사용자의 질문을 하나의 프롬프트에 전달해 분류와 답변 생성을 함께 처리했습니다.
  • 이 구조는 이전 대화가 생략된 후속 질문을 이해하기 어렵고, 서비스 범위를 벗어난 질문도 답변 생성 단계까지 전달되는 문제가 있었습니다.

해결

  • LangGraph의 상태에 원본 질문, 최근 대화, 재작성된 질문, 안전성 검사 결과와 추천 의도를 저장했습니다. 각 단계의 결과에 따라 다음 처리 경로를 결정하고, 서비스 범위 밖 질문은 검색과 답변 생성 전에 종료했습니다.
  • 요금제 추천이 필요한 질문에만 pgvector 검색을 수행해 질문 유형마다 필요한 처리만 실행하도록 구성했습니다.

결과

U-FIT RAG 및 LLM 설계 개선 결과
평가 항목개선 전개선 후
질문당 평균 LLM 호출2.6회1.9회
평균 응답 시간4.2초2.7초
P95 응답 시간6.8초4.4초
벡터 DB 검색 수행100건38건
평균 입력·출력 토큰3,240개2,180개

U-FIT: 회고

  • 처음 PGVector를 사용하면서 벡터 검색은 단순히 데이터를 임베딩해 저장하는 것으로 끝나는 것이 아니라, 문서 구성과 metadata 설계가 검색 품질을 크게 좌우한다는 점을 배웠습니다. 특히 요금제의 가격·데이터·혜택 정보를 하나의 검색 가능한 문장으로 가공하고, 원본 ID를 metadata로 관리하면서 실제 서비스 데이터와 벡터 데이터의 정합성이 중요하다는 것을 경험했습니다.
  • 또한 GPT와 Claude 모델을 교체해 사용하면서 동일한 프롬프트라도 의도 분류의 안정성, JSON 형식 준수, 추천 설명의 구체성, 응답 속도와 비용에서 차이가 발생한다는 점을 확인했습니다. 이를 통해 모든 과정에 하나의 모델을 사용하는 것보다, 분류 단계에는 일관성이 높은 저비용 모델을 사용하고 최종 답변에는 표현력이 좋은 모델을 사용하는 방식이 효율적이라고 판단했습니다.
  • 향후에는 모델별 분기 정확도와 검색 적합도, 응답 시간 및 비용을 정량적으로 측정해 최적의 모델 조합을 찾고 싶습니다. 또한 로컬 LLM도 적용해 외부 API 의존도와 비용을 줄이고, 개인정보를 외부로 전송하지 않는 온프레미스 환경에서 모델 크기와 양자화 수준에 따른 품질·속도 차이도 검증해 보고 싶습니다.

FireFly: OTT 콘텐츠 추천 서비스 (web)

팀원: BE 4명 FE 4명

프로젝트 개요

‘FireFly’는 사용자의 OTT 구독 정보와 콘텐츠 선호도를 바탕으로 여러 플랫폼의 콘텐츠를 탐색하고 개인화된 추천을 받을 수 있는 OTT 통합 서비스입니다.

FireFly 기술 구성: Next.js·React, Spring Boot·Batch, MySQL·Redis, AWS, Prometheus·Grafana
FireFly 모바일 서비스의 추천 결과, 콘텐츠 상세 정보 및 작품 찜하기 화면

역할

  • 백오피스: 콘텐츠 및 연관 데이터 관리 기능 구현
  • 데이터 처리: Spring Batch 기반 콘텐츠 변경 예약 및 일괄 처리 시스템 구축
  • 모니터링: Prometheus를 통한 메트릭 수집, Grafana대시보드 구축
  • 인프라: AWS VPC 구성 및 Bastion Host 운영 지원

FireFly: OTT 콘텐츠 추천 서비스 (web)

시스템 아키텍처

FireFly AWS 시스템 구성도: VPC의 Spring Boot·Batch 서버, RDS·Redis·S3 및 Prometheus·Grafana 모니터링

FireFly: 1. 백오피스

문제

  • 사용자의 콘텐츠 평가가 등록될 때마다 콘텐츠,장르,플랫폼,국가별 통계를 즉시 갱신했습니다.
  • 하나의 콘텐츠가 여러 장르와 플랫폼에 연결되어 있어 연관 데이터를 순회하는 과정에서 피드백 한 건당 약 40회의 조회·수정 쿼리가 발생했습니다. 요청량이 증가하면 여러 트랜잭션이 동일한 통계 데이터를 동시에 수정하면서 DB 경합과 처리 지연이 발생했습니다.

실패한 접근

  • 초기에는 사용자 응답 시간을 줄이기 위해 통계 집계 작업을 비동기로 분리했습니다. 그러나 집계 시점만 분리됐을 뿐 DB 쓰기 횟수는 줄지 않았고, 동시에 실행되는 트랜잭션과 커넥션 사용량이 증가했습니다
  • API 응답은 빨라졌지만 전체 집계 완료 시간과 DB 부하는 오히려 증가했습니다. 이를 통해 병목의 원인은 동기 처리 자체가 아니라 반복적인 데이터 조회와 수정이라는 점을 확인했습니다.

FireFly: 1. 백오피스

원인 분석

실행 쿼리와 트랜잭션 범위를 분석한 결과, 문제의 핵심은 동기 처리 여부가 아니라 반복적인 개별 조회와 수정이었습니다.

피드백 저장

├─ 콘텐츠 통계 조회 및 수정

├─ 장르별 통계 조회 및 수정 × N

├─ 플랫폼별 통계 조회 및 수정 × N

└─ 국가별 통계 조회 및 수정 × N

각 연관 데이터를 순회하면서 조회와 수정이 반복됐고, 같은 통계 데이터가 여러 번 갱신되고 있었습니다.

해결

  • 연관 데이터를 한 번에 조회한 뒤 애플리케이션 메모리에서 집계 결과를 계산하도록 변경했습니다. 이후 변경된 데이터만 일괄 반영해 반복적인 조회와 쓰기를 줄였습니다.
  • 또한 사용자 요청 처리와 통계 반영의 트랜잭션 범위를 분리하고, 실패한 집계 작업을 추적할 수 있도록 처리 결과를 기록했습니다.

결과

FireFly 백오피스 개선 결과
개선 전개선 후
피드백 1건당 쿼리최대 50회최대 8회
평균 처리 시간820ms210ms
P95 처리 시간1,740ms460ms
초당 처리량18 TPS63 TPS
DB 커넥션 사용38개14개

FireFly: 2. 배치 시스템 구축

문제

  • 관리자가 콘텐츠를 등록·수정·삭제할 때 변경 사항이 실시간으로 반영되면, 서비스 이용 중 콘텐츠 정보가 갑자기 바뀌어 사용자에게 혼란을 줄 수 있었습니다.
  • 콘텐츠는 장르, 플랫폼, 국가, 감독, 출연진 등 여러 데이터와 연결되어 있어 변경 요청을 처리할 경우 작업 시간이 길어지는 문제가 있었습니다.

해결

  • 관리자의 변경 요청과 실제 데이터 반영 시점을 분리했습니다.
  • 관리자 요청은 예약 작업으로 저장하고, 서비스 이용량이 적은 시간에 Spring Batch가 처리하도록 구성했습니다. 등록·수정·삭제 작업을 각각의 Step으로 분리하고 Chunk 단위로 처리했습니다.
    • 일시적인 DB 연결 오류: 최대 3회 재시도
    • 잘못된 개별 콘텐츠 데이터: 해당 항목만 제외하고 계속 처리
    • 처리 실패: 실패 원인과 대상 ID 저장
    • 작업 현황: Prometheus 메트릭 수집 및 Grafana 시각화

결과

  • 대량 변경 작업이 사용자 요청과 경쟁하지 않도록 실행 시점을 통제했습니다. 일부 콘텐츠 처리에 실패하더라도 전체 배치가 중단되지 않았으며, 실패 내역을 바탕으로 원인을 확인하고 재처리할 수 있게 됐습니다.

FireFly: 회고

  • 이번 프로젝트를 통해 비동기나 배치 같은 기술을 적용하기 전에 병목의 원인을 정확히 파악하는 것이 중요하다는 점을 배웠습니다. 피드백 집계 과정의 약 40회 DB 쓰기를 비동기로 처리했지만, 쓰기 횟수는 줄지 않아 오히려 부하가 증가하는 경험을 했습니다. 이를 통해 비동기는 병목을 해결하는 수단이 아니라 처리 시점을 분리하는 방식이며, 쿼리 수와 데이터 접근 구조를 먼저 개선해야 한다는 점을 배웠습니다.
  • 이후 관리자 요청과 실제 반영 시점을 분리하고, Spring Batch로 콘텐츠 변경 시점을 통제해 사용자 혼란과 데이터 불일치 가능성을 줄였습니다. 또한 Retry·Skip, 실패 이력 관리와 Prometheus, Grafana 모니터링을 구성하며, 기능 구현뿐 아니라 장애 대응과 운영 가시성까지 고려하는 백엔드 설계의 중요성을 배웠습니다.

Thank you

기술을 사용하는 개발자를 넘어,
문제와 선택을 설명할 수 있는 개발자가 되겠습니다.