1. 程式人生 > >Redis可以做哪些事?

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不存在,預設鍵為`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 | name | age | | ---- | -------- | ---- | | 1 | Java旅途 | 18 | 將以上資訊存入redis,用表明:id作為key,使用者屬性作為值: ```xml 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 使用者標籤 例如一個使用者對籃球、足球感興趣,另一個使用者對橄欖球、乒乓球感興趣,這些興趣點就是一個標籤。有了這些資料就可以得到喜歡同一個標籤的人,以及使用者的共同感興趣的標籤。給使用者打標籤的時候需要①給使用者打標籤,②給標籤加使用者,需要給這兩個操作增加事務。 - 給使用者打標籤 ```xml sadd user:1:tags tag1 tag2 ``` - 給標籤新增使用者 ```xml sadd tag1:users user:1 sadd tag2:users user:1 ``` 使用交集(sinter)求兩個user的共同標籤 ```xml 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 ```xml zadd user:article 0 a ``` 有人給文章a點贊,遞增`1` ```xml zincrby user:article 1 a ``` 查詢點贊前三篇文章 ```xml zrevrangebyscore user:article 0 2 ``` 查詢點贊後三篇文章 ```xml zrangebyscore user:article 0 2 ``` #### 5.2.2 延遲訊息佇列 下單系統,下單後需要在15分鐘內進行支付,如果15分鐘未支付則自動取消訂單。將下單後的十五分鐘後時間作為score,訂單作為value存入redis,消費者輪詢去消費,如果消費的大於等於這筆記錄的score,則將這筆記錄移除佇列,取消訂單。 ## 總結 在開發中,字串型別是用的最多的資料型別,導致我們忽視了redis的其他四種資料型別,在具體場景下選擇具體的資料型別對提升redis效能有非常大的幫助。redis雖然支援訊息佇列的實現,但是並不支援ack。所以redis實現的訊息佇列不能保證訊息的可靠性,除非自己實現訊息確認機制,不過這非常麻煩,所以如果是重要的訊息還是推薦使用專門的訊息佇列去做。 --- ## 點關注、不迷路 如果覺得文章不錯,歡迎**關注**、**點贊**、**收藏**,你們的支援是我創作的動力,感謝大家。 如果文章寫的有問題,請不要吝惜文筆,歡迎留言指出,我會及時核查修改。 如果你還想更加深入的瞭解我,可以微信搜尋「**Java旅途**」進行關注。回覆「**1024**」即可獲得學習視訊及精美電子書。每天7:30準時推送技術文章,讓你的上班路不在孤獨,而且每月還有送書活動,助你提升硬實力!