Java-分布式框架-redis-5

一阱飘、概述

一個高并發(fā)的框架中,往往會設(shè)置多層緩存速妖,比如Nginx應(yīng)用層的緩存高蜂、web層JVM中的緩存、redis集群緩存罕容,最后才會到數(shù)據(jù)庫备恤。但是生產(chǎn)環(huán)境下的使用并沒有那么簡單,還需要考慮多種情況锦秒。


image.png

二烘跺、高并發(fā)下的緩存問題

緩存穿透

緩存穿透是指查詢一個根本不存在的數(shù)據(jù), 緩存層和存儲層都不會命中脂崔, 通常出于容錯的考慮滤淳, 如果從存儲 層查不到數(shù)據(jù)則不寫入緩存層。
緩存穿透將導(dǎo)致不存在的數(shù)據(jù)每次請求都要到存儲層去查詢砌左, 失去了緩存保護后端存儲的意義脖咐。 造成緩存穿透的基本原因有兩個:

  • 自身業(yè)務(wù)代碼或者數(shù)據(jù)出現(xiàn)問題。
  • 一些惡意攻擊汇歹、 爬蟲等造成大量空命中屁擅。

緩存穿透問題解決方案:

  1. 緩存空對象
String get(String key) { 
    // 從緩存中獲取數(shù)據(jù) 
    String cacheValue = cache.get(key); 
    // 緩存為空 
    if (StringUtils.isBlank(cacheValue)) { 
        // 從存儲中獲取 
        String storageValue = storage.get(key); 
        cache.set(key, storageValue); 
        /** 如果存儲數(shù)據(jù)為空,需要設(shè)置一個過期時間(300秒)产弹,原因有二派歌,
            一是值為空的緩存短時間防止惡意高并發(fā)請求,但是過后沒意義要刪除痰哨;
            二是防止后面真的存在該key胶果,需要重新緩存。
        **/
        if (storageValue == null) {   
            cache.expire(key, 60 * 5); 
        } 
        return storageValue; 
    // 緩存非空 
    } else {     
        return cacheValue; 
    } 
} 
  1. 布隆過濾器

對于惡意攻擊斤斧,向服務(wù)器請求大量不存在的數(shù)據(jù)造成的緩存穿透早抠,還可以用布隆過濾器先做一次過濾,對于不 存在的數(shù)據(jù)布隆過濾器一般都能夠過濾掉撬讽,不讓請求再往后端發(fā)送蕊连。當(dāng)布隆過濾器說某個值存在時悬垃,這個值可 能不存在;當(dāng)它說不存在時甘苍,那就肯定不存在尝蠕。

image.png

布隆過濾器就是一個大型的位數(shù)組和幾個不一樣的無偏 hash 函數(shù)。所謂無偏就是能夠把元素的 hash 值算得 比較均勻载庭。
向布隆過濾器中添加 key 時趟佃,會使用多個 hash 函數(shù)對 key 進行 hash 算得一個整數(shù)索引值然后對位數(shù)組長度 進行取模運算得到一個位置,每個 hash 函數(shù)都會算得一個不同的位置昧捷。再把位數(shù)組的這幾個位置都置為 1 就 完成了 add 操作。
向布隆過濾器詢問 key 是否存在時罐寨,跟 add 一樣靡挥,也會把 hash 的幾個位置都算出來,看看位數(shù)組中這幾個位 置是否都為 1鸯绿,只要有一個位為 0跋破,那么說明布隆過濾器中這個key 不存在。如果都是 1瓶蝴,這并不能說明這個 key 就一定存在毒返,只是極有可能存在,因為這些位被置為 1 可能是因為其它的 key 存在所致舷手。如果這個位數(shù)組 比較稀疏拧簸,這個概率就會很大,如果這個位數(shù)組比較擁擠男窟,這個概率就會降低盆赤。
這種方法適用于數(shù)據(jù)命中不高、 數(shù)據(jù)相對固定歉眷、 實時性低(通常是數(shù)據(jù)集較大) 的應(yīng)用場景牺六, 代碼維護較為 復(fù)雜, 但是緩存空間占用很少汗捡。

可以用guvua包自帶的布隆過濾器淑际,引入依賴:

<dependency> 
    <groupId>com.google.guava</groupId> 
    <artifactId>guava</artifactId> 
    <version>22.0</version> 
</dependency>

示例偽代碼:

import com.google.common.hash.BloomFilter;
//初始化布隆過濾器
//1000:期望存入的數(shù)據(jù)個數(shù),0.001:期望的誤差率 
BloomFilter<String> bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charset.forName("utf‐8")), 1000, 0.001);
//把所有數(shù)據(jù)存入布隆過濾器 
void init(){ 
    for String key: keys) { 
        bloomFilter.put(key); 
    } 
}

String get(String key) { 
    // 從布隆過濾器這一級緩存判斷下key是否存在 
    Boolean exist = bloomFilter.mightContain(key); 
    if(!exist){ 
        return ""; 
    } 
    // 從緩存中獲取數(shù)據(jù) 
    String cacheValue = cache.get(key); 
    // 緩存為空 
    if (StringUtils.isBlank(cacheValue)) { 
        // 從存儲中獲取 
        String storageValue = storage.get(key); 
        cache.set(key, storageValue); 
        // 如果存儲數(shù)據(jù)為空扇住, 需要設(shè)置一個過期時間(300秒) 
        if (storageValue == null) { 
            cache.expire(key, 60 * 5); 
        } 
        return storageValue; 
    } else { 
        // 緩存非空 
        return cacheValue; 
    } 
}
緩存失效

由于大批量緩存在同一時間失效可能導(dǎo)致大量請求同時穿透緩存直達數(shù)據(jù)庫春缕,可能會造成數(shù)據(jù)庫瞬間壓力過大甚至掛掉,對于這種情況我們在批量增加緩存時好將這一批數(shù)據(jù)的緩存過期時間設(shè)置為一個時間段內(nèi)的不同時間艘蹋。

緩存失效問題解決方案:

String get(String key) { 
    // 從緩存中獲取數(shù)據(jù) 
    String cacheValue = cache.get(key); 
    // 緩存為空 
    if (StringUtils.isBlank(cacheValue)) { 
        // 從存儲中獲取 
        String storageValue = storage.get(key); 
        cache.set(key, storageValue);
        //設(shè)置一個過期時間(300到600之間的一個隨機數(shù)) 淡溯,防止多個key在同一個時間內(nèi)失效。
        int expireTime = new Random().nextInt(300) + 300; 
        if (storageValue == null) { 
            cache.expire(key, expireTime); 
        } 
        return storageValue; 
    // 緩存非空
    } else { 
        return cacheValue; 
    } 
}

注意:在有些應(yīng)用場景下簿训,若知道某個時間段中會發(fā)生高并發(fā)咱娶,那么最好提前做好緩存預(yù)熱米间,把數(shù)據(jù)庫中的數(shù)據(jù)提前放在緩存中,比如電商搶購的場景膘侮。

緩存雪崩

緩存雪崩指的是緩存層支撐不住或宕掉后屈糊, 流量會像奔逃的野牛一樣, 打向后端存儲層琼了。
由于緩存層承載著大量請求逻锐, 有效地保護了存儲層, 但是如果緩存層由于某些原因不能提供服務(wù)(比如超大并 發(fā)過來雕薪,緩存層支撐不住昧诱,或者由于緩存設(shè)計不好,類似大量請求訪問bigkey所袁,導(dǎo)致緩存能支撐的并發(fā)急劇下 降)盏档, 于是大量請求都會達到存儲層, 存儲層的調(diào)用量會暴增燥爷, 造成存儲層也會級聯(lián)宕機的情況蜈亩。
預(yù)防和解決緩存雪崩問題, 可以從以下三個方面進行著手前翎。

  1. 保證緩存層服務(wù)高可用性稚配,比如使用Redis Sentinel或Redis Cluster。
  2. 依賴隔離組件為后端限流并降級港华。比如使用Hystrix限流降級組件道川。
  3. 提前演練。 在項目上線前立宜, 演練緩存層宕掉后愤惰, 應(yīng)用以及后端的負載情況以及可能出現(xiàn)的問題, 在此基 礎(chǔ)上做一些預(yù)案設(shè)定赘理。
熱點緩存key重建優(yōu)化

開發(fā)人員使用“緩存+過期時間”的策略既可以加速數(shù)據(jù)讀寫宦言, 又保證數(shù)據(jù)的定期更新, 這種模式基本能夠滿 足絕大部分需求商模。 但是有兩個問題如果同時出現(xiàn)奠旺, 可能就會對應(yīng)用造成致命的危害:

  • 當(dāng)前key是一個熱點key(例如一個熱門的娛樂新聞),并發(fā)量非常大施流。
  • 重建緩存不能在短時間完成响疚, 可能是一個復(fù)雜計算, 例如復(fù)雜的SQL瞪醋、 多次IO忿晕、 多個依賴等。

在緩存失效的瞬間银受, 有大量線程來重建緩存践盼, 造成后端負載加大鸦采, 甚至可能會讓應(yīng)用崩潰。 要解決這個問題主要就是要避免大量線程同時重建緩存咕幻。 我們可以利用互斥鎖來解決渔伯,此方法只允許一個線程重建緩存, 其他線程等待重建緩存的線程執(zhí)行完肄程, 重新從 緩存獲取數(shù)據(jù)即可锣吼。

高并發(fā)緩存key重建優(yōu)化問題解決方案:

String get(String key) { 
    // 從Redis中獲取數(shù)據(jù) 
    String value = redis.get(key); 
    // 如果value為空, 則開始重構(gòu)緩存 
    if (value == null) { 
         // 只允許一個線程重建緩存蓝厌, 使用nx玄叠, 并設(shè)置過期時間
         String mutexKey = "mutext:key:" + key; 
         if (redis.set(mutexKey, "1", "ex 180", "nx")) { 
              // 從數(shù)據(jù)源獲取數(shù)據(jù) 
              value = db.get(key); 
              // 回寫Redis, 并設(shè)置過期時間 
              redis.setex(key, timeout, value);
              // 刪除key_mutex 
              redis.delete(mutexKey); 
         }
         // 其他線程休息50毫秒后重試 
        else { 
              Thread.sleep(50); 
              get(key); 
        } 
    } 
    return value; 
}

三拓提、開發(fā)規(guī)范與性能優(yōu)化

key名設(shè)計
  • 【建議】: 可讀性和可管理性
    以業(yè)務(wù)名(或數(shù)據(jù)庫名)為前綴(防止key沖突)读恃,用冒號分隔,比如業(yè)務(wù)名:表名:id
trade:order:1
  • 【建議】:簡潔性
    保證語義的前提下崎苗,控制key的長度,當(dāng)key較多時舀寓,內(nèi)存占用也不容忽視胆数,例如:
user:{uid}:friends:messages:{mid} 簡化為 u:{uid}:fr:m:{mid}
  • 【強制】:不要包含特殊字符
    反例:包含空格、換行互墓、單雙引號以及其他轉(zhuǎn)義字符
value設(shè)計
  • 【強制】:拒絕bigkey(防止網(wǎng)卡流量必尼、慢查詢)

在Redis中,一個字符串大512MB篡撵,一個二級數(shù)據(jù)結(jié)構(gòu)(例如hash判莉、list、set育谬、zset)可以存 儲大約40億個(2^32-1)個元素券盅,但實際中如果下面兩種情況,我就會認為它是bigkey膛檀。

  1. 字符串類型:它的big體現(xiàn)在單個value值很大锰镀,一般認為超過10KB就是bigkey。
  2. 非字符串類型:哈希咖刃、列表泳炉、集合、有序集合嚎杨,它們的big體現(xiàn)在元素個數(shù)太多花鹅。

