積壓策略
1)為什麼要結結,在哪裏做
Kesh是一層快速存儲器,可減少潛在性和昂貴資源的負擔(CPU/DB/外部 API)。重要目標是:- 速度(p95/p99)、成本(少於egress/CPU)、穩定性(少於峰值下的依賴)。
- 平滑峰並與「嘈雜的鄰居」隔離。
1.客戶端(瀏覽器/移動)-HTTP kesh, IndexedDB,本地存儲。
2.Edge/CDN-POP節點更接近用戶,緩存靜態和API的一部分。
3.L7網關/逆向-Nginx/Envoy/Varnish(微網,SWR)。
4.服務緩存-群集內的Redis/Memcached。
5.進程內-內存(Caffeine/Guava/LRU-map)。
6.DB中的緩存是材料表示,次要索引。
規則:盡可能接近消費者,但保留真相一次。
2)腰帶模式
2.1 Cache-aside (“lazy loading”)
應用程序首先從緩存中讀取;錯過時-從源中,然後寫入緩存。
優點:簡單,控制。缺點:寒冷的開始,爭吵的窗口。
2.2 Read-through
讀取總是通過高速緩存,該高速緩存本身會在錯誤時到達源(庫/伸縮層)。
集中TTL/灰化策略非常方便。
2.3 Write-through / Write-back (write-behind)
寫入:寫入緩存和源同步→一致性更高,潛伏性更高。
寫回:寫入緩存,異步閃存寫入源→快,但損失和沖突的風險。
2.4 Refresh-ahead (proactive)
預測「TTL即將到期」,並在背景中更新鑰匙,防止踩踏。
2.5 Negative caching
在短的TTL上散列「無數據/404/空白」可減少源負載。
2.6 Micro-caching
非常短的TTL(0。5-5 c)在L7上「接近揚聲器」(列表,主要)-顯著降低尾巴。
3) HTTP-kesh: 標題和控制
3.1基本標題
`Cache-Control`: `max-age`, `s-maxage` (для shared кэшей), `public/private`, `no-store`, `stale-while-revalidate`, `stale-if-error`.
驗證者:「ETag」(內容哈希),「Last-Modified」。
條件查詢:「If-None-Match」、「If-Modified-Since」 → 304 Not Modified。
3.2 Vary和鑰匙
「Vary:Accept-Encoding,授權,Cookie,Accept-Language」-形成不同的緩存選項。盡量減少「Vary」以免被「炸毀」基數。
3.3 HTTP響應示例
Cache-Control: public, max-age=60, s-maxage=300, stale-while-revalidate=60
ETag: "a1b2c3"
Vary: Accept-Encoding
4)密鑰設計和TTL
4.1個鑰匙
構造:「tenant: user: {id}:profile: v3」(包括架構版本)。
避免使用PII。
對於集合-鍵+查詢參數(歸一化和排序)。
4.2 TTL和一致性
短的TTL減少了爭執,但增加了失誤。
對於關鍵數據-驗證器(「ETag」)和SWR(stale-wile-revalidate)。
對於很少改變的人來說,長期TTL+「炸彈」致殘。
4.3轉化/罷工
如果更改不兼容,請更改密鑰前綴/版本(「v2 → v3」)。
對於靜態資源,文件名中的content hash。
5)殘疾: 戰略和做法
5.1直接刪除
代理上的「DEL key」/「PURGE」。危險:刪除和多讀者之間的種族。
5.2個Tagi/Surrogate鍵
將文檔與標簽集(類別/作者)關聯。殘疾-按標簽。
В Varnish/Edge — `Surrogate-Key: article:42 tag:author:7` + `BAN tag:author:7`.
5.3事件驅動殘疾
Pub/Sub (Kafka/NATS):更改源時,我們發布「入侵」事件。
緩存用戶收聽並刪除/更新密鑰。
5.4雙相
首先,通過標記已過時的密鑰(soft TTL),我們為stale服務,我們更新背景並用原子替換。
6)對抗stampede/dogpile和熱鍵
6.1 Request coalescing (singleflight)
一個制作人更新密鑰,其余的則等待結果(mutex/標簽「更新」)。
6.2 Jitter к TTL
在TTL中添加隨機性(± 10-20%),以避免同步擦傷。
6.3 Soft-TTL + hard-TTL
從緩存到軟式TTL,與觸發緩存平行;根據hard-TTL-我們認為是錯誤的。
6.4熱鍵
本地緩存高於一般緩存(二級)。
將熱鍵復制到多個硬盤和隨機選擇(僅讀取)。
更新特定密鑰的限額。
6.5 Redis+Lua示例(單機草圖)
lua
-- SETNX lock with TTL to avoid deadlocks local ok = redis. call("SET", KEYS[1], "1", "NX", "EX", ARGV[1])
if ok then return "LOCKED"
else return "WAIT"
end
7)置換策略和接受緩存
7.1 Eviction
LRU:簡單且適合本地化。
LFU:在「長壽」熱鍵下更好。
ARC/TinyLFU:回收/頻率平衡。
7.2 Admission(進口)
不要讓巨型稀有物體(TinyLFU/Bloom過濾器)。
在「大小/潛伏」邊界上壓縮大值(LZ4/Zstd)。
8)硬化和拓撲
8.1 Consistent hashing
穩定地將密鑰分布在指節上,減少群集生長/壓縮時的移動。
8.2 Redis/Memcached拓撲
Redis Cluster (插槽/shards), Sentinel (failover), read-only復制。
Memcached是客戶端側面的sharding(ketama hashing),沒有服務器級復制。
8.3本地+分布
級聯:proc(微型TTL/LRU)→ Redis(TTL更長)→源。
小心TTL冒號和緩存驗證器。
9) Edge、CDN和L7-kesh
9.1 Micro-cache на Nginx
nginx proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=api:100m inactive=10m;
map $request_method $skip_cache { default 0; POST 1; PUT 1; DELETE 1; }
server {
location /api/list {
if ($skip_cache) { add_header Cache-Control "no-store"; }
proxy_cache api;
proxy_cache_valid 200 2s; # micro-cache proxy_cache_use_stale error timeout updating;
proxy_cache_background_update on; # SWR add_header X-Cache $upstream_cache_status;
proxy_pass http://upstream;
}
}
9.2 Envoy (SWR和條件)
yaml http_filters:
- name: envoy. filters. http. cache typed_config:
"@type": type. googleapis. com/envoy. extensions. filters. http. cache. v3. CacheConfig typed_config:
"@type": type. googleapis. com/envoy. extensions. http. cache. file_system_http_cache. v3. FileSystemHttpCacheConfig cache_path: "/var/cache/envoy"
9.3 Varnish (Surrogate keys)
按標簽使用「Surrogate-Key」和「ban」進行批處理殘疾。
10) Kesh和數據一致性
10.1 Read-your-writes
對於自定義配置文件/購物車,請提供短的TTL或通過緩存寫入(write-through)或客戶端標記(寫入後N秒的旁路)。
10.2 Eventual vs Strong
對於推薦/分析-eventual+長的TTL。
對於金錢/訂單狀態-短TTL,驗證,有時在關鍵路徑上沒有緩存。
10.3不變量
在沒有嚴格的TTL和重新檢查的情況下,不要取消影響安全/ACL的字段。
11)可觀察性,SLO和控制
11.1個指標
hit_ratio (общий и per-route), byte_hit_ratio, miss_rate.
stampede_prevented_total, refresh_ahead_total, ban/purge_total.
潛伏期:來自緩存的p50/p95/p99來自源。
hot_keys_topN和QPS/字節。
11.2個日誌和跟蹤
編寫「X-Cache: HIT/MISS/STALE/UPDATING」。
在預告片中,標記響應源(「cache=true」,「tier=edge」服務「local」)。
11.3 SLO方法
示例:"對於API/catalog p99 ≤ 250毫秒,cache命中≥ 85%,stampede ≤ 0。1%的查詢"。
11.4 Runbooks
「失誤增加」→檢查TTL,加熱/殘疾,熱鍵,緩存大小和接受策略。
12)安全性和多重性
將tenant-id嵌入鍵中(以及HTTP下的「Vary」中)。
不要將私人回應稱為「公共」。
使用敏感數據加密緩存或僅存儲非PII/ID。
13)典型食譜
13.1目錄/磁帶(接近揚聲器)
Edge-Microcash 1-3 with+SWR, Inside-Redis on 15-60 s,殘疾升級事件。
13.2用戶配置文件
Cache-aside with TTL 30-120 s, bypass 5-10 with profile update (cookie/header) or write-through。
13.3文憑課程/參考書
長的TTL(分鐘-小時)+發布新數據時的目標殘疾;條件性GET的「ETag」。
13.4搜索引證
Edge-Microcesh 1-2,內部為refresh-ahead和coalescing,將密鑰中的查詢參數標準化。
14)反模式
無障礙緩存:只有TTL的希望→無關緊要的長窗口。
巨型「Vary」:變種的「爆炸」→低命中率。
prod/experiments的單一緩存→汙染。
TTL到期時,源頭上沒有阻塞→峰保護。
現金/權利/ACL緩存沒有嚴格的保證。
「全部連續」壓縮是額外的CPU,小型設施的p99惡化。
15)實施支票
- 確定腰果水平及其目標(edge/service/local)。
- 設計按鍵(轉換,tenant,參數標準化)。
- 選擇模式(cache-aside/read-through/refresh-ahead)。
- 配置TTL/soft-TTL/jitter,啟用SWR。
- 實現coalescing/singleflight, stampede保護。
- 組織殘疾(事件,標簽,purge/ban)。
- 輸入「X-Cache」的hit-ratio/latency和dashbords度量。
- 使用熱鍵進行負載測試。
- 請參考SLO和runbooks。
- 檢查安全/tenant隔離和「Vary」。
16) FAQ
Q: 選擇什麼-cache-aside或read-through?
A:對於簡單的服務-cache-aside。需要集中化和統一的政策-閱讀。
Q: 如何理解最佳TTL?
答:從允許的過時性,更新的頻率和目標命中率出發;添加jitter並觀察p95/p99/成本。
Q: write-back何時合適?
答:對於高負載流,可以接受事件一致性,並且存在「附加值」的可靠隊列/日誌。
Q:授權答案可以取消嗎?
答:是的,但標記「私人」和/或將tenant/用戶包含在/「Vary」鍵中。對於truly-private-客戶端緩存。
Q: 如何加熱緩存?
A:流行鍵列表,背景蠕蟲,爬行動物從日誌,發布/高峰前加熱(黑色星期五等)。
17)結果
有效的懸掛是按鍵設計+合理的TTL+精心選擇的模式,並通過事件殘疾,SWR/refresh-ahead和抗踩踏保護來增強。分層緩存(客戶端/邊緣/服務),添加可觀察性和SLO-並獲得穩定的潛伏尾巴、可預測的成本和對峰值負載的抵抗力。