天天看點

Redis常用技術

Redis設定過期時間

Redis中有個設定時間過期的功能,即對存儲在Redis中的值可以設定一個過期時間。作為一個緩存資料庫,這是非常實用的。如我們一般在項目中的一些token session或者一些其他的登入資訊,或者短信驗證碼,按照傳統的資料庫處理方式,我們需要自己判斷是否過期,這樣肯定會影響項目的性能。

我們 set key 的時候,都可以給一個 expire time,就是過期時間,通過過期時間我們可以指定這個 key 可以存活的時間。

如果假設你設定了一批 key 隻能存活1個小時,那麼接下來1小時後,redis是怎麼對這批key進行删除的?

定期删除+惰性删除

通過名稱都能想出來删除方式了

  • 定期删除:redis預設是每隔 100ms 就随機抽取一些設定了過期時間的key,檢查其是否過期,如果過期就删除。注意這裡是随機抽取的。為什麼要随機呢?你想一想假如 redis 存了幾十萬個 key ,每隔100ms就周遊所有的設定過期時間的 key 的話,就會給 CPU 帶來很大的負載!
  • 惰性删除 :定期删除可能會導緻很多過期 key 到了時間并沒有被删除掉。是以就有了惰性删除。假如你的過期 key,靠定期删除沒有被删除掉,還停留在記憶體裡,除非你的系統去查一下那個 key,才會被redis給删除掉。這就是所謂的惰性删除,也是夠懶的哈!

但是僅僅通過設定過期時間還是有問題的。我們想一下:如果定期删除漏掉了很多過期 key,然後你也沒及時去查,也就沒走惰性删除,此時會怎麼樣?如果大量過期key堆積在記憶體裡,導緻redis記憶體塊耗盡了。怎麼解決這個問題呢? redis 記憶體淘汰機制。

Redis 記憶體淘汰機制(MySQL裡有1000w資料,Redis中隻存10w的資料,如何保證Redis中的資料都是熱點資料?)

 redis 配置檔案 redis.conf 中有相關注釋,大家可以自行查閱或者通過這個網址檢視: http://download.redis.io/redis-stable/redis.conf

redis 提供 6種資料淘汰政策:

  1. volatile-lru:從已設定過期時間的資料集(server.db[i].expires)中挑選最近最少使用的資料淘汰
  2. volatile-ttl:從已設定過期時間的資料集(server.db[i].expires)中挑選将要過期的資料淘汰
  3. volatile-random:從已設定過期時間的資料集(server.db[i].expires)中任意選擇資料淘汰
  4. allkeys-lru:當記憶體不足以容納新寫入資料時,在鍵空間中,移除最近最少使用的key(這個是最常用的)
  5. allkeys-random:從資料集(server.db[i].dict)中任意選擇資料淘汰
  6. no-eviction:禁止驅逐資料,也就是說當記憶體不足以容納新寫入資料時,新寫入操作會報錯。這個應該沒人使用吧!

4.0版本後增加以下兩種:

  1. volatile-lfu:從已設定過期時間的資料集(server.db[i].expires)中挑選最不經常使用的資料淘汰
  2. allkeys-lfu:當記憶體不足以容納新寫入資料時,在鍵空間中,移除最不經常使用的key

Redis持久化

很多時候我們需要持久化資料也就是将記憶體中的資料寫入到硬碟裡面,大部分原因是為了之後重用資料(比如重新開機機器、機器故障之後回複資料),或者是為了防止系統故障而将資料備份到一個遠端位置。

Redis不同于Memcached的很重一點就是,Redis支援持久化,而且支援兩種不同的持久化操作。Redis的一種持久化方式叫快照(snapshotting,RDB),另一種方式是隻追加檔案(append-only file,AOF).這兩種方法各有千秋,下面我會詳細這兩種持久化方法是什麼,怎麼用,如何選擇适合自己的持久化方法。

快照(snapshotting)持久化(RDB)

Redis可以通過建立快照來獲得存儲在記憶體裡面的資料在某個時間點上的副本。Redis建立快照之後,可以對快照進行備份,可以将快照複制到其他伺服器進而建立具有相同資料的伺服器副本(Redis主從結構,主要用來提高Redis性能),還可以将快照留在原地以便重新開機伺服器的時候使用。

快照持久化是Redis預設采用的持久化方式,在redis.conf配置檔案中預設有此下配置:

save 900 1              #在900秒(15分鐘)之後,如果至少有1個key發生變化,Redis就會自動觸發BGSAVE指令建立快照。

save 300 10            #在300秒(5分鐘)之後,如果至少有10個key發生變化,Redis就會自動觸發BGSAVE指令建立快照。

save 60 10000        #在60秒(1分鐘)之後,如果至少有10000個key發生變化,Redis就會自動觸發BGSAVE指令建立快照。
           

