1. 程式人生 > >redis資料結構、持久化、快取淘汰策略

redis資料結構、持久化、快取淘汰策略

Redis 單執行緒高效能,它所有的資料都在記憶體中,所有的運算都是記憶體級別的運算,而且單執行緒避免了多執行緒的切換效能損耗問題。redis利用epoll來實現IO多路複用,將連線資訊和事件放到佇列中,依次放到檔案事件分派器,事件分派器將事件分發給事件處理器。

 

1.Redis資料結構及簡單操作指令

String、list、set、hash、zset(有序set)

總體來說redis都是通過Key-Value的形式來儲存資料的。只是不用資料型別Value的形式不同。

 

String:最簡單資料結構,比如我們將一個物件轉成json串來儲存

  set key value 存放資料

  get key 獲取資料

  exists key 檢視資料是否存在,存在返回1否則0

  del key 刪除資料 返回操作成功的條數

 

  mset key1 value1 key2 value2 key3 value3...存放多組資料

  mget key1 ke2y key3... 獲取多個key的資料,返回一個集合,類似Map的values方法

 

  expire key second 設定key 過去時間,單位秒

  setex key second value設定key 過去時間,單位秒(等價於先set,再expire)

  setnx key value 如果key不存在就set 返回1.如果存在返回0(可以基於此實現分散式鎖)

 

List:並不是java裡面的list,redis的list更像一個連結串列或者說佇列/棧的結構。這就意味著它的刪除插入快,但是通過索引定位就比較慢了。當列表彈出了最後一個元素之後,該資料結構自動被刪除,記憶體被回收。

Redis 的列表結構常用來做非同步佇列使用。將需要延後處理的任務塞進 Redis 的列表,另一個執行緒從這個列表中輪詢資料進行處理。

 

  rpush key value1 value2 value3...  插入list資料

  llen key     檢視長度

  lpop key    按加入順序獲取(先進先出,類似佇列)

  rpop key   後進先出,有點類似棧

  列表取資料,取完後整個列表都被回收了,就是說只能取一次資料。

 

Hash:類似java的hashMap,和字串相比,我們儲存資料的時候可以只儲存物件的部分屬性,而字串則需要完整將整個物件轉換。當然hash儲存結構的消耗肯定是高於字串的

  hset redisKey hashKey1 value1

    hset redisKey hashKey2 value2  插入資料

  hgetall redisKey  獲取資料,key value間隔出現

  hlen redisKey  檢視hash長度

  hget redisKey hashKey 獲取hashKey 對應的value

  hmset redisKey hashKey1 value1 hashKey2 value2 hashKey2 value3 批量插入值

 

Set : 類似HashSet,但是list類似,最後一個數據取完之後,該結構會被清理,無法再次獲取資料

  sadd key value         

  sadd key value1 value2   批量新增

  smembers key    檢視所有

  sismember key value  查詢某個值是否存在,存在返回1

  scard  key   檢視大小

  spop key    獲取一個元素

 

原子計數操作

如果value是整數的話還可以實現自增操作(也可以用於實現分散式鎖,該增長有限,最大到long max,超過該值會直接報錯)

incr key 自增 如果key不存在預設從0自增1

incrby key step 設定增加步長step

 

2.redis持久化

雖然說redis都是記憶體級別的操作,其實也是有持久化的。

一種是基於RDB快照,

Redis 將記憶體資料庫快照儲存在名字為 dump.rdb 的二進位制檔案中。

 

 

 

可以對 Redis 進行設定, 讓它在N 秒內資料集至少有 M 個改動這一條件被滿足時, 自動儲存一次資料集。

 

 

 

另一種是AOF(append-only file)

快照並不可靠,上次快照之後,還未到達下一次快照條件時,這時候服務出現了問題,那麼這期間的資料是無法儲存到快照版本中的。這個時候就需要AOF了,它將每一條指令都記錄進檔案,當redis重啟的時候,重新執行這個檔案裡面指令,就可以恢復所有的資料到記憶體中了。

可以通過配置appendonly yes 來開啟AOF,預設是關閉的

 

 

AOF也有三種同步資料的策略,

每次有操作都去重新整理檔案,很慢,但安全

每秒同步重新整理一次:可能會丟失一秒內的資料

從不同步同步重新整理:讓作業系統在需要的時候重新整理資料,不安全

