로컬 Spring 애플리케이션과 Docker 기반 MySQL, Redis, Prometheus, Grafana 환경입니다.
docker compose up -d
./gradlew bootRun기본 접속 주소입니다.
- MySQL은
localhost:3306입니다. - Redis는
localhost:6379입니다. - Prometheus는
http://localhost:9090입니다. - Grafana는
http://localhost:3000입니다. - Actuator Prometheus 지표는
http://localhost:8080/actuator/prometheus입니다.
Grafana 기본 계정은 admin과 admin이며, 처음 시작하면 Prometheus 데이터 소스와 Redis Performance 대시보드가 자동으로 등록됩니다.
기본값은 로컬 개발용입니다. MYSQL_DATABASE, MYSQL_USER, MYSQL_PASSWORD, MYSQL_ROOT_PASSWORD, MYSQL_EXPORTER_USER, MYSQL_EXPORTER_PASSWORD, REDIS_PASSWORD, GRAFANA_ADMIN_USER, GRAFANA_ADMIN_PASSWORD로 Compose 값을 변경할 수 있습니다.
Spring 애플리케이션은 MYSQL_HOST, MYSQL_PORT, MYSQL_DATABASE, MYSQL_USER, MYSQL_PASSWORD, REDIS_HOST, REDIS_PORT, REDIS_PASSWORD를 사용합니다.
MySQL 초기화 계정 정보를 변경하려면 기존 named volume을 제거한 뒤 다시 시작해야 합니다.
GET /videos/{id}는 Redis에 동영상 조회 DTO를 JSON으로 저장합니다. JPA 엔티티를 직접 캐시하지 않아 지연 로딩 프록시를 직렬화하지 않습니다.
- 캐시 키는
video:detail:{id}이며, 신선한 값은 30초 동안 사용합니다. - 신선 TTL이 지나도 30초 동안 stale 값을 즉시 반환합니다. 이때
video:detail:lock:{id}Lock을 획득한 요청 한 건만 DB를 비동기로 조회해 캐시를 갱신합니다. - Lock은 UUID 토큰과 10초 TTL을 사용하며, Lua 스크립트로 Lock 소유자만 해제합니다.
- 존재하지 않는 영상은 5초 동안 음수 캐시합니다.
- Redis 오류나 최초 캐시 미스의 Lock 대기 1초 초과 시에는 DB로 조회를 대체합니다.
VIDEO_CACHE_ENABLED로 동일 애플리케이션에서 캐시 적용 전후를 비교할 수 있습니다. 기본값은 true입니다.
VIDEO_CACHE_ENABLED=false ./gradlew bootRun
VIDEO_CACHE_ENABLED=true ./gradlew bootRunDocker Compose와 애플리케이션을 실행한 뒤 k6가 설치된 환경에서 아래 명령을 실행합니다.
K6_WEB_DASHBOARD=true k6 run k6/video-cache-stampede.js명령이 실행되는 동안 http://localhost:5665/ui/?endpoint=/에서 k6 요청 수, 응답 시간, 체크 성공률을 실시간으로 확인할 수 있습니다. 이 대시보드는 k6 실행 프로세스에 포함되므로 테스트가 종료되면 더 이상 접속할 수 없습니다.
스크립트는 회원과 영상을 HTTP API로 자동 생성한 뒤, 해당 영상의 캐시를 채우고 31초 대기해 stale 상태로 만듭니다. 이후 동일 영상에 200개 동시 요청을 보내며, 실행 마지막에는 Actuator의 video_find_by_id_db_load_total 증가량을 출력합니다. 실행마다 테스트 회원과 동영상 데이터가 추가됩니다.
동일한 로컬 환경에서 캐시 비활성·활성 실행을 각각 수행하고, k6 요약의 http_req_duration p95와 출력된 DB 조회 증가량을 아래 표에 기록합니다.
| 설정 | DB 조회 증가량 | p95 |
|---|---|---|
VIDEO_CACHE_ENABLED=false |
200 | 141.84ms |
VIDEO_CACHE_ENABLED=true |
1 | 89.18ms |
캐시 활성화 시 정상 DB 응답 시간이 Lock 대기 시간 1초 이내라는 전제에서, 부하 구간의 DB 조회 증가량은 1이어야 합니다. p95는 머신과 실행 상태에 따라 달라지므로 고정된 통과 기준으로 사용하지 않고 실측값을 비교합니다.
Grafana에서 캐시 적용 전후의 요청률과 DB 조회율을 비교하려면 아래 시나리오를 실행합니다.
K6_WEB_DASHBOARD=true k6 run k6/video-cache-sustained.js스크립트는 캐시를 채운 동일 영상에 초당 50회씩 60초간 요청합니다. 캐시 활성 상태에서는 30초 fresh TTL 뒤 stale 갱신이 한 번 일어나므로 DB 조회 증가량이 적게 나타나며, 비활성 상태에서는 대부분의 요청이 DB를 조회합니다. 두 설정에서 각각 실행한 뒤 Grafana의 15분 시간 범위에서 Video GET Request Rate, Video DB Load Rate, Video DB Loads In Selected Range 패널을 비교합니다. Spring 애플리케이션 지표는 이 관측을 위해 1초 간격으로 수집됩니다.