偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

面試題:什么是緩存擊穿、緩存穿透和緩存雪崩?它們分別會(huì)帶來什么危害?該如何解決和預(yù)防?

開發(fā)
緩存穿透是指查詢一個(gè)一定不存在的數(shù)據(jù),由于緩存是不命中時(shí)需要從數(shù)據(jù)庫查詢,查不到數(shù)據(jù)則不寫入緩存,這將導(dǎo)致這個(gè)不存在的數(shù)據(jù)每次請(qǐng)求都要到數(shù)據(jù)庫去查詢,造成緩存穿透。

一、面試官:請(qǐng)說說看什么是緩存擊穿,他會(huì)帶來什么危害,以及該如何解決?

1.緩存擊穿

(1) 定義:緩存擊穿是指在高并發(fā)訪問下,某個(gè)熱點(diǎn)數(shù)據(jù)的緩存過期失效,而此時(shí)恰好有大量并發(fā)請(qǐng)求訪問該數(shù)據(jù),導(dǎo)致這些請(qǐng)求直接繞過緩存,訪問后端數(shù)據(jù)庫或存儲(chǔ)系統(tǒng),使數(shù)據(jù)庫或存儲(chǔ)系統(tǒng)負(fù)載急劇增加,甚至可能引發(fā)系統(tǒng)崩潰的現(xiàn)象。

(2) 危害:

  • 數(shù)據(jù)庫壓力增大:大量請(qǐng)求直接訪問數(shù)據(jù)庫,可能導(dǎo)致數(shù)據(jù)庫負(fù)載過高,響應(yīng)時(shí)間延長,甚至引發(fā)數(shù)據(jù)庫崩潰。
  • 系統(tǒng)性能下降:由于數(shù)據(jù)庫處理請(qǐng)求的速度遠(yuǎn)低于緩存,因此緩存擊穿會(huì)導(dǎo)致系統(tǒng)整體性能下降。

(3) 解決方案:

① 互斥鎖(Mutex)和分布式鎖(在分布式系統(tǒng)中):

在緩存失效時(shí),使用互斥鎖機(jī)制確保只有一個(gè)請(qǐng)求能夠訪問數(shù)據(jù)庫并更新緩存,其他請(qǐng)求則等待鎖釋放后從緩存中獲取數(shù)據(jù)。

下面是一個(gè)使用 Redis 分布式鎖和 Redis 事務(wù)來解決緩存擊穿問題的具體代碼示例(Python實(shí)現(xiàn))。


import redis
import time
import uuid

# 連接到 Redis 服務(wù)器
redis_client = redis.StrictRedis(host='localhost', port=6379, db=0)

# 設(shè)置分布式鎖的鍵和過期時(shí)間(秒)
LOCK_KEY = 'cache_擊穿_lock'
LOCK_EXPIRE = 10  # 鎖的有效期,可以根據(jù)需要調(diào)整

# 緩存的鍵和值(示例)
CACHE_KEY = 'some_hot_data'

def acquire_lock(redis_client, lock_key, lock_value, expire):
    """
    嘗試獲取分布式鎖
    :param redis_client: Redis 客戶端
    :param lock_key: 鎖的鍵
    :param lock_value: 鎖的值(通常是唯一標(biāo)識(shí)符)
    :param expire: 鎖的過期時(shí)間(秒)
    :return: 是否成功獲取鎖
    """
    while True:
        # 嘗試設(shè)置鎖,NX 表示只有鍵不存在時(shí)才設(shè)置,PX 表示過期時(shí)間(毫秒)
        result = redis_client.set(lock_key, lock_value, nx=True, px=expire * 1000)
        if result:
            return True
        # 休眠一小段時(shí)間后重試,避免忙等待
        time.sleep(0.01)

def release_lock(redis_client, lock_key, lock_value):
    """
    釋放分布式鎖
    :param redis_client: Redis 客戶端
    :param lock_key: 鎖的鍵
    :param lock_value: 鎖的值(必須是獲取鎖時(shí)使用的相同值)
    :return: 是否成功釋放鎖
    """
    # 使用 Lua 腳本確保原子性釋放鎖
    lua_script = """
    if redis.call("get", KEYS[1]) == ARGV[1] then
        return redis.call("del", KEYS[1])
    else
        return 0
    end
    """
    redis_client.eval(lua_script, 1, lock_key, lock_value)
    return True

def get_data_with_cache_and_lock(redis_client, cache_key):
    """
    使用緩存、分布式鎖和 Redis 事務(wù)獲取數(shù)據(jù)
    :param redis_client: Redis 客戶端
    :param cache_key: 緩存的鍵
    :return: 數(shù)據(jù)值或 None(如果數(shù)據(jù)不存在)
    """
    # 嘗試從緩存中獲取數(shù)據(jù)
    cache_value = redis_client.get(cache_key)
    if cache_value is not None:
        return cache_value.decode('utf-8')  # 假設(shè)數(shù)據(jù)是字符串類型

    # 嘗試獲取分布式鎖
    lock_value = str(uuid.uuid4())
    if acquire_lock(redis_client, LOCK_KEY, lock_value, LOCK_EXPIRE):
        try:
            # 使用 Redis 事務(wù)確保原子性
            pipe = redis_client.pipeline(True)
            try:
                # 嘗試再次從緩存中獲取數(shù)據(jù)(防止其他客戶端在獲取鎖后更新了緩存)
                pipe.watch(cache_key)
                cache_value = pipe.get(cache_key)
                if cache_value is not None:
                    pipe.unwatch()
                    pipe.reset()
                    return cache_value.decode('utf-8')

                # 從數(shù)據(jù)庫中獲取數(shù)據(jù)(模擬)
                # 在實(shí)際應(yīng)用中,這里應(yīng)該是訪問數(shù)據(jù)庫的邏輯
                data_from_db = "data_from_db"  # 假設(shè)從數(shù)據(jù)庫中獲取的數(shù)據(jù)

                # 更新緩存
                pipe.multi()
                pipe.set(cache_key, data_from_db)
                pipe.execute()

                # 返回從數(shù)據(jù)庫中獲取的數(shù)據(jù)
                return data_from_db

            except redis.WatchError:
                # 如果在事務(wù)執(zhí)行過程中,緩存被其他客戶端更新,則重新嘗試獲取數(shù)據(jù)
                pass

        finally:
            # 釋放鎖
            release_lock(redis_client, LOCK_KEY, lock_value)

    # 如果無法獲取鎖或緩存仍然為空,則返回 None(或根據(jù)業(yè)務(wù)邏輯返回默認(rèn)值)
    return None

# 示例調(diào)用
data = get_data_with_cache_and_lock(redis_client, CACHE_KEY)
print(f"獲取的數(shù)據(jù): {data}")

② 熱點(diǎn)數(shù)據(jù)永不過期:

對(duì)于重要的熱點(diǎn)數(shù)據(jù),可以設(shè)置其永不過期,以避免緩存過期引發(fā)的擊穿問題。

但需要注意數(shù)據(jù)更新時(shí)的及時(shí)性和準(zhǔn)確性,以及可能帶來的內(nèi)存占用問題。

③ 提前異步刷新緩存:

在緩存即將過期之前,通過定時(shí)任務(wù)或后臺(tái)線程提前異步加載緩存數(shù)據(jù),確保在緩存失效之前已經(jīng)有新的數(shù)據(jù)加載到緩存中。

二、面試官:再說說看什么是緩存穿透,如何檢測(cè)是否存在緩存穿透,以及該如何解決?

緩存穿透是指查詢一個(gè)一定不存在的數(shù)據(jù),由于緩存是不命中時(shí)需要從數(shù)據(jù)庫查詢,查不到數(shù)據(jù)則不寫入緩存,這將導(dǎo)致這個(gè)不存在的數(shù)據(jù)每次請(qǐng)求都要到數(shù)據(jù)庫去查詢,造成緩存穿透。

如果數(shù)據(jù)庫查詢不到這條數(shù)據(jù),則不會(huì)寫入緩存,這將導(dǎo)致這個(gè)不存在的數(shù)據(jù)每次請(qǐng)求都會(huì)去查詢數(shù)據(jù)庫,對(duì)數(shù)據(jù)庫造成很大的壓力。

緩存穿透通常是由惡意用戶或攻擊者請(qǐng)求不存在于緩存和后端存儲(chǔ)中的數(shù)據(jù)來發(fā)起的攻擊。

一般來說,緩存穿透一開始會(huì)由開發(fā)者發(fā)現(xiàn)系統(tǒng)接口變慢或監(jiān)控告警發(fā)覺,再檢測(cè)系統(tǒng)日志證實(shí)。檢查數(shù)據(jù)庫訪問日志和緩存訪問日志,查看是否存在大量對(duì)不存在的鍵的查詢。這些查詢?nèi)绻l繁發(fā)生,那么很可能是緩存穿透。

另外,監(jiān)控緩存的命中率。如果命中率突然下降,且伴隨著數(shù)據(jù)庫訪問量的增加,這可能是緩存穿透的征兆。

再者,可以分析系統(tǒng)接收到的請(qǐng)求參數(shù),特別是那些明顯不符合業(yè)務(wù)邏輯的非法參數(shù)。

以下是兩種防止緩存穿透的策略:

1.布隆過濾器(Bloom Filter)

布隆過濾器是一種空間效率很高的數(shù)據(jù)結(jié)構(gòu),它利用多個(gè)哈希函數(shù)來將一個(gè)元素映射到一個(gè)位數(shù)組的多個(gè)位中。當(dāng)查詢一個(gè)元素時(shí),它會(huì)檢查對(duì)應(yīng)的位是否都為1,如果是,則認(rèn)為元素可能存在(注意是可能存在,因?yàn)榇嬖诠_突的情況),否則認(rèn)為元素一定不存在。

在緩存穿透的場(chǎng)景中,可以在查詢緩存之前先使用布隆過濾器檢查元素是否存在。如果布隆過濾器認(rèn)為元素不存在,則直接返回一個(gè)錯(cuò)誤信息或默認(rèn)值,而不去查詢數(shù)據(jù)庫。這樣可以有效減少對(duì)數(shù)據(jù)庫的無效查詢。

布隆過濾器的缺點(diǎn):

  • 誤判率:布隆過濾器通過多個(gè)哈希函數(shù)將元素映射到位數(shù)組中,因此存在哈希沖突的可能性。這意味著,當(dāng)查詢一個(gè)元素時(shí),布隆過濾器可能會(huì)誤判該元素存在(即位數(shù)組中對(duì)應(yīng)的位都為1),而實(shí)際上該元素在數(shù)據(jù)庫中并不存在。雖然誤判率可以通過增加哈希函數(shù)數(shù)量和位數(shù)組長度來降低,但這也會(huì)增加計(jì)算復(fù)雜度和空間開銷。
  • 刪除困難:布隆過濾器不支持直接刪除元素。如果要從布隆過濾器中刪除一個(gè)元素,需要將其對(duì)應(yīng)的所有位都重置為0。然而,這可能會(huì)影響其他元素的判斷,因?yàn)槎鄠€(gè)元素可能共享同一個(gè)位。因此,在實(shí)際應(yīng)用中,布隆過濾器通常用于只讀場(chǎng)景或需要頻繁查詢但很少更新的場(chǎng)景。

2.空值緩存(并不推薦):

對(duì)于那些查詢結(jié)果為空的數(shù)據(jù),也將其緩存起來,但設(shè)置一個(gè)較短的過期時(shí)間。這樣,當(dāng)下次再次查詢這個(gè)不存在的數(shù)據(jù)時(shí),可以直接從緩存中獲取空值,而不是去查詢數(shù)據(jù)庫。

控制緩存的缺點(diǎn):

  • 額外的內(nèi)存消耗:當(dāng)數(shù)據(jù)庫中不存在某個(gè)數(shù)據(jù)時(shí),系統(tǒng)仍然需要將其作為一個(gè)空值(或特殊標(biāo)記)緩存起來。這會(huì)導(dǎo)致緩存中存儲(chǔ)大量的空值或特殊標(biāo)記,從而占用額外的內(nèi)存空間。如果這類空值數(shù)據(jù)過多,會(huì)顯著影響緩存的存儲(chǔ)效率和性能。
  • 數(shù)據(jù)不一致性:空值緩存的過期時(shí)間需要合理設(shè)置。如果過期時(shí)間設(shè)置得過長,當(dāng)數(shù)據(jù)庫中實(shí)際數(shù)據(jù)發(fā)生變化(例如,原本不存在的數(shù)據(jù)被插入)時(shí),緩存中的空值數(shù)據(jù)仍然有效,這會(huì)導(dǎo)致數(shù)據(jù)不一致的問題。相反,如果過期時(shí)間設(shè)置得過短,可能會(huì)頻繁觸發(fā)緩存失效和數(shù)據(jù)庫查詢,增加系統(tǒng)負(fù)擔(dān)。
  • 難以維護(hù):空值緩存需要額外的邏輯來處理過期時(shí)間和數(shù)據(jù)更新等問題。這增加了系統(tǒng)的復(fù)雜性和維護(hù)成本。同時(shí),由于空值數(shù)據(jù)在緩存中的存在,也可能導(dǎo)致緩存污染和命中率下降等問題。

