Skip to content

vividswan/layered-cache-benchmark-k6

Repository files navigation

레이어드 캐시 성능 증명

Caffeine(로컬) + Redis(리모트) 레이어드 캐시가 읽기 TPS에 얼마나 영향을 주는지, K6 부하테스트로 DB만 / Redis만 / Caffeine+Redis 3단 비교합니다.

┌──────────────────────────────────────────────────────────────┐
│                        K6 부하 (100 VUs)                     │
└─────────────────────────┬────────────────────────────────────┘
                          │
                          ▼
┌──────────────────────────────────────────────────────────────┐
│                     Spring Boot API                          │
│                                                              │
│     ┌──────────┐   ┌────────────┐   ┌──────────────────┐    │
│     │ db-only  │   │ redis-only │   │     layered      │    │
│     │          │   │            │   │                  │    │
│     │  → DB    │   │ → Redis    │   │ → Caffeine       │    │
│     │          │   │   → DB     │   │   → Redis        │    │
│     │          │   │            │   │     → DB          │    │
│     └──────────┘   └────────────┘   └──────────────────┘    │
└──────────────────────────────────────────────────────────────┘

필요 환경

도구 버전 설치 확인
Docker & Docker Compose - docker --version
Java 21 java --version
K6 - k6 version

K6 설치: brew install k6 (Mac) / 공식 가이드


실행 방법

Step 1. 인프라 시작 + 10만건 시드

docker-compose up -d

첫 실행 시 10만건 상품 데이터가 자동 생성됩니다 (약 1~2분).

MySQL이 Ready 상태인지 확인:

docker logs -f cache-proof-mysql 2>&1 | grep "ready for connections"

ready for connections 메시지가 2번 나오면 준비 완료입니다. Ctrl+C로 로그 확인을 종료하세요.

데이터 확인 (선택):

docker exec cache-proof-mysql mysql -uroot -proot cache_proof -e "SELECT COUNT(*) FROM product;"

결과가 100000이면 성공입니다.


Step 2. 테스트 실행

터미널 2개를 사용합니다. 하나는 앱 실행, 하나는 K6 실행.

2-A. DB Only 모드

# 터미널 1: 앱 시작
CACHE_MODE=db-only ./gradlew bootRun
# 터미널 2: K6 부하테스트
k6 run k6/load-test.js

테스트 완료 후 Ctrl+C로 앱을 종료합니다.

2-B. Redis Only 모드

# 터미널 1: 앱 재시작
CACHE_MODE=redis-only ./gradlew bootRun
# 터미널 2: K6 부하테스트
k6 run k6/load-test.js

2-C. Layered 모드 (Caffeine + Redis)

# 터미널 1: 앱 재시작
CACHE_MODE=layered ./gradlew bootRun
# 터미널 2: K6 부하테스트
k6 run k6/load-test.js

Step 3. 결과 비교

K6 출력에서 아래 항목을 비교합니다:

http_req_duration ← avg, p(50), p(95), p(99)
http_reqs         ← total / duration = TPS
detail_latency    ← 상품 상세 조회 latency
list_latency      ← 상품 목록 조회 latency

결과 기록 예시

모드 avg p(95) p(99) TPS
DB Only 3.17 ms 8.70 ms 20.98 ms 2,736 /s
Redis Only 1.34 ms 3.69 ms 8.06 ms 2,931 /s
Layered 1.08 ms 3.40 ms 11.26 ms 2,954 /s

환경(CPU, 메모리, Docker 리소스)에 따라 수치가 달라집니다. 중요한 것은 모드 간 상대적 차이입니다.

참고: 이 테스트는 상품 ID를 1~100,000 균등 랜덤으로 요청하므로, 캐시에 가장 불리한 조건입니다. Layered의 p(99)가 Redis Only보다 높은 것은 Caffeine miss 시 cold path(Redis+DB 동기 로딩) 때문입니다. 실무에서 인기 상품 위주로 트래픽이 집중되면 Caffeine hit rate가 올라가며 p(99)도 개선됩니다.


유틸리티 엔드포인트

엔드포인트 설명
GET /api/mode 현재 캐시 모드 확인
GET /api/stats DB 쿼리 수, Redis/Caffeine hit/miss 통계
POST /api/stats/reset 통계 초기화
POST /api/cache/reset 모든 캐시(Redis + Caffeine) 초기화
# 예시: 통계 확인
curl -s http://localhost:8080/api/stats | python3 -m json.tool

프로젝트 구조

round5-blog-proof/
├── docker-compose.yml          # MySQL + Redis
├── build.gradle.kts            # Spring Boot + Kotlin
├── k6/
│   └── load-test.js            # K6 부하테스트 스크립트
├── sql/
│   ├── 01-schema.sql           # 테이블 + 인덱스 생성
│   └── 02-seed-data.sql        # 10만건 시드 데이터
└── src/main/kotlin/.../
    ├── Application.kt          # Spring Boot 메인
    ├── Product.kt              # JPA Entity + DTO
    ├── ProductRepository.kt    # Spring Data JPA
    ├── ProductFacade.kt        # 3-mode 캐시 전략 (핵심)
    └── ProductController.kt    # REST API

ProductFacade — 핵심 로직

CACHE_MODE 환경변수에 따라 읽기 경로가 달라집니다:

  • db-only: ProductRepository → DB 직접 조회
  • redis-only: Redis → miss 시 DB 조회 → Redis에 저장
  • layered: Caffeine(2초 리프레시) → Redis → DB

동일한 API, 동일한 요청, 캐시 모드만 다르게 해서 순수하게 캐시 레이어의 효과만 비교합니다.


정리

# 컨테이너 + 볼륨 삭제 (데이터 초기화)
docker-compose down -v

다시 docker-compose up -d하면 10만건이 새로 생성됩니다.

About

Caffeine(로컬) + Redis(리모트) 레이어드 캐시가 읽기 TPS에 얼마나 영향을 주는지, K6 부하테스트로 DB만 / Redis만 / Caffeine+Redis 3단 비교

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors