From ab8da3373c4d54c0beea07d9a5b451a2df216f3b Mon Sep 17 00:00:00 2001 From: CyC2018 Date: Wed, 4 Nov 2026 22:39:58 +0800 Subject: [PATCH] =?UTF-8?q?Update=20=E7=BC=93=E5=AD=98.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 补充 CDN 的调度、版本化文件名与刷新,击穿时等待的时长上限,以及 lazyfree-lazy-server-del。 --- notes/缓存.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/notes/缓存.md b/notes/缓存.md index 59f5c5fc..4c1a1617 100644 --- a/notes/缓存.md +++ b/notes/缓存.md @@ -106,7 +106,7 @@ CPU 为了解决运算速度与主存访问速度不匹配的问题,引入了 内容分发网络(Content Delivery Network, CDN)是一种互连的网络系统,它利用更靠近用户的服务器从而更快更可靠地将 HTML、CSS、JavaScript、音乐、图片、视频等静态资源分发给用户。 -用户请求通过 DNS 被调度到最近的 CDN 节点,节点未命中缓存时再回源站获取。 +用户请求通过 DNS 被调度到最近的 CDN 节点,节点未命中缓存时再回源站获取。调度一般靠 CNAME:网站把域名用 CNAME 指向 CDN 提供的域名,由 CDN 的调度系统按查询来源的位置返回较近的节点,例子见 [域名系统](计算机网络%20-%20应用层.md#域名系统) 中 www.jd.com 的解析结果。 CDN 主要有以下优点: @@ -114,6 +114,10 @@ CDN 主要有以下优点: - 通过部署多台服务器,从而提高系统整体的带宽性能; - 多台服务器可以看成是一种冗余机制,从而具有高可用性。 +静态资源更新后,节点上可能还缓存着旧版本。常用的做法是在文件名中带上版本或内容的哈希,例如 app.3f2a9c.js,并设置很长的缓存时间,内容一变文件名就变;入口的 HTML 用 no-cache,每次向源站确认,见 [强缓存与协商缓存](HTTP.md#5-强缓存与协商缓存)。也可以调用 CDN 的刷新接口让节点上的旧缓存失效,但一次刷新大量文件会让回源请求突然增多,AWS CloudFront 的文档也推荐用带版本号的文件名更新内容。 + +按用户生成的内容、带 Cache-Control: private 的响应和实时变化的接口不适合由 CDN 缓存。缓存键中包含查询参数时,与内容无关的参数(例如统计来源的 from=campaign)要去掉,否则同一个文件会被缓存成很多份,命中率下降。 +

## 四、缓存问题 🔥🔥 @@ -153,7 +157,7 @@ Redis 8 起内置了布隆过滤器(BF.RESERVE、BF.ADD、BF.EXISTS),Redis 解决方案: -- 互斥锁:缓存未命中时用 `SET lock:product:1024 <随机值> NX EX 3` 抢锁,抢到的请求先再查一次缓存(可能别人已经写回),仍然没有才查询数据库并写回缓存,最后释放锁(释放时要确认锁仍是自己的,见 [分布式锁](分布式.md#redis-的-set-nx-指令));没抢到的请求等待一小段时间(例如 10 毫秒)后重新读缓存。锁的过期时间要长于重建缓存的耗时,否则锁会在重建期间过期,其它请求再次抢到锁并回源,例如锁 100 毫秒、重建 300 毫秒时,100 个并发请求回源 4 次(见[附录 A5](#a5-缓存击穿的三种做法));耗时难以估计时可以给锁续期,见[分布式锁](分布式.md#redis-的-set-nx-指令); +- 互斥锁:缓存未命中时用 `SET lock:product:1024 <随机值> NX EX 3` 抢锁,抢到的请求先再查一次缓存(可能别人已经写回),仍然没有才查询数据库并写回缓存,最后释放锁(释放时要确认锁仍是自己的,见 [分布式锁](分布式.md#redis-的-set-nx-指令));没抢到的请求等待一小段时间(例如 10 毫秒)后重新读缓存,等待的总时长要有上限,超过后返回默认值或报错,否则持锁的请求崩溃时,其它请求要一直等到锁过期。锁的过期时间要长于重建缓存的耗时,否则锁会在重建期间过期,其它请求再次抢到锁并回源,例如锁 100 毫秒、重建 300 毫秒时,100 个并发请求回源 4 次(见[附录 A5](#a5-缓存击穿的三种做法));耗时难以估计时可以给锁续期,见[分布式锁](分布式.md#redis-的-set-nx-指令); - 逻辑过期:键不设置过期时间,而是在值中保存一个过期时间。读到已经过期的值时,抢到锁的请求启动后台线程重建缓存,所有请求都直接返回旧值,不等待。这些键不会被 volatile 开头的淘汰策略淘汰,不再需要时要主动删除。

@@ -249,7 +253,7 @@ Redis 8 起内置了布隆过滤器(BF.RESERVE、BF.ADD、BF.EXISTS),Redis - 用 redis-cli --bigkeys 或者 --memkeys 扫描,它们使用 SCAN 命令遍历,不会阻塞服务器;用 MEMORY USAGE 查看单个键占用的内存; - 拆分:例如把一个大的 HASH 按字段的哈希值拆成 16 个小 HASH,user:1001:fav:0 到 user:1001:fav:15,读写字段 f 时访问第 hash(f) % 16 个;大的字符串可以压缩,或者把文件放到对象存储,Redis 中只保存地址; -- 删除用 UNLINK,并开启 lazyfree-lazy-expire 和 lazyfree-lazy-eviction,让过期和淘汰也在后台释放内存;读取集合时用 HSCAN、SSCAN 分批读取,不要一次读出所有元素。 +- 删除用 UNLINK,并开启 lazyfree-lazy-expire、lazyfree-lazy-eviction 和 lazyfree-lazy-server-del,让过期、淘汰以及 SET、RENAME 覆盖旧值时的删除也在后台释放内存;读取集合时用 HSCAN、SSCAN 分批读取,不要一次读出所有元素。 热 Key 的问题是请求集中到同一个节点,集群中其它节点再多也无法分担。处理方法: