---
id: daily-golang-samber-hot
name: "golang-samber-hot"
url: https://skills.yangsir.net/skill/daily-golang-samber-hot
author: samber
domain: ai-backend-engineering
tags: ["caching", "performance", "backend-development", "data-management", "optimization"]
install_count: 31900
rating: 4.60 (40 reviews)
github: https://github.com/samber/cc-skills-golang
---

# golang-samber-hot

> Go 内存缓存系统设计，根据访问模式选择淘汰算法，基于工作集数据规划缓存大小，内置过期、加载失败和监控处理

**Stats**: 31,900 installs · 4.6/5 (40 reviews)

## Before / After 对比

### 缓存命中率优化

**Before**:

使用通用缓存配置，未针对实际访问模式优化，缓存命中率仅 60%，频繁缓存穿透导致数据库压力，接口响应时间 P99 为 800ms

**After**:

自动分析访问模式选择最佳淘汰算法，动态调整缓存大小和过期策略，命中率提升至 92%，接口响应时间 P99 降至 150ms

| Metric | Before | After | Change |
|---|---|---|---|
| 缓存命中率 | 60% | 92% | +53% |
| P99 响应时间 | 800ms | 150ms | -81% |

## Readme

# golang-samber-hot

**Persona:** You are a Go engineer who treats caching as a system design decision. You choose eviction algorithms based on measured access patterns, size caches from working-set data, and always plan for expiration, loader failures, and monitoring.

# Using samber/hot for In-Memory Caching in Go

Generic, type-safe in-memory caching library for Go 1.22+ with 9 eviction algorithms, TTL, loader chains with singleflight deduplication, sharding, stale-while-revalidate, and Prometheus metrics.

**Official Resources:**

- [pkg.go.dev/github.com/samber/hot](https://pkg.go.dev/github.com/samber/hot)

- [github.com/samber/hot](https://github.com/samber/hot)

This skill is not exhaustive. Please refer to library documentation and code examples for more information. Context7 can help as a discoverability platform.

```
go get -u github.com/samber/hot

```

## Algorithm Selection

Pick based on your access pattern — the wrong algorithm wastes memory or tanks hit rate.

Algorithm
Constant
Best for
Avoid when

**W-TinyLFU**
`hot.WTinyLFU`
General-purpose, mixed workloads (default)
You need simplicity for debugging

**LRU**
`hot.LRU`
Recency-dominated (sessions, recent queries)
Frequency matters (scan pollution evicts hot items)

**LFU**
`hot.LFU`
Frequency-dominated (popular products, DNS)
Access patterns shift (stale popular items never evict)

**TinyLFU**
`hot.TinyLFU`
Read-heavy with frequency bias
Write-heavy (admission filter overhead)

**S3FIFO**
`hot.S3FIFO`
High throughput, scan-resistant
Small caches (<1000 items)

**ARC**
`hot.ARC`
Self-tuning, unknown patterns
Memory-constrained (2x tracking overhead)

**TwoQueue**
`hot.TwoQueue`
Mixed with hot/cold split
Tuning complexity is unacceptable

**SIEVE**
`hot.SIEVE`
Simple scan-resistant LRU alternative
Highly skewed access patterns

**FIFO**
`hot.FIFO`
Simple, predictable eviction order
Hit rate matters (no frequency/recency awareness)

**Decision shortcut:** Start with `hot.WTinyLFU`. Switch only when profiling shows the miss rate is too high for your SLO.

For detailed algorithm comparison, benchmarks, and a decision tree, see [Algorithm Guide](https://github.com/samber/cc-skills-golang/blob/HEAD/skills/golang-samber-hot/./references/algorithm-guide.md).

## Core Usage

### Basic Cache with TTL

```
import "github.com/samber/hot"

cache := hot.NewHotCache[string, *User](hot.WTinyLFU, 10_000).
    WithTTL(5 * time.Minute).
    WithJanitor().
    Build()
defer cache.StopJanitor()

cache.Set("user:123", user)
cache.SetWithTTL("session:abc", session, 30*time.Minute)

value, found, err := cache.Get("user:123")

```

### Loader Pattern (Read-Through)

Loaders fetch missing keys automatically with singleflight deduplication — concurrent `Get()` calls for the same missing key share one loader invocation:

```
cache := hot.NewHotCache[int, *User](hot.WTinyLFU, 10_000).
    WithTTL(5 * time.Minute).
    WithLoaders(func(ids []int) (map[int]*User, error) {
        return db.GetUsersByIDs(ctx, ids) // batch query
    }).
    WithJanitor().
    Build()
defer cache.StopJanitor()

user, found, err := cache.Get(123) // triggers loader on miss

```

## Capacity Sizing

Before setting the cache capacity, estimate how many items fit in the memory budget:

- **Estimate single-item size** — estimate size of the struct, add the size of heap-allocated fields (slices, maps, strings). Include the key size. A rough per-entry overhead of ~100 bytes covers internal bookkeeping (pointers, expiry timestamps, algorithm metadata).

- **Ask the developer** how much memory is dedicated to this cache in production (e.g., 256 MB, 1 GB). This depends on the service's total memory and what else shares the process.

- **Compute capacity** — `capacity = memoryBudget / estimatedItemSize`. Round down to leave headroom.

```
Example: *User struct ~500 bytes + string key ~50 bytes + overhead ~100 bytes = ~650 bytes/entry
         256 MB budget → 256_000_000 / 650 ≈ 393,000 items

```

If the item size is unknown, ask the developer to measure it with a unit test that allocates N items and checks `runtime.ReadMemStats`. Guessing capacity without measuring leads to OOM or wasted memory.

## Common Mistakes

- **Forgetting `WithJanitor()`** — without it, expired entries stay in memory until the algorithm evicts them. Always chain `.WithJanitor()` in the builder and `defer cache.StopJanitor()`.

- **Calling `SetMissing()` without missing cache config** — panics at runtime. Enable `WithMissingCache(algorithm, capacity)` or `WithMissingSharedCache()` in the builder first.

- **`WithoutLocking()` + `WithJanitor()`** — mutually exclusive, panics. `WithoutLocking()` is only safe for single-goroutine access without background cleanup.

- **Oversized cache** — a cache holding everything is a map with overhead. Size to your working set (typically 10-20% of total data). Monitor hit rate to validate.

- **Ignoring loader errors** — `Get()` returns `(zero, false, err)` on loader failure. Always check `err`, not just `found`.

## Best Practices

- Always set TTL — unbounded caches serve stale data indefinitely because there is no signal to refresh

- Use `WithJitter(lambda, upperBound)` to spread expirations — without jitter, items created together expire together, causing thundering herd on the loader

- Monitor with `WithPrometheusMetrics(cacheName)` — hit rate below 80% usually means the cache is undersized or the algorithm is wrong for the workload

- Use `WithCopyOnRead(fn)` / `WithCopyOnWrite(fn)` for mutable values — without copies, callers mutate cached objects and corrupt shared state

For advanced patterns (revalidation, sharding, missing cache, monitoring setup), see [Production Patterns](https://github.com/samber/cc-skills-golang/blob/HEAD/skills/golang-samber-hot/./references/production-patterns.md).

For the complete API surface, see [API Reference](https://github.com/samber/cc-skills-golang/blob/HEAD/skills/golang-samber-hot/./references/api-reference.md).

If you encounter a bug or unexpected behavior in samber/hot, open an issue at [https://github.com/samber/hot/issues](https://github.com/samber/hot/issues).

## Cross-References

- → See `samber/cc-skills-golang@golang-performance` skill for general caching strategy and when to use in-memory cache vs Redis vs CDN

- → See `samber/cc-skills-golang@golang-observability` skill for Prometheus metrics integration and monitoring

- → See `samber/cc-skills-golang@golang-database` skill for database query patterns that pair with cache loaders

- → See `samber/cc-skills@promql-cli` skill for querying Prometheus cache metrics via CLI

Weekly Installs664Repository[samber/cc-skills-golang](https://github.com/samber/cc-skills-golang)GitHub Stars1.1KFirst SeenMar 22, 2026Security Audits[Gen Agent Trust HubPass](/samber/cc-skills-golang/golang-samber-hot/security/agent-trust-hub)[SocketPass](/samber/cc-skills-golang/golang-samber-hot/security/socket)[SnykPass](/samber/cc-skills-golang/golang-samber-hot/security/snyk)Installed onopencode647cursor640codex638gemini-cli636github-copilot635amp634

---
*Source: https://skills.yangsir.net/skill/daily-golang-samber-hot*
*Markdown mirror: https://skills.yangsir.net/api/skill/daily-golang-samber-hot/markdown*