agentsclimarketplace

Caching

Skill iceflower/agent-skills/caching

Agent Skills 오픈 표준 기반 AI 코딩 에이전트용 스킬 컬렉션 (Java, Kotlin, Spring, NestJS, K8s, Terraform, GraphQL, gRPC, OpenTelemetry, a11y, i18n 등 60개)

Install
npx -y skills add iceflower/agent-skills --skill caching

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Framework-agnostic caching strategies including cache selection, TTL design, invalidation patterns, stampede prevention, and anti-patterns. Use when designing or reviewing cache logic.

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

17.2 KB, as published. Nobody here has run it

Caching Rules

1. Cache Strategy Selection

When to Cache

ScenarioCache?Reason
Frequently read, rarely written dataYesHigh read-to-write ratio
Expensive computation resultsYesReduce CPU/DB load
External API responsesYesReduce latency and rate limits
User session dataYesAvoid repeated DB lookups
Real-time data (stock prices, etc.)NoStale data is unacceptable
Write-heavy dataNoCache invalidation too frequent
Security-critical data (permissions)CarefulMust invalidate on change

Cache Placement

TypeLatencyScopeUse Case
Local (L1)~1msSingle instanceHot data, high read frequency
Distributed~5msAll instancesShared state, session data
HTTP cacheVariesClient/CDNStatic assets, public APIs
Two-level~1ms+L1 + distributedHot data across instances

Two-Level Cache Pattern

Request → L1 (local) → L2 (distributed) → Data source
             ↑ miss         ↑ miss              │
             └──────────────┴───── populate ─────┘
  • L1 (Caffeine, Guava): sub-millisecond, per-instance
  • L2 (Redis, Memcached): single-digit ms, shared
  • On L1 miss, check L2 before hitting the data source
  • Invalidate both levels on writes

2. TTL Design Guidelines

Recommended TTL by Data Type

Data TypeRecommended TTLRationale
Static config1-24 hoursRarely changes
User profile15-30 minutesModerate change frequency
Search results5-10 minutesFreshness matters
API rate limit counters1 minute windowMust be accurate
Session data30 min - 2 hoursBalance UX and security
Product catalog1-6 hoursChanges infrequently
Dashboard aggregations1-5 minutesNear-real-time acceptable

TTL Rules

  • Always set a TTL — never cache indefinitely
  • Shorter TTL for data that affects user experience when stale
  • Longer TTL for reference data that changes infrequently
  • Use explicit eviction on writes in addition to TTL
  • Consider TTL jitter to avoid cache stampede

TTL Jitter

Effective TTL = base_ttl + random(0, jitter_range)

Example: base 10min, jitter 2min → actual TTL between 10-12min

Without jitter, cached entries expire simultaneously, causing a thundering herd to the data source.


3. Cache Key Design

Key Structure

<namespace>:<entity>:<identifier>[:<variant>]

Examples:
  user:profile:12345
  product:detail:SKU-001:v2
  search:results:shoes:page=1:size=20

Key Design Rules

RuleReason
Include type prefixPrevents key collisions across entities
Include version if neededSupports cache-friendly schema changes
Keep keys shortSaves memory in distributed cache
Avoid user input in keysPrevents cache poisoning attacks
Normalize key componentsEnsures consistent lookups

4. Cache Invalidation Patterns

Write-Through

Update the cache entry simultaneously when writing to the data store. Ensures cache is always consistent but adds write latency.

Write request → Update DB → Update cache → Return

Evict on Write (Cache-Aside)

Evict the cache entry on write and let the next read repopulate it. Simpler to implement and avoids stale data from failed cache updates.

Write: Write request → Update DB → Evict cache → Return
Read:  Read request → Cache miss → Read DB → Populate cache → Return

Write-Behind (Write-Back)

Write to cache first, then asynchronously persist to the data store. Lowest write latency but risks data loss.

Write request → Update cache → Return (async persist to DB)

Event-Based Invalidation

Invalidate cache entries via events (message queue, application events) for cross-service consistency. Best for distributed systems where multiple services share cached data.

Invalidation Rules

  • Prefer explicit eviction over TTL-only for mutable data
  • Invalidate on all write paths (update, delete, bulk operations)
  • Use event-based invalidation for cross-service cache consistency
  • Test cache invalidation paths — stale cache bugs are hard to diagnose

