Skip to content

피드 Profile 집계가 회원 기록 수에 정비례한다 — 명세된 Redis 캐시 미구현 #196

Description

@minyongP

급한 문제가 아닙니다. 지금 배포 데이터로는 실해가 없고(운영 record 162건), 기록이 많은
헤비 유저가 생겼을 때 드러나는 문제입니다. 명세된 캐시가 미구현이라는 사실과 실측 근거를
남겨 두는 것이 목적이고, 개선 여부와 시점은 AI 파트 판단에 맡깁니다.

무엇을 발견했나

FeedKeywordRepository.PROFILE_KEYWORDS_SQL(회원 관심 Keyword 집계)이 회원 본인의 기록 수에
정비례
하고, 피드 요청마다 실행됩니다.

천만 건 벤치 볼륨(S15P11A705-283, postgres 1Gi 한도)에서 회원 규모별 실측:

회원 record 수 Profile 쿼리
697건 5.8 ms
4,000건 14.5 ms
20,000건 216.4 ms

record 20,000건 회원의 피드 API가 197ms인데 그중 163ms가 이 쿼리입니다
(S15P11A705-303으로 최신 채널을 236ms → 2.3ms로 줄인 뒤 남은 몫).

FeedService.rank()가 커서 페이지마다 다시 도는 구조라(코드 주석에 명시됨) 스크롤할 때마다
반복
됩니다.

계획·인덱스로는 못 고칩니다

enable_mergejoin = off로 Nested Loop를 강제해 보면 77ms로 보이지만 8.8만 블록(약 690MB)을
만지며
ai.context_keyword를 Parallel Seq Scan으로 두 번 훑습니다. 어느 계획을 골라도 회원의
맥락 26,666건 × 키워드 테이블 조인 비용은 남습니다.

즉 쿼리 튜닝 대상이 아니라 호출 빈도를 줄이는 문제로 보입니다.

해법이 이미 명세에 있습니다

docs/ai/spec/feed-profile-cache.md 첫 줄:

현재 코드가 없는 구현 예정 명세입니다.

Cache Key TTL
사용자 관심 Profile feed:profile:{memberId} 6시간
Collection 특징 feed:coll:{collectionId} 1시간

TTL 6시간의 근거도 이 쿼리를 두고 쓴 문장으로 읽힙니다 — "Record 하나가 추가돼도 분포가 크게
흔들리지 않으므로 길게 잡습니다. 계산 비용도 상대적으로 큽니다."

Redis는 이미 떠 있고 현재는 refresh token 저장에만 쓰고 있습니다(@Cacheable 0건).

측정 해석에 중요한 한계

벤치 데이터에는 AI 파생 행이 없습니다.

ai.context_keyword 전체        213,290행  (전부 옛 시드 것)
회원 3008의 context_keyword         0행
회원 3008의 context            26,666행

즉 위 216ms는 결과가 0건인데도 나온 값입니다. 실제 운영처럼 맥락에 키워드가 붙어 있으면
조인이 행을 만들어 더 비싸질 수도 있고, 반대로 통계가 달라져 플래너가 다른 계획을 고를
수도 있습니다. AI 파생 데이터가 있는 볼륨에서 재측정해야 확정됩니다 — 그 판단과 재측정은
AI 파트 영역이라 제가 하지 않았습니다.

재현 방법

# 천만 건 벤치 볼륨 적재 (약 5분, 디스크 5.9GB)
bash loadtest/tools/run-massive.sh

# 운영과 같은 자원 한도를 얹고 측정
docker compose -p back -f compose.yaml -f compose.bench.yaml up -d postgres

# 회원 규모별 Profile 쿼리 비교 — 괴물 회원은 member 3008~3057 (record 20,000건)

되돌리기는 loadtest/tools/teardown-massive.sql입니다. 자세한 실행법은
loadtest/README.md「대량 벤치」절에 있습니다.

배경 문서

경계에 대해

FeedCandidateRepository·FeedKeywordRepositoryai 스키마는 AI 파트 소유이고 정본 명세도
그쪽에 있습니다. 저는 관측과 근거만 남깁니다. 캐시 도입은 TTL 동안 새 기록이 취향에
반영되지 않는 트레이드오프를 포함하므로(명세는 이벤트 기반 무효화 없이 TTL만 쓰기로 정하고
있습니다) 정책 결정이 필요한 사안으로 보입니다.

필요하면 재측정이나 벤치 환경 세팅은 도와드릴 수 있습니다.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions