Categories
程式開發

Redis可以做哪些事?


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

一字符串

字符串類型是Redis最基礎的數據結構,字符串類型可以是JSON、XML甚至是二進制的圖片等數據,但是最大值不能超過512MB。

1.1 內部編碼

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

字符串類型的內部編碼有3種:

int:8個字節的長整型。 embstr:小於等於39個字節的字符串。 raw:大於39個字節的字符串。

1.2 使用場景

1.2.1 緩存

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

1.2.2 計數

Redis中有一個字符串相關的命令incr key,incr命令對值做自增操作,返回結果分為以下三種情況:

值不是整數,返回錯誤值是整數,返回自增後的結果key不存在,默認鍵為0,返回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 | 名稱| 年齡|

| —- | ——– | —- |

| 1 | Java旅途| 18 |

將以上信息存入redis,用表明:id作為key,用戶屬性作為值:

hset user:1 name Java旅途 age 18

使用哈希存儲會比字符串更加方便直觀

三列表

列表類型用來存儲多個有序的字符串,一個列表最多可以存儲2^32-1個元素,列表的兩端都可以插入和彈出元素。

3.1 內部編碼

列表的內部編碼有兩種:

ziplist(壓縮列表):當哈希類型元素個數小於list-max-ziplist-entries配置(默認512個)同時所有值都小於list-max-ziplist-value配置(默認64字節)時使用。 ziplist使用更加緊湊的結構實現多個元素的連續存儲,所以比hashtable更加節省內存。 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個元素,集合元素個數不變

會員鑰匙 [count]

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

spop鍵 [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

查詢點贊前三篇文章

zrevrangebyscore user:article 0 2

查詢點贊後三篇文章

zrangebyscore user:article 0 2

5.2.2 延遲消息隊列

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

總結

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

點關注、不迷路

如果覺得文章不錯,歡迎關注、*點贊*、收藏,你們的支持是我創作的動力,感謝大家。

如果文章寫的有問題,請不要吝惜文筆,歡迎留言指出,我會及時核查修改。

如果你還想更加深入的了解我,可以微信搜索「Java旅途」進行關注。回复「1024」即可獲得學習視頻及精美電子書。每天7:30準時推送技術文章,讓你的上班路不在孤獨,而且每月還有送書活動,助你提升硬實力!