Files
2nd/10_Wiki/Topics/Domain_Programming/Coding/CS_Cache_Eviction.md
T
Antigravity Agent c24165b8bc refactor(topics): 멀티 에이전트용 지식 재편 — _Common(공통 기본기) + Domain_* 구조
에이전트 8종(대화형/프로그래머 C·S/디자이너/설계자/기획자/QA/PD/PM)에게
[공통 기본 능력 + 롤별 Specialty] 2층으로 지식을 주입하기 위한 재분류.
문서 내용·포맷은 무수정, 폴더 이동만 (6,372개 문서 수 보존 확인).

- Topic_Programming → Domain_Programming (내부 구조 보존)
- Topic_Graphic → Domain_Design
- Topic_Business → Domain_Product
- Topic_General → Domain_General
- _Common 신설: Math(구 Topic_Math_Specialty), Reasoning(구 General/From_Thinking & Reasoning),
  Reasoning_Creativity(구 General/From_창의성), Communication(Poetic_Blog_Writing + From_writing)
- 타 도메인의 From_* 폴더는 유지 (출처 표기일 뿐, 이미 도메인에 맞게 분류된 문서)
- 빈 폴더 정리 (memory/procedures)
- 에이전트→폴더 매핑은 workspace의 .astra/agent-knowledge-map.json (9개 에이전트)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 11:05:56 +09:00

7.0 KiB

id, title, category, status, source_trust_level, verification_status, created_at, updated_at, tags, tech_stack, applied_in, aliases
id title category status source_trust_level verification_status created_at updated_at tags tech_stack applied_in aliases
cs-cache-eviction Cache Eviction — LRU / LFU / ARC / TinyLFU Coding draft B conceptual 2026-05-09 2026-05-09
cs
cache
eviction
vibe-coding
language applicable_to
TS
Backend
LRU
LFU
ARC
TinyLFU
W-TinyLFU
cache eviction
hit rate

Cache Eviction

Cache 가득 = 무엇을 빼지? LRU (가장 오래 안 본), LFU (가장 적게 본), ARC (Adaptive), W-TinyLFU (Caffeine). Workload 따라 hit rate 큰 차이.

📖 핵심 개념

  • LRU: Least Recently Used.
  • LFU: Least Frequently Used.
  • ARC: Adaptive — 둘 다 + auto.
  • TinyLFU / W-TinyLFU: 빈도 + 최근성 + admission.

💻 코드 패턴

LRU (가장 일반)

class LRUCache<K, V> {
  private cache = new Map<K, V>();  // Map 가 insertion order 유지
  
  constructor(private max: number) {}
  
  get(key: K): V | undefined {
    if (!this.cache.has(key)) return undefined;
    const v = this.cache.get(key)!;
    this.cache.delete(key);
    this.cache.set(key, v);  // 최근 접근으로
    return v;
  }
  
  set(key: K, value: V) {
    if (this.cache.has(key)) this.cache.delete(key);
    this.cache.set(key, value);
    if (this.cache.size > this.max) {
      const first = this.cache.keys().next().value;
      this.cache.delete(first!);  // 가장 오래된
    }
  }
}

lru-cache (Node)

import LRU from 'lru-cache';

const cache = new LRU<string, User>({
  max: 1000,
  ttl: 60_000,           // 60초 TTL
  updateAgeOnGet: true,  // get 시 age reset
  fetchMethod: async (key) => {
    return await db.users.find(key);
  },
});

const user = await cache.fetch('u1');

LFU (빈도)

class LFUCache<K, V> {
  private cache = new Map<K, { value: V; freq: number }>();
  
  constructor(private max: number) {}
  
  get(key: K): V | undefined {
    const entry = this.cache.get(key);
    if (!entry) return undefined;
    entry.freq++;
    return entry.value;
  }
  
  set(key: K, value: V) {
    if (this.cache.size >= this.max) {
      // 가장 적게 본 것 evict
      let minFreq = Infinity;
      let minKey: K | undefined;
      for (const [k, e] of this.cache) {
        if (e.freq < minFreq) { minFreq = e.freq; minKey = k; }
      }
      this.cache.delete(minKey!);
    }
    this.cache.set(key, { value, freq: 0 });
  }
}

⚠️ Pure LFU 의 문제: cache pollution (오래된 popular 가 영원 남음).

ARC (Adaptive Replacement Cache)

4개 list 관리:
- T1: recent (한 번 본)
- T2: frequent (여러 번 본)
- B1: T1 evict ghost
- B2: T2 evict ghost

Hit on B1 → T1 가중치 ↑
Hit on B2 → T2 가중치 ↑
Adaptive

→ IBM 특허 — 사용 제한 가능.

W-TinyLFU (Caffeine, Java)

