更多精彩文章,關注公衆號【ToBeTopJavaer】,更有數萬元精品vip資源免費等你來拿!!!
整體來講:String、Hash、Set、List、Zset、Hyperloglog、Geo、Streamjava
經常使用的數據類型:redis
最基本最經常使用的數據類型就是String。set 和 get 命令就是 String 的操做命令。spring
一、 String字符串數據庫
能夠用來存儲字符串,整數,浮點數。數組
1.一、 基本操做緩存
設置多個值(批量操做,原子性)安全
設置值,如何Key存在,設置不成功session
基於此可實現分佈式鎖。 用 del key 釋放鎖。數據結構
但若是釋放鎖的操做失敗了, 致使其餘節點永遠獲取不到鎖, 怎麼辦?分佈式
加過時時間。 單獨用 expire 加過時, 也失敗了, 沒法保證原子性, 怎麼辦? 多參數。
set key value [expiration EX seconds|PX milliseconds][NX|XX]
(整數) 值遞增
(整數) 值遞減
浮點數增量
獲取多個值
獲取值長度
字符串追加內容
獲取指定範圍的字符
1.二、 存儲實現原理
數據模型
set name javaHuang爲例,由於 Redis 是 KV 的數據庫,它是經過 hashtable 實現的(我
們把這個叫作外層的哈希)。因此每一個鍵值對都會有一個 dictEntry,裏面指向了 key 和 value 的指針。next 指向下一個 dictEntry。源碼以下:
typedef struct dictEntry { void *key; /* key 關鍵字定義 */ union { void *val; uint64_t u64; /* value 定義 */ int64_t s64; double d; } v; struct dictEntry *next; /* 指向下一個鍵值對節點 */ } dictEntry;
key 是字符串,可是 Redis 沒有直接使用 C 的字符數組,而是存儲在自定義的 SDS
中。
value 既不是直接做爲字符串存儲,也不是直接存儲在 SDS 中,而是存儲在
redisObject 中。實際上五種經常使用的數據類型的任何一種,都是經過 redisObject 來存儲
的。
redisObject
redisObject 的定義的源碼以下:
typedef struct redisObject { unsigned type:4; /* 對象的類型, 包括: OBJ_STRING、 OBJ_LIST、 OBJ_HASH、 OBJ_SET、 OBJ_ZSET */ unsigned encoding:4; /* 具體的數據結構 */ unsigned lru:LRU_BITS; /* 24 位, 對象最後一次被命令程序訪問的時間, 與內存回收有關 */ int refcount; /* 引用計數。 當 refcount 爲 0 的時候, 表示該對象已經不被任何對象引用, 則能夠進行垃圾回收了 */ void *ptr; /* 指向對象實際的數據結構 */ } robj;
可使用 type 命令來查看對外的類型。
下面我來設置三種Key
而後咱們獲取這三種Key的內部編碼
因而咱們可知,字符串類型的內部編碼有三種:
一、int,存儲 8 個字節的長整型(long,2^63-1)。
二、embstr, 表明 embstr 格式的 SDS(Simple Dynamic String 簡單動態字符串),
存儲小於 44 個字節的字符串。
三、raw,存儲大於 44 個字節的字符串(3.2 版本以前是 39 字節)。
/* object.c */ #define OBJ_ENCODING_EMBSTR_SIZE_LIMIT 44
2.一、什麼是SDS
SDS是Redis 中字符串的實現。
在 3.2 之後的版本中,SDS 又有多種結構(sds.h):sdshdr五、sdshdr八、sdshdr1六、
sdshdr3二、sdshdr64,用於存儲不一樣的長度的字符串,分別表明 2^5=32byte,
2^8=256byte,2^16=65536byte=64KB,2^32byte=4GB。
struct __attribute__ ((__packed__)) sdshdr8 { uint8_t len; /* 當前字符數組的長度 */ uint8_t alloc; /*當前字符數組總共分配的內存大小 */ unsigned char flags; /* 當前字符數組的屬性、 用來標識究竟是 sdshdr8 仍是 sdshdr16 等 */ char buf[]; /* 字符串真正的值 */ };
2.二、爲何 Redis 要用 SDS 實現字符串?
咱們知道,C 語言自己沒有字符串類型(只能用字符數組 char[]實現)。
一、使用字符數組必須先給目標變量分配足夠的空間,不然可能會溢出。
二、若是要獲取字符長度,必須遍歷字符數組,時間複雜度是 O(n)。
三、C 字符串長度的變動會對字符數組作內存重分配。
四、經過從字符串開始到結尾碰到的第一個'\0'來標記字符串的結束,所以不能保存圖片、音頻、視頻、壓縮文件等二進制(bytes)保存的內容,二進制不安全。
SDS 的特色:
一、不用擔憂內存溢出問題,若是須要會對 SDS 進行擴容。
二、獲取字符串長度時間複雜度爲 O(1),由於定義了 len 屬性。
三、經過「空間預分配」( sdsMakeRoomFor)和「惰性空間釋放」,防止屢次重分配內存。
四、判斷是否結束的標誌是 len 屬性(它一樣以'\0'結尾是由於這樣就可使用 C 語言中函數庫操做字符串的函數了),能夠包含'\0'。
2.三、embstr 和 raw 的區別
embstr 的使用只分配一次內存空間(由於 RedisObject 和 SDS 是連續的),而 raw須要分配兩次內存空間(分別爲 RedisObject 和 SDS 分配空間)。
所以與 raw 相比,embstr 的好處在於建立時少分配一次空間,刪除時少釋放一次空間,以及對象的全部數據連在一塊兒,尋找方便。
而 embstr 的壞處也很明顯,若是字符串的長度增長鬚要從新分配內存時,整個RedisObject 和 SDS 都須要從新分配空間,所以 Redis 中的 embstr 實現爲只讀。
2.四、int 和 embstr 何時轉化爲 raw
當 int 數 據 不 再 是 整 數 , 或 大 小 超 過 了 long 的 範 圍(2^63-1=9223372036854775807)時,自動轉化爲 embstr。
2.五、明明沒有超過閾值,爲何變成 raw 了
對於 embstr,因爲其實現是隻讀的,所以在對 embstr 對象進行修改時,都會先轉化爲 raw 再進行修改。
所以,只要是修改 embstr 對象,修改後的對象必定是 raw 的,不管是否達到了 44個字節。
2.六、當長度小於閾值時,會還原嗎
關於 Redis 內部編碼的轉換,都符合如下規律:編碼轉換在 Redis 寫入數據時完成,且轉換過程不可逆,只能從小內存編碼向大內存編碼轉換(可是不包括從新 set)。
2.七、爲何要對底層的數據結構進行一層包裝呢
經過封裝,能夠根據對象的類型動態地選擇存儲結構和可使用的命令,實現節省空間和優化查詢速度。
緩存
String 類型
例如:熱點數據緩存,對象緩存,全頁緩存。能夠提高熱點數據的訪問速度。
數據共享分佈式
STRING 類型,由於 Redis 是分佈式的獨立服務,能夠在多個應用之間共享,例如:分佈式 Session
<dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> </dependency>
分佈式鎖
STRING 類型 setnx 方法,只有不存在時才能添加成功,返回 true。
簡單代碼以下:
public Boolean getLock(Object lockObject){ jedisUtil = getJedisConnetion(); boolean flag = jedisUtil.setNX(lockObj, 1); if(flag){ expire(locakObj,10); } return flag; } public void releaseLock(Object lockObject){ del(lockObj); }
全局 ID
INT 類型,INCRBY,利用原子性
incrby userid 1000
計數器
INT 類型,INCR 方法
例如:文章的閱讀量,微博點贊數,容許必定的延遲,先寫入 Redis 再定時同步到數據庫。
限流
INT 類型,INCR 方法
以訪問者的 IP 和其餘信息做爲 key,訪問一次增長一次計數,超過次數則返回 false。
位統計
String 類型的 BITCOUNT(1.6.6 的 bitmap 數據結構介紹)。
字符是以 8 位二進制存儲的。
set k1 a setbit k1 6 1 setbit k1 7 0 get k1
a 對應的 ASCII 碼是 97,轉換爲二進制數據是 01100001
b 對應的 ASCII 碼是 98,轉換爲二進制數據是 01100010
由於 bit 很是節省空間(1 MB=8388608 bit),能夠用來作大數據量的統計。
例如:在線用戶統計,留存用戶統計
setbit onlineusers 0 1 setbit onlineusers 1 1 setbit onlineusers 2 0
支持按位與、按位或等等操做。
BITOP AND destkey key [key ...] , 對一個或多個 key 求邏輯並, 並將結果保存到 destkey 。 BITOP OR destkey key [key ...] , 對一個或多個 key 求邏輯或, 並將結果保存到 destkey 。 BITOP XOR destkey key [key ...] , 對一個或多個 key 求邏輯異或, 並將結果保存到 destkey 。 BITOP NOT destkey key , 對給定 key 求邏輯非, 並將結果保存到 destkey 。
例子:計算出 7 天都在線的用戶
BITOP "AND" "7_days_both_online_users" "day_1_online_users" "day_2_online_users" ... "day_7_online_users"
基本數據類型String基本算是分析透了,接下來還有幾個經常使用的基本類型的深刻探討,敬請期待。
更多精彩文章,關注公衆號【ToBeTopJavaer】,更有數萬元精品vip資源免費等你來拿!!!