根據配置,快照将被寫入dbfilename選項指定的檔案裡面,并存儲在dir選項指定的路徑上面。如果在新的快照檔案建立完畢之前,Redis、系統或者硬體這三者中的任意一個崩潰了,那麼Redis将丢失最近一次建立快照寫入的所有資料。

舉個例子:假設Redis的上一個快照是2:35開始建立的,并且已經建立成功。下午3:06時,Redis又開始建立新的快照,并且在下午3:08快照建立完畢之前,有35個鍵進行了更新。如果在下午3:06到3:08期間,系統發生了崩潰,導緻Redis無法完成新快照的建立工作,那麼Redis将丢失下午2:35之後寫入的所有資料。另一方面,如果系統恰好在新的快照檔案建立完畢之後崩潰,那麼Redis将丢失35個鍵的更新資料。

建立快照的辦法有如下幾種:

  • BGSAVE指令: 用戶端向Redis發送 BGSAVE指令 來建立一個快照。對于支援BGSAVE指令的平台來說(基本上所有平台支援,除了Windows平台),Redis會調用fork來建立一個子程序,然後子程序負責将快照寫入硬碟,而父程序則繼續處理指令請求。
  • SAVE指令: 用戶端還可以向Redis發送 SAVE指令 來建立一個快照,接到SAVE指令的Redis伺服器在快照建立完畢之前不會再響應任何其他指令。SAVE指令不常用,我們通常隻會在沒有足夠記憶體去執行BGSAVE指令的情況下,又或者即使等待持久化操作執行完畢也無所謂的情況下,才會使用這個指令。
  • save選項: 如果使用者設定了save選項(一般會預設設定),比如 save 60 10000,那麼從Redis最近一次建立快照之後開始算起,當“60秒之内有10000次寫入”這個條件被滿足時,Redis就會自動觸發BGSAVE指令。
  • SHUTDOWN指令: 當Redis通過SHUTDOWN指令接收到關閉伺服器的請求時,或者接收到标準TERM信号時,會執行一個SAVE指令,阻塞所有用戶端,不再執行用戶端發送的任何指令,并在SAVE指令執行完畢之後關閉伺服器。
  • 一個Redis伺服器連接配接到另一個Redis伺服器: 當一個Redis伺服器連接配接到另一個Redis伺服器,并向對方發送SYNC指令來開始一次複制操作的時候,如果主伺服器目前沒有執行BGSAVE操作,或者主伺服器并非剛剛執行完BGSAVE操作,那麼主伺服器就會執行BGSAVE指令

如果系統真的發生崩潰,使用者将丢失最近一次生成快照之後更改的所有資料。是以,快照持久化隻适用于即使丢失一部分資料也不會造成一些大問題的應用程式。不能接受這個缺點的話,可以考慮AOF持久化。

AOF(append-only file)持久化

與快照持久化相比,AOF持久化 的實時性更好,是以已成為主流的持久化方案。預設情況下Redis沒有開啟AOF(append only file)方式的持久化,可以通過appendonly參數開啟:

appendonly yes
           

開啟AOF持久化後每執行一條會更改Redis中的資料的指令,Redis就會将該指令寫入硬碟中的AOF檔案。AOF檔案的儲存位置和RDB檔案的位置相同,都是通過dir參數設定的,預設的檔案名是appendonly.aof。

在Redis的配置檔案中存在三種同步方式,它們分别是:

appendfsync always     #每次有資料修改發生時都會寫入AOF檔案,這樣會嚴重降低Redis的速度
appendfsync everysec  #每秒鐘同步一次,顯示地将多個寫指令同步到硬碟
appendfsync no      #讓作業系統決定何時進行同步
           

appendfsync always 可以實作将資料丢失減到最少,不過這種方式需要對硬碟進行大量的寫入而且每次隻寫入一個指令,十分影響Redis的速度。另外使用固态硬碟的使用者謹慎使用appendfsync always選項,因為這會明顯降低固态硬碟的使用壽命。

為了兼顧資料和寫入性能,使用者可以考慮 appendfsync everysec選項 ,讓Redis每秒同步一次AOF檔案,Redis性能幾乎沒受到任何影響。而且這樣即使出現系統崩潰,使用者最多隻會丢失一秒之内産生的資料。當硬碟忙于執行寫入操作的時候,Redis還會優雅的放慢自己的速度以便适應硬碟的最大寫入速度。

appendfsync no 選項一般不推薦,這種方案會使Redis丢失不定量的資料而且如果使用者的硬碟處理寫入操作的速度不夠的話,那麼當緩沖區被等待寫入的資料填滿時,Redis的寫入操作将被阻塞,這會導緻Redis的請求速度變慢。

雖然AOF持久化非常靈活地提供了多種不同的選項來滿足不同應用程式對資料安全的不同要求,但AOF持久化也有缺陷——AOF檔案的體積太大。

更深入的一些學習可以進入:深入學習Redis:持久化

繼續閱讀