1. 程式人生 > >StringRedisTemplate常用操作 / Redis中刪除過期Key的三種策略

StringRedisTemplate常用操作 / Redis中刪除過期Key的三種策略

  1. stringRedisTemplate.opsForValue().set("test""100",60*10,TimeUnit.SECONDS);//向redis裡存入資料和設定快取時間
  1. stringRedisTemplate.boundValueOps("test").increment(-1);//val做-1操作
  1. stringRedisTemplate.opsForValue().get("test")//根據key獲取快取中的val
  1. stringRedisTemplate.boundValueOps("test").increment(1);//val +1
  1. stringRedisTemplate.getExpire(
    "test")//根據key獲取過期時間
  1. stringRedisTemplate.getExpire("test",TimeUnit.SECONDS)//根據key獲取過期時間並換算成指定單位
  1. stringRedisTemplate.delete("test");//根據key刪除快取
  1. stringRedisTemplate.hasKey("546545");//檢查key是否存在,返回boolean值
  1. stringRedisTemplate.opsForSet().add("red_123""1","2","3");//向指定key中存放set集合
  1. stringRedisTemplate.expire(
    "red_123",1000 , TimeUnit.MILLISECONDS);//設定過期時間
  2. stringRedisTemplate.opsForSet().isMember("red_123""1")//根據key檢視集合中是否存在指定資料
  1. stringRedisTemplate.opsForSet().members("red_123");//根據key獲取set集合

=============================================================================

專案中有個介面要頻繁呼叫查詢資料庫中的資料,為了降低資料庫的壓力,所以把一部分記錄先快取在

Redis中,對redis中的資料設定了期限。今天無意間發現一個問題,使用dbsize查詢出來的數量,比實際快取量要高一部分。用

redis-cli keys '*'|wc -l
  • 1
  • 1

獲取到的資料和實際情況是一樣的。如下面兩圖: 
這裡寫圖片描述 
這裡寫圖片描述 
對比發現,redis中key的總量為286957,比資料庫中的264032高出了20000多個!為什麼會這樣呢?查詢程式原因,並沒有發現邏輯問題。查詢redis相關資料,發現原來是redis對過期鍵處理機制導致的誤差。 
dbsize返回的是包含過期鍵的總數,所以造成了誤差!結合查詢的資料,拿來一起分享。

Redis對於過期鍵有三種清除策略

  • 被動刪除:當讀/寫一個已經過期的key時,會觸發惰性刪除策略,直接刪除掉這個過期key
  • 主動刪除:由於惰性刪除策略無法保證冷資料被及時刪掉,所以Redis會定期主動淘汰一批已過期的key
  • 當前已用記憶體超過maxmemory限定時,觸發主動清理策略

被動刪除

只有key被操作時(如GET),REDIS才會被動檢查該key是否過期,如果過期則刪除之並且返回NIL。 
1、這種刪除策略對CPU是友好的,刪除操作只有在不得不的情況下才會進行,不會對其他的expire key上浪費無謂的CPU時間。 
2、但是這種策略對記憶體不友好,一個key已經過期,但是在它被操作之前不會被刪除,仍然佔據記憶體空間。如果有大量的過期鍵存在但是又很少被訪問到,那會造成大量的記憶體空間浪費。expireIfNeeded(redisDb *db, robj *key)函式位於src/db.c。 
但僅是這樣是不夠的,因為可能存在一些key永遠不會被再次訪問到,這些設定了過期時間的key也是需要在過期後被刪除的,我們甚至可以將這種情況看作是一種記憶體洩露—-無用的垃圾資料佔用了大量的記憶體,而伺服器卻不會自己去釋放它們,這對於執行狀態非常依賴於記憶體的Redis伺服器來說,肯定不是一個好訊息。

主動刪除

先說一下時間事件,對於持續執行的伺服器來說, 伺服器需要定期對自身的資源和狀態進行必要的檢查和整理, 從而讓伺服器維持在一個健康穩定的狀態, 這類操作被統稱為常規操作(cron job)

在 Redis 中, 常規操作由 redis.c/serverCron 實現, 它主要執行以下操作

  • 更新伺服器的各類統計資訊,比如時間、記憶體佔用、資料庫佔用情況等。
  • 清理資料庫中的過期鍵值對。
  • 對不合理的資料庫進行大小調整。
  • 關閉和清理連線失效的客戶端。
  • 嘗試進行 AOF 或 RDB 持久化操作。
  • 如果伺服器是主節點的話,對附屬節點進行定期同步。
  • 如果處於叢集模式的話,對叢集進行定期同步和連線測試。

Redis 將 serverCron 作為時間事件來執行, 從而確保它每隔一段時間就會自動執行一次, 又因為 serverCron 需要在 Redis 伺服器執行期間一直定期執行, 所以它是一個迴圈時間事件: serverCron 會一直定期執行,直到伺服器關閉為止。

在 Redis 2.6 版本中, 程式規定 serverCron 每秒執行 10 次, 平均每 100 毫秒執行一次。 從 Redis 2.8 開始, 使用者可以通過修改 hz選項來調整 serverCron 的每秒執行次數, 具體資訊請參考 redis.conf 檔案中關於 hz 選項的說明也叫定時刪除,這裡的“定期”指的是Redis定期觸發的清理策略,由位於src/redis.c的activeExpireCycle(void)函式來完成。

serverCron是由redis的事件框架驅動的定位任務,這個定時任務中會呼叫activeExpireCycle函式,針對每個db在限制的時間REDIS_EXPIRELOOKUPS_TIME_LIMIT內遲可能多的刪除過期key,之所以要限制時間是為了防止過長時間 的阻塞影響redis的正常執行。這種主動刪除策略彌補了被動刪除策略在記憶體上的不友好。

因此,Redis會週期性的隨機測試一批設定了過期時間的key並進行處理。測試到的已過期的key將被刪除。典型的方式為,Redis每秒做10次如下的步驟:

  1. 隨機測試100個設定了過期時間的key
  2. 刪除所有發現的已過期的key
  3. 若刪除的key超過25個則重複步驟1

這是一個基於概率的簡單演算法,基本的假設是抽出的樣本能夠代表整個key空間,redis持續清理過期的資料直至將要過期的key的百分比降到了25%以下。這也意味著在任何給定的時刻已經過期但仍佔據著記憶體空間的key的量最多為每秒的寫操作量除以4.

Redis-3.0.0中的預設值是10,代表每秒鐘呼叫10次後臺任務。

除了主動淘汰的頻率外,Redis對每次淘汰任務執行的最大時長也有一個限定,這樣保證了每次主動淘汰不會過多阻塞應用請求,以下是這個限定計算公式:


#define ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC 25 /* CPU max % for keys collection */  

...  

timelimit = 1000000*ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC/server.hz/100;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

hz調大將會提高Redis主動淘汰的頻率,如果你的Redis儲存中包含很多冷資料佔用記憶體過大的話,可以考慮將這個值調大,但Redis作者建議這個值不要超過100。我們實際線上將這個值調大到100,觀察到CPU會增加2%左右,但對冷資料的記憶體釋放速度確實有明顯的提高(通過觀察keyspace個數和used_memory大小)。

可以看出timelimit和server.hz是一個倒數的關係,也就是說hz配置越大,timelimit就越小。換句話說是每秒鐘期望的主動淘汰頻率越高,則每次淘汰最長佔用時間就越短。這裡每秒鐘的最長淘汰佔用時間是固定的250ms(1000000*ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC/100),而淘汰頻率和每次淘汰的最長時間是通過hz引數控制的。

從以上的分析看,當redis中的過期key比率沒有超過25%之前,提高hz可以明顯提高掃描key的最小個數。假設hz為10,則一秒內最少掃描200個key(一秒呼叫10次*每次最少隨機取出20個key),如果hz改為100,則一秒內最少掃描2000個key;另一方面,如果過期key比率超過25%,則掃描key的個數無上限,但是cpu時間每秒鐘最多佔用250ms。

當REDIS執行在主從模式時,只有主結點才會執行上述這兩種過期刪除策略,然後把刪除操作”del key”同步到從結點。

maxmemory 
當前已用記憶體超過maxmemory限定時,觸發主動清理策略

  • volatile-lru:只對設定了過期時間的key進行LRU(預設值)
  • allkeys-lru : 刪除lru演算法的key
  • volatile-random:隨機刪除即將過期key
  • allkeys-random:隨機刪除
  • volatile-ttl : 刪除即將過期的
  • noeviction : 永不過期,返回錯誤

當mem_used記憶體已經超過maxmemory的設定,對於所有的讀寫請求,都會觸發redis.c/freeMemoryIfNeeded(void)函式以清理超出的記憶體。注意這個清理過程是阻塞的,直到清理出足夠的記憶體空間。所以如果在達到maxmemory並且呼叫方還在不斷寫入的情況下,可能會反覆觸發主動清理策略,導致請求會有一定的延遲。

清理時會根據使用者配置的maxmemory-policy來做適當的清理(一般是LRU或TTL),這裡的LRU或TTL策略並不是針對redis的所有key,而是以配置檔案中的maxmemory-samples個key作為樣本池進行抽樣清理。

maxmemory-samples在redis-3.0.0中的預設配置為5,如果增加,會提高LRU或TTL的精準度,redis作者測試的結果是當這個配置為10時已經非常接近全量LRU的精準度了,並且增加maxmemory-samples會導致在主動清理時消耗更多的CPU時間,建議:

  • 儘量不要觸發maxmemory,最好在mem_used記憶體佔用達到maxmemory的一定比例後,需要考慮調大hz以加快淘汰,或者進行叢集擴容。
  • 如果能夠控制住記憶體,則可以不用修改maxmemory-samples配置;如果Redis本身就作為LRU cache服務(這種服務一般長時間處於maxmemory狀態,由Redis自動做LRU淘汰),可以適當調大maxmemory-samples。

這裡提一句,實際上redis根本就不會準確的將整個資料庫中最久未被使用的鍵刪除,而是每次從資料庫中隨機取5個鍵並刪除這5個鍵裡最久未被使用的鍵。上面提到的所有的隨機的操作實際上都是這樣的,這個5可以用過redis的配置檔案中的maxmemeory-samples引數配置。

Replication link和AOF檔案中的過期處理

為了獲得正確的行為而不至於導致一致性問題,當一個key過期時DEL操作將被記錄在AOF檔案並傳遞到所有相關的slave。也即過期刪除操作統一在master例項中進行並向下傳遞,而不是各salve各自掌控。這樣一來便不會出現資料不一致的情形。當slave連線到master後並不能立即清理已過期的key(需要等待由master傳遞過來的DEL操作),slave仍需對資料集中的過期狀態進行管理維護以便於在slave被提升為master會能像master一樣獨立的進行過期處理。

參考博文:


相關推薦

StringRedisTemplate常用操作 / Redis刪除過期Key策略

stringRedisTemplate.opsForValue().set("test", "100",60*10,TimeUnit.SECONDS);//向redis裡存入資料和設定快取時間 stringRedisTemplate.boundValueOps("t

Redis刪除過期Key策略

專案中有個介面要頻繁呼叫查詢資料庫中的資料,為了降低資料庫的壓力,所以把一部分記錄先快取在redis中,對redis中的資料設定了期限。今天無意間發現一個問題,使用dbsize查詢出來的數量,比實際快取量要高一部分。用 redis-cli keys '*'|wc -l 1 獲取到的資料和實際情

Redis取得所有Key過期時間配置與獲取、Key過期通知。