5. Cache Stampede Prevention

A cache stampede occurs when many requests simultaneously miss the cache and hit the data source.

Prevention Strategies

StrategyDescriptionTrade-off
Mutex/lockOnly one request rebuilds, others waitAdds latency for waiters
Probabilistic expiryRefresh before TTL expires with some probabilitySlightly stale data
Background refreshAsync refresh before expiryMore complexity
Stale-while-revalidateServe stale, refresh in backgroundBrief staleness window

Probabilistic Early Recomputation

Instead of waiting for exact expiry, each request probabilistically decides whether to recompute. As TTL approaches, the probability of recomputation increases.

should_recompute = (current_time - (expiry - ttl * beta * log(rand()))) > 0

beta: tuning factor (typically 1.0)
rand(): uniform random in (0, 1]
  • When beta = 1.0, roughly 1 request recomputes before expiry under normal load
  • Higher beta increases early recomputation probability
  • No coordination overhead — purely probabilistic, no locks required
  • Best suited for high-throughput keys where occasional early recomputation is acceptable

Locking Strategy Details

1. Thread A: cache miss → acquire lock → recompute → populate cache → release lock
2. Thread B: cache miss → lock unavailable → wait or return stale value
  • Blocking lock: waiters block until the lock holder populates the cache; simple but increases tail latency
  • Try-lock with stale fallback: if lock is unavailable, serve the stale value; requires keeping the expired entry accessible
  • Distributed lock (e.g., Redis SET NX EX): required when multiple instances share the cache; set a short lock TTL to avoid deadlocks

Request Coalescing (Singleflight)

Multiple concurrent requests for the same key are collapsed into a single data-source call. Only the first request triggers computation; subsequent requests wait for and share the result.

Request A ─┐
Request B ──┼─→ single fetch → result shared to all
Request C ─┘
  • Eliminates redundant calls entirely, not probabilistically
  • Must be implemented in the application layer (e.g., Go singleflight, custom deduplication map)
  • Scope is per-instance; combine with distributed locking for multi-instance protection

6. Cache Warming

When to Warm

  • Application startup with predictable hot data
  • After cache flush or failover
  • Before traffic spike (scheduled events, promotions)

Warming Rules

  • Warm only high-frequency keys — not the entire dataset
  • Stagger warming to avoid overwhelming the data source
  • Set shorter TTL for warmed entries if staleness risk is high

7. Anti-Patterns

  • Caching without TTL (memory leak risk)
  • Caching mutable objects (caller modifies cached reference)
  • Cache key collisions (using only entity ID without type prefix)
  • Caching null values without explicit handling
  • Ignoring cache in delete/update paths (stale reads)
  • Over-caching (caching everything "just in case")
  • No monitoring of cache hit/miss rates
  • Using distributed cache for data that only needs local caching
  • Cache-aside without stampede protection on hot keys
  • Storing large objects (> 1MB) in distributed cache without compression

8. Cache Patterns Comparison

Sections 1 and 4 introduce individual patterns. This section provides a systematic comparison to guide pattern selection.

Read Patterns

PatternHow It WorksProsConsBest For
Cache-AsideApp checks cache; on miss, reads DB, then populates cacheSimple, app controls cache logicPossible stale data until TTL or explicit evictionGeneral-purpose read-heavy workloads
Read-ThroughCache itself fetches from DB on miss (transparent to app)Cleaner app code, cache handles data sourceCache library must support loader integrationWhen cache layer can encapsulate data access

Write Patterns

PatternHow It WorksProsConsBest For
Write-ThroughWrites go to cache and DB synchronouslyStrong consistency between cache and DBHigher write latency (two synchronous writes)Read-heavy with strict consistency needs
Write-BehindWrites go to cache first; DB is updated asynchronouslyLowest write latencyRisk of data loss if cache fails before DB persistWrite-heavy with tolerance for eventual persist

Pattern Selection Guide

Read-heavy, simple setup?           → Cache-Aside
Read-heavy, want transparent cache? → Read-Through
Need write consistency?             → Write-Through
Need fast writes, tolerate risk?    → Write-Behind
High read + high write?             → Write-Behind + Read-Through