Window LRU (1%) + Main (LFU + LRU).

Admission policy:
새 entry 가 window 통과 → 빈도 비교 → 통과 시 main 으로.

매우 좋은 hit rate.

→ Java Caffeine 가 이 알고리즘.

Node — better-cache

import { Cache } from 'cache-manager';

const cache = new Cache({
  store: 'memory',
  max: 1000,
  ttl: 60_000,
});

await cache.set('key', value);
const v = await cache.get('key');

Two-tier cache

L1: in-process (LRU, 작은) — ns access
L2: Redis (큰) — ms access

Get: L1 → miss → L2 → miss → DB
async function getUser(id: string): Promise<User> {
  const l1 = lru.get(id);
  if (l1) return l1;
  
  const l2 = await redis.get(`user:${id}`);
  if (l2) {
    const user = JSON.parse(l2);
    lru.set(id, user);
    return user;
  }
  
  const user = await db.users.find(id);
  lru.set(id, user);
  await redis.setex(`user:${id}`, 60, JSON.stringify(user));
  return user;
}

Cache stampede (위 redis 문서 참조)

1000 concurrent miss → 모두 DB 호출.
→ Singleflight / lock.
const inflight = new Map<string, Promise<User>>();

async function getUser(id: string): Promise<User> {
  const cached = lru.get(id);
  if (cached) return cached;
  
  if (inflight.has(id)) return inflight.get(id)!;
  
  const promise = db.users.find(id).then(user => {
    lru.set(id, user);
    inflight.delete(id);
    return user;
  });
  inflight.set(id, promise);
  return promise;
}

→ 같은 key 동시 fetch = 1번만.

TTL + jitter

const ttl = 60_000 + Math.random() * 10_000;  // 60-70s
cache.set(key, value, { ttl });

→ 동시 expire 방지 (thundering herd).

Cache key design

// ❌ 너무 specific
`user:${id}:${page}:${filter}:${sort}`  // 매번 다른 key

// ✅ 분리
`user:${id}` +  user  page list 별도

Negative cache (없는 것도 cache)

async function getUser(id: string): Promise<User | null> {
  const cached = cache.get(id);
  if (cached === '__NULL__') return null;
  if (cached) return cached as User;
  
  const user = await db.users.find(id);
  if (!user) {
    cache.set(id, '__NULL__', { ttl: 30_000 });  // 짧게
    return null;
  }
  cache.set(id, user);
  return user;
}

→ "없는 user" 반복 query 방지.

Hit rate 측정

class InstrumentedCache<K, V> {
  private hits = 0;
  private misses = 0;
  
  get(key: K) {
    const v = this.cache.get(key);
    if (v) { this.hits++; return v; }
    this.misses++;
    return undefined;
  }
  
  hitRate() { return this.hits / (this.hits + this.misses); }
}

→ 80%+ 가 일반 목표.

Sized cache (memory budget)

const cache = new LRU<string, Buffer>({
  maxSize: 100 * 1024 * 1024,  // 100 MB
  sizeCalculation: (value) => value.length,
});

Cache 종류 비교

Code-level:        Map / LRU
In-memory shared:  Memcached / Redis
CDN:               Cloudflare / CloudFront
Browser:           HTTP cache + Service Worker
DB:                shared_buffers / buffer pool

패턴

Cache-aside (look-aside): App 가 read miss 시 cache.set
Read-through: Cache 가 자동 fetch (lru-cache fetchMethod)
Write-through: Write 가 DB + cache 같이
Write-behind: Write cache → 비동기 DB
Refresh-ahead: TTL 임박 시 미리 refresh

🤔 의사결정 기준

워크로드 추천
일반 web LRU
Skewed (popular minority) LFU / W-TinyLFU
Adaptive ARC (legal 시) / W-TinyLFU
큰 throughput Caffeine (Java) / 자체
분산 Redis + 클라 LRU L1
Workload 다양 W-TinyLFU 가 안정

안티패턴

  • TTL 없음: stale.
  • 무한 size: OOM.
  • Hit rate 모니터링 X: cache 효과 모름.
  • Cache stampede 무시: 동시 1000 miss = DB 다운.
  • Negative cache 없음: "없는 거" 반복 query.
  • Key namespace 충돌: prefix 명시.
  • Cache pollution (모든 거 cache): 빈도 낮은 거 evict 자주.
  • Pure LFU 사용 + 패턴 변화: 옛 popular 가 영원.

🤖 LLM 활용 힌트

  • LRU + TTL + jitter 가 안전 default.
  • Hot/cold 가 strict 면 W-TinyLFU.
  • Stampede = singleflight 또는 lock.
  • Hit rate 모니터링 + alarm.

🔗 관련 문서