Files
kebab/crates
altair823 74e28293ba refactor(app): #231 derivation cache 배칭 + 계측 — 가설은 재현 안 됨
#231 은 "캐시가 히트하는데도 우회하고 전량 재임베딩하는 편이 더 빠르다" 고
보고하면서 본문에 "⚠️ 정량 실측 보완 필요 … 수치 미기록" 이라고 표를 비워
뒀다. 그 표를 채우는 것이 이 커밋의 핵심이다.

측정 (나무위키 792문서 / 16,379 chunk, ollama arctic-embed2 1024-dim,
--force-reingest 로 전 문서 full re-process):

  캐시 히트 경로              139.1초   236 chunk/초
  캐시 우회(전량 재임베딩)   1179.6초    28 chunk/초

캐시 히트가 8.5배 빠르다. 가설은 이 환경에서 재현되지 않는다.

새로 넣은 계측으로 139초의 내역을 보면 더 분명하다 (히트 32,758 / 미스 0):

  Lance upsert + 레코드 구성   74.6초  53%
  SQLite 문서·청크 기록        56.7초  41%
  chunk                         4.4초   3%
  캐시 경로 전체(조회+삽입+touch) 0.6초   0.4%

이슈가 지목한 여섯 원인이 전부 합쳐 run 의 0.4% 다.

다만 "보고가 틀렸다" 로 읽으면 안 된다. 보고 이후 #229#230 이 머지됐고,
#231 본문 스스로 #229 를 "같은 Mutex<Connection> 을 공유하므로 상호 증폭"
이라고 적었다. 원 보고 환경에서는 캐시 조회 52,000회가 그 뮤텍스를 잡았다
놓는데 같은 뮤텍스 위에서 chunk 삭제가 FTS5 전체 스캔을 돌리고 있었다.
"#229 를 먼저 고치면 체감이 줄어든다" 도 이슈의 예측이다. 이 머신이 61 GB
RAM 이라 DB 가 통째로 페이지 캐시에 올라간다는 점도 함께 적어 둔다.

반영한 것:

제안 1·2·4 는 실측과 무관하게 왕복이 줄 뿐 잃는 게 없어 넣었다. 다만 A/B
벽시계는 139.1초 → 139.3초로 측정 오차 안이다. 이 코퍼스에서는 체감이 없다.

  - derivation_cache_get_many — `WHERE cache_key IN (…)` 배치 조회.
    문서 하나가 평균 21 chunk 이라 왕복이 21회에서 1회가 된다.
  - derivation_cache_put_many — 미스 벡터를 한 트랜잭션에. 기존 단건 put 은
    명시 트랜잭션 밖이라 행마다 암묵 커밋이었다.
  - prepare_cached — get/put/touch 셋 다. query_row 는 호출마다 SQL 을
    다시 파싱한다.

제안 5(계측 노출)가 실질 산출물이다. `asset_timings` 에 cache_hit /
cache_miss / cache_ms 를 additive 로 실었다. 이전에는 hit/miss 가
tracing::info! 로 stderr 에만 나가 run 이 끝나면 사라졌고, "내 코퍼스에서
캐시가 이득인가" 를 확인할 방법이 없었다. cache_ms 에는 touch 도 포함한다 —
이슈의 가장 날카로운 지적이 "읽기 전용이어야 할 히트 경로가 쓰기를 만든다"
인데, touch 를 빼고 재는 지표로는 그 주장을 검증할 수 없다.

네 out-param 은 CacheStats 구조체로 묶었다. 함께 읽히고 함께 보고되는
값들이고, 셋만 갱신하고 하나를 빠뜨리면 캐시가 공짜인 것처럼 보고된다.

반영하지 않은 것:

  - 제안 3(touch 를 히트 경로에서 분리). 캐시 경로 전체가 0.6초라 touch 만
    떼어낼 이유가 없고, 권한 (c)안은 LRU 를 age 기반 축출로 바꾸는 의미
    변경이다. 근거 없이 할 변경이 아니다.
  - 제안 6(캐시 우회 스위치). 이슈 스스로 "1~4 로 해결되면 불필요 —
    플래그부터 만들지 말 것" 이라고 적었다.
  - 원인 6(4 KB BLOB overflow). page_size 변경은 기존 DB 에서 VACUUM 을
    요구하는데 kebab 은 VACUUM 을 실행하지 않는다. 0.4% 에 낼 비용이 아니다.

곁다리로 #228 에서 내가 넣은 flaky test 를 고쳤다.
`ingest_log_records_the_deleted_file_sweep` 이 두 run 의 로그 중 뒤엣것을
파일명 정렬로 골랐는데, run id 가 `<초 단위 타임스탬프>-<난수 hex>` 라 같은
초에 끝난 두 run 은 난수 쪽으로 정렬된다. 이번 전체 테스트에서 우연히 터져
잡았다. 첫 run 의 로그 집합을 기록해 두고 차집합으로 고르도록 바꿨다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017c9JwQq8ZkGvYjpKXMiDhF
2026-08-16 23:39:07 +09:00
..