預設的是每秒刷一次

 

 

 

混合持久化:

RDB快照資料恢復速度快,但是可能會有大量資料丟失,所以通常恢復資料還是用的AOF日誌重放,但是AOF相對來說速度會很慢,尤其是在資料量大的時候。因此在4.0的時候帶來了混合持久化,也就是AOF在重新整理的時候,先記錄上次的快照版本,然後記錄上次快照版本到現在的增量操作,然後合併成一個檔案,覆蓋原來的appendonly.aof檔案。Redis重啟的時候,先載入RDB快照的內容,在重放AOF日誌中增量操作的內容就可以了。

開啟混合持久化:aof-use-rdb-preamble yes

混合持久化中appendonly.aof內容格式,一部分是RDB檔案內容格式,另外的才是AOF檔案的內容格式。

 

3.快取淘汰策略:

當 Redis 記憶體超出實體記憶體限制時,記憶體的資料會開始和磁碟產生頻繁的交換 。會讓 Redis 的效能急劇下降,對於訪問量比較頻繁的 Redis 來說,這樣存取效率基本上等於不可用。

在生產環境中我們是不允許 Redis 出現交換行為的,為了限制最大使用記憶體,Redis 提供了配置引數 maxmemory 來限制記憶體超出期望大小。

當實際記憶體超出 maxmemory 時,Redis 提供了幾種可選策略 (maxmemory-policy) 來讓使用者自己決定該如何騰出新的空間以繼續提供讀寫服務。

 

 maxmemory <bytes>

# MAXMEMORY POLICY: how Redis will select what to remove when maxmemory
# is reached. You can select among five behaviors:
#
# volatile-lru -> Evict using approximated LRU among the keys with an expire set.
# allkeys-lru -> Evict any key using approximated LRU.
# volatile-lfu -> Evict using approximated LFU among the keys with an expire set.
# allkeys-lfu -> Evict any key using approximated LFU.
# volatile-random -> Remove a random key among the ones with an expire set.
# allkeys-random -> Remove a random key, any key.
# volatile-ttl -> Remove the key with the nearest expire time (minor TTL)
# noeviction -> Don't evict anything, just return an error on write operations.
#
# LRU means Least Recently Used
# LFU means Least Frequently Used
#
# Both LRU, LFU and volatile-ttl are implemented using approximated
# randomized algorithms.
#
# Note: with any of the above policies, Redis will return an error on write
#       operations, when there are no suitable keys for eviction.
#
#       At the date of writing these commands are: set setnx setex append
#       incr decr rpush lpush rpushx lpushx linsert lset rpoplpush sadd
#       sinter sinterstore sunion sunionstore sdiff sdiffstore zadd zincrby
#       zunionstore zinterstore hset hsetnx hmset hincrby incrby decrby
#       getset mset msetnx exec sort
#
# The default is:
#
# maxmemory-policy noeviction

noeviction 不會繼續處理寫請求 (del,read請求可以繼續進行)。這樣可以保證不會丟失資料,但是會讓線上的寫相關的業務不能持續進行。這是預設的淘汰策略。

volatile-lru 嘗試淘汰設定了過期時間的 key,最少使用的 key 優先被淘汰。沒有設定過期時間的 key 不會被淘汰,這樣可以保證需要持久化的資料不會突然丟失。

volatile-ttl 跟上面一樣,除了淘汰的策略不是 LRU,而是 key 的剩餘壽命 ttl 的值,ttl 越小越優先被淘汰。

volatile-random 跟上面一樣,不過淘汰的 key 是過期 key 集合中隨機的 key。

allkeys-lru 區別於 volatile-lru,這個策略要淘汰的 key 物件是全體的 key 集合,而不只是過期的 key 集合。這意味著沒有設定過期時間的 key 也會被淘汰。

allkeys-random 跟上面一樣,不過淘汰的策略是隨機的 key。

volatile-xxx 策略只會針對帶過期時間的 key 進行淘汰,allkeys-xxx 策略會對所有的 key 進行淘汰。如果你只是拿 Redis 做快取,那應該使用 allkeys-xxx,客戶端寫快取時不必攜帶過期時間。如果你還想同時使用 Redis 的持久化功能,那就使用 volatile-xxx 策略,這樣可以保留沒有設定過期時間的 key,它們是永久的 key 不會被 LRU 演算法淘汰。

&n