一般來說,string類型控制在10KB以內(nèi)枫浙,hash刨肃、list古拴、set、zset元素個數(shù)不要超過5000之景。 反例:一個包含200萬個元素的list斤富。
非字符串的bigkey,不要使用del刪除锻狗,使用hscan满力、sscan、zscan方式漸進式刪除轻纪,同時要注 意防止bigkey過期時間自動刪除問題(例如一個200萬的zset設(shè)置1小時過期油额,會觸發(fā)del操作,造 成阻塞)

  • bigkey的危害
  1. 導(dǎo)致redis阻塞
  2. 網(wǎng)絡(luò)擁塞
    bigkey也就意味著每次獲取要產(chǎn)生的網(wǎng)絡(luò)流量較大刻帚,假設(shè)一個bigkey為1MB潦嘶,客戶端每秒訪問 量為1000,那么每秒產(chǎn)生1000MB的流量崇众,對于普通的千兆網(wǎng)卡(按照字節(jié)算是128MB/s)的服務(wù) 器來說簡直是滅頂之災(zāi)掂僵,而且一般服務(wù)器會采用單機多實例的方式來部署,也就是說一個bigkey 可能會對其他實例也造成影響顷歌,其后果不堪設(shè)想锰蓬。
  3. 過期刪除
    有個bigkey,它安分守己(只執(zhí)行簡單的命令眯漩,例如hget芹扭、lpop、zscore等)赦抖,但它設(shè)置了過 期時間舱卡,當(dāng)它過期后,會被刪除队萤,如果沒有使用Redis 4.0的過期異步刪除(lazyfree-lazyexpire yes)轮锥,就會存在阻塞Redis的可能性。
  • bigkey的產(chǎn)生
    一般來說要尔,bigkey的產(chǎn)生都是由于程序設(shè)計不當(dāng)交胚,或者對于數(shù)據(jù)規(guī)模預(yù)料不清楚造成的,來看幾 個例子:
  1. 社交類:粉絲列表盈电,如果某些明星或者大v不精心設(shè)計下肉瓦,必是bigkey等缀。
  2. 統(tǒng)計類:例如按天存儲某項功能或者網(wǎng)站的用戶集合霹抛,除非沒幾個人用栅表,否則必是bigkey。
  3. 緩存類:將數(shù)據(jù)從數(shù)據(jù)庫load出來序列化放到Redis里,這個方式非常常用互拾,但有兩個地方需 要注意歪今,第一,是不是有必要把所有字段都緩存颜矿;第二寄猩,有沒有相關(guān)關(guān)聯(lián)的數(shù)據(jù),有的同學(xué)為了 圖方便把相關(guān)數(shù)據(jù)都存一個key下骑疆,產(chǎn)生bigkey田篇。
  • 如何優(yōu)化bigkey

  1. big list: list1、list2箍铭、...listN
    big hash:可以講數(shù)據(jù)分段存儲泊柬,比如一個大的key,假設(shè)存了1百萬的用戶數(shù)據(jù)诈火,可以拆分成 200個key兽赁,每個key下面存放5000個用戶數(shù)據(jù)
  2. 如果bigkey不可避免,也要思考一下要不要每次把所有元素都取出來(例如有時候僅僅需要 hmget冷守,而不是hgetall)刀崖,刪除也是一樣,盡量使用優(yōu)雅的方式來處理拍摇。
命令使用
  1. 【推薦】 O(N)命令關(guān)注N的數(shù)量
    例如hgetall亮钦、lrange、smembers授翻、zrange或悲、sinter等并非不能使用孙咪,但是需要明確N的值堪唐。有 遍歷的需求可以使用hscan、sscan翎蹈、zscan代替淮菠。
  2. 【推薦】:禁用命令 禁止線上使用keys、flushall荤堪、flushdb等合陵,通過redis的rename機制禁掉命令,或者使用scan的 方式漸進式處理澄阳。
  3. 【推薦】合理使用select redis的多數(shù)據(jù)庫較弱拥知,使用數(shù)字進行區(qū)分,很多客戶端支持較差碎赢,同時多業(yè)務(wù)用多數(shù)據(jù)庫實際還 是單線程處理低剔,會有干擾
  4. 【推薦】使用批量操作提高效率

