diff --git a/notes/缓存.md b/notes/缓存.md
index 91dfc0e7..64007854 100644
--- a/notes/缓存.md
+++ b/notes/缓存.md
@@ -2,12 +2,12 @@
* [缓存](#缓存)
* [一、缓存特征](#一缓存特征)
- * [二、缓存位置](#二缓存位置)
+ * [二、缓存位置](#二缓存位置) 🔥
* [三、CDN](#三cdn)
- * [四、缓存问题](#四缓存问题)
+ * [四、缓存问题](#四缓存问题) 🔥🔥
* [五、数据分布](#五数据分布)
* [六、一致性哈希](#六一致性哈希)
- * [七、LRU](#七lru)
+ * [七、LRU](#七lru) 🔥
* [附录:实测](#附录实测)
* [参考资料](#参考资料)
@@ -37,7 +37,7 @@
除了容量淘汰,缓存通常还会为数据设置过期时间,到期后自动失效。
-## 二、缓存位置
+## 二、缓存位置 🔥
### 浏览器
@@ -114,7 +114,7 @@ CDN 主要有以下优点:
-## 四、缓存问题
+## 四、缓存问题 🔥🔥
穿透、击穿和雪崩都是请求越过缓存直接到达数据库,区别在于原因:穿透查询的是缓存和数据库中都不存在的数据,击穿是一个热点键过期,雪崩是大量的键同时过期或者缓存整体不可用。
@@ -194,7 +194,7 @@ Redis 8 起内置了布隆过滤器(BF.RESERVE、BF.ADD、BF.EXISTS),Redis
常用的补救措施:
-- 为缓存设置过期时间作为兜底;
+- 为缓存设置过期时间作为兜底,需要注意过期时间从这次写回缓存时算起,慢读请求很晚才写回旧值时,旧值最长还会保留一个完整的过期时间;
- 延迟双删:更新数据库并删除缓存之后,隔一段时间再删除一次,清掉慢读请求写回的旧值,间隔要大于读请求从查询数据库到写回缓存的耗时;
- 删除失败时重试:把要删除的键发到消息队列,由消费者删除,失败就重新投递;
- 订阅数据库的 binlog(例如使用 Canal)异步删除缓存,失败时重试,业务代码中不再需要删除缓存;
@@ -285,7 +285,7 @@ binlog 方案把删除缓存从业务代码中移出:Canal 伪装成 MySQL 的
Redis Cluster 使用的不是一致性哈希,而是把 Key 映射到固定的 16384 个哈希槽上,再把哈希槽分配给各个节点,节点变化时只需要迁移对应的哈希槽。
-## 七、LRU
+## 七、LRU 🔥
以下是基于双向链表和 HashMap 的 LRU 算法实现,对算法的解释如下: