天天看點

Redis可以做哪些事?

Redis是一種基于鍵值對的NoSQL資料庫,它的值主要由string(字元串),hash(哈希),list(清單),set(集合),zset(有序集合)五種基本資料結構構成,除此之外還支援一些其他的資料結構和算法。key都是由字元串構成的,那麼這五種資料結構的使用場景有哪些?一起來看看!

一 字元串

字元串類型是Redis最基礎的資料結構,字元串類型可以是

JSON

XML

甚至是二進制的圖檔等資料,但是最大值不能超過512MB。

1.1 内部編碼

Redis會根據目前值的類型和長度決定使用哪種内部編碼來實作。

字元串類型的内部編碼有3種:

  1. int:8個位元組的長整型。
  2. embstr:小于等于39個位元組的字元串。
  3. raw:大于39個位元組的字元串。

1.2 使用場景

1.2.1 緩存

在web服務中,使用MySQL作為資料庫,Redis作為緩存。由于Redis具有支撐高并發的特性,通常能起到加速讀寫和降低後端壓力的作用。web端的大多數請求都是從Redis中擷取的資料,如果Redis中沒有需要的資料,則會從MySQL中去擷取,并将擷取到的資料寫入redis。

1.2.2 計數

Redis中有一個字元串相關的指令

incr key

incr

指令對值做自增操作,傳回結果分為以下三種情況:

  • 值不是整數,傳回錯誤
  • 值是整數,傳回自增後的結果
  • key不存在,預設鍵為 ,傳回

    1

比如文章的閱讀量,視訊的播放量等等都會使用redis來計數,每播放一次,對應的播放量就會加1,同時将這些資料異步存儲到資料庫中達到持久化的目的。

1.2.3 共享Session

在分布式系統中,使用者的每次請求會通路到不同的伺服器,這就會導緻session不同步的問題,假如一個用來擷取使用者資訊的請求落在A伺服器上,擷取到使用者資訊後存入session。下一個請求落在B伺服器上,想要從session中擷取使用者資訊就不能正常擷取了,因為使用者資訊的session在伺服器A上,為了解決這個問題,使用redis集中管理這些session,将session存入redis,使用的時候直接從redis中擷取就可以了。

1.2.4 限速

為了安全考慮,有些網站會對IP進行限制,限制同一IP在一定時間内通路次數不能超過n次。

二 哈希

Redis中,哈希類型是指一個鍵值對的存儲結構。

2.1 内部編碼

哈希類型的内部編碼有兩種:

  • ziplist(壓縮清單):當哈希類型元素個數小于

    hash-max-ziplist-entries

    配置(預設512個)同時所有值都小于

    hash-max-ziplist-value

    配置(預設64位元組)時使用。ziplist使用更加緊湊的結構實作多個元素的連續存儲,是以比hashtable更加節省記憶體。
  • hashtable(哈希表):當ziplist不能滿足要求時,會使用hashtable。

2.2 使用場景

由于hash類型存儲的是一個鍵值對,比如資料庫有以下一個使用者表結構

id name age
1 Java旅途 18

将以上資訊存入redis,用表明:id作為key,使用者屬性作為值:

hset user:1 name Java旅途 age 18           

使用哈希存儲會比字元串更加友善直覺

三 清單

清單類型用來存儲多個有序的字元串,一個清單最多可以存儲

2^32-1

個元素,清單的兩端都可以插入和彈出元素。

3.1 内部編碼

清單的内部編碼有兩種:

  • list-max-ziplist-entries

    list-max-ziplist-value

  • linkedlist(連結清單):當ziplist不能滿足要求時,會使用linkedlist。

3.2 使用場景

3.2.1 消息隊列

清單用來存儲多個有序的字元串,既然是有序的,那麼就滿足消息隊列的特點。使用

lpush

+

rpop

或者

rpush

lpop

實作消息隊列。除此之外,redis支援阻塞操作,在彈出元素的時候使用阻塞指令來實作阻塞隊列。

3.2.2 棧

由于清單存儲的是有序字元串,滿足隊列的特點,也就能滿足棧先進後出的特點,使用

lpush

lpop

rpush

rpop

實作棧。

3.2.3 文章清單

因為清單的元素不但是有序的,而且還支援按照索引範圍擷取元素。是以我們可以使用指令

lrange key 0 9

分頁擷取文章清單

四 集合

集合類型也可以儲存多個字元串元素,與清單不同的是,集合中不允許有重複元素并且集合中的元素是無序的。一個集合最多可以存儲

2^32-1

個元素。

4.1 内部編碼

集合類型的内部編碼有兩種:

  • intset(整數集合):當集合中的元素都是整數且元素個數小于

    set-max-intset-entries

    配置(預設512個)時,redis會選用intset來作為集合的内部實作,進而減少記憶體的使用。
  • hashtable(哈希表):當intset不能滿足要求時,會使用hashtable。

4.2 使用場景

4.2.1 使用者标簽

例如一個使用者對籃球、足球感興趣,另一個使用者對橄榄球、乒乓球感興趣,這些興趣點就是一個标簽。有了這些資料就可以得到喜歡同一個标簽的人,以及使用者的共同感興趣的标簽。給使用者打标簽的時候需要①給使用者打标簽,②給标簽加使用者,需要給這兩個操作增加事務。

  • 給使用者打标簽
sadd user:1:tags tag1 tag2           
  • 給标簽添加使用者
sadd tag1:users user:1

sadd tag2:users user:1           

使用交集(sinter)求兩個user的共同标簽

sinter user:1:tags user:2:tags           

4.2.2 抽獎功能

集合有兩個指令支援擷取随機數,分别是:

  • 随機擷取count個元素,集合元素個數不變

srandmember key [count]

  • 随機彈出count個元素,元素從集合彈出,集合元素個數改變

spop key [count]

使用者點選抽獎按鈕,參數抽獎,将使用者編号放入集合,然後抽獎,分别抽一等獎、二等獎,如果已經抽中一等獎的使用者不能參數抽二等獎則使用

spop

,反之使用

srandmember

五 有序集合

有序集合和集合一樣,不能有重複元素。但是可以排序,它給每個元素設定一個score作為排序的依據。最多可以存儲

2^32-1

5.1 内部編碼

有序集合類型的内部編碼有兩種:

  • ziplist(壓縮清單):當有序集合的元素個數小于

    list-max-ziplist-entries

    配置(預設128個)同時所有值都小于

    list-max-ziplist-value

    配置(預設64位元組)時使用。ziplist使用更加緊湊的結構實作多個元素的連續存儲,更加節省記憶體。
  • skiplist(跳躍表):當不滿足ziplist的要求時,會使用skiplist。

5.2 使用場景

5.2.1 排行榜

使用者釋出了n篇文章,其他人看到文章後給喜歡的文章點贊,使用score來記錄點贊數,有序集合會根據score排行。流程如下

使用者釋出一篇文章,初始點贊數為0,即score為0

zadd user:article 0 a           

有人給文章a點贊,遞增

1

zincrby user:article 1 a           

查詢點贊前三篇文章

zrevrange user:article 0 2           

查詢點贊後三篇文章

zrange user:article 0 2           

5.2.2 延遲消息隊列

下單系統,下單後需要在15分鐘内進行支付,如果15分鐘未支付則自動取消訂單。将下單後的十五分鐘後時間作為score,訂單作為value存入redis,消費者輪詢去消費,如果消費的大于等于這筆記錄的score,則将這筆記錄移除隊列,取消訂單。

總結

在開發中,字元串類型是用的最多的資料類型,導緻我們忽視了redis的其他四種資料類型,在具體場景下選擇具體的資料類型對提升redis性能有非常大的幫助。redis雖然支援消息隊列的實作,但是并不支援ack。是以redis實作的消息隊列不能保證消息的可靠性,除非自己實作消息确認機制,不過這非常麻煩,是以如果是重要的消息還是推薦使用專門的消息隊列去做。