ive exceptio config lee var url multipl -c class string connection = "127.0.0.1:6379,password=xxxxx,connectRetry=5"; [TestM

Redis過期刪除策略

我們知道在Redis資料庫中,我們可以為相應的鍵設定過期時間 那麼在相應鍵的過期時間到了,我們要通過什麼方法來回收相應的鍵呢? 對於上面的問題,我們有以下三種不同的刪除策略 定時刪除:在設定鍵過期時間的同時,建立一個定時器,讓定時器在過期時間來臨的時

springBoot 使用redisStringRedisTemplate 常用操作

spring boot 使用 redis :1,pom 引入 redis,貌似springboot 1.5以上的版本,引入redis必須加 <version></version><dependency> <groupId&

如何提取Redis的大KEY

ash xxx obj zset 隨著 pre tin 功能 平滑 工作中,經常有些Redis實例使用不恰當,或者對業務預估不準確,或者key沒有及時進行處理等等原因,導致某些KEY相當大。 那麽大Key會帶來哪些問題呢? 如果是集群模式下,無法做到負載均衡,導致請求傾

35課時 可變列表list常用操作 添加/刪除/插入

2-2 cnblogs 操作 http mage src 刪除 app .cn x.append(1)單個元素 x.extend([1,2]) 多個元素 刪除 del 此處有誤 應該是在第i+1個位置插入m 35課時 可變列表list常用操作 添加/刪除/插入

Spring Data操作Redis時,發現key值出現 xacxedx00x05tx00 b

成了 內存 format string obj 但是 tail 就是 urn 原文鏈接:http://blog.csdn.net/yunhaibin/article/details/9001198 最近在研究redis,以及spring data對redis的支持發現了

springboot redis 監聽過期key值事件

redis 中的key值過期後,觸發通知事件   1、建立springboot工程,建立監聽類   maven配置 <dependencies> <dependency> <groupId>org.springfr

php操作redis和memcache過期時間

php-redis 設定過期時間setTimeOut 命令列expireredis過期時間redis術語裡面,把設定了expire time的key 叫做:volatile keys。 意思就是不穩定的key。沒有設定過期時間的也就是永久儲存 set:set('key','value')將值 valu

匯出redis的特定 key的結果 並輸出到檔案

redis-cli -a Jx123456 -p 6379 --scan --pattern "*.com" >> temp.log // redis-cli 小寫 -a 密碼 排序輸出: sort china.txt | uniq -u >china_u

StringRedisTemplate常用操作

stringRedisTemplate.opsForValue().set("test", "100",60*10,TimeUnit.SECONDS);//向redis裡存入資料和設定快取時間stri

StringRedisTemplate簡單操作Redis

StringRedisTemplate SpringBoot中註解@Autowired即可 import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.be

java操作Redis快取設定過期時間

關於Redis的概念和應用本文就不再詳解了,說一下怎麼在java應用中設定過期時間。 在應用中我們會需要使用redis設定過期時間,比如單點登入中我們需要隨機生成一個token作為key,將使用者的資訊轉為json串作為value儲存在redis中,通常做法是: //生成

3.jupyter的常用操作

前言 上課啦,我們繼續學習常用操作 我們先從選單說起 看得我都餓了 選單欄 選單是這樣的 1. File File裡面比較常用的就是將程式碼另存為其他格式 特別是.py 格式 因為有些人喜歡用其他編輯器 例如Pycharm 而jupy

Spring Data操作Redis時,發現key值出現 \xac\xed\x00\x05t\x00\tb

最近在研究redis,以及spring data對redis的支援發現了一個奇怪的現象 先說現象吧,通過redisTemplate下的opsForHash方法儲存hash型別的值,操作成功以後,去redis控制檯顯示keys * 的時候,發現一個奇怪的現象,插入的has

Redis過期命令

鍵過期命令EXPIRE key seconds 將鍵 key 的生存時間設定為指定的秒數。複雜度為O(1) PEXPIRE key milliseconds 將鍵 key 的生存時間

jedis操作redis的hash(封裝)

一、由來 之前的redis pool的文章,講解了如何封裝一個redis pool以及操作redis中的字串,部落格地址如下: 還有一篇文章封裝了一些 操作redis中的list 。。。。 還有一篇文章封裝了一些 操作redis中的set 。。。。 關於

redis 設置過期Key 的 maxmemory-policy 六方式

方式 rim oev evict 默認值 ati onf 即將 默認 redis.conf中的默認的過期策略是 volatile-lru maxmemory-policy 六種方式 1、volatile-lru:只對設置了過期時間的key進行LRU(默認值) 2、a

Redis 過期元素是如何被處理的?視訊+圖文版給你答案——面試突擊 002 期

本文以面試問題「Redis 中的過期元素是如何被處理的?」為切入點,用視訊加圖文的方式和大家聊聊 Redis 過期元素被處理的相關知識點。 涉及的知識點 過期刪除策略有哪些? 這些過期策略有哪些優缺點? Redis 使用的是什麼過期策略? Redis 是如何優化和執行過期策略的? 視訊答案 點選檢視視