新手村:Redis基礎補充知識

1. 前言

新手村的第一篇文章(Redis基礎)是村民的處女做,在以後的學習中回看這篇文章,以爲有一些紕漏之處,甚是慚愧,這也是本篇文章的由來和內容。從此本村民會努力作得更好些,還請你們多多支持多選參數。web

2. Key的命名建議

雖然Redis單個key最多能夠存入512M大小,但這並不意味這咱們就能夠亂存。咱們編寫程序代碼時,對變量的命名每每有所要求,對於Redis中key的命名有如下三條建議:redis

  1. key的命名不要太長,儘可能不要超過1024字節,不然對於內存的消耗和查找的效率而言,無疑是一場噩夢。
  2. key的命名也不要過短,過短的命名每每沒法清晰表達key的含義。
  3. 在一個項目中,使用統一的命名模式去規範key。例如user:1:nickname,user:2:nickname。

3. Redis鍵(key)命令

Redis基礎篇中直接收錄了Redis的五種數據類型及其經常使用的一些命令,而對於Redis中對key的一些經常使用基本命令卻沒有介紹,在此補上,這些命令對全部數據類型的key都適用。數據庫

  1. del key:當key存在時刪除key,返回值爲被刪除key的數量。
    > del mykey1 # 鍵mykey1未設置
    (integer) 0 > set mykey1 "redis" # 設置鍵mykey1 OK > del mykey1 # 刪除鍵mykey1 (integer) 1 複製代碼
  2. exists key:檢查key是否存在,存在返回1,不然返回0。
    > exists mykey1  # 鍵mykey1已經用del命令刪除
    (integer) 0 > set mykey1 "redis" # 從新設置mykey1 OK > exists mykey1 # 在此檢查鍵mykey1是否存在 (integer) 1 複製代碼
  3. expire key seconds:設置key的過時時間,過時後自動刪除,以秒爲單位。設置成功返回1,當key不存在或不能設置時返回0。
    > expire time1 2 # 爲不存在的鍵time1設置過時時間
    (integer) 0 > set time1 "2s" # 設置鍵time1 OK > expire time1 2 (integer) 1 複製代碼
  4. expireat key timestamp:以秒級時間戳設置key的過時時間。
    > set time2 "2020年3月10日20時過時"
    OK >expireat time2 1583841600 (integer) 1 複製代碼
  5. pexpire key milliseconds:設置key的過時時間,以毫秒爲單位。
    > set time3 "3000ms"
    OK > pexire time3 3000 (integer) 1 複製代碼
  6. pexpireat key milliseconds-timestamp:以毫秒級時間戳設置key的過時時間。
    > set time4 "2020年3月10日21時過時"
    OK > pexireat time4 1583845200000 (integer) 1 複製代碼
  • expire、expireat、pexpire和pexpireat命令都是設置成功時返回1,當key不存在或沒法設置時返回0。
  • 時間戳是指格林威治時間1970年01月01日00時00分00秒(北京時間1970年01月01日08時00分00秒)起至如今的總毫秒數。在實際應用中時間戳有秒級和毫秒級,通常咱們經常使用秒級。
  1. ttl key:當key不存在時,返回-2;當key存在但沒有設置過時時間時,返回-1;不然,以秒爲單位返回key的剩餘過時時間。
    > ttl time5  # time5不存在
    (integer) -2 > set time5 "5s" #設置time5但不設置過時時間 OK > ttl time5 (integer) -1 # time5永久保持有效 >expire time5 5 # 設置5秒後過時 (integer) 1 > ttl time5 (integer) 2 > ttl time5 (integer) -2 複製代碼
  2. pttl key:當key不存在時,返回-2;當key存在但沒有設置過時時間時,返回-1;不然,以毫秒秒爲單位返回key的剩餘過時時間。
    > ttl time6  # time6不存在
    (integer) -2 > set time5 "6s" #設置time6但不設置過時時間 OK > ttl time6 (integer) -1 # time6永久保持有效 >expire time6 6 # 設置6秒後過時 (integer) 1 > ttl time6 (integer) 2 > ttl time6 (integer) -2 複製代碼
  3. persist key:移除key的過時時間,使其永久保持有效。移除成功返回1,若key不存在或未設置過時時間時返回0。
    > persist time7
    (integer) 0 > set time7 "7s" OK > expire time7 7 (integer) 1 > ttl time7 (integer) 4 > persist time7 (integer) 1 > ttl time7 (integer) -1 # ttl命令返回值-1表示time7永久有效 複製代碼
  4. keys pattern:查找全部符合給定模式pattern的key
    >mset NPC1 "NO.1" NPC2 "NO.2" NPC3 "NO.3" NPC4 "NO.4"
    OK > keys NPC* 1) "NPC3" 2) "NPC4" 3) "NPC1" 4) "NPC2" 複製代碼
  5. randomkey:隨機返回一個key
    > randomkey
    "NPC2" > randomkey "NPC4" 複製代碼
  6. renamenx key newkey:當newkey不存在時修改key的名稱。修改爲功返回1,當newkey存在時返回0。
    >renamenx NPC1 NPC2
    (integer) 0 >renamenx NPC1 NPC (integer) 1 複製代碼
  7. type key:返回key所存儲的value的類型。none(key不存在)、string、list、hash、set、zset。
    > type NPC
    string > type NPC5 none 複製代碼

4. String類型應用場景

  1. String一般用於保存單個字符串或JSON字符串數據
  2. String類型是二進制安全的,所以能夠把常被調取的圖片文件的內容做爲字符串來存儲
  3. 利用incr、incrby、decr、decrby命令做常規計數,例如記錄點擊數、粉絲數等。

5. Hash類型應用場景

Hash類型經常使用於存儲一個對象,好比存儲用戶的我的信息,存儲用戶的購物車信息等等。緩存

6. 爲何不用String存儲一個對象?

當咱們用String類型的key-value結構存儲一個對象,好比說存儲用戶的id、姓名、年齡、住址等信息時,主要有2種存儲結構:安全

# 第一種
key:id value:序列化的其餘信息 複製代碼

第一種方式將用戶ID做爲key,其餘信息封裝成一個對象並序列化做爲value的方式存儲。這種方式有幾點缺陷:服務器

  • 存取信息時增長了序列化/反序列化的開銷。
  • 若須要修改用戶的一個信息時,要取出一整個對象。
  • 修改操做必須保持原子性,須要對併發狀況進行保護。
# 第二種
key:user:1:name value:姓名值 key:user:1:age value:年齡值 key:user:1:address value:地址值 key:user:2:name value:姓名值 ······ 複製代碼

第二種方式將對應用戶id:屬性名做爲key,屬性值做爲value的方式進行存儲。這種方式雖然解決了第一種方式中序列化/反序列化的問題和併發問題,可是以這種方式存儲,用戶id信息會重複存儲,且一個用戶的信息就使用了好幾個key-value對,當用戶數量較大時,佔用大量內存空間,形成內存浪費。 Hash是最接近關係數據庫結構的數據類型,能夠將數據庫的一條記錄或程序中的一個對象轉換成HashMap存放在Redis中。使用Hash類型存儲一個對象不只節省空間,對信息進行操做也有相應的命令,比較安全。數據結構

7. List類型應用場景

List類型很適合實現多種數據結構,好比棧、隊列等等。使用rpush和rpop命令可實現棧,使用rpush和lpop可實現隊列。併發

8. Set類型應用場景

Set類型經常使用於對兩個集合之間的數據求交集、並集、差集。好比說咱們能夠求出兩個用戶的共同好友、共同喜歡的歌曲,求當日首次登錄的新用戶等等。dom

9. Zset類型應用場景

因爲Zset類型相對於Set類型多存儲了分數以進行排序,所以Zset類型經常使用於各類排行榜。好比說班級中考試成績的排行,熱搜榜的排行等等。除此以外,咱們還能夠利用分數作權重,造成可變優先級的隊列,將重要的操做權重增長,這樣就能夠保證先執行這些操做。編輯器

10. Redis的內存維護策略

Redis把數據存在內存中以保證較高的存取性能,然而相比於磁盤空間大小,內存的容量是至關有限的。若是Redis一直存入,不對數據進行淘汰,必然會佔用大量內存空間,最終將致使內存溢出並影響CPU的執行效率,形成服務器宕機等嚴重後果。所以,Redis做爲優秀的中間緩存件,即便採起了集羣部署來動態擴容,也應該即時整理內存,維持較高的系統性能。在Redis中有兩種解決方案: 一爲數據設置超時時間:Redis中提供了幾個設置數據過時時間的命令

expire key seconds  # 以秒爲單位,是最經常使用的方式
setex key seconds value # 在設置key-value對的同時設置過時時間,string類型專用 複製代碼
  • 只有string類型有專用命令,其餘數據類型都要依靠key基本命令expire等設置過時時間
  • 若是沒有設置過時時間,那麼key永久保持有效
  • 若是設置了過時時間以後想讓key再次永久保持有效,使用persist key命令

二爲使用Redis提供的淘汰策略:在生產環境中,咱們使用配置參數maxmemory來限制內存的大小,使用配置參數maxmemory-policy來選擇淘汰策略。在默認狀況下,maxmemory爲0,表示內存使用不受限制,而maxmemorey-policy爲noeviction。

  1. volatile-lru:設定過時時間的數據中,刪除最不經常使用的數據。
  2. allkeys-lru:優先刪除最近沒有被使用的key,應用最爲普遍
  3. volatile-random:在設定了過時時間的數據中隨機刪除。
  4. allkeys-random:在全部數據中隨機刪除某個key。
  5. volatile-ttl:查詢所有設定了過時時間的數據,並進行排序,刪除立刻將要過時的數據。
  6. noeviction:對內存沒有限制,只有當內存使用達到閾值時,新申請內存的命令會報錯。

上述是Redis的6種淘汰策略,可是咱們該如何選擇哪種策略來提升性能呢?答案是因地制宜,咱們必須根據自身系統特徵來選擇合適的策略。

  • 根據數據訪問頻率:若是有一部分數據的訪問頻率較高,其他部分廣泛較低,或者咱們也不知道數據的訪問頻率時,可使用allkeys-lru;若是數據的訪問頻率都基本差很少時,咱們能夠選擇allkeys-random。
  • 若是咱們須要設置過時時間來判斷數據過時的前後順序,讓Redis知曉應該先淘汰哪些數據時,可使用volatile-ttl。
  • 當咱們但願一些數據能夠被長期保存,用於持久化,而一些數據只用於緩存,使用後能被淘汰掉時,咱們能夠選用volatile-lru或者volatile-random。
  • 在咱們爲數據設置過時時間時會消耗額外的內存,若是須要減小這一部分的浪費,那麼能夠選用allkeys-lru策略,這樣就能夠更加高效的利用內存了。

最後吟唱

本文使用 mdnice 排版

相關文章
相關標籤/搜索