三、面試官:什么是緩存雪崩,緩存雪崩產(chǎn)生的常見原因有哪些?

緩存雪崩是指在分布式系統(tǒng)中,緩存中的大量數(shù)據(jù)同時(shí)失效或過期,導(dǎo)致大量請(qǐng)求直接訪問數(shù)據(jù)庫或后端服務(wù),造成系統(tǒng)性能急劇下降甚至癱瘓的現(xiàn)象。

這種現(xiàn)象通常會(huì)對(duì)系統(tǒng)造成災(zāi)難性的影響,因?yàn)樗鼤?huì)導(dǎo)致后端數(shù)據(jù)庫或服務(wù)承受巨大的壓力,可能引發(fā)服務(wù)不可用或數(shù)據(jù)丟失等問題。

雪崩和擊穿、熱key的問題不太?樣的是,他是指?規(guī)模的緩存都過期失效了。

緩存雪崩產(chǎn)生的常見原因主要包括以下幾點(diǎn):

  • 緩存中大量key同時(shí)過期:如果系統(tǒng)中存在大量緩存數(shù)據(jù)的過期時(shí)間被設(shè)置為相同或相近,那么當(dāng)這些緩存數(shù)據(jù)同時(shí)過期時(shí),系統(tǒng)將無法從緩存中獲取數(shù)據(jù),轉(zhuǎn)而直接訪問數(shù)據(jù)庫。這將導(dǎo)致數(shù)據(jù)庫承受巨大的訪問壓力,可能引發(fā)性能下降或崩潰。
  • 緩存服務(wù)器故障:緩存服務(wù)器作為系統(tǒng)中的關(guān)鍵組件,如果發(fā)生故障或宕機(jī),將導(dǎo)致緩存數(shù)據(jù)無法被訪問。此時(shí),系統(tǒng)同樣會(huì)轉(zhuǎn)向直接訪問數(shù)據(jù)庫,從而引發(fā)緩存雪崩。
  • 系統(tǒng)壓力增大:在高并發(fā)或大規(guī)模用戶訪問的情況下,系統(tǒng)壓力會(huì)急劇增大。如果此時(shí)緩存無法有效承載這些請(qǐng)求,或者緩存的命中率顯著下降,那么大量請(qǐng)求將直接落到數(shù)據(jù)庫上,從而引發(fā)緩存雪崩。

為了預(yù)防緩存雪崩的發(fā)生,可以采取以下措施:

  • 避免大量key同時(shí)過期:可以通過微調(diào)key的過期時(shí)間,使其有一定的相差間隔,從而避免大量key同時(shí)過期的場(chǎng)景。
  • 使用緩存降級(jí)策略:在緩存失效或訪問壓力過大的情況下,可以啟動(dòng)降級(jí)策略,如返回默認(rèn)值或錯(cuò)誤信息,以減少對(duì)后端系統(tǒng)的壓力。
  • 緩存預(yù)熱:在系統(tǒng)啟動(dòng)時(shí),提前將部分或全部熱點(diǎn)數(shù)據(jù)加載到緩存中。
  • 后備緩存:使用二級(jí)緩存(如本地緩存)作為后備,當(dāng)主緩存失效時(shí),可以從后備緩存中獲取數(shù)據(jù)。
責(zé)任編輯:趙寧寧 來源: 程序員阿沛
相關(guān)推薦

2019-11-05 14:24:31

緩存雪崩框架

2020-09-14 06:57:30

緩存穿透雪崩

2021-06-05 09:01:01

Redis緩存雪崩緩存穿透

2019-10-12 14:19:05

Redis數(shù)據(jù)庫緩存

2023-03-10 13:33:00

緩存穿透緩存擊穿緩存雪崩

2020-12-28 12:37:36

緩存擊穿穿透

2022-03-08 00:07:51

緩存雪崩數(shù)據(jù)庫

2021-12-25 22:28:27

緩存穿透緩存擊穿緩存雪崩

2023-11-10 14:58:03

2020-03-16 14:57:24

Redis面試雪崩

2024-03-12 10:44:42

2020-10-23 10:46:03

緩存雪崩擊穿

2022-05-27 07:57:20

緩存穿透緩存雪崩緩存擊穿

2023-12-06 13:38:00

Redis緩存穿透緩存擊穿

2022-11-18 14:34:28

2025-06-30 01:55:00

2020-03-05 09:09:18

緩存原因方案

2023-04-14 07:34:19

2018-12-13 12:43:07

Redis緩存穿透

2025-05-28 02:25:00

高并發(fā)緩存穿透雪崩
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)