Redis(缓存)
一 什么是缓存
1. 生活上的例子
比如有一个行李箱和一个手机,每次把手机放到行李箱在拿出来肯定很麻烦,如果放到裤兜里就会方便很多,所以裤兜算作行李箱的一个缓存,不仅仅是裤兜,甚至可以一直拿在手上等其他有存储介质的东西。
说白了缓存就是用来提高效率的,比如 内存 作为 CPU 和 外设 的缓存,和接下来要讲的 Redis 作为 MySQL 的缓存,MySQL 和磁盘打交道,磁盘是外设 I/O 效率慢,并且是随机寻址就更慢了,而 Redis 工作在内存,用来缓存 MySQL 的部分数据来分摊压力再合适不过了。
二 缓存如何更新
1. 定期更新
顾名思义:每隔一段时间来对缓存进行更新,比如每个一段时间统计访问频率最多的 100 个单词写入到日志里,到了时间在同步到 Redis 进行缓存更新。
定期更新带来的问题:隔的这段时间可能某些冷门词突然就变高频了,但是定期更新,所以无法及时更新到缓存里,导致绕过 Redis ,压力就导到 MySQL 中了,为了解决这个问题引入实时更新。
2. 实时更新
顾名思义:只要查不到缓存,就去 MySQL 中查,查到了在放到缓存里。
Redis 是跑在内存中的,内存大小有限,且不止有 Redis 这一个服务在使用,所以一直更新就会导致 Redis 占用内存直到内存用尽,所以引入了缓存淘汰策略。
3. 淘汰策略
1. FIFO(先进先出)
先进缓存的先淘汰。
2. LRU(最久未访问的)
最久未访问的先淘汰。
3. LFU(最少访问次数)
最少访问次数的先淘汰。
4. Random(随机淘汰)
随机淘汰。
5. Redis 支持的淘汰选项:
Volation-LRU:在设置了过期的 Key 中淘汰最久未访问的。
AllKeys-LRU:在所有的 Key 中淘汰最久未访问的。
Volation-LFU:在设置了过期的 Key 中淘汰最少访问次数的。
AllKeys-LFU:在所有的 Key 中淘汰最少访问次数的。
AllKeys-Random:在设置了过期的 Key 中随机淘汰。
Volation-Randon:在所有的 Key 中随机淘汰。
Volation-TTL:在设置了过期的 Key 中淘汰越早过期的。
Noeviction(默认策略):没有任何淘汰机制,写超了直接报错(不适用与实时更新)。
三 缓存使用事项
1. 缓存预热
缓存更新采用实时更新的时候:
原因:
- Redis 服务刚启动,什么也没有,压力全部到 MySQL 中,并把查到的数据缓存到 Redis,一开始 MySQL 就会承担大量的并发请求导致压力过大。
解决办法:
- 最开始的时候把 定期更新 和 实时更新 相结合,先把预先的高频日志导到 Redis,后续在采用实时更新,避免了一开始大量并发到 MySQL。
定期更新没有缓存预热的情况。
2. 缓存穿透
当查询某些 Key,Redis MySQL 中都不存在,MySQL 压力也会增大。
原因:
- MySQL 删除误删了数据。
- Key 本身不合法。
解决办法:
- 对不合法的 Key 检测。
- 采用布隆过滤器提前检测 Key 是否存在。
3. 缓存雪崩
某一时间端大量的 Key 失效,导致 MySQL 压力过大。
原因:
- 如果同一时间内设置了过期的 Key ,并且过期时间相同。
- Redis 服务挂了。
解决办法:
- 过期时间添加其他因子避免过期时间相同。
- 引入集群,哨兵自动管理挂掉的 Redis 服务器。
4. 缓存击穿
某一时间端热点 Key 失效,导致 MySQL 压力过大,和缓存雪崩类似。
原因:
- 和缓存雪崩类似。
解决办法:
- 热点 Key 尽量不要设置过期时间。
- 引入分布式锁,访问 MySQL 次数上限则锁住,避免 MySQL 压力过大。