Skip to content

humandelivery/backend

Repository files navigation

실시간 택시 배차 시스템

인간배달 로고

발표자료

발표 PPT

팀원 소개

이름 역할 GitHub
김진규 백엔드 개발 https://github.com/gimjingyu
두희님 백엔드 개발 https://github.com/Duhikim
혜원님 택시 클라이언트 개발 https://github.com/choihywon
정환님 승객 클라이언트 개발 https://github.com/jeonghwan123

프로젝트 개요

이 프로젝트는 백엔드 서버의 성능 진단 및 병목 현상 분석을 목적으로 기획되었으며,
실시간 메시지 처리 시스템의 모델로 **택시 배차 서비스(예: 카카오택시)**를 선정하였습니다.

실시간으로 위치 정보와 상태 정보를 주고받는 구조는 서버에 지속적인 트래픽을 발생시키므로,
메시지 큐 시스템, Redis, WebSocket 등 다양한 기술을 활용해 성능을 테스트하고 개선하는 것이 핵심 목표입니다.


주요 목표 및 기술 스택

  • 메시지 큐 성능 비교: Kafka, RabbitMQ, BlockingQueue 등
  • 부하 테스트: 자체 자바 프로세스 + k6
  • 모니터링 시스템: Spring Actuator + Prometheus + Grafana
  • WebSocket + STOMP + JWT 인증 처리
  • Redis 기반 캐시 및 위치 정보 처리

사용 기술: Spring Boot, Kafka, Redis, MySQL, k6, Prometheus, Grafana, RabbitMQ


시스템 아키텍처

  • WebSocket 기반 실시간 양방향 통신
  • STOMP 프로토콜을 통한 주제 기반 메시지 전송
  • Redis GEO 자료구조로 반경 내 택시 탐색
  • Kafka 기반 콜 요청 분산 처리
  • JWT 기반 사용자 인증 및 Principal 설정

전체 흐름 요약

  1. 승객은 출발지/도착지를 입력해 콜 요청을 전송
  2. 서버는 요청을 Kafka에 전송, 메시지 소비 후 Redis에서 인접 택시 탐색
  3. 택시기사는 요청을 수신하고 수락 여부 결정 → 서버로 응답
  4. 서버는 Redis의 SET NX 명령어로 선착순 배차 처리
  5. 배차 완료 후 위치 정보는 WebSocket을 통해 주기적으로 주고받음
  6. 모니터링 스케줄러가 비정상 상태를 감지하고 자동 취소 처리 가능

핵심 기술 설명

Redis + SET NX

  • 콜 요청은 고유 키(call:{callId})로 Redis에 저장
  • 택시기사가 콜을 수락하면 SET NX로 해당 키에 자신의 ID 저장
  • 먼저 저장한 기사만 배차 확정 → 동시성 제어 및 분산 락 구현
  • Lua 스크립트로 Redis 조회 + SET을 원자적으로 처리

WebSocket + STOMP + JWT

  • WebSocket 연결 시 JWT를 헤더에 포함
  • Spring Security ChannelInterceptor에서 토큰 검증 후 Principal 설정
  • @MessageMapping 메서드에서 자동으로 사용자 정보 접근 가능
  • @SendToUser로 특정 사용자에게 메시지 응답 가능

Kafka

  • 다수의 서버 인스턴스에서 안정적으로 메시지 처리 가능
  • Partition을 활용한 메시지 분산 처리 구조
  • 처리량, 확장성, 장애 복구에 유리

모니터링

  • Spring Actuator로 JVM 지표 노출
  • Prometheus가 메트릭 수집
  • Grafana로 실시간 시각화
  • Kafka 상태도 함께 모니터링 가능

성능 테스트 & 트러블슈팅

부하 테스트

  • 승객/기사 각 70명씩 총 140개 프로세스 실행
  • 내장 브로커 vs RabbitMQ 브로커 릴레이 비교
  • CPU, 힙 메모리, 응답 속도 등 다양한 항목 측정

주요 이슈: 중복 배차

  • 문제: 동일한 택시기사가 여러 콜을 수락하는 현상 발생
  • 원인: 상태 조회와 SET NX가 분리되어 동시성 이슈 발생
  • 해결: Lua 스크립트로 두 연산을 원자적으로 처리

프로젝트 일정

  • 1주차: 기획 및 아키텍처 설계
  • 2주차: 개발, 테스트, 성능 개선

팀 구성 및 협업 방식

  • 김진규 (발표자), 두희님 – 백엔드 개발
  • 혜원님, 정환님 – 클라이언트 개발
  • 이벤트 스토밍으로 도메인 모델 정리
  • 기술 공유 및 학습 문서화 적극 진행

개선점 및 회고

  • WebSocket 테스트 코드 미작성은 아쉬움
  • 성능 비교 분석이 예상보다 깊이 있게 못 이루어짐
  • 하지만 실시간 시스템 아키텍처에 대한 실전 감각을 익힌 좋은 기회였음

마무리

이 프로젝트를 통해 다양한 실시간 처리 기술과 성능 개선 방법론을 실습할 수 있었으며,
향후 실제 서비스 수준에서도 적용 가능한 인사이트를 많이 얻었습니다.

멘토 리뷰

Redis 클러스터는 데이터를 해시 슬롯 기반으로 분산 저장합니다. → 하나의 Lua 스크립트에서 여러 키가 서로 다른 노드에 존재할 경우, Redis는 "CROSSSLOT" 오류를 반환하며 스크립트 실행이 실패합니다.

따라서 Redis 클러스터에서는 Lua 스크립트의 원자성을 보장하기 어렵고, 운영 환경에서는 락만 Redis에서 잡고, 실제 로직은 애플리케이션 서버에서 실행하는 방식이 더 권장됩니다.

이처럼 분산 환경에서는 Redis를 단순한 분산 락 도구로 사용하고, 슬롯 충돌을 피하거나 키 해싱을 일관되게 유지하려면 해시 태그(hash tag, 예: user:{123}:lock)를 활용해야 합니다.

About

springboot backend server

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •  

Languages