Spring Boot + MySQL + Redis + k6 + InfluxDB + Grafana로 캐시 미스 전략을 비교하는 실험용 프로젝트입니다.
핵심 비교 대상은 4가지입니다.
db-direct: 캐시 없이 MySQL 직조회ttl-jitter: TTL을 랜덤화하지만 같은 키 폭주 자체는 막지 못하는 전략distributed-lock: 캐시 미스 시 Redis 분산 락으로 최초 1개 요청만 DB 조회precache: 만료 전에 캐시를 미리 채워 cache miss 순간 자체를 줄이는 전략
- 앱 대시보드:
http://localhost:8080 - Grafana:
http://localhost:3000/d/cache-stampede-lab - InfluxDB:
http://localhost:8086 - MySQL:
localhost:3306 - Redis:
localhost:6379
흐름은 아래처럼 나뉩니다.
- 서비스 조회 대상 DB:
MySQL - 캐시:
Redis - 부하 생성:
k6 - 결과 저장:
InfluxDB - 시각화:
Grafana
docker compose up -d./gradlew bootRun기본 연결 정보:
- MySQL:
cache_lab/root/root - Redis:
localhost:6379 - Cache TTL:
30초
주요 환경변수:
MYSQL_HOST,MYSQL_PORT,MYSQL_DATABASE,MYSQL_USERNAME,MYSQL_PASSWORDREDIS_HOST,REDIS_PORTDB_SIMULATED_LATENCY_MSCACHE_TTL_SECONDSCACHE_TTL_JITTER_SECONDS
Grafana datasource와 starter dashboard는 자동 provisioning 됩니다.
- URL:
http://localhost:3000/d/cache-stampede-lab - admin:
admin - password:
admin
익명 조회도 켜두었기 때문에 index.html 안 iframe에서도 바로 볼 수 있습니다.
curl http://localhost:8080/api/db/products/1
curl "http://localhost:8080/api/redis/products/1?mode=ttl-jitter"
curl "http://localhost:8080/api/redis/products/1?mode=distributed-lock"
curl "http://localhost:8080/api/redis/products/1?mode=precache"curl -X DELETE http://localhost:8080/api/redis/products/1
curl -X DELETE http://localhost:8080/api/redis/products
curl -X POST "http://localhost:8080/api/redis/prewarm?mode=precache&ids=1"
curl -X POST "http://localhost:8080/api/redis/prewarm?mode=ttl-jitter&ids=1,2,3,4,5&ttlSeconds=30&jitterSeconds=12"k6 run --out influxdb=http://localhost:8086/k6 k6/db-load.jsMODE=ttl-jitter k6 run --out influxdb=http://localhost:8086/k6 k6/redis-load.js
MODE=distributed-lock k6 run --out influxdb=http://localhost:8086/k6 k6/redis-load.js
MODE=precache k6 run --out influxdb=http://localhost:8086/k6 k6/redis-load.jsredis-load.js는 기본적으로 1000 VU x 1 iteration burst로 동작합니다.
k6 run --out influxdb=http://localhost:8086/k6 k6/compare.jscompare.js는 다음 순서로 실행됩니다.
db-directttl-jitterdistributed-lockprecache
각 구간은 Grafana에서 strategy 태그 기준으로 분리해서 볼 수 있습니다.
MODE=db-direct k6 run --out influxdb=http://localhost:8086/k6 k6/vuser-ramp.js
MODE=ttl-jitter k6 run --out influxdb=http://localhost:8086/k6 k6/vuser-ramp.js
MODE=distributed-lock k6 run --out influxdb=http://localhost:8086/k6 k6/vuser-ramp.js
MODE=precache k6 run --out influxdb=http://localhost:8086/k6 k6/vuser-ramp.js기본 단계는 10 -> 50 -> 100 -> 200 -> 400 VU입니다.
ttl-jitter는 근본 해결책이 아닙니다.- 같은 키가 miss 나는 순간의 폭주는 여전히 남습니다.
distributed-lock은 최초 1개만 DB를 치고 나머지는 기다린 뒤 캐시를 재사용합니다.precache는 miss 자체를 줄여서 가장 안정적으로 보일 수 있습니다.
p95 latencyp99 latencyrequest ratefailure rate
이 프로젝트의 starter dashboard는 그 4개 패널을 기본으로 제공합니다.