buildrisk-radar

ADR-022 조회 캐시 — 목록까지 read-through, 무효화는 Job 이 끝나는 한 곳에서

배경 (2026-09-26 부하 시험) 메모리 문제를 고친 뒤에도 부하 중 db 가 CPU 152% 를 쓰며 목록 API 가 300~600 ms 로 느려졌다. 기업 상세 · 수주 · 백테스트는 Redis 에 캐시돼 p95 30 ms 였지만, 부하의 대부분을 차지하는 기업 목록 · 경보 목록 · 대시보드 · 지역 목록 · 지역 시계열은 요청마다 DB 를 조회했다. 각각은 혼자 부르면 10~21 ms 지만 같은 쿼리가 초당 수백 번 반복됐다. 또 기업 목록 쿼리는 ‘기업별 최신 기간’ CTE 가 인라인되어 기업 43곳마다 다시 집계됐다(EXPLAIN ANALYZE: loops=43).

데이터가 바뀌는 때는 정해져 있다 — 배치 Job 이 끝날 때와 사람이 경보를 확인(ACK)할 때뿐이다.

결정

결과 k6 50 VU · 90초: 약 3,400 req/s · API p95 30 ms · 오류 0 (전: 504 req/s · 307 ms). RuleEvalJobIT.Job_이_끝나면_캐시된_경보_목록이_바로_새_경보를_보여_준다 가 캐시된 목록이 Job 직후 새 경보를 보여 주는지, 리스너가 없는 Job 도 세대를 올리는지 확인한다.

관측 buildrisk_cache_requests_total{result=hit·miss·error} 카운터와 Grafana ‘조회 캐시 적중률’ 패널로 캐시가 실제로 DB 부하를 덜어 주는지 본다 (error = Redis 를 쓸 수 없어 캐시 없이 조회한 요청 — 캐시는 장애 때 기능을 막지 않고 성능만 잃는다).

한계 make psql 로 DB 를 직접 고치면 캐시가 최대 10분 옛 값을 보여 준다(세대를 올리려면 아무 Job 이나 한 번 실행). api 가 여러 대여도 세대 키가 Redis 하나에 있으므로 함께 무효화된다.

덧붙임 (2026-10-09, VERIFICATION 105 · 138)

덧붙임 (2026-10-11, VERIFICATION 175 · 186 · 194) — 대상 기업만 · 규칙 변경 무효화 · 같은 키 계산 하나로