緩存又掛了?內存又爆了?只需要一招完美解決!
O!NO!緩存又掛了,redis不給力啊;哎喲我去,內存爆了?DBA干啥去了,怎么老是掛啊?
你的緩存是不是經常爆掉呢?是不是討厭DBA經常叨叨叨的?跟唐僧一個樣?如果是,那么可能是你還沒玩會redis哦,為什么?因為緩存是用來對抗高并發熱點數據請求的,而你可能將大量的長時間不使用的數據也放在里面了,白白浪費了內存。
今天教你一招,解決大量冷點數據白白浪費內存。
Redis中有個設置時間過期的功能,即對存儲在redis數據庫中的值可以設置一個過期時間。作為一個緩存數據庫,這是非常實用的。然而很多的程序員并沒有認識到這一點,比如我們要緩存用戶的token,那么是不是你會將所有的都放入緩存?是的,然后問題是,下次又想緩存用戶登錄賬號和密碼加密串,又放入緩存,如果你有1000萬用戶,是不是發現內存不夠了?
那么我們有必要將所有用戶的token都一直保存在內存中嗎?
答案顯然不是,我們只需要緩存最近經常用的。那些1、2年都不登錄一次的,顯然放mysql更經濟實惠。
那問題又來了,我怎么知道用戶什么時候登錄?
是的,不知道,所以用戶注冊之后,我們需要放進入,但是如果用戶1個月沒有登錄,我們就可以刪除了,釋放內存。
哦。OK,我知道了,我寫個定時任務,自動去判斷就是了。
NO,NO,NO,根本用不著,redis已經給你解決方案了。那就是過期時間。只需要寫入key的時候,設置好過期時間即可,剩下的交給redis。
如我們一般項目中的token或者一些登錄信息,尤其是短信驗證碼都是有時間限制的。這正是它的用武之地。
有效時間設置:
redis對存儲值的過期處理實際上是針對該值的鍵(key)處理的,即時間的設置也是設置key的有效時間。Expires字典保存了所有鍵的過期時間,Expires也被稱為過期字段。
redis> SET key va1ue
OK
redis> EXPlRE key 1000
(integer) 1
四種處理策略
1. EXPIRE 將key的生存時間設置為ttl秒
2. PEXPIRE 將key的生成時間設置為ttl毫秒
3. EXPIREAT 將key的過期時間設置為timestamp所代表的的秒數的時間戳
4. PEXPIREAT 將key的過期時間設置為timestamp所代表的的毫秒數的時間戳
其實以上幾種處理方式都是根據PEXPIREAT來實現的,設置生存時間的時候是redis內部計算好時間之后在內存處理的,最終的處理都會轉向PEXPIREAT。 1、2兩種方式是設置一個過期的時間段,就是咱們處理驗證碼最常用的策略,設置三分鐘或五分鐘后失效,把分鐘數轉換成秒或毫秒存儲到redis中。 3、4兩種方式是指定一個過期的時間 ,比如優惠券的過期時間是某年某月某日,只是單位不一樣。
過期處理
過期鍵的處理就是把過期鍵刪除,這里的操作主要是針對過期字段處理的。 Redis中有三種處理策略:定時刪除、惰性刪除和定期刪除。
1. 定時刪除:在設置鍵的過期時間的時候創建一個定時器,當過期時間到的時候立馬執行刪除操作。不過這種處理方式是即時的,不管這個時間內有多少過期鍵,不管服務器現在的運行狀況,都會立馬執行,所以對CPU不是很友好。因此,請注意,不要將大量的key過期時間設置到同一時間,因為同一時間刪除操作,將消耗大量資源,可能導致線上redis不穩定,甚至crash。
2. 惰性刪除:惰性刪除策略不會在鍵過期的時候立馬刪除,而是當外部指令獲取這個鍵的時候才會主動刪除。處理過程為:接收get執行、判斷是否過期(這里按過期判斷)、執行刪除操作、返回nil(空)。這種策略需要注意,因為可能會導致內存大量最近很少使用的key,占據內存,很少使用,則這個key沒有訪問,也就不會刪除,還是占著內存。
3. 定期刪除:這個一般是線上推薦方式,定期刪除是設置一個時間間隔,每個時間段都會檢測是否有過期鍵,如果有執行刪除操作。同時也要注意,不要將大量的key過期時間設置為同一時間,同1策略類似。沒有2策略的問題。
看完上面三種策略后可以得出以下結論: (1) 1、3為主動刪除,2為被動刪除。 (2) 1是實時執行的,線上慎重使用。(3) 2、3為被動刪除,所以過期鍵應該會存在一定的時間,這樣就使得過期鍵不會被立馬刪除,仍然占用著內存。但是惰性刪除的時候一般是單個刪除,相對來說對線上業務基本沒有影響。(4)定期刪除執行不能過于頻繁,否則就可能會演變成定時刪除,如果執行的過少就有可能造成過多過期鍵未被刪除而占用過多內存。因此應該根據線上情況進行合理設置。
持久化與復制的影響
過期鍵刪除策略對持久化以及復制的影響大致如下。
RDB: 1. 主服務器模式運行在載入RDB文件時,程序會檢查文件中的鍵,只會加載未過期的,過期的會被忽略,所以RDB模式下過期鍵不會對主服務器產生影響。 2. 從服務器運行載入RDB文件時,會載入所有鍵,包括過期和未過期。當主服務器進行數據同步的時候,從服務器的數據會被清空,所以RDB文件的過期鍵一般不會對從服務器產生影響。
AOF: AOF文件不會受過期鍵的影響。如果有過期鍵未被刪除,會執行以下動作: 客戶端請求時(過期鍵):
1. 從數據庫充刪除被訪問的過期鍵;
2. 追加一條DEL 命令到AOF文件;
3. 向執行請求的客戶端回復nil(空)。
復制:
1. 主服務器刪除過期鍵之后,向從服務器發送一條DEL指令,告知刪除該過期鍵。
2. 從服務器接收到get指令的時候不會對過期鍵進行處理,只會當做未過期鍵一樣返回。(為了保持主從服務器數據的一致性)
3. 從服務器只有接到主服務器發送的DEL指令后才會刪除過期鍵。
清理內存全局策略
當前已用內存超過maxmemory限定時,將觸發主動清理策略。因為內存已經使用完了,然而緩存的數據中,可能存在一些長時間沒有使用的數據,這時候我們可以根據一定的策略,進行有選擇的刪除清理,以保障內存中緩存的都盡可能是熱點數據。
volatile-lru:只對設置了過期時間的key進行LRU(默認值)因此采用這種策略的redis,請將所有key設置過期時間。一般線上我們也推薦設置過期時間。
allkeys-lru : 刪除lru算法的key,這種策略不區分是否設置過期時間,key是否過期,是判斷哪些是最近最少使用的,進行刪除,避免有的設置了過期時間,而有的沒有設置,永不過期。
volatile-random:隨機刪除即將過期key,隨機刪除,但只是刪除快要過期的當中去隨機刪除。如果你沒有設置過期時間,則不會刪除。
allkeys-random:隨機刪除,這是類似volatile-random,不同的是,它不區分是否過期,對所有key有效。
volatile-ttl : 刪除即將過期的。這個策略,則不計算LRU原則,而是只判斷即將要過期的,如果沒有設置過期時間,則不會刪除。
noeviction : 永不過期,返回錯誤。如果你所有的key都設置的永不過期,那么你有000萬用戶登錄過,你的redis將會很快內存用完。無法寫入的問題。線上杜絕全部都是永不過期。
Lru是什么?就是按照最近最少使用的原則,比如長時間沒有登錄過的用戶,就可以刪除它的key,下次登錄從數據庫讀取出來。因為redis大多在內存操作,因此內存是很寶貴的,一定是給最常用的進行緩存,也就是緩存熱點數據。
看完今天的內容,是不是應該理解一下數據庫管理的抱怨,數據庫被爆滿,內存枯竭,其實很多都是我們程序寫入數據的時候,不配置過期時間,導致實際上存了大量不常用的數據,而內存經常不夠用,或是內存消耗過高。
尊敬的程序員朋友們,今天的小知識mark到了嗎?