原生命令:例如mget、mset。
非原生命令:可以使用pipeline提高效率
管道(Pipeline) 客戶端可以一次性發(fā)送多個請求而不用等待服務(wù)器的響應(yīng)襟齿,待所有命令都發(fā)送完后再一次性讀取服務(wù)的響 應(yīng)姻锁,這樣可以極大的降低多條命令執(zhí)行的網(wǎng)絡(luò)傳輸開銷,管道執(zhí)行多條命令的網(wǎng)絡(luò)開銷實際上只相當(dāng)于一 次命令執(zhí)行的網(wǎng)絡(luò)開銷猜欺。需要注意到是用pipeline方式打包命令發(fā)送位隶,redis必須在處理完所有命令前先緩 存起所有命令的處理結(jié)果。打包的命令越多开皿,緩存消耗內(nèi)存也越多涧黄。所以并不是打包的命令越多越好。 pipeline中發(fā)送的每個command都會被server立即執(zhí)行副瀑,如果執(zhí)行失敗弓熏,將會在此后的響應(yīng)中得到信 息;也就是pipeline并不是表達“所有command都一起成功”的語義糠睡,管道中前面命令失敗挽鞠,后面命令 不會有影響,繼續(xù)執(zhí)行狈孔。
詳細代碼示例見上面jedis連接示例:

Pipeline pl = jedis.pipelined();
for (int i = 0; i < 10; i++) { 
    pl.incr("pipelineKey"); 
    pl.set("zhuge" + i, "zhuge"); 
} 
List<Object> results = pl.syncAndReturnAll(); 
System.out.println(results);

但要注意控制一次批量操作的元素個數(shù)(例如500以內(nèi)信认,實際也和元素字節(jié)數(shù)有關(guān))。 注意兩者不同:

  • 原生是原子操作均抽,pipeline是非原子操作嫁赏。
  • pipeline可以打包不同的命令,原生做不到
  • pipeline需要客戶端和服務(wù)端同時支持油挥。
  1. 【建議】Redis事務(wù)功能較弱潦蝇,不建議過多使用,可以用lua替代
客戶端使用
  1. 【推薦】 避免多個應(yīng)用使用一個Redis實例
    正例:不相干的業(yè)務(wù)拆分深寥,公共數(shù)據(jù)做服務(wù)化攘乒。

2.【推薦】
使用帶有連接池的數(shù)據(jù)庫,可以有效控制連接惋鹅,同時提高效率则酝,標準使用方式:

JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); 
jedisPoolConfig.setMaxTotal(5); 
jedisPoolConfig.setMaxIdle(2); 
jedisPoolConfig.setTestOnBorrow(true);
JedisPool jedisPool = new JedisPool(jedisPoolConfig, "192.168.0.60", 6379, 3000, null);
Jedis jedis = null; 
try { 
    jedis = jedisPool.getResource(); 
    //具體的命令 
    jedis.executeCommand() 
} catch (Exception e) { 
    logger.error("op key {} error: " + e.getMessage(), key, e); 
} finally { 
    //注意這里不是關(guān)閉連接,在JedisPool模式下闰集,Jedis會被歸還給資源池沽讹。
    if (jedis != null) 
        jedis.close(); 
}

連接池參數(shù)含義:

序號 參數(shù)名 含義 默認值 使用建議
1 maxTotal 資源池中大連接數(shù) 8 設(shè)置建議見下面
2 maxIdle 資源池允許大空閑的連接數(shù) 8 設(shè)置建議見下面
3 minIdle 資源池確保少空閑 的連接數(shù) 0 設(shè)置建議見下面
4 blockWhenExhausted 當(dāng)資源池用盡后,調(diào)用者是否要等待武鲁。只有當(dāng)為true時爽雄,下面的maxWaitMillis才會 生效 true 建議使用默認值
5 maxWaitMillis 當(dāng)資源池連接用盡 后,調(diào)用者的大等 待時間(單位為毫秒) -1:表示永不超時 不建議使用默認值
6 testOnBorrow 向資源池借用連接時 是否做連接有效性檢 測(ping)沐鼠,無效連接 會被移除 false 業(yè)務(wù)量很大時候建議 設(shè)置為false(多一次 ping的開銷)挚瘟。
7 testOnReturn 向資源池歸還連接時 是否做連接有效性檢 測(ping),無效連接 會被移除 false 業(yè)務(wù)量很大時候建議 設(shè)置為false(多一次 ping的開銷)。
8 jmxEnabled 是否開啟jmx監(jiān)控刽沾,可 用于監(jiān)控 true 建議開啟本慕,但應(yīng)用本

