chinese直男口爆体育生外卖, 99久久er热在这里只有精品99, 又色又爽又黄18禁美女裸身无遮挡, gogogo高清免费观看日本电视,私密按摩师高清版在线,人妻视频毛茸茸,91论坛 兴趣闲谈,欧美 亚洲 精品 8区,国产精品久久久久精品免费

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Redis緩存的經(jīng)典問(wèn)題和解決方案

馬哥Linux運(yùn)維 ? 來(lái)源:馬哥Linux運(yùn)維 ? 2025-08-20 16:24 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

Redis緩存穿透、雪崩、擊穿三大難題的解決方案與實(shí)戰(zhàn)

作為一名資深運(yùn)維工程師,我在生產(chǎn)環(huán)境中處理過(guò)無(wú)數(shù)次Redis相關(guān)的故障。今天分享三個(gè)讓無(wú)數(shù)運(yùn)維人員半夜被叫醒的經(jīng)典問(wèn)題及其完整解決方案。

前言:那些讓人崩潰的凌晨電話

凌晨3點(diǎn),手機(jī)鈴聲急促響起:"系統(tǒng)掛了!用戶無(wú)法登錄!數(shù)據(jù)庫(kù)CPU飆到100%!"這樣的場(chǎng)景,相信每個(gè)運(yùn)維工程師都不陌生。而在我7年的運(yùn)維生涯中,80%的此類故障都與Redis緩存的三大經(jīng)典問(wèn)題有關(guān):緩存穿透、緩存雪崩、緩存擊穿。

一、緩存穿透:惡意攻擊的噩夢(mèng)

問(wèn)題現(xiàn)象

用戶瘋狂查詢數(shù)據(jù)庫(kù)中不存在的數(shù)據(jù),每次查詢都繞過(guò)緩存直接打到數(shù)據(jù)庫(kù),導(dǎo)致數(shù)據(jù)庫(kù)壓力驟增。

真實(shí)案例回顧

某電商平臺(tái)遭遇惡意攻擊,攻擊者使用隨機(jī)生成的商品ID瘋狂查詢商品信息。由于這些ID在數(shù)據(jù)庫(kù)中根本不存在,Redis緩存無(wú)法命中,每次請(qǐng)求都直接打到MySQL,導(dǎo)致數(shù)據(jù)庫(kù)連接池瞬間耗盡。

監(jiān)控?cái)?shù)據(jù)觸目驚心:

? 數(shù)據(jù)庫(kù)QPS:從平時(shí)的500/s飆升到8000/s

? 緩存命中率:從95%跌至10%

? 系統(tǒng)響應(yīng)時(shí)間:從50ms激增到5000ms

解決方案詳解

方案一:布隆過(guò)濾器(推薦指數(shù))

布隆過(guò)濾器是解決緩存穿透最優(yōu)雅的方案,其核心思想是"寧可錯(cuò)殺,不可放過(guò)"。

實(shí)現(xiàn)步驟:

importredis
importmmh3
frombitarrayimportbitarray

classBloomFilter:
 def__init__(self, capacity=1000000, error_rate=0.001):
   """
    初始化布隆過(guò)濾器
    capacity: 預(yù)計(jì)數(shù)據(jù)量
    error_rate: 誤判率
    """
   self.capacity = capacity
   self.error_rate = error_rate
   self.bit_num =self._get_bit_num()
   self.hash_num =self._get_hash_num()
   self.bit_array = bitarray(self.bit_num)
   self.bit_array.setall(0)
   self.redis_client = redis.Redis(host='localhost', port=6379, db=0)
   
 def_get_bit_num(self):
   """計(jì)算位數(shù)組大小"""
   returnint(-self.capacity * math.log(self.error_rate) / (math.log(2) **2))
 
 def_get_hash_num(self):
   """計(jì)算哈希函數(shù)個(gè)數(shù)"""
   returnint(self.bit_num * math.log(2) /self.capacity)
 
 def_hash(self, value):
   """多重哈希函數(shù)"""
    h1 = mmh3.hash(value,0)
    h2 = mmh3.hash(value, h1)
   foriinrange(self.hash_num):
     yield(h1 + i * h2) %self.bit_num
 
 defadd(self, value):
   """添加元素"""
   forindexinself._hash(value):
     self.bit_array[index] =1
 
 defis_exist(self, value):
   """判斷元素是否存在"""
   forindexinself._hash(value):
     ifnotself.bit_array[index]:
       returnFalse
   returnTrue

# 業(yè)務(wù)層面的使用
defget_product_info(product_id):
 # 先經(jīng)過(guò)布隆過(guò)濾器檢查
 ifnotbloom_filter.is_exist(product_id):
   return{"error":"商品不存在"}
 
 # 查詢緩存
  cache_key =f"product:{product_id}"
  cached_data = redis_client.get(cache_key)
 
 ifcached_data:
   returnjson.loads(cached_data)
 
 # 查詢數(shù)據(jù)庫(kù)
  product = database.query_product(product_id)
 ifproduct:
   # 緩存數(shù)據(jù)
    redis_client.setex(cache_key,3600, json.dumps(product))
   returnproduct
 else:
   # 緩存空值,防止重復(fù)查詢
    redis_client.setex(cache_key,300, json.dumps({}))
   return{"error":"商品不存在"}

運(yùn)維部署建議:

? 布隆過(guò)濾器數(shù)據(jù)存儲(chǔ)在Redis中,支持集群部署

? 定期重建布隆過(guò)濾器,避免誤判率過(guò)高

? 監(jiān)控布隆過(guò)濾器的容量使用情況

方案二:空值緩存

簡(jiǎn)單但有效的方案,將查詢結(jié)果為空的Key也緩存起來(lái)。

defquery_with_null_cache(key):
 # 1. 查詢緩存
  cached_data = redis_client.get(f"cache:{key}")
 ifcached_dataisnotNone:
   returnjson.loads(cached_data)ifcached_data !="null"elseNone
 
 # 2. 查詢數(shù)據(jù)庫(kù)
  data = database.query(key)
 
 # 3. 緩存結(jié)果(包括空值)
 ifdata:
    redis_client.setex(f"cache:{key}",3600, json.dumps(data))
 else:
   # 緩存空值,但設(shè)置較短的過(guò)期時(shí)間
    redis_client.setex(f"cache:{key}",300,"null")
 
 returndata

注意事項(xiàng):

? 空值緩存時(shí)間要比正常數(shù)據(jù)短

? 需要考慮存儲(chǔ)成本

? 要有清理機(jī)制防止垃圾數(shù)據(jù)堆積

二、緩存雪崩:系統(tǒng)癱瘓的元兇

問(wèn)題現(xiàn)象

大量緩存在同一時(shí)間失效,導(dǎo)致大量請(qǐng)求直接打到數(shù)據(jù)庫(kù),引發(fā)數(shù)據(jù)庫(kù)壓力過(guò)大甚至宕機(jī)。

血淚教訓(xùn)

某金融系統(tǒng)在促銷活動(dòng)期間,由于緩存批量過(guò)期,瞬間10萬(wàn)+用戶的查詢請(qǐng)求全部打到數(shù)據(jù)庫(kù),導(dǎo)致整個(gè)交易系統(tǒng)癱瘓45分鐘,直接損失超過(guò)500萬(wàn)。

解決方案

方案一:隨機(jī)過(guò)期時(shí)間

importrandom
importtime

defset_cache_with_random_expire(key, data, base_expire=3600):
 """
  設(shè)置帶隨機(jī)過(guò)期時(shí)間的緩存
  base_expire: 基礎(chǔ)過(guò)期時(shí)間(秒)
  """
 # 在基礎(chǔ)時(shí)間上增加隨機(jī)波動(dòng)(±20%)
  random_factor = random.uniform(0.8,1.2)
  expire_time =int(base_expire * random_factor)
 
  redis_client.setex(key, expire_time, json.dumps(data))
 
 # 記錄日志便于運(yùn)維監(jiān)控
  logger.info(f"Cache set:{key}, expire:{expire_time}s")

# 批量緩存預(yù)熱時(shí)的應(yīng)用
defbatch_warm_up_cache(data_list):
 """批量緩存預(yù)熱,避免同時(shí)過(guò)期"""
 fordataindata_list:
    key =f"product:{data['id']}"
   # 每個(gè)緩存的過(guò)期時(shí)間都不同
    set_cache_with_random_expire(key, data,3600)
   # 控制頻率,避免Redis壓力過(guò)大
    time.sleep(0.01)

方案二:多級(jí)緩存架構(gòu)

classMultiLevelCache:
 def__init__(self):
   self.l1_cache = {} # 本地緩存
   self.l2_cache = redis.Redis() # Redis緩存
   self.l3_cache = memcached.Client(['127.0.0.1:11211']) # Memcached緩存
 
 defget(self, key):
   # L1緩存命中
   ifkeyinself.l1_cache:
     self.metrics.incr('l1_hit')
     returnself.l1_cache[key]
   
   # L2緩存命中
    l2_data =self.l2_cache.get(key)
   ifl2_data:
     self.metrics.incr('l2_hit')
     # 回寫L1緩存
     self.l1_cache[key] = json.loads(l2_data)
     returnself.l1_cache[key]
   
   # L3緩存命中
    l3_data =self.l3_cache.get(key)
   ifl3_data:
     self.metrics.incr('l3_hit')
     # 回寫上級(jí)緩存
     self.l1_cache[key] = l3_data
     self.l2_cache.setex(key,3600, json.dumps(l3_data))
     returnl3_data
   
   # 緩存未命中,查詢數(shù)據(jù)庫(kù)
   self.metrics.incr('cache_miss')
   returnNone
 
 defset(self, key, value, expire=3600):
   # 同時(shí)寫入所有緩存層級(jí)
   self.l1_cache[key] = value
   self.l2_cache.setex(key, expire, json.dumps(value))
   self.l3_cache.set(key, value, time=expire)

方案三:互斥鎖重建緩存

importthreading
fromcontextlibimportcontextmanager

classCacheRebuildManager:
 def__init__(self):
   self.rebuilding_keys =set()
   self.lock = threading.Lock()
 
  @contextmanager
 defrebuild_lock(self, key):
   """互斥鎖控制緩存重建"""
   withself.lock:
     ifkeyinself.rebuilding_keys:
       # 如果正在重建,等待一段時(shí)間
        time.sleep(0.1)
       yieldFalse
     else:
       self.rebuilding_keys.add(key)
       try:
         yieldTrue
       finally:
         self.rebuilding_keys.discard(key)

rebuild_manager = CacheRebuildManager()

defget_data_with_rebuild_protection(key):
 # 查詢緩存
  cached_data = redis_client.get(key)
 ifcached_data:
   returnjson.loads(cached_data)
 
 # 緩存未命中,嘗試獲取重建鎖
 withrebuild_manager.rebuild_lock(key)asshould_rebuild:
   ifshould_rebuild:
     # 獲得鎖,進(jìn)行數(shù)據(jù)重建
      data = database.query(key)
     ifdata:
       # 設(shè)置隨機(jī)過(guò)期時(shí)間防止雪崩
        expire_time = random.randint(3600,4320) # 1-1.2小時(shí)
        redis_client.setex(key, expire_time, json.dumps(data))
     returndata
   else:
     # 等待重建完成后再次查詢緩存
      time.sleep(0.1)
      cached_data = redis_client.get(key)
     returnjson.loads(cached_data)ifcached_dataelseNone

三、緩存擊穿:熱點(diǎn)數(shù)據(jù)的陷阱

問(wèn)題描述

某個(gè)熱點(diǎn)Key突然失效,導(dǎo)致大量請(qǐng)求同時(shí)查詢數(shù)據(jù)庫(kù),造成瞬時(shí)壓力。

經(jīng)典案例

視頻平臺(tái)的熱門視頻緩存過(guò)期,瞬間5000+并發(fā)請(qǐng)求打到數(shù)據(jù)庫(kù)查詢視頻信息,導(dǎo)致數(shù)據(jù)庫(kù)連接池耗盡,整個(gè)視頻服務(wù)不可用。

解決方案

方案一:永不過(guò)期 + 邏輯過(guò)期

importjson
importtime
importthreading

classLogicalExpireCache:
 def__init__(self):
   self.redis_client = redis.Redis()
   self.executor = ThreadPoolExecutor(max_workers=10)
 
 defset_with_logical_expire(self, key, data, expire_seconds):
   """設(shè)置帶邏輯過(guò)期時(shí)間的緩存"""
    cache_data = {
     'data': data,
     'expire_time': time.time() + expire_seconds
    }
   # 永不過(guò)期,但包含邏輯過(guò)期時(shí)間
   self.redis_client.set(key, json.dumps(cache_data))
 
 defget_with_logical_expire(self, key):
   """獲取帶邏輯過(guò)期檢查的緩存"""
    cached_json =self.redis_client.get(key)
   ifnotcached_json:
     returnNone
   
    cached_data = json.loads(cached_json)
    current_time = time.time()
   
   # 檢查是否邏輯過(guò)期
   ifcurrent_time < cached_data['expire_time']:
? ? ? ? ? ??# 未過(guò)期,直接返回
? ? ? ? ? ??return?cached_data['data']
? ? ? ??else:
? ? ? ? ? ??# 已過(guò)期,異步刷新緩存,先返回舊數(shù)據(jù)
? ? ? ? ? ??self.executor.submit(self._refresh_cache_async, key)
? ? ? ? ? ??return?cached_data['data']
? ??
? ??def?_refresh_cache_async(self, key):
? ? ? ??"""異步刷新緩存"""
? ? ? ??try:
? ? ? ? ? ??# 獲取分布式鎖,避免并發(fā)刷新
? ? ? ? ? ? lock_key =?f"lock:{key}"
? ? ? ? ? ??if?self.redis_client.set(lock_key,?"1", nx=True, ex=10):
? ? ? ? ? ? ? ??# 獲得鎖,開(kāi)始刷新
? ? ? ? ? ? ? ? new_data = database.query(key)
? ? ? ? ? ? ? ??if?new_data:
? ? ? ? ? ? ? ? ? ??self.set_with_logical_expire(key, new_data,?3600)
? ? ? ? ? ? ? ??self.redis_client.delete(lock_key)
? ? ? ??except?Exception?as?e:
? ? ? ? ? ? logger.error(f"異步刷新緩存失敗:?{key}, 錯(cuò)誤:?{e}")

# 使用示例
cache_manager = LogicalExpireCache()

def?get_hot_video_info(video_id):
? ? cache_key =?f"video:{video_id}"
? ??
? ??# 嘗試從緩存獲取
? ? video_info = cache_manager.get_with_logical_expire(cache_key)
? ??
? ??if?video_info?is?None:
? ? ? ??# 緩存完全不存在,同步查詢
? ? ? ? video_info = database.query_video(video_id)
? ? ? ??if?video_info:
? ? ? ? ? ? cache_manager.set_with_logical_expire(cache_key, video_info,?3600)
? ??
? ??return?video_info

方案二:分布式鎖 + 雙重檢查

importuuid
importtime

classDistributedLock:
 def__init__(self, redis_client, key, timeout=10):
   self.redis_client = redis_client
   self.key =f"lock:{key}"
   self.timeout = timeout
   self.identifier =str(uuid.uuid4())
 
 def__enter__(self):
   # 嘗試獲取鎖
    end_time = time.time() +self.timeout
   whiletime.time() < end_time:
? ? ? ? ? ??if?self.redis_client.set(self.key,?self.identifier, nx=True, ex=self.timeout):
? ? ? ? ? ? ? ??return?self
? ? ? ? ? ? time.sleep(0.001)
? ? ? ??raise?TimeoutError("獲取分布式鎖超時(shí)")
? ??
? ??def?__exit__(self, exc_type, exc_val, exc_tb):
? ? ? ??# 釋放鎖(使用Lua腳本確保原子性)
? ? ? ? unlock_script =?"""
? ? ? ? if redis.call("get", KEYS[1]) == ARGV[1] then
? ? ? ? ? ? return redis.call("del", KEYS[1])
? ? ? ? else
? ? ? ? ? ? return 0
? ? ? ? end
? ? ? ? """
? ? ? ??self.redis_client.eval(unlock_script,?1,?self.key,?self.identifier)

def?get_data_with_distributed_lock(key):
? ??"""使用分布式鎖防止緩存擊穿"""
? ??# 第一次檢查緩存
? ? cached_data = redis_client.get(key)
? ??if?cached_data:
? ? ? ??return?json.loads(cached_data)
? ??
? ??# 緩存未命中,嘗試獲取分布式鎖
? ??try:
? ? ? ??with?DistributedLock(redis_client, key, timeout=5):
? ? ? ? ? ??# 獲得鎖后,再次檢查緩存(雙重檢查)
? ? ? ? ? ? cached_data = redis_client.get(key)
? ? ? ? ? ??if?cached_data:
? ? ? ? ? ? ? ??return?json.loads(cached_data)
? ? ? ? ? ??
? ? ? ? ? ??# 查詢數(shù)據(jù)庫(kù)并緩存
? ? ? ? ? ? data = database.query(key)
? ? ? ? ? ??if?data:
? ? ? ? ? ? ? ? redis_client.setex(key,?3600, json.dumps(data))
? ? ? ? ? ??return?data
? ??
? ??except?TimeoutError:
? ? ? ??# 獲取鎖超時(shí),直接查詢數(shù)據(jù)庫(kù)(降級(jí)策略)
? ? ? ? logger.warning(f"獲取鎖超時(shí),直接查數(shù)據(jù)庫(kù):?{key}")
? ? ? ??return?database.query(key)

四、生產(chǎn)環(huán)境最佳實(shí)踐

監(jiān)控告警體系

classCacheMonitor:
 def__init__(self):
   self.metrics = {}
 
 defrecord_cache_hit_rate(self):
   """監(jiān)控緩存命中率"""
    hit_rate =self.redis_client.get('cache_hit_rate')
   ifhit_rateandfloat(hit_rate) 0.85:
     self.send_alert("Redis內(nèi)存使用過(guò)高",f"使用率:{memory_usage:.2%}")
 
 defcheck_slow_queries(self):
   """檢查慢查詢"""
    slow_logs =self.redis_client.slowlog_get(10)
   forloginslow_logs:
     iflog['duration'] >10000: # 超過(guò)10ms
       self.send_alert("發(fā)現(xiàn)慢查詢",f"耗時(shí):{log['duration']}μs, 命令:{log['command']}")

# 定時(shí)監(jiān)控任務(wù)
defmonitoring_task():
  monitor = CacheMonitor()
 whileTrue:
   try:
      monitor.record_cache_hit_rate()
      monitor.monitor_redis_memory()
      monitor.check_slow_queries()
   exceptExceptionase:
      logger.error(f"監(jiān)控任務(wù)異常:{e}")
    time.sleep(60)

緩存預(yù)熱策略

classCacheWarmUp:
 def__init__(self):
   self.redis_client = redis.Redis()
   self.thread_pool = ThreadPoolExecutor(max_workers=20)
 
 defwarm_up_hot_data(self):
   """預(yù)熱熱點(diǎn)數(shù)據(jù)"""
   # 獲取熱點(diǎn)商品ID列表
    hot_products = database.query("SELECT id FROM products WHERE is_hot = 1")
   
   # 并發(fā)預(yù)熱
    futures = []
   forproductinhot_products:
      future =self.thread_pool.submit(self._warm_single_product, product['id'])
      futures.append(future)
   
   # 等待所有任務(wù)完成
    success_count =0
   forfutureinfutures:
     try:
        future.result(timeout=30)
        success_count +=1
     exceptExceptionase:
        logger.error(f"預(yù)熱失敗:{e}")
   
    logger.info(f"緩存預(yù)熱完成,成功:{success_count}/{len(hot_products)}")
 
 def_warm_single_product(self, product_id):
   """預(yù)熱單個(gè)商品緩存"""
   try:
      product_info = database.query_product(product_id)
     ifproduct_info:
        cache_key =f"product:{product_id}"
        expire_time = random.randint(3600,4320) # 隨機(jī)過(guò)期時(shí)間
       self.redis_client.setex(cache_key, expire_time, json.dumps(product_info))
   exceptExceptionase:
      logger.error(f"預(yù)熱商品{product_id}失敗:{e}")
     raise

# 應(yīng)用啟動(dòng)時(shí)執(zhí)行緩存預(yù)熱
if__name__ =="__main__":
  warm_up = CacheWarmUp()
  warm_up.warm_up_hot_data()

容災(zāi)備份方案

classCacheDisasterRecovery:
 def__init__(self):
   self.master_redis = redis.Redis(host='master-redis')
   self.slave_redis = redis.Redis(host='slave-redis')
   self.local_cache = {}
 
 defget_with_fallback(self, key):
   """多級(jí)降級(jí)查詢"""
   try:
     # 1. 主Redis
      data =self.master_redis.get(key)
     ifdata:
       returnjson.loads(data)
   exceptExceptionase:
      logger.warning(f"主Redis故障:{e}")
   
   try:
     # 2. 從Redis
      data =self.slave_redis.get(key)
     ifdata:
       returnjson.loads(data)
   exceptExceptionase:
      logger.warning(f"從Redis故障:{e}")
   
   # 3. 本地緩存
   ifkeyinself.local_cache:
      cache_item =self.local_cache[key]
     iftime.time() < cache_item['expire_time']:
? ? ? ? ? ? ? ? logger.info(f"命中本地緩存:?{key}")
? ? ? ? ? ? ? ??return?cache_item['data']
? ? ? ??
? ? ? ??# 4. 數(shù)據(jù)庫(kù)查詢
? ? ? ??try:
? ? ? ? ? ? data = database.query(key)
? ? ? ? ? ??if?data:
? ? ? ? ? ? ? ??# 同步到本地緩存
? ? ? ? ? ? ? ??self.local_cache[key] = {
? ? ? ? ? ? ? ? ? ??'data': data,
? ? ? ? ? ? ? ? ? ??'expire_time': time.time() +?300??# 5分鐘本地緩存
? ? ? ? ? ? ? ? }
? ? ? ? ? ??return?data
? ? ? ??except?Exception?as?e:
? ? ? ? ? ? logger.error(f"數(shù)據(jù)庫(kù)查詢失敗:?{e}")
? ? ? ? ? ??return?None

五、性能優(yōu)化與調(diào)優(yōu)

Redis配置優(yōu)化

# redis.conf 生產(chǎn)環(huán)境推薦配置

# 內(nèi)存優(yōu)化
maxmemory 8gb
maxmemory-policy allkeys-lru

# 持久化配置
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-erroryes
rdbcompressionyes
rdbchecksumyes

# 網(wǎng)絡(luò)優(yōu)化
tcp-keepalive 300
timeout0

# 慢查詢?nèi)罩?slowlog-log-slower-than 10000
slowlog-max-len 128

# 客戶端連接
maxclients 10000

連接池配置

importredis.connection

# Redis連接池配置
redis_pool = redis.ConnectionPool(
  host='localhost',
  port=6379,
  db=0,
  max_connections=100,   # 最大連接數(shù)
  retry_on_timeout=True,  # 超時(shí)重試
  health_check_interval=30,# 健康檢查間隔
  socket_connect_timeout=5,# 連接超時(shí)
  socket_timeout=5,    # 讀寫超時(shí)
)

redis_client = redis.Redis(connection_pool=redis_pool)

六、故障排查實(shí)戰(zhàn)手冊(cè)

常見(jiàn)問(wèn)題診斷

# 1. 查看Redis內(nèi)存使用情況
redis-cli info memory

# 2. 監(jiān)控慢查詢
redis-cli slowlog get 10

# 3. 查看客戶端連接
redis-cli info clients

# 4. 監(jiān)控鍵空間命中率
redis-cli info stats | grep keyspace

# 5. 查看過(guò)期鍵統(tǒng)計(jì)
redis-cli info keyspace

應(yīng)急處理腳本

#!/usr/bin/env python3
"""Redis應(yīng)急處理工具"""

importredis
importsys
importtime

classRedisEmergencyKit:
 def__init__(self, host='localhost', port=6379):
   self.redis_client = redis.Redis(host=host, port=port)
 
 defflush_expired_keys(self):
   """清理過(guò)期鍵"""
   print("開(kāi)始清理過(guò)期鍵...")
    count =0
   forkeyinself.redis_client.scan_iter():
     ifself.redis_client.ttl(key) ==0:
       self.redis_client.delete(key)
        count +=1
   print(f"清理完成,共刪除{count}個(gè)過(guò)期鍵")
 
 defanalyze_big_keys(self, limit=10):
   """分析大鍵"""
   print(f"分析占用內(nèi)存最大的{limit}個(gè)鍵...")
    big_keys = []
   
   forkeyinself.redis_client.scan_iter():
      memory =self.redis_client.memory_usage(key)
     ifmemory:
        big_keys.append((key.decode(), memory))
   
    big_keys.sort(key=lambdax: x[1], reverse=True)
   
   forkey, memoryinbig_keys[:limit]:
     print(f"{key}:{memory /1024:.2f}KB")
 
 defemergency_cache_clear(self, pattern):
   """緊急清理指定模式的緩存"""
   print(f"緊急清理模式{pattern}的緩存...")
    count =0
   forkeyinself.redis_client.scan_iter(match=pattern):
     self.redis_client.delete(key)
      count +=1
   print(f"清理完成,共刪除{count}個(gè)鍵")

if__name__ =="__main__":
 iflen(sys.argv) ")
   print("命令: flush_expired | analyze_big_keys | clear_pattern ")
    sys.exit(1)
 
  kit = RedisEmergencyKit()
  command = sys.argv[1]
 
 ifcommand =="flush_expired":
    kit.flush_expired_keys()
 elifcommand =="analyze_big_keys":
    kit.analyze_big_keys()
 elifcommand =="clear_pattern"andlen(sys.argv) >2:
    kit.emergency_cache_clear(sys.argv[2])
 else:
   print("未知命令")

總結(jié)

通過(guò)本文的深入分析,我們了解了Redis三大經(jīng)典問(wèn)題的本質(zhì)和解決方案:

緩存穿透:使用布隆過(guò)濾器或空值緩存,構(gòu)建第一道防線
緩存雪崩:通過(guò)隨機(jī)過(guò)期時(shí)間、多級(jí)緩存、互斥鎖等方式分散風(fēng)險(xiǎn)
緩存擊穿:采用邏輯過(guò)期或分布式鎖,保護(hù)熱點(diǎn)數(shù)據(jù)

作為運(yùn)維工程師,我們不僅要掌握這些解決方案,更要建立完善的監(jiān)控體系、預(yù)熱機(jī)制和應(yīng)急預(yù)案。記住:好的運(yùn)維不是沒(méi)有故障,而是故障發(fā)生時(shí)能夠快速響應(yīng)和恢復(fù)。

在我的運(yùn)維生涯中,這些方案幫我避免了無(wú)數(shù)次半夜的緊急電話。希望這篇文章能對(duì)各位同行有所幫助,讓我們一起構(gòu)建更穩(wěn)定、更高效的系統(tǒng)!

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • cpu
    cpu
    +關(guān)注

    關(guān)注

    68

    文章

    11186

    瀏覽量

    221192
  • 緩存
    +關(guān)注

    關(guān)注

    1

    文章

    248

    瀏覽量

    27565
  • 數(shù)據(jù)庫(kù)
    +關(guān)注

    關(guān)注

    7

    文章

    3978

    瀏覽量

    67407
  • Redis
    +關(guān)注

    關(guān)注

    0

    文章

    390

    瀏覽量

    11853

原文標(biāo)題:Redis緩存穿透、雪崩、擊穿三大難題的解決方案與實(shí)戰(zhàn)

文章出處:【微信號(hào):magedu-Linux,微信公眾號(hào):馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    關(guān)于Redis緩存的原因及解決方案

    下面開(kāi)始今天的正文,看見(jiàn)小小怎么辛苦的份上,滑到底下,給個(gè)素質(zhì)三連? 緩存雪崩 緩存雪崩是指在某一個(gè)時(shí)間段內(nèi),緩存集中過(guò)期失效,如果這個(gè)時(shí)間段內(nèi)有大量請(qǐng)求,而查詢數(shù)據(jù)量巨大,所有的請(qǐng)求都會(huì)達(dá)到存儲(chǔ)層
    的頭像 發(fā)表于 10-16 15:22 ?3560次閱讀
    關(guān)于<b class='flag-5'>Redis</b><b class='flag-5'>緩存</b>的原因及<b class='flag-5'>解決方案</b>

    恒流源輸出漏電問(wèn)題分析和解決方案

    這個(gè)問(wèn)題是逛TI論壇時(shí)看到的一個(gè)恒流源輸出漏電的問(wèn)題,原帖沒(méi)有給出合適的解決方案,并且這個(gè)問(wèn)題比較經(jīng)典,所以與各位道友一同分享我的看法和解決思路。
    的頭像 發(fā)表于 03-03 09:47 ?1661次閱讀
    恒流源輸出漏電問(wèn)題分析<b class='flag-5'>和解決方案</b>

    Redis緩存和MySQL數(shù)據(jù)不一致原因和解決方案

    高并發(fā)架構(gòu)系列:Redis緩存和MySQL數(shù)據(jù)一致性方案詳解
    發(fā)表于 03-27 15:55

    使用Redis緩存model層

    〈譯〉使用REDIS處理RAILS MODEL緩存
    發(fā)表于 04-18 17:07

    redis緩存注解怎么使用

    spring boot —— redis 緩存注解使用教程
    發(fā)表于 09-11 14:43

    Redis在高速緩存系統(tǒng)中的序列化算法研究

    Redis是一個(gè)key?value存儲(chǔ)系統(tǒng),通過(guò)對(duì)Redis高速緩存系統(tǒng)的序列化算法優(yōu)化,可提高緩存讀取的效率和存儲(chǔ)容量。引入現(xiàn)代統(tǒng)計(jì)學(xué)中Bootstrap理論,提出基于隨機(jī)相位高斯偽
    發(fā)表于 11-23 16:07 ?0次下載

    Java 使用Redis緩存工具的詳細(xì)解說(shuō)

    本文是關(guān)于Java 使用Redis緩存工具的詳細(xì)解說(shuō)。詳細(xì)步驟請(qǐng)看下文
    的頭像 發(fā)表于 02-09 14:10 ?8141次閱讀
    Java 使用<b class='flag-5'>Redis</b><b class='flag-5'>緩存</b>工具的詳細(xì)解說(shuō)

    redis緩存mysql數(shù)據(jù)

    Redis作Mysql數(shù)據(jù)庫(kù)緩存,必須解決2個(gè)問(wèn)題。首先,應(yīng)該確定用何種數(shù)據(jù)結(jié)構(gòu)存儲(chǔ)來(lái)自Mysql的數(shù)據(jù);在確定數(shù)據(jù)結(jié)構(gòu)之后,還要考慮用什么標(biāo)識(shí)作為該數(shù)據(jù)結(jié)構(gòu)的鍵。
    的頭像 發(fā)表于 02-09 15:42 ?4366次閱讀

    Redis實(shí)戰(zhàn)的常見(jiàn)問(wèn)題和解決方法

    小伙伴們對(duì)Redis應(yīng)該不陌生,Redis是系統(tǒng)必備的分布式緩存中間件,主要用來(lái)解決高并發(fā)下分擔(dān)DB資源的負(fù)載,從而提升系統(tǒng)吞吐量。
    的頭像 發(fā)表于 05-03 18:22 ?4059次閱讀
    <b class='flag-5'>Redis</b>實(shí)戰(zhàn)的常見(jiàn)問(wèn)題<b class='flag-5'>和解</b>決方法

    Redis常見(jiàn)面試題及答案

    本文的面試題如下: Redis 持久化機(jī)制 緩存雪崩、緩存穿透、緩存預(yù)熱、緩存更新、緩存降級(jí)等問(wèn)
    的頭像 發(fā)表于 12-16 11:44 ?2688次閱讀
    <b class='flag-5'>Redis</b>常見(jiàn)面試題及答案

    緩存雪崩/穿透/擊穿的解決方案

    緩存是我們項(xiàng)目應(yīng)用肯定會(huì)使用,是我們數(shù)據(jù)庫(kù)的守護(hù)神,能夠保證數(shù)據(jù)庫(kù)的穩(wěn)定,能夠提高整個(gè)系統(tǒng)的性能。一般我們采用市面上的redis、memcahce方案;redis已經(jīng)非常強(qiáng)大了,每秒支
    發(fā)表于 01-26 09:44 ?1502次閱讀
    <b class='flag-5'>緩存</b>雪崩/穿透/擊穿的<b class='flag-5'>解決方案</b>

    Redis緩存的異常原因及其處理辦法分析

    Redis 是當(dāng)前最流行的 NoSQL 數(shù)據(jù)庫(kù)。Redis 主要用來(lái)做緩存使用,在提高數(shù)據(jù)查詢效率、保護(hù)數(shù)據(jù)庫(kù)等方面起到了關(guān)鍵性的作用,很大程度上提高系統(tǒng)的性能。
    的頭像 發(fā)表于 02-06 15:02 ?1217次閱讀

    如何在SpringBoot中解決Redis緩存穿透等問(wèn)題

    今天給大家介紹一下如何在SpringBoot中解決Redis緩存穿透、緩存擊穿、緩存雪崩的問(wèn)題。
    的頭像 發(fā)表于 04-28 11:35 ?1084次閱讀

    Oracle與Redis Enterprise協(xié)同,作為企業(yè)緩存解決方案

    單獨(dú)使用Oracle作為企業(yè)緩存數(shù)據(jù)庫(kù)時(shí),會(huì)出現(xiàn)哪些問(wèn)題呢?使用Redis Enterprise與Oracle共同用作企業(yè)級(jí)緩存或副本數(shù)據(jù)庫(kù),會(huì)出現(xiàn)哪些喜人的提升呢?Orcle配合使用Redi
    的頭像 發(fā)表于 11-22 10:00 ?826次閱讀
    Oracle與<b class='flag-5'>Redis</b> Enterprise協(xié)同,作為企業(yè)<b class='flag-5'>緩存</b><b class='flag-5'>解決方案</b>

    Redis Enterprise vs ElastiCache——如何選擇緩存解決方案

    使用Redis或AmazonElastiCache來(lái)作為緩存加速已經(jīng)是業(yè)界主流的解決方案,二者各有什么優(yōu)勢(shì)?又有哪些區(qū)別呢?文況速覽:Redis是什么?RedisEnterprise
    的頭像 發(fā)表于 11-26 08:06 ?903次閱讀
    <b class='flag-5'>Redis</b> Enterprise vs ElastiCache——如何選擇<b class='flag-5'>緩存</b><b class='flag-5'>解決方案</b>?