本文目录导读:

缓存雪崩是指大量缓存数据在同一时间过期失效,导致所有请求直接打到数据库,造成数据库压力骤增甚至崩溃,Python脚本预防缓存雪崩的常用策略如下:
设置随机过期时间
避免所有缓存使用相同的过期时间,在基础过期时间上增加随机偏移:
import random
import time
def get_random_expiry(base_ttl=3600):
"""基础过期时间上增加随机偏移(0-600秒)"""
return base_ttl + random.randint(0, 600)
# 使用示例
cache.set(key, value, ex=get_random_expiry())
缓存预热(预加载)
在系统低峰期提前加载热点数据到缓存:
def warm_up_cache():
"""系统启动或低峰期预加载热点数据"""
hot_keys = get_hot_keys_from_db() # 从数据库获取热点key
for key in hot_keys:
if not cache.exists(key):
value = db.query(key) # 从数据库获取数据
cache.set(key, value, ex=get_random_expiry())
互斥锁(加锁单线程重建缓存)
当缓存失效时,只允许一个线程去重建缓存,其他线程等待:
import threading
class CacheManager:
def __init__(self):
self.locks = {}
self.lock = threading.Lock()
def get_with_lock(self, key, rebuild_func, ttl=3600):
# 尝试从缓存获取数据
data = cache.get(key)
if data is not None:
return data
# 获取或创建key对应的锁
with self.lock:
if key not in self.locks:
self.locks[key] = threading.Lock()
key_lock = self.locks[key]
# 加锁重建缓存
with key_lock:
# 双重检查,防止其他线程已重建
data = cache.get(key)
if data is not None:
return data
# 从数据库重建缓存
data = rebuild_func()
cache.set(key, data, ex=ttl)
return data
使用Redis分布式锁
对于分布式系统,使用Redis的SETNX实现分布式锁:
import redis
import time
r = redis.Redis()
def get_with_distributed_lock(key, rebuild_func, ttl=3600, lock_timeout=10):
"""使用分布式锁防止缓存雪崩"""
data = r.get(key)
if data:
return data
lock_key = f"lock:{key}"
lock_value = str(time.time())
# 尝试获取锁,设置过期时间防止死锁
if r.setnx(lock_key, lock_value):
r.expire(lock_key, lock_timeout)
try:
# 双重检查
data = r.get(key)
if data:
return data
# 重建缓存
data = rebuild_func()
r.setex(key, ttl, data)
return data
finally:
# 释放锁(只释放自己的锁)
if r.get(lock_key) == lock_value:
r.delete(lock_key)
else:
# 获取锁失败,等待重试
time.sleep(0.1)
return get_with_distributed_lock(key, rebuild_func, ttl, lock_timeout)
多级缓存策略
使用本地缓存(如LRU)配合Redis缓存:
from functools import lru_cache
import redis
r = redis.Redis()
class MultiLevelCache:
def __init__(self, local_ttl=300, redis_ttl=3600):
self.local_ttl = local_ttl
self.redis_ttl = redis_ttl
# 本地缓存(一级缓存,过期时间短)
@lru_cache(maxsize=1000)
def get_local(self, key):
return None # 实际实现需要存储时间和值
def get(self, key, rebuild_func):
# 1. 尝试本地缓存
data = self.get_local(key)
if data:
return data
# 2. 尝试Redis缓存
data = r.get(key)
if data:
self.set_local(key, data) # 回写本地缓存
return data
# 3. 从数据库获取
data = rebuild_func()
# 4. 写入各级缓存
self.set_local(key, data, self.local_ttl)
r.setex(key, self.redis_ttl, data)
return data
限流与降级
控制同时重建缓存的并发数,必要时降级:
from contextlib import contextmanager
import threading
class CircuitBreaker:
def __init__(self, max_concurrent=5):
self.semaphore = threading.Semaphore(max_concurrent)
self.is_open = False
@contextmanager
def acquire(self):
if self.is_open:
raise Exception("Circuit breaker is open")
acquired = self.semaphore.acquire(blocking=False)
if not acquired:
raise Exception("Too many concurrent requests")
try:
yield
finally:
self.semaphore.release()
circuit_breaker = CircuitBreaker()
def safe_get_data(key, rebuild_func):
try:
with circuit_breaker.acquire():
return rebuild_func()
except Exception:
# 降级处理
return get_stale_data(key) # 返回过期数据或默认值
综合应用示例
import random
import time
from functools import wraps
def anti_cache_avalanche(ttl=3600, lock_timeout=10):
"""装饰器实现缓存雪崩防护"""
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
key = f"{func.__name__}:{args}:{kwargs}"
# 启用熔断机制
if hasattr(wrapper, 'breaker') and wrapper.breaker.is_open:
return get_fallback_value(key) # 返回降级数据
# 尝试获取缓存(带随机过期)
data = cache.get(key)
if data:
return data
# 使用互斥锁重建缓存
lock_key = f"lock:{key}"
if cache.setnx(lock_key, 1, ex=lock_timeout):
try:
# 双重检查
data = cache.get(key)
if data:
return data
# 执行原始函数获取数据
data = func(*args, **kwargs)
# 设置缓存(随机过期时间)
actual_ttl = ttl + random.randint(0, 600)
cache.set(key, data, ex=actual_ttl)
return data
finally:
cache.delete(lock_key)
else:
# 等待并重试
time.sleep(0.1)
return wrapper(*args, **kwargs)
return wrapper
return decorator
# 使用示例
@anti_cache_avalanche(ttl=3600)
def get_user_info(user_id):
# 从数据库获取用户信息
return db.query(f"SELECT * FROM users WHERE id={user_id}")
- 过期时间分散化:使用随机过期时间
- 预加载机制:在低峰期预热热点数据
- 互斥锁保护:只允许单线程重建缓存
- 多级缓存配合:本地缓存 + Redis,内存溢出保护
- 熔断降级:当重建缓存压力过大时,返回过期数据或默认值
- 监控报警:监控缓存命中率、过期key数量、数据库压力等指标
根据系统规模和业务特性,选择适合的组合策略,并做好监控和压测。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播