關於Redis中的數據類型

来源:http://www.cnblogs.com/chenpingzhao/archive/2016/02/29/5220498.html
-Advertisement-
Play Games

一、 Redis常用數據類型 Redis最為常用的數據類型主要有以下: String Hash List Set Sorted set 一張圖說明問題的本質 圖一: 圖二: 代碼: /* Object types */ #define REDIS_STRING 0 #define REDIS_LIS


一、 Redis常用數據類型

Redis最為常用的數據類型主要有以下:

  • String

  • Hash

  • List

  • Set

  • Sorted set

一張圖說明問題的本質

圖一:

圖二:

代碼:

/* Object types */
#define REDIS_STRING 0
#define REDIS_LIST 1
#define REDIS_SET 2
#define REDIS_ZSET 3
#define REDIS_HASH 4
 
/* Objects encoding. Some kind of objects like Strings and Hashes can be
 * internally represented in multiple ways. The 'encoding' field of the object
 * is set to one of this fields for this object. */
#define REDIS_ENCODING_RAW 0     /* Raw representation */
#define REDIS_ENCODING_INT 1     /* Encoded as integer */
#define REDIS_ENCODING_HT 2      /* Encoded as hash table */
#define REDIS_ENCODING_ZIPMAP 3  /* Encoded as zipmap */
#define REDIS_ENCODING_LINKEDLIST 4 /* Encoded as regular linked list */
#define REDIS_ENCODING_ZIPLIST 5 /* Encoded as ziplist */
#define REDIS_ENCODING_INTSET 6  /* Encoded as intset */
#define REDIS_ENCODING_SKIPLIST 7  /* Encoded as skiplist */
#define REDIS_ENCODING_EMBSTR 8  /* Embedded sds string encoding */

redisobject

/* The actual Redis Object */
#define REDIS_LRU_BITS 24
#define REDIS_LRU_CLOCK_MAX ((1<<REDIS_LRU_BITS)-1) /* Max value of obj->lru */
#define REDIS_LRU_CLOCK_RESOLUTION 1000 /* LRU clock resolution in ms */
typedef struct redisObject {
    unsigned type:4;
    unsigned encoding:4;
    unsigned lru:REDIS_LRU_BITS; /* lru time (relative to server.lruclock) */
    int refcount;
    void *ptr;
} robj;

struct sdshdr {
    unsigned int len;
    unsigned int free;
    char buf[];
};

二、各種數據類型應用和實現方式

robj *createObject(int type, void *ptr) {
    robj *o = zmalloc(sizeof(*o));
    o->type = type;    
    o->encoding = REDIS_ENCODING_RAW;
    o->ptr = ptr;
    o->refcount = 1;   
                 
    /* Set the LRU to the current lruclock (minutes resolution). */
    o->lru = LRU_CLOCK();
    return o;    
}

1、String

  • 如果一個字元串保存的是整數值,並且這個整數值可以用long類型表示,那麼字元串對象會把整數值保存到ptr所指的空間里,編碼設為int

  • 如果是普通字元串,並且長度大於39位元組,使用redis自己實現的SDS類型

  • 如果是普通字元串,並且長度小於等於39位元組,採用embstr存儲

#define REDIS_ENCODING_EMBSTR_SIZE_LIMIT 39
robj *createStringObject(char *ptr, size_t len) {
    if (len <= REDIS_ENCODING_EMBSTR_SIZE_LIMIT)
        return createEmbeddedStringObject(ptr,len);
    else                   
        return createRawStringObject(ptr,len);
}   

embstr 編碼是專門用於保存短字元串的一種優化編碼方式, 這種編碼和 raw 編碼一樣, 都使用 redisObject 結構和 sdshdr 結構來表示字元串對象, 但 raw 編碼會調用兩次記憶體分配函數來分別創建 redisObject 結構和 sdshdr 結構, 而 embstr 編碼則通過調用一次記憶體分配函數來分配一塊連續的空間, 空間中依次包含 redisObject 和 sdshdr 兩個結構

應用場景:String是最常用的一種數據類型,普通的key/ value 存儲都可以歸為此類.即可以完全實現目前 Memcached 的功能,並且效率更高。還可以享受Redis的定時持久化,操作日誌及 Replication等功能。

除了提供與 Memcached 一樣的get、set、incr、decr 等操作外,Redis還提供了下麵一些操作:

  • 獲取字元串長度

  • 往字元串append內容

  • 設置和獲取字元串的某一段內容

  • 設置及獲取字元串的某一位(bit)

  • 批量設置一系列字元串的內容

127.0.0.1:6379> set name "This is a test"
OK
127.0.0.1:6379> get name
"This is a test"

2、Hash

預設使用 REDIS_ENCODING_ZIPLIST 編碼, 當以下任何一個條件被滿足時, 程式將編碼從 REDIS_ENCODING_ZIPLIST 切換為 REDIS_ENCODING_HT

  • 哈希表中某個鍵或某個值的長度大於 server.hash_max_ziplist_value (預設值為 64 )

  • 壓縮列表中的節點數量大於 server.hash_max_ziplist_entries (預設值為 512 )

應用場景:在Memcached中,我們經常將一些結構化的信息打包成HashMap,在客戶端序列化後存儲為一個字元串的值,比如用戶的昵稱、年齡、性別、積分等,這時候在需要修改其中某一項時,通常需要將所有值取出反序列化後,修改某一項的值,再序列化存儲回去。這樣不僅增大了開銷,也不適用於一些可能併發操作的場合(比如兩個併發的操作都需要修改積分)。而Redis的Hash結構可以使你像在資料庫中Update一個屬性一樣只修改某一項屬性值。

我們簡單舉個實例來描述下Hash的應用場景

比如我們要存儲一個用戶信息對象數據,包含以下信息:用戶ID為查找的key,存儲的value用戶對象包含姓名,年齡,生日等信息,如果用普通的key/value結構來存儲,主要有以下2種存儲方式:

第一種方式將用戶ID作為查找key,把其他信息封裝成一個對象以序列化的方式存儲,這種方式的缺點是,增加了序列化/反序列化的開銷,並且在需要修改其中一項信息時,需要把整個對象取回,並且修改操作需要對併發進行保護,引入CAS等複雜問題。

第二種方法是這個用戶信息對象有多少成員就存成多少個key-value對兒,用用戶ID+對應屬性的名稱作為唯一標識來取得對應屬性的值,雖然省去了序列化開銷和併發問題,但是用戶ID為重覆存儲,如果存在大量這樣的數據,記憶體浪費還是非常可觀的。

那麼Redis提供的Hash很好的解決了這個問題,Redis的Hash實際是內部存儲的Value為一個HashMap,並提供了直接存取這個Map成員的介面

Key仍然是用戶ID, value是一個Map,這個Map的key是成員的屬性名,value是屬性值,這樣對數據的修改和存取都可以直接通過其內部Map的Key(Redis里稱內部Map的key為field), 也就是通過 key(用戶ID) + field(屬性標簽) 就可以操作對應屬性數據了,既不需要重覆存儲數據,也不會帶來序列化和併發修改控制的問題,很好的解決了問題。

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

 

127.0.0.1:6379> HMSET user:1 username root password 123456 score 100
OK
127.0.0.1:6379> hgetall user:1
1) "username"
2) "root"
3) "password"
4) "123456"
5) "score"
6) "100"

3、List

預設使用 REDIS_ENCODING_ZIPLIST 編碼, 當以下任意一個條件被滿足時, 列表會被轉換成 REDIS_ENCODING_LINKEDLIST 編碼

  • 往列表新添加一個字元串值且這個字元串的長度超過 server.list_max_ziplist_value (預設值為 64 )

  • ziplist 包含的節點超過 server.list_max_ziplist_entries (預設值為 512 )

應用場景:Redis list的應用場景非常多,也是Redis最重要的數據結構之一,比如twitter的關註列表,粉絲列表等都可以用Redis的list結構來實現。Lists 就是鏈表,相信略有數據結構知識的人都應該能理解其結構。使用Lists結構,我們可以輕鬆地實現最新消息排行等功能。Lists的另一個應用就是消息隊列,

可以利用Lists的PUSH操作,將任務存在Lists中,然後工作線程再用POP操作將任務取出進行執行。Redis還提供了操作Lists中某一段的api,你可以直接查詢,刪除Lists中某一段的元素。

127.0.0.1:6379> lpush list mysql
(integer) 1
127.0.0.1:6379> lpush list mssql
(integer) 2
127.0.0.1:6379> lpush list oracle
(integer) 3
127.0.0.1:6379> lrange list 0 3
1) "oracle"
2) "mssql"
3) "mysql"

4、Set

  • 如果第一個元素可以表示為 long long 類型值(也即是,它是一個整數), 那麼集合的初始編碼為 REDIS_ENCODING_INTSET

  • 否則集合的初始編碼為 REDIS_ENCODING_HT

如果一個集合使用 REDIS_ENCODING_INTSET 編碼, 那麼當以下任何一個條件被滿足時, 這個集合會被轉換成 REDIS_ENCODING_HT 編碼

  • intset 保存的整數值個數超過 server.set_max_intset_entries (預設值為 512 )

  • 試圖往集合里添加一個新元素,並且這個元素不能被表示為 long long 類型(也即是,它不是一個整數)

應用場景:Redis set對外提供的功能與list類似是一個列表的功能,特殊之處在於set是可以自動排重的,當你需要存儲一個列表數據,又不希望出現重覆數據時,set是一個很好的選擇,並且set提供了判斷某個成員是否在一個set集合內的重要介面,這個也是list所不能提供的。

Sets 集合的概念就是一堆不重覆值的組合。利用Redis提供的Sets數據結構,可以存儲一些集合性的數據,比如在微博應用中,可以將一個用戶所有的關註人存在一個集合中,將其所有粉絲存在一個集合。Redis還為集合提供了求交集、並集、差集等操作,可以非常方便的實現如共同關註、共同喜好、二度好友等功能,對上面的所有集合操作,你還可以使用不同的命令選擇將結果返回給客戶端還是存集到一個新的集合中。

127.0.0.1:6379> sadd sets  redis 
(integer) 1
127.0.0.1:6379> sadd sets mongodb
(integer) 1
127.0.0.1:6379> sadd sets hbase
(integer) 1
127.0.0.1:6379> smembers sets
1) "hbase"
2) "redis"
3) "mongodb"

5、Sorted Set

如果第一個元素符合以下條件的話, 就創建一個 REDIS_ENCODING_ZIPLIST 編碼的有序集

  • 伺服器屬性 server.zset_max_ziplist_entries 的值大於 0 (預設為 128 ),元素的 member 長度小於伺服器屬性 server.zset_max_ziplist_value 的值(預設為 64 )

  • 否則,程式就創建一個 REDIS_ENCODING_SKIPLIST 編碼的有序集

對於一個 REDIS_ENCODING_ZIPLIST 編碼的有序集, 只要滿足以下任一條件, 就將它轉換為 REDIS_ENCODING_SKIPLIST 編碼

  • ziplist 所保存的元素數量超過伺服器屬性 server.zset_max_ziplist_entries 的值(預設值為 128 )

  • 新添加元素的 member 的長度大於伺服器屬性 server.zset_max_ziplist_value 的值(預設值為 64 )

使用場景:Redis sorted set的使用場景與set類似,區別是set不是自動有序的,而sorted set可以通過用戶額外提供一個優先順序(score)的參數來為成員排序,並且是插入有序的,即自動排序。當你需要一個有序的並且不重覆的集合列表,那麼可以選擇sorted set數據結構,比如twitter 的public timeline可以以發表時間作為score來存儲,這樣獲取時就是自動按時間排好序的。

另外還可以用Sorted Sets來做帶權重的隊列,比如普通消息的score為1,重要消息的score為2,然後工作線程可以選擇按score的倒序來獲取工作任務。讓重要的任務優先執行。

127.0.0.1:6379> zadd ssets 0 redis 
(integer) 1
127.0.0.1:6379> zadd ssets 0 mongodb
(integer) 1
127.0.0.1:6379> zadd ssets 0 hbase
(integer) 1
127.0.0.1:6379> zrangebyscore ssets 0 10
1) "hbase"
2) "mongodb"
3) "redis"

三、其他

1、Pub/Sub

Pub/Sub 從字面上理解就是發佈(Publish)與訂閱(Subscribe),在Redis中,你可以設定對某一個key值進行消息發佈及消息訂閱,當一個key值上進行了消息發佈後,所有訂閱它的客戶端都會收到相應的消息。這一功能最明顯的用法就是用作實時消息系統,比如普通的即時聊天,群聊等功能

2、Transactions

誰說NoSQL都不支持事務,雖然Redis的Transactions提供的並不是嚴格的ACID的事務(比如一串用EXEC提交執行的命令,在執行中伺服器宕機,那麼會有一部分命令執行了,剩下的沒執行),但是這個Transactions還是提供了基本的命令打包執行的功能(在伺服器不出問題的情況下,可以保證一連串的命令是順序在一起執行的,中間有會有其它客戶端命令插進來執行)。Redis還提供了一個Watch功能,你可以對一個key進行Watch,然後再執行Transactions,在這過程中,如果這個Watched的值進行了修改,那麼這個Transactions會發現並拒絕執行


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • null是什麼? 不知道。我是說,他的意思就是不知道(unknown)。 它和true、false組成謂詞的三個邏輯值,代表“未知”。與true和false相比,null最難以令人捉摸,因為它沒有明確的值,在不同的場景下,它能代表不同的含義。下文以例子的方式給大家分享下null使用的典型場景及對應的
  • 在工作中我碰到這樣一個問題,session表需要用到timestamp的欄位,在進行timestamp欄位更新時出現了為題,比如需要對session的有效期增加1小時。採用 systimestamp + 1/24 會丟失秒後的精度,感覺增加之後就變成了date型的樣子。經過研究發現oracle 有個
  • ubuntu上mysql預設安裝使用的字元集是latin1。 1 查看字元集支持 show character set; 2 查看字元集相關變數 show variables like "character_set%"; 3 設置預設字元集 為解決亂碼問題,最簡單的辦法就是修改預設字元集。修改預設字
  • (一)是否存在一個伺服器性能基線? (1)、有了基線才有一個衡量的指標,否則一切計數器都是沒有意思。否則可能我的系統本來就很慢,例如現在公司就有一個OLAP系統,每天就花了三個小時產生一個報表。也不是問題。 (2)、有了基線才能確認我的伺服器確實存在調整的必要了,例如今天發佈新的代碼後,性能明顯偏離
  • 本文目錄列表: 1、SQL Server中的基準日期 2、smalldatetime的日期範圍 3、smalldatetime的日期範圍和無符號2位元組整數的關係 4、總結語 5、參考清單列表 SQL Server中的基準日期 SQL Server 中針對datetime和smalldatetime這
  • 1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.Linq; 7
  • hiredis 是 redis 的client端C語言 lib, hiredis擁有同步和非同步的API, 非同步API的實現有多種方法,分別依賴libev, libevent, libuv, ae等等,其中ae是redis內部實現的一個非同步事件處理模塊。 稍微修改了hiredis的example-ae
  • 寫完DML語句(update, insert, delete)後,需要手動COMMIT,如果沒有COMMIT,更新的內容會被保存到記憶體中,而不是提交到資料庫中,將不會被其他Session(對話)看見。其他對話看到的是更新前的數據。當用戶退出對話時,Oracle才會自動Commit。 而DDL語句(c
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...