優(yōu)化建議:
maxTotal:大連接數(shù),早期的版本叫maxActive
實際上這個是一個很難回答的問題侧漓,考慮的因素比較多:

  • 業(yè)務(wù)希望Redis并發(fā)量
  • 客戶端執(zhí)行命令時間
  • Redis資源:例如 nodes(例如應(yīng)用個數(shù)) * maxTotal 是不能超過redis的大連接數(shù) maxclients锅尘。
  • 資源開銷:例如雖然希望控制空閑連接(連接池此刻可馬上使用的連接),但是不希望因 為連接池的頻繁釋放創(chuàng)建連接造成不必靠開銷布蔗。

以一個例子說明藤违,假設(shè):

  • 一次命令時間(borrow|return resource + Jedis執(zhí)行命令(含網(wǎng)絡(luò)) )的平均耗時約為 1ms,一個連接的QPS大約是1000
  • 業(yè)務(wù)期望的QPS是50000

那么理論上需要的資源池大小是50000 / 1000 = 50個纵揍。但事實上這是個理論值顿乒,還要考慮到要 比理論值預(yù)留一些資源,通常來講maxTotal可以比理論值大一些泽谨。 但這個值不是越大越好璧榄,一方面連接太多占用客戶端和服務(wù)端資源,另一方面對于Redis這種高 QPS的服務(wù)器吧雹,一個大命令的阻塞即使設(shè)置再大資源池仍然會無濟于事骨杂。

maxIdle和minIdle

maxIdle實際上才是業(yè)務(wù)需要的大連接數(shù),maxTotal是為了給出余量雄卷,所以maxIdle不要設(shè)置 過小搓蚪,否則會有new Jedis(新連接)開銷。
連接池的最佳性能是maxTotal = maxIdle丁鹉,這樣就避免連接池伸縮帶來的性能干擾妒潭。但是如果 并發(fā)量不大或者maxTotal設(shè)置過高,會導(dǎo)致不必要的連接資源浪費揣钦。一般推薦maxIdle可以設(shè)置 為按上面的業(yè)務(wù)期望QPS計算出來的理論連接數(shù)雳灾,maxTotal可以再放大一倍。
minIdle(小空閑連接數(shù))拂盯,與其說是小空閑連接數(shù)佑女,不如說是"至少需要保持的空閑連接 數(shù)"记靡,在使用連接的過程中谈竿,如果連接數(shù)超過了minIdle,那么繼續(xù)建立連接摸吠,如果超過了 maxIdle空凸,當(dāng)超過的連接執(zhí)行完業(yè)務(wù)后會慢慢被移出連接池釋放掉。
如果系統(tǒng)啟動完馬上就會有很多的請求過來寸痢,那么可以給redis連接池做預(yù)熱呀洲,比如快速的創(chuàng)建一 些redis連接,執(zhí)行簡單命令,類似ping()道逗,快速的將連接池里的空閑連接提升到minIdle的數(shù)量兵罢。

連接池預(yù)熱示例代碼:

List<Jedis> minIdleJedisList = new ArrayList<Jedis>(jedisPoolConfig.getMinIdle());
for (int i = 0; i < jedisPoolConfig.getMinIdle(); i++) { 
    Jedis jedis = null; 
    try { 
        jedis = pool.getResource(); 
        minIdleJedisList.add(jedis); 
        jedis.ping(); 
    } catch (Exception e) { 
        logger.error(e.getMessage(), e); 
    } finally { 
        //注意,這里不能馬上close將連接還回連接池滓窍,否則最后連接池里只會建立1個連接卖词。。 
        //jedis.close(); 
    } 
} 
//統(tǒng)一將預(yù)熱的連接還回連接池 
for (int i = 0; i < jedisPoolConfig.getMinIdle(); i++) { 
    Jedis jedis = null; 
    try { 
        jedis = minIdleJedisList.get(i); 
        //將連接歸還回連接池 
        jedis.close(); 
    } catch (Exception e) { 
        logger.error(e.getMessage(), e); 
    } finally { 
    } 
}

總之吏夯,要根據(jù)實際系統(tǒng)的QPS和調(diào)用redis客戶端的規(guī)模整體評估每個節(jié)點所使用的連接池大小此蜈。

3.【建議】
高并發(fā)下建議客戶端添加熔斷功能(例如netflix hystrix)

4.【推薦】
設(shè)置合理的密碼,如有必要可以使用SSL加密訪問

5.【建議】
Redis對于過期鍵有三種清除策略:

  • 被動刪除:當(dāng)讀/寫一個已經(jīng)過期的key時噪生,會觸發(fā)惰性刪除策略裆赵,直接刪除掉這個過期key。
  • 主動刪除:由于惰性刪除策略無法保證冷數(shù)據(jù)被及時刪掉跺嗽,所以Redis會定期主動淘汰一批已過期的key战授。
  • 當(dāng)前已用內(nèi)存超過maxmemory限定時,觸發(fā)主動清理策略桨嫁。

當(dāng)REDIS運行在主從模式時陈醒,只有主結(jié)點才會執(zhí)行被動和主動這兩種過期刪除策略,然后把刪除 操作”del key”同步到從結(jié)點瞧甩。

第三種策略的情況如下:

當(dāng)前已用內(nèi)存超過maxmemory限定時钉跷,會觸發(fā)主動清理策略。
根據(jù)自身業(yè)務(wù)類型肚逸,選好maxmemory-policy(大內(nèi)存淘汰策略)爷辙,設(shè)置好過期時間。如果不設(shè) 置大內(nèi)存朦促,當(dāng) Redis 內(nèi)存超出物理內(nèi)存限制時膝晾,內(nèi)存的數(shù)據(jù)會開始和磁盤產(chǎn)生頻繁的交換 (swap), 會讓 Redis 的性能急劇下降务冕。
默認策略是volatile-lru血当,即超過大內(nèi)存后,在過期鍵中使用lru算法進行key的剔除禀忆,保證不過 期數(shù)據(jù)不被刪除臊旭,但是可能會出現(xiàn)OOM問題。 其他策略如下:

  • allkeys-lru:根據(jù)LRU算法刪除鍵箩退,不管數(shù)據(jù)有沒有設(shè)置超時屬性离熏,直到騰出足夠空間 為止。
  • allkeys-random:隨機刪除所有鍵戴涝,直到騰出足夠空間為止滋戳。
  • volatile-random: 隨機刪除過期鍵钻蔑,直到騰出足夠空間為止。
  • volatile-ttl:根據(jù)鍵值對象的ttl屬性奸鸯,刪除近將要過期數(shù)據(jù)咪笑。如果沒有,回退到 noeviction策略娄涩。
  • noeviction:不會剔除任何數(shù)據(jù)蒲肋,拒絕所有寫入操作并返回客戶端錯誤信息"(error) OOM command not allowed when used memory",此時Redis只響應(yīng)讀操作钝满。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末兜粘,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子弯蚜,更是在濱河造成了極大的恐慌孔轴,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件碎捺,死亡現(xiàn)場離奇詭異路鹰,居然都是意外死亡,警方通過查閱死者的電腦和手機收厨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門晋柱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人诵叁,你說我怎么就攤上這事雁竞。” “怎么了拧额?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵碑诉,是天一觀的道長。 經(jīng)常有香客問我侥锦,道長进栽,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任恭垦,我火速辦了婚禮快毛,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘番挺。我一直安慰自己唠帝,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布建芙。 她就那樣靜靜地躺著没隘,像睡著了一般懂扼。 火紅的嫁衣襯著肌膚如雪禁荸。 梳的紋絲不亂的頭發(fā)上右蒲,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天,我揣著相機與錄音赶熟,去河邊找鬼瑰妄。 笑死,一個胖子當(dāng)著我的面吹牛映砖,可吹牛的內(nèi)容都是我干的间坐。 我是一名探鬼主播,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼邑退,長吁一口氣:“原來是場噩夢啊……” “哼竹宋!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起地技,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤蜈七,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后莫矗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體飒硅,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年作谚,在試婚紗的時候發(fā)現(xiàn)自己被綠了三娩。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡妹懒,死狀恐怖雀监,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情眨唬,我是刑警寧澤滔悉,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站单绑,受9級特大地震影響回官,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜搂橙,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一歉提、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧区转,春花似錦苔巨、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蜻韭,卻和暖如春悼尾,著一層夾襖步出監(jiān)牢的瞬間柿扣,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工闺魏, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留未状,地道東北人。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓析桥,卻偏偏與公主長得像司草,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子泡仗,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內(nèi)容