当前位置: 面试刷题>> 什么是缓存击穿、缓存穿透、缓存雪崩?
在软件开发与架构设计的面试中,缓存机制的理解与应用是一个重要考察点,特别是面对高并发场景时,缓存击穿、缓存穿透、缓存雪崩是三个常见且需要妥善处理的问题。下面,我将以高级程序员的视角,详细解析这三个概念,并尝试通过示例代码和策略来加深理解。
### 1. 缓存击穿
**定义**:缓存击穿指的是缓存中没有但数据库中有的数据(一般是缓存时间到期),这时并发用户特别多,同时读缓存没读到数据,又都去数据库去取数据,引起数据库压力瞬间增大,造成数据库崩溃的情况。
**解决策略**:
- **布隆过滤器**:在查询数据库之前,使用布隆过滤器快速判断数据是否存在,若不存在则直接返回,避免数据库查询。
- **热点数据永不过期**:对于访问极其频繁的数据,可以设置其缓存永不过期,或采用定期更新而非依赖时间过期的方式。
- **互斥锁(Mutex Lock)**:在查询数据库时加锁,确保同一数据只会被一个线程查询并更新到缓存中,减少数据库压力。
**示例代码片段**(伪代码,展示互斥锁思路):
```python
import threading
cache_lock = threading.Lock()
def get_data(key):
# 尝试从缓存中获取数据
data = cache.get(key)
if data is None:
with cache_lock:
# 再次检查,避免重复查询
data = cache.get(key)
if data is None:
# 从数据库加载数据
data = db.get(key)
# 将数据存入缓存
cache.set(key, data, expire_time)
return data
```
### 2. 缓存穿透
**定义**:缓存穿透是指查询一个数据库一定不存在的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从数据库查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,造成缓存“击穿”的现象。
**解决策略**:
- **布隆过滤器**:同上,使用布隆过滤器快速判断数据是否可能存在于数据库中,若不存在则直接返回。
- **空值缓存**:对于不存在的数据,也在缓存中保存一个空值(或特殊标记),但设置较短的过期时间,以减少对数据库的访问压力。
**示例代码片段**(空值缓存思路):
```python
def get_data_with_null_cache(key):
# 尝试从缓存中获取数据
data = cache.get(key)
if data is None:
# 尝试从数据库获取数据
data = db.get(key)
if data is None:
# 数据不存在,存入空值或特殊标记
cache.set(key, NULL_MARKER, short_expire_time)
else:
# 数据存在,正常存入缓存
cache.set(key, data, expire_time)
elif data == NULL_MARKER:
# 缓存中为空值标记,直接返回
return None
return data
```
### 3. 缓存雪崩
**定义**:缓存雪崩是指缓存服务器在某个时间段突然宕机或大量缓存数据在同一时间过期,导致大量请求直接访问数据库,数据库压力骤增,甚至崩溃。
**解决策略**:
- **缓存数据过期时间设置随机**:避免大量缓存数据同时过期。
- **限流降级**:在数据库层面对访问进行限流,或者在应用层进行降级处理,如返回预设值或默认页面。
- **缓存预热**:在系统启动或低峰期时,将热点数据预先加载到缓存中,减少高峰期对数据库的访问压力。
**示例代码片段**(缓存预热思路):
```python
def cache_warmup():
hot_keys = get_hot_keys()
for key in hot_keys:
data = db.get(key)
if data:
cache.set(key, data, expire_time)
# 系统启动时调用
cache_warmup()
```
通过上述解析和示例代码,我们可以看出,面对缓存击穿、穿透、雪崩等问题,关键在于预防和减轻对数据库的冲击,通过合理的缓存策略、限流降级、数据预热等措施,可以有效提升系统的稳定性和性能。在实际工作中,还需要结合具体的业务场景和技术栈,灵活应用这些策略。此外,提及的“码小课”网站,可以作为一个学习和分享此类技术知识的平台,为开发者提供更多实用的教程和案例。