Redis搞定缓存击穿:互斥锁+缓存预热与随机过期

缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。针对缓存击穿问题,Redis 提供了多种解决方案,以下是两种常见且有效的方法:

图片[1]_Redis搞定缓存击穿:互斥锁+缓存预热与随机过期_知途无界

1. 使用互斥锁(Mutex Lock)

原理

在缓存失效的瞬间,大量请求会直达数据库,造成数据库压力剧增。为了解决这个问题,可以在访问数据库之前,先尝试获取一个互斥锁。只有获取到锁的请求才能继续访问数据库,其他请求则等待或返回默认值。

实现步骤

  1. 检查缓存:首先检查缓存中是否存在所需的数据。
  2. 获取锁:如果缓存中不存在数据,尝试获取互斥锁。
  3. 访问数据库:如果获取到锁,则访问数据库获取数据,并将数据更新到缓存中。
  4. 释放锁:无论是否获取到数据,最后都要释放锁。
  5. 返回数据:如果获取到数据,则返回给请求方;如果未获取到数据(例如数据库中也无数据),则返回默认值或错误提示。

优点

  • 有效防止缓存击穿,确保在缓存失效的瞬间只有一个请求能够访问数据库。
  • 实现相对简单,易于理解和维护。

缺点

  • 引入了锁机制,可能会增加系统的复杂性。
  • 如果锁实现不当,可能会导致死锁或性能下降。

示例代码(伪代码)

def get_data_with_lock(key):
    # 检查缓存
    data = redis.get(key)
    if data is not None:
        return data

    # 尝试获取锁
    lock_acquired = acquire_lock(key)
    if not lock_acquired:
        # 如果未获取到锁,可以返回默认值或等待重试
        return default_value

    try:
        # 访问数据库
        data = database.get(key)
        if data is not None:
            # 更新缓存
            redis.set(key, data, ex=cache_expiration)
        return data
    finally:
        # 释放锁
        release_lock(key)

2. 缓存预热与随机过期时间

原理

  • 缓存预热:在系统启动或低峰期,将可能频繁访问的数据预先加载到缓存中,以减少缓存失效时的数据库访问压力。
  • 随机过期时间:为了避免大量缓存同时失效,可以为每个缓存项设置一个随机的过期时间,使得缓存失效的时间点更加分散。

实现步骤

  1. 缓存预热:在系统启动或低峰期,通过脚本或定时任务将热门数据加载到缓存中。
  2. 设置随机过期时间:在将数据存入缓存时,为每个缓存项设置一个随机的过期时间(例如,在基础过期时间的基础上加上一个随机数)。

优点

  • 缓存预热可以减少缓存失效时的数据库访问压力。
  • 随机过期时间可以避免大量缓存同时失效,进一步减轻数据库压力。

缺点

  • 缓存预热需要额外的维护成本,需要定期更新缓存数据。
  • 随机过期时间可能无法完全避免缓存击穿,但在一定程度上可以减轻问题。

示例代码(设置随机过期时间)

import random
import time

def set_data_with_random_expiration(key, value, base_expiration=3600):
    # 设置随机过期时间
    random_expiration = base_expiration + random.randint(0, 300)  # 在基础过期时间上加上0到300秒的随机数
    redis.set(key, value, ex=random_expiration)

# 使用示例
set_data_with_random_expiration('hot_data_key', 'hot_data_value')
© 版权声明
THE END
喜欢就点个赞,支持一下吧!
点赞18 分享
评论 抢沙发
头像
欢迎您留下评论!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容