Combining Read and Write Patterns

  • Read-Through + Write-Through: full cache transparency with strong consistency; higher write latency
  • Read-Through + Write-Behind: full cache transparency with fast writes; eventual consistency for writes
  • Cache-Aside + Write-Through: app controls reads, cache stays consistent on writes; most common combination

9. Distributed Cache Patterns

Consistent Hashing

Maps cache keys to nodes on a hash ring. When a node is added or removed, only a fraction of keys are remapped.

Hash Ring:

    Node A (0°)
       ╱          ╲
  Node D (270°)    Node B (90°)
       ╲          ╱
    Node C (180°)

Key "user:123" hashes to 110° → assigned to Node C (next node clockwise)
Node B removed → only keys between A and B remap to C
  • Virtual nodes: each physical node maps to multiple points on the ring, improving key distribution
  • Without virtual nodes, adding/removing nodes causes uneven load
  • Commonly used by Redis Cluster, Memcached client libraries, and application-level sharding

Near Cache (L1/L2 Architecture)

Extends the two-level cache concept (Section 1) with consistency mechanisms for distributed environments.

AspectL1 (Near / Local)L2 (Remote / Distributed)
LocationApplication heapExternal cache cluster
LatencySub-millisecondSingle-digit milliseconds
ScopePer-instanceCluster-wide
ConsistencyEventually consistent with L2Source of truth for cached data
SizeSmall (hundreds to thousands of keys)Large (millions of keys)

Consistency Strategies for Near Cache

  • Invalidation events: L2 publishes invalidation messages (e.g., Redis Pub/Sub); L1 evicts on receive
  • Short L1 TTL: keep L1 TTL short (seconds) to limit staleness window without events
  • Version check: L1 stores version tag; on read, compare with L2 version before serving

Cache Replication vs Partitioning

AspectReplicationPartitioning (Sharding)
Data modelEvery node holds a full copyEach node holds a subset of keys
Read scalabilityExcellent (any node can serve any read)Good (reads routed to owning node)
Write costHigh (must propagate to all replicas)Low (write to one node)
CapacityLimited by single node memoryScales horizontally with nodes
Fault toleranceHigh (any replica can serve)Needs rebalancing on node failure
Best forRead-heavy, small datasetLarge dataset, write-heavy
  • Hybrid approach: partition data across shards, replicate each shard (e.g., Redis Cluster with replicas)
  • Replication lag causes temporary inconsistency; design reads to tolerate this

10. Cache Sizing and Monitoring

Cache Sizing Guidelines

FactorGuidance
Working set sizeEstimate the number of unique keys accessed within one TTL window
Object sizeMeasure serialized size; set max entry size limits
Memory budgetAllocate based on infra capacity; leave headroom for eviction overhead
Hit rate target80-95% hit rate is typical; diminishing returns above 95%
Eviction headroomKeep 10-20% free to avoid constant eviction churn

Sizing Formula

Required memory ≈ working_set_count × avg_serialized_size × (1 + overhead_factor)

overhead_factor: ~0.1–0.3 depending on data structure and cache implementation
  • Start with a conservative estimate, then adjust based on actual hit rate and eviction metrics
  • For distributed caches, divide by partition count to get per-node sizing

Key Metrics to Monitor

MetricWhat It Tells YouAlert Threshold (Typical)
Hit rateCache effectivenessBelow 80% warrants investigation
Miss rateUncached or expired requestsInverse of hit rate
Eviction rateCache is too small or TTL too longSustained increase is a warning
Latency (p50, p99)Cache performancep99 > 10ms for distributed cache
Memory usageCapacity utilizationAbove 80% of allocated memory
Connection countClient pressure on cache clusterNear max connections limit
Key countTotal entries storedUnexpected growth may be a leak

Monitoring Rules

  • Track hit rate per cache region or namespace, not just globally
  • Set up alerts for hit rate drops — they often indicate a bug, not a capacity issue
  • Monitor eviction rate alongside memory usage; high eviction with low memory means the cache is undersized
  • Track latency percentiles (p50, p95, p99), not just averages
  • Log cache misses for hot keys to identify stampede candidates

Additional References

  • For Redis caching strategies, cache-aside, write-through, TTL management, and eviction policies, see references/redis-patterns.md
  • For Spring Boot implementation patterns (Caffeine, Redis, @Cacheable), see spring-framework skill — references/caching.md

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.