天天看點

Redis特性、應用場景和常見的資料結構

Redis簡介

redis是用C語言開發的一個基于記憶體的、高性能key-value鍵值對的、開源nosql資料庫。目前,redis的key是字元串類型的,但value支援多種資料類型:字元串(string)、哈希(hash)、清單(list)、集合(set)、有序集合(sortedset),通過提供多種鍵值資料類型來适應不同場景下的存儲需求。

Redis應用場景

介紹幾種常見的應用:

  1. 建構隊列系統

    可以用list可以建構隊列系統,使用sorted set甚至可以建構有優先級的隊列系統

  2. pub、sub釋出訂閱建構實時消息系統、消息隊列
  3. 計數器應用

    redis的指令如INCR,DECR都是原子性的,可以通過這些指令來建構計數器系統

  4. 分布式叢集架構中session共享

Redis特性

  1. 基于記憶體存儲,資料通路速度快,性能好

    根據官方提供的測試資料:50個并發執行100000個請求,讀的速度是110000次/s,寫的速度是81000次/s【資料僅供參考,根據伺服器配置會有不同結果】

  2. 資料持久化機制

    目前支援APF和RDB兩種持久化機制,下文會詳細闡述

  3. 支援叢集模式,容量可以線性擴充

    注意:Redis3.X開始才支援叢集模式

  4. 支援豐富的資料結構

    這一點是相比其他緩存工具如memcache比較鮮明的優勢

Redis資料結構

首先強調一點,redis的key是字元串類型,但value支援多種資料類型。關于key的定義,有幾點建議:

1.key不要太長,太長不僅消耗記憶體還會降低查找效率。建議不要超過1024個位元組
2.key不要太短,要具有可讀性
3.在實際項目中,key最好有一個統一的命名規範
下面詳細介紹一下redis的value目前支援的資料類型:
           

string類型

字元串是redis支援的最基礎的資料類型,它在redis中是二進制安全的,應用最多。

操作redis的string類型資料常用指令:

set(設定)、get(擷取)、getset(擷取并設定)、del(删除)

Redis特性、應用場景和常見的資料結構
Redis特性、應用場景和常見的資料結構

一次性插入或者擷取多條資料:

MGET key1 key2
MSET key1 value1 key2 value2 ……
           

在插入一條string類型資料的同時為它指定一個存活期限:

setex username 10 張三
           

對string類型資料進行增減操作的幾個指令:

incr:将指定的key的value原子性的遞增1。如果該key不存在,其初始值為0,在incr之後其值為1

decr:将指定的key的value原子性的遞減1。如果該key不存在,其初始值為0,在decr之後其值為-1

incrby key increment:将指定的key的value原子性增加increment。如果該key不存在,其初始值為0,在incrby之後,該值為increment

decrby key decrement:将指定的key的value原子性減少decrement,如果該key不存在,其初始值為0,在decrby之後,該值為decrement。

append key value:拼湊字元串。如果該key存在,則在原有的value後追加該值;如果該key不存在,則重新建立一個key/value。

注意:
decr incr decrby incrby 都是原子性操作。進行增減前提是:key可以轉換為整型否則報錯。相信做過SparkStreaming流式計算統計pv、uv中,中間狀态存儲會熟悉該特性的應用。
           

list類型

筆者強調一點:redis中list底層是雙端連結清單結構,這個在面試中經常會問。redis為什麼這麼快,其實不僅僅是因為基于記憶體存儲,底層還多了很多的優化,這隻是其中之一,下圖是對雙端連結清單的一個圖形描述:

Redis特性、應用場景和常見的資料結構

常用的操作指令:

lpush:從頭部(左邊)插入資料
rpush:從尾部(右邊)插入資料
lrange key start end:讀取list中指定範圍的values。start、end從0開始計數;也可為負數,若為-1則表示連結清單尾部的元素,-2則表示倒數第二個,依次類推…
lpop:從頭部彈出一個元素
rpop:從尾部彈出一個元素
rpoplpush:從一個list的尾部彈出一個元素插入到另一個list。原子性操作,沒有key2會建立key2,一旦key1的list元素被取完,key1會被清除
llen key:傳回指定的key關聯的連結清單中的元素的數量
           
list資料類型應用案例:消息隊列

比如有這樣一個需求:實作一個任務排程系統==>生産者不斷産生任務,放入task-queue排隊,消費者不斷拿出任務來處理,同時放入一個tmp-queue暫存,如果任務處理成功,則清除tmp-queue;否則,将任務彈回task-queue。

筆者這裡提供一個實作思路,就不貼代碼了,其實就是上述API的簡單應用:

  1. 生産者将生産的任務lpush進task-queue中
  2. 消費者通過rpoplpush将taks-queue中取任務并暫存任務到tmp-queue中
  3. 如果任務處理成功,tmp-queue通過rpop清除相應任務;任務處理失敗,則rpoplpush将任務從tmp-queue中清除并存入task-queue中
  4. 為了避免消費者程式在處理任務失敗之後沒有及時将rpoplpush失敗的任務時就已經挂掉,可以加入一個管理tmp-queque的角色,以便在這種情況時也能将處理失敗的任務lpush進task-queue中。

hash類型

redis中的hash類型可以看成具有map容器,适合存儲值對象的資訊。如username、password等。

常用指令:

hset key field value:為指定的key設定field/value對(鍵值對)

hmset key field value [field2 value2 …]:設定key中的多個filed/value

hincrby key field increment:設定key中filed的值增加increment

hexists key field:判斷指定的key中的filed是否存在
           

set類型

無序、無重複元素。和list類型相比,set類型在功能上還存在着一個非常重要的特性,即在伺服器端完成多個set之間的聚合計算操作,如并集、交集、差集的計算。由于這些操作均在服務端完成,是以效率極高,而且也節省了大量的網絡IO開銷。

常用指令:

添加: sadd key values[value1、value2…] [多個value間空格分隔]

删除:srem key members[member1、member2…] 删除set中指定的成員(成員可以是多個)[]

查詢:smembers key 檢視指定key的set中的資料

判斷:sismember key value [判斷參數中指定的成員是否在該set中,1表示存在,0表示不存在或者該key本身就不存在。(無論集合中有多少元素都可以極速的傳回結果)]

統計set元素個數:scard key [指定key對應的set的元素數]

srandmember key:随機傳回set中的一個成員

sdiff、sunion、sinter:差集、并集、交集
           

sortedset類型

sortedset中的每一個元素都會有一個分數與之關聯,redis正是通過分數來為集合中的元素進行排序,預設正序。注意:sortedset中的資料不能重複,但分數卻可以重複。

常用指令:

zadd key score member score2 member2 … :将所有成員以及該成員的分數存放到sorted-set中。如果該元素已經存在則會用新的分數替換原有的分數。傳回值是新加入到集合中的元素個數,不包含之前已經存在的元素。(score可以重複,member不可以重複)

zscore key member:傳回指定成員的分數

zcard key:擷取集合中的成員數量

zrem key member[member…]:移除集合中指定的成員,可以指定多個成員

zrange key start end [withscores]:擷取集合中腳标為start-end的成員,[withscores]參數表明傳回的成員包含其分數。(withscores可選參數)

zrevrange key start stop [withscores]:按照元素分數從大到小的順序傳回索引從start到stop之間的所有元素(包含兩端的元素)