1、我往Redis里寫的數據怎么沒了?
使用Redis的同學你要明白一點,你為什么用Redis?用redis的作用是什么?用redis的好處是什么?凡事多思考一下為什么,多想想背后的原因。
就在不久前有朋友跟我說過,說他們生產環境的Redis怎么經常會丟掉一些數據?寫進去了,過一會兒可能就沒了。我的天啊,你問這個問題就說明Redis你就沒用對啊。Redis是緩存,你給當存儲了用了是吧?
首先要明白一點啥叫緩存?為啥用緩存?
Redis是用內存當緩存的。內存是無限的嗎?相反,內存是很寶貴而且是有限的,磁盤是廉價而且是大量的。可能一臺機器就幾十個G的內存,但是可以有幾個T的硬盤空間。Redis主要是基于內存來進行高性能、高并發的讀寫操作的。
那既然內存是有限的,比如Redis就只能用10個G,你一直往里面寫數據,一直寫一直寫最后10個G都用的差不多了,你還寫會,你想想會發生什么?當然會干掉一些的數據了,然后就保留10個G的數據。你說會不會造成數據丟失?
那Redis會干掉哪些數據?保留哪些數據呢?當然是干掉不常用的數據,保留常用的數據了。
所以說,這是緩存的一個最基本的概念:數據是會過期的。要么是你自己設置個過期時間,要么是Redis自己給干掉。
所以你的Redis如果使用不當,把生產數據存到里面,又沒有去持久化到mysql,那就會有丟失的可能。
2、我的數據明明都過期了,怎么還占用著內存啊?
還有一種就是如果你給key設置好了一個過期時間,你知道到一定的時間再去查這個key就沒有了,但是你知道redis是怎么給你弄成過期的嗎?什么時候刪除掉?
如果你不知道,在實際的使用過程中你就可能會發現這么一個問題:為啥好多數據明明應該過期了,結果發現redis內存占用還是很高?那是因為你不知道Redis是怎么刪除那些過期key的。
舉例,Redis 內存一共是10個G,你現在往里面寫了5個G的數據,然后你對這些數據全都設置了10分鐘之后過期,結果10分鐘之后,你再來查看看,Redis的內存使用率怎么還是50%呢?5個G的數據都過期了,我從redis里查,是查不到了,結果過期的數據為啥還占用著Redis的內存呢。
如果你連這個問題都不知道,上來就懵了,回答不出來,建議你使用Redis之前多做做功課,不然你寫代碼的時候,想當然的認為寫進Redis的數據就一定會存在,后面導致系統各種漏洞和bug,就不好弄了。
3、問題剖析
(1)設置過期時間
set key value 過期時間(1小時)
表示set進去的key,1小時之后就沒了,就失效了。
我們set key的時候,都可以給一個expire time,就是過期時間,指定這個key比如說只能存活1個小時?10分鐘?這個很有用,我們自己可以指定緩存到期就失效。
如果假設你設置一批key只能存活1個小時,那么接下來1小時后,redis是怎么對這批key進行刪除的?
答案是:定期刪除+惰性刪除
所謂定期刪除,指的是Redis默認是每隔100ms就隨機抽取
一些設置了過期時間的key,檢查其是否過期,如果過期就刪除。
為什么是隨機抽取?
假設Redis里放了10萬個key,都設置了過期時間,你每隔幾百毫秒,就檢查10萬個key,那redis基本上就死了,因為這樣cpu負載會很高的,全都消耗在你的檢查過期key上了。
所以這里可不是每隔100ms就遍歷所有的設置過期時間的key,Redis如果設置成檢查所有Key那將是一場性能上的災難。所以實際上redis是每隔100ms隨機抽取
一些key來檢查和刪除的。
但是問題是,隨機抽取檢測key是否過去會導致定期刪除
策略可能會導致很多過期key到了時間并沒有被刪除掉,那咋整呢?所以Redis還有另一個策略就是惰性刪除
。
惰性刪除?就是說,在你獲取某個key的時候,Redis會檢查一下 ,這個key如果設置了過期時間那么是否過期了?如果過期了此時就會刪除,不會給你返回任何東西。
所以并不是key到時間就被刪除掉,而是你查詢這個key的時候,Redis再懶惰的檢查一下。
通過上述兩種手段,保證過期的key一定會被干掉。
那么剛才的問題就不難理解了,就是說,你的過期key,靠定期刪除沒有被刪除掉,還停留在內存里,占用著你的內存呢,除非你的系統去查一下那個key,才會被redis給刪除掉。如果都過期了,定期刪除才刪了一點點,而你又沒有去查,沒有觸發惰性刪除,那么短時間內你的redis內存占用率還是會下不來。
但是實際上這還是有問題的,如果定期刪除漏掉了很多過期key,然后你也沒及時去查,也就沒走惰性刪除,此時會怎么樣?如果大量過期key堆積在內存里,導致redis內存塊耗盡了,咋整?
別擔心Redis還有方案:內存淘汰機制。
(2)內存淘汰策略
如果Redis的內存占用過多的時候,此時會進行內存淘汰,Redis提供如下豐富的可選策略:
1)noeviction:
當內存不足以容納新寫入數據時,新寫入操作會報錯。
(這個一般沒人用吧,實在是太惡心了)
2)allkeys-lru:
當內存不足以容納新寫入數據時,在所有鍵空間中,移除最近最少使用的key
(這個是最常用的)
3)allkeys-random:
當內存不足以容納新寫入數據時,在所有鍵空間中,隨機移除某個key。
(這個一般沒人用吧,為啥要隨機,把我重要的key干掉了咋整,肯定是把最近最少使用的干掉)
4)volatile-lru:
當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,移除最近最少使用的key。
(這個一般不太合適)
5)volatile-random:
當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,隨機移除某個key。
6)volatile-ttl:
當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,有更早過期時間的key優先移除。
例如:Redis 里有10個key,現在內存已經滿了,設置的淘汰策略是allkeys-lru
,此時Redis需要刪除掉一些key來保證你可以繼續寫入。在這10個key中,其中1個key,最近1分鐘被查詢了100次,1個key,最近10分鐘被查詢了50次,1個key,最近1個小時被查詢了1次。肯定那些最近最少使用的被干掉了。
為啥存redis的數據有時候會丟失?
很簡單,你寫的數據太多了,內存占滿了,或者觸發了什么條件,如redis使用了allkeys-lru內存淘汰策略,自動給你清理掉了一些最近很少使用的數據。
如何獲取免費架構學習資料?
由于篇幅限制小編,pdf文檔的詳解資料太全面,細節內容實在太多啦,所以只把部分知識點截圖出來粗略的介紹,每個小節點里面都有更細化的內容!有需要的程序猿(媛)可以戳這里即可免費獲取哦
識點截圖出來粗略的介紹,每個小節點里面都有更細化的內容!有需要的程序猿(媛)可以戳這里即可免費獲取哦