Redis

Redis 單線程為什么還這么快?

  1. 命令執(zhí)行基于內(nèi)存操作。
  2. 單線程操作,沒(méi)有線程切換的開(kāi)銷。
  3. 基于IO多路復(fù)用機(jī)制,提升Redis的I/O利用率。
  4. 高效的數(shù)據(jù)存儲(chǔ)結(jié)構(gòu):全局hash表以及多種高效的數(shù)據(jù)結(jié)構(gòu)(比如:跳表、壓縮列表、鏈表)

緩存穿透

緩存穿透是指查詢一個(gè)根本不存在的數(shù)據(jù),緩存層和存儲(chǔ)層都不會(huì)命中,通常服務(wù)端出于容錯(cuò)的考慮,如果從存儲(chǔ)層查不到數(shù)據(jù)則不寫(xiě)入緩存層

緩存穿透模型,協(xié)助理解

緩存穿透將導(dǎo)致不存在的數(shù)據(jù)每次請(qǐng)求都要到存儲(chǔ)層去查詢,失去了緩存保護(hù)后端存儲(chǔ)的意義,
解決方案:

  1. 緩存空對(duì)象
    當(dāng)存儲(chǔ)層不命中時(shí),仍然將空對(duì)象保存到緩存層中,之后在訪問(wèn)這個(gè)數(shù)據(jù)的話,將從緩存中獲取,從而保護(hù)了后端數(shù)據(jù)源
    緩存空對(duì)象也有幾個(gè)問(wèn)題
    1. 空值做了緩存,意味著緩存層中存了更多的鍵,需要更多的內(nèi)存空間(如果是攻擊,問(wèn)題更嚴(yán)重),比較有效的方法是針對(duì)這類數(shù)據(jù)設(shè)置一個(gè)較短的過(guò)期時(shí)間,讓其自動(dòng)剔除。
    2. 緩存層和存儲(chǔ)層的數(shù)據(jù)會(huì)有一段時(shí)間窗口的不一致,可能會(huì)對(duì)業(yè)務(wù)有一定影響。例如過(guò)期時(shí)間設(shè)置為5分鐘,如果此時(shí)存儲(chǔ)層添加了這個(gè)數(shù)據(jù),那此段時(shí)間就會(huì)出現(xiàn)緩存層和存儲(chǔ)數(shù)據(jù)的不一致,此時(shí)可以利用消息系統(tǒng)或者其他方法清除掉緩存層中的空對(duì)象。
  2. 布隆過(guò)濾器攔截
    在訪問(wèn)緩存層和存儲(chǔ)層之前,將存在的key用布隆過(guò)濾器提前保存起來(lái),做第一層攔截。
  3. 兩種解決辦法總結(jié)


    方案對(duì)比

緩存擊穿

緩存擊穿是指緩存中沒(méi)有但數(shù)據(jù)庫(kù)中有的數(shù)據(jù)(一般是緩存時(shí)間到期),這時(shí)由于并發(fā)用戶特別多,同時(shí)讀緩存沒(méi)讀到數(shù)據(jù),又同時(shí)去數(shù)據(jù)庫(kù)去取數(shù)據(jù),引起數(shù)據(jù)庫(kù)壓力瞬間增大,造成過(guò)大壓力。

  1. 預(yù)先設(shè)置熱門(mén)數(shù)據(jù):在redis高峰訪問(wèn)前,把一些熱門(mén)數(shù)據(jù)提前存入redis中,加大這些熱門(mén)數(shù)據(jù)key的時(shí)長(zhǎng)實(shí)時(shí)調(diào)整 現(xiàn)場(chǎng)監(jiān)控哪些數(shù)據(jù)是熱門(mén)數(shù)據(jù),實(shí)時(shí)調(diào)整key的過(guò)期時(shí)長(zhǎng)。
  2. 加互斥鎖:互斥鎖可以控制查詢數(shù)據(jù)庫(kù)的線程訪問(wèn),但這種方案會(huì)導(dǎo)致系統(tǒng)的吞吐量下降,需要根據(jù)實(shí)際情況使用。
public String get(key) {
  String value = redis.get(key);
  if (value == null) { // 代表緩存值過(guò)期
      // 設(shè)置3min的超時(shí),防止del操作失敗的時(shí)候,下次緩存過(guò)期一直不能load db
      if (redis.setnx(key_mutex, 1, 3 * 60) == 1) {  // 代表設(shè)置成功
          value = db.get(key);
          redis.set(key, value, expire_secs);
          redis.del(key_mutex);
      } else {  // 這個(gè)時(shí)候代表同時(shí)候的其他線程已經(jīng)load db并回設(shè)到緩存了,這時(shí)候重試獲取緩存值即可
          sleep(50);
          get(key);  // 重試
      }
  } else {
      return value;      
  }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容