redis各數據類型應用概述

前言

  1. redis是一個開源的使用ANSI C語言編寫、支持網絡、可基於內存、亦可持久化的日誌型、key-value數據庫,並提供多種語言的API。
  2. 它是內存存儲的數據結構服務器,可用作數據庫、高速緩存和消息隊列代理。
  3. 通過數據全部in-momery的方式保證高速訪問,同時提供數據落地的功能,這是redis最主要的適用場景。
  4. reids內置複製、Lua腳本、LRU收回、事物以及不同級別磁盤持久化功能,同時通過redis Sentinel提供高可用,通過Redis Cluster提供自動分區。
  5. redis支持字符串、哈希表、列表、集合、有序集合、位圖、hyperloglogs等數據類型。
  6. redis最爲常用的數據類型:stirng、hash、list、set、sorted set、pub/sub、transactions。

String類型

  1. string類型就是簡單的key-value類型,value不僅僅是string,也可以是數字。
  2. 常用命令:set、get、decr、incr、mget等。
  3. 除了提供與memcached一樣的get、set、incr、decr 等操作外,redis還提供了下面的一些操作:

    (1)獲取字符串長度;
    (2)往字符串append內容;
    (3)設置和獲取字符串的某一段內容;
    (4)設置及獲取字符串的某一位(bit);
    (5)批量設置一系列字符串的內容;

Hash類型

  1. hash特別適合用於存儲對象。
  2. 常用命令:hget、hset、hgetall等。
  3. 應用場景:存儲一些結構化的數據,比如用戶的暱稱、年齡、性別、積分等,存儲一個用戶信息對象數據。
  4. 我們舉個簡單的實例來描述下Hash的應用場景,比如我們存儲一個用戶信息對象數據,包含以下信息:

    (1)用戶id爲查找的key;
    (2)存儲的value包括姓名、年齡、生日等信息
  5. 實例解析:

    (1)key是用戶id,value是一個Map。
    (2)這個Map的key是成員的屬性名,value是屬性值;
    (3)這樣對數據的修改和存取都可以直接通過其內部的Map的key(redis裏稱內部Map的key爲field),也就是key(用戶名id)+field(屬性名)就可以操作對應屬性數據了。
  6. 注意:

    (1)redis提供了接口(hgetall)可以直接取到全部的屬性數據,但是如果內部Map的成員很多,那麼涉及到遍歷整個Map的操作。
    (2)由於redis單線程模型的緣故,這個遍歷操作可能會比較耗時,而令其他客戶端的請求完全響應不到,這點需要注意。

List類型

  1. list類型實質是一個每個元素都是string類型的雙向鏈表,這使得list既可以用作棧,也可以用作隊列。
  2. list類型經常會被用於消息隊列的服務,以完成多程序之間的消息交換。
  3. 常用命令:lpush、rpush、lpop、rpop、lrange等。
  4. 應用場景:實現最新消息排行等功能,還有消息隊列。
  5. 簡單消息隊列舉例分析:

    (1)假設一個應用程序執行lpush向鏈表中添加新的元素,我們通常將這樣的程序稱之爲“生產者(producer)”;
    (2)而另外一個應用程序正在執行rpop操作從鏈表中取出元素,我們稱這樣的程序爲“消費者(consumer)”;
    (3)在消費者消費消息的過程中,需要不停調用rpop查看list中是否有待處理消息。每調用一次都會發起一次鏈接,造成不必要的浪費。
    (4)另外,如果生產者速度大於消費者速度,消息隊列長度會一直增大,時間久了會佔用大量內存空間;
    (5)所以,可以使用brpop命令,這個命令只有在有元素時返回,沒有則會阻塞直到超時返回null。

Set類型

  1. set類型是string類型的無序集合。
  2. set集合的概念就是一堆不重複值的組合。
  3. set元素最大可以包含(2的32次方-1)個元素。
  4. set內部實現是一個value永遠爲null的HashMap。
  5. set對外提供的功能與list類似是一個列表的功能,特殊之處在於set時可以自動排重的。
  6. 常用命令:sadd、spop、smembers、sunion等。
  7. 當你需要存儲一個列表數據,又不希望出現重複數據時,set是一個很好的選擇。
  8. 並且set提供了判斷某個成員是否在一個set集合內的重要接口,這個是list不能提供的。
  9. 利用set數據結構,可以存儲一些集合性的數據,比如在微博應用中,可以將一個用戶所有的關注人存在一個集合中,將其所有粉絲存在一個集合。
  10. redis還爲集合提供了求交集、並集、差集等操作,可以非常方便的實現如共同關注、共同喜好、二度好友等功能。

Zset類型

  1. 和set一樣,sorted set也是stirng類型元素的集合。不同的是每個元素都會關聯一個double類型的score,元素順序由score決定。
  2. sorted set是插入有序的,即自動排序。
  3. 常用命令:zadd、zrange、zrem、zcard等。
  4. 當你需要一個有序的並且不重複的集合列表時,那麼可以選擇sorted set數據結構。
  5. 應用舉例:

    (1)例如存儲全班同學的成績,其集合value可以是同學的學號,而score就可以是成績。
    (2)排行榜應用,根據得分列出topN的用戶等。

pub/sub

  1. subscribe、unsubscribe和publish三個命令實現了發佈與訂閱泛型。
  2. 發送者(發送信息的客戶端)不是直接將信息發給特定的接收者(接受信息的客戶端),而是將信息發給頻道(channel),然後由頻道將信息轉發給所有對這個頻道感興趣的訂閱者。
  3. 發送者無需知道任何關於訂閱者的信息,而訂閱者也無需知道是哪個客戶端給它發送信息,它只要關注自己感興趣的頻道即可。
  4. 發佈/訂閱在redis中,被設計的非常輕量級和簡潔,它做到了消息的發佈和訂閱的基本能力;但是尚未提供關於消息持久化等各種企業級的特性。
  5. 一個redis client發佈消息,其他多個redis client訂閱消息,發佈的消息即發即失,redis不會持久保存發佈的消息;消息訂閱者也只能得到訂閱後的消息,通道中此前的消息無從獲得。
  6. 消息發佈者,即publish客戶端,無需獨佔鏈接,你可以在publish消息的同時,使用同一個redis-client鏈接進行其他操作(如incr等);
  7. 消息訂閱者,即subscribe客戶端,需要獨佔鏈接,即進行subscribe期間,redis-client無法穿插其他操作。
  8. 此時client以阻塞的方式等待publish端的消息,因此subscribe需要使用單獨的鏈接,甚至需要在額外的線程中使用。
  9. tcp默認連接時間固定,如果在這世間內sub端沒有接收到pub端消息,或pub端沒有消息產生,sub端的連接都會強制回收。
  10. 這就需要特殊手段解決,用定時器來模擬pub和sub之間的保活機制,定時器時間不能超過tcp最大連接時間。
  11. 一旦subscribe端斷開鏈接,將會失去部分消息,即鏈接失效期間的消息將會被丟失,所以,這裏需要考慮redis的list來持久化;
  12. 如果你非常關注每個消息,那麼你應該基於redis做一些額外的補充工作,如果你希望訂閱是持久的,那麼如下設計思路可以借鑑:

    (1)subscribe端:首先向一個set集合中增加“訂閱者id”,此set集合保存了“活躍訂閱”者;訂閱者id標記每個唯一的訂閱者,此set爲“活躍訂閱者集合”。
    (2)subscribe端開啓訂閱操作,並基於redis創建一個以訂閱者id爲key的list數據結構,此list中存儲了所有的尚未消費的消息,此list稱爲“訂閱者消息隊列”;
    (3)publish端:每發佈一條消息之後,publish端都需要遍歷活躍訂閱者集合,並依次向每個“訂閱者消息隊列”尾部追加此次發佈的消息;
    (4)到此爲止,我們基本可以保證,發佈的每一條消息,都會持久的保存在每個“訂閱者消息隊列”中;
    (5)subscribe端,每接收到一個訂閱消息,在消費周後,必須刪除自己的“訂閱者消息隊列”頭部的一條消息;
    (6)subscribe端啓動時,如果發現自己的“訂閱者消息隊列”中有殘存記錄,那麼將會首先消費這些消息,然後再去訂閱。
  13. 以上方法可以保證成功到達的消息必消費不丟失

transactions

  1. redis事務可以一次執行多個命令。
  2. 一個事務從開始到執行會經歷三個階段:

    (1)開始事務
    (2)命令入隊
    (3)執行事務
  3. 事務是一個單獨的隔離操作:事務中的所有命令都會序列化、按順序執行。
  4. 事務在執行的過程中,不會被其他客戶端發送來的命令請求所打斷。
  5. 單個redis命令的執行時原子性的,但redis沒有在事務上增加任何維持原子性的機制,所以redis事務的執行並不是原子性的。
  6. 事務可以理解爲一個打包的批量執行腳本,但批量指令並非原子化的操作,中間某條指令的失敗不會導致前面已做指令的回滾,也不會造成後續的指令不做。
  7. multi、exec、discard和watch命令是redis事務的基礎。
  8. multi:

    (1)multi命令用於開啓一個事務,它總是返回ok。
    (2)multi命令執行之後,客戶端可以繼續向服務器發送任意多條命令;
    (3)這些命令不會立即被執行,而是被放到一個隊列中;
    (4)當exec命令被調用時,所有隊列中的命令纔會被執行。
  9. exec:

    (1)exec命令負責觸發並執行事務中的所有命令;
    (2)如果客戶端在使用multi開啓了一個事務後,卻因爲斷線而沒有成功執行exec命令,那麼事務中所有的命令都不會被執行。
    (3)另一方面,如果客戶端成功在開啓事務之後執行exec命令,那麼事務中的所有命令都會被執行。
  10. discard:

    (1)通過調用discard,客戶端可以清空事務隊列,並放棄執行事務。
  11. watch:

    (1)watch命令可以爲redis事務提供check-and-set (CAS)行爲。 
    (2)watch使得exec命令有條件的執行:事務只能在所有被監控健都沒有被修改的前提下執行,如果這個前提不能滿足,事務就不會執行。
    (3)如果你用watch監視來一個帶過期時間的健,那麼即使這個健過期了,事務仍然可以執行。
    (4)watch可以被調用多次,對健的監視從watch被執行之後就生效,直到調用exec爲止。
    (5)當exec被調用時,不管事務是否被成功執行,對所有健的監視都會被取消。
    (6)當客戶端斷開鏈接時,該客戶端對健的監視也會被取消。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章