Skip to content

Cache and Performance

ddddd edited this page Sep 15, 2026 · 2 revisions

缓存与性能 / Cache and Performance

SPACK 的性能设计主要依赖 prepared snapshot、request-path fast path、small-file memory cache、sendfile 和清晰的 cache policy。

SPACK performance is built around prepared snapshots, request-path fast paths, small-file memory cache, sendfile, and explicit cache policy.

热路径结构 / Hot Path Structure

flowchart LR
    Request["request"] --> Clean["path fast path"]
    Clean --> Prepared["prepared snapshot lookup"]
    Prepared --> Headers["precomputed headers"]
    Prepared --> Body{"body source"}
    Body -->|small| Memory["prepared body / memory cache"]
    Body -->|large| Sendfile["sendfile"]
    Body -->|range| Range["sendfile range"]
    Headers --> Response["response"]
    Memory --> Response
    Sendfile --> Response
    Range --> Response
Loading

中文:核心思想是把尽可能多的计算移动到 catalog 更新阶段,而不是 HTTP 请求阶段。

English: The core idea is to move as much computation as possible to catalog update time instead of HTTP request time.

Prepared Snapshot

Prepared snapshot 保存:

  • route-indexed response plans
  • source and generated variant pointers
  • selected static headers
  • cache policy result
  • immutable cache headers for fingerprinted assets
  • resource hints for HTML
  • small eligible in-memory bodies

The prepared snapshot stores:

  • route-indexed response plans
  • source and generated variant pointers
  • selected static headers
  • cache policy result
  • immutable cache headers for fingerprinted assets
  • resource hints for HTML
  • small eligible in-memory bodies

优点:

  • 请求路径更短。
  • 减少重复 map/list 遍历和 header 拼接。
  • catalog 更新时原子发布新 snapshot。
  • 事件触发 rebuild,不阻塞普通请求。

Benefits:

  • Shorter request path.
  • Less repeated map/list traversal and header construction.
  • New snapshots are published atomically after catalog updates.
  • Event-triggered rebuilds do not block normal requests.

HTTP Cache Policy

SPACK 输出:

  • ETag
  • Last-Modified
  • Cache-Control
  • Expires
  • Vary

策略:

  • HTML 通常保持可重新验证,避免 SPA 发布后客户端长期使用旧入口。
  • fingerprinted assets 可以使用 long-lived immutable cache。
  • compression variants 必须带 Vary: Accept-Encoding。
  • image format negotiation 应带对应 Vary 信息。

Policy:

  • HTML is usually revalidated so SPA deployments do not keep stale entries forever.
  • Fingerprinted assets can use long-lived immutable cache.
  • Compression variants must include Vary: Accept-Encoding.
  • Image format negotiation should emit corresponding Vary information.

旧版本资源恢复 / Stale Asset Recovery

中文:frontend.stale_asset_recovery.enable 默认开启。旧页面请求已经不存在的带指纹 .js 文件时,运行时会返回 200、application/javascript 和 Cache-Control: no-store 的刷新脚本,尝试重新加载页面。这与小文件内存缓存及带指纹文件的长期 immutable 缓存是不同的机制;CSS、图片和普通 JS 不会触发。浏览器、Service Worker 或 CDN 若自行命中旧资源,请求不会到达该兜底。详见配置参考。

English: frontend.stale_asset_recovery.enable is on by default. If an old page requests a fingerprinted .js file that the runtime cannot resolve, SPACK responds with a reload script using 200, application/javascript, and Cache-Control: no-store. This is separate from the small-file memory cache and long-lived immutable caching of fingerprinted assets. It does not cover CSS, images, or plain JavaScript, and cannot act when a browser, service worker, or CDN serves the request without contacting SPACK. See Configuration.

Memory Cache

Memory cache 面向小型热文件:

  • 默认开启。
  • 默认启动 warmup。
  • 只缓存小于 http.memory_cache.max_file_size 的文件。
  • 使用 http.memory_cache.max_entries 和 http.memory_cache.max_bytes 控制容量。
  • TTL 默认 5m。

The memory cache targets small hot files:

  • Enabled by default.
  • Startup warmup is enabled by default.
  • Only caches files smaller than http.memory_cache.max_file_size.
  • Capacity is controlled by http.memory_cache.max_entries and http.memory_cache.max_bytes.
  • Default TTL is 5m.

k6 本地 HTTP 压测 / Local HTTP k6 Benchmarks

SPACK 提供 Docker 化 k6 压测,完整走 HTTP 协议,对比:

  • SPACK non-prefork
  • SPACK prefork
  • Nginx

SPACK provides Docker-based k6 benchmarks over real HTTP comparing:

  • SPACK non-prefork
  • SPACK prefork
  • Nginx

命令:

task perf:k6
task perf:k6:frontend
task perf:k6:split

调参:

$env:K6_VUS = "128"
$env:K6_DURATION = "60s"
$env:ACCEPT_ENCODING = "identity"
task perf:k6:frontend

结果文件:

tmp/k6/results/spack.json
tmp/k6/results/spack-prefork.json
tmp/k6/results/nginx.json
tmp/k6/results/spack-frontend.json
tmp/k6/results/spack-prefork-images.json
tmp/k6/results/nginx-js.json

最近基准 / Recent Baseline

环境:Docker 本地压测,64 VUs,30s,完整前端页面加载模型。

Environment: local Docker benchmark, 64 VUs, 30 seconds, full frontend page-load model.

Target Requests/s Pages/s Throughput Avg latency p95 p99
SPACK 2764.96 307.21 338.82 MB/s 60.91 ms 203.15 ms 230.09 ms
SPACK prefork 2693.15 299.24 330.02 MB/s 60.50 ms 207.01 ms 242.25 ms
Nginx 1366.44 151.82 166.65 MB/s 104.39 ms 276.69 ms 336.85 ms

资源分类 8s 快速基准:

Split resource quick baseline, 8 seconds:

Group SPACK rps / p95 SPACK prefork rps / p95 Nginx rps / p95
HTML 52965.61 / 3.73 ms 52080.37 / 3.57 ms 2901.56 / 46.52 ms
JS 1001.03 / 95.85 ms 995.52 / 101.83 ms 775.08 / 196.40 ms
CSS 38786.68 / 4.76 ms 31586.26 / 5.91 ms 2077.16 / 73.47 ms
Images 3300.74 / 61.56 ms 3347.00 / 62.24 ms 1648.71 / 69.53 ms
Other 5309.34 / 26.20 ms 5106.19 / 27.41 ms 2348.95 / 46.93 ms

注意:这些数字是本地 Docker 环境下的基准,不应该直接当作生产承诺。它们更适合用于回归检测和实现改动前后的对比。

Note: These numbers are local Docker baselines, not production guarantees. They are best used for regression detection and before/after comparisons.

Profile Entrypoints

task perf:profile:resolver
task perf:profile:cache
task perf:profile:pipeline
task perf:profile:http
go tool pprof .\tmp\perf\resolver.cpu.pprof

覆盖的热点:

  • resolver.Resolve
  • assetcache.GetOrLoad
  • pipeline.Service.Enqueue
  • HTTP asset delivery through memory-cache-hit and sendfile paths

Covered hot paths:

  • resolver.Resolve
  • assetcache.GetOrLoad
  • pipeline.Service.Enqueue
  • HTTP asset delivery through memory-cache-hit and sendfile paths

性能优化方向 / Optimization Directions

当前架构适合继续优化:

  • 减少 header write 分支。
  • 降低 variant selection allocations。
  • 增强 prepared snapshot coverage。
  • 让 source rescan 更增量化。
  • 对 HTML resource hints 做更强缓存。
  • 按 media type 和 size 优化 pipeline eligibility。

Future optimization areas:

  • Reduce header write branches.
  • Lower variant selection allocations.
  • Expand prepared snapshot coverage.
  • Make source rescans more incremental.
  • Cache HTML resource-hint extraction more aggressively.
  • Optimize pipeline eligibility by media type and size.

Clone this wiki locally