Redis數據結構解析

redis安裝

  1. 下載redis的安裝包(直接去官網下一個就行)
  2. tar -zxvf 解壓
  3. cd 到解壓後的目錄
  4. 執行make 完成編譯

可能會遇到的錯誤node

  • 須要安裝tcl (yum -y install tcl 、 yum -y install gcc)
  • error: jemalloc/jemalloc.h: No such file or directory 說關於分配器allocator, 若是有MALLOC 這個 環境變量, 會有用這個環境變量的 去創建Redis。 並且libc 並非默認的 分配器, 默認的是 jemalloc, 由於 jemalloc 被證實 有更少的 fragmentation problems 比libc。 可是若是你又沒有jemalloc 而只有 libc 固然 make 出錯。 因此加這麼一個參數。 解決辦法 make MALLOC=libc
  1. make test 測試編譯狀態redis

  2. make install {PREFIX=/path} (示例:make PREFIX=/soft/redis install)算法

  3. 環境變量配置數據庫

    export REDIS_HOME=/soft/redisjson

    export PATH=PATH:REDIS_HOME/bin安全

redis服務文件相關命令bash

Redis-server Redis服務器服務器

Redis-cli Redis命令行客戶端數據結構

Redis-benchmark Redis性能測試工具函數

Redis-check-aof Aof文件修復工具

Redis-check-dump Rdb文件檢查工具

Redis-sentinel Sentinel服務器(2.8之後)

reids對基於key-value存儲,數據基礎命令

KEYS * 得到當前數據庫的全部鍵

EXISTS key [key ...] 判斷鍵是否存在,返回個數,若是key有同樣的也是疊加數

DEL key [key ...] 刪除鍵,返回刪除的個數

TYPE key 獲取減值的數據類型(string,hash,list,set,zset)

FLUSHALL 清空全部數據庫

CONFIG [get、set] redis配置

詳解redis數據結構

Redis的五種數據類型:

字符串(String)

存儲說明: 字符串類型是redis中最基本的數據類型,它能存儲任何形式的字符串,包括二進制數據。你能夠用它存儲用戶的郵箱、json化的對象甚至是圖片。一個字符類型鍵容許存儲的最大容量是512M。

數據結構: 在Redis內部,String類型經過int、SDS(simpledynamicstring)做爲結構存儲,int用來存放整型數據,sds存放字節/字符串和浮點型數據.redis是用C語言寫的。能夠在redis的源碼[sds.h]中看到sds的結構以下:

typedef char *sds;

redis3.2分支引入了五種sdshdr類型,默認是sdshdr8。目的是爲了知足不一樣長度字符串可使用不一樣大小的Header,從而節省內存,每次在建立一個sds時根據sds的實際長度判斷應該選擇什麼類型的sdshdr,不一樣類型的sdshdr佔用的內存空間不一樣。這樣細分一下能夠省去不少沒必要要的內存開銷。

sdshdr8數據結構以下:

struct __attribute__ ((__packed__)) sdshdr8 { 
  //8表示字符串最大長度是2^8-1 (長度爲255)
uint8_t len;//表示當前sds的長度(單位是字節)
uint8_t alloc; //表示已爲sds分配的內存大小(單位是字節)
unsigned char flags; //用一個字節表示當前sdshdr的類型,由於有sdshdr有五種類型,因此至少須要3位來表示000:sdshdr5,001:sdshdr8,010:sdshdr16,011:sdshdr32,100:sdshdr64。高5位用不到因此都爲0。
char buf[];//sds實際存放的位置};
複製代碼

String的函數說明:

最基本的命令:GET、SET 語法:GET key,SET key value value若是有空格須要雙引號以示區分

整數遞增:INCR 語法:INCR key 默認值爲0,因此首先執行命令獲得 1 ,不是整型提示錯誤

增長指定的整數:INCRBY 語法:INCRBY key increment

整數遞減:DECR 語法:DECR key 默認值爲0,因此首先執行命令獲得 -1,不是整型提示錯誤

減小指定的整數:DECRBY 語法:DECRBY key increment

增長指定浮點數:INCRBYFLOAT 語法:INCRBYFLOAT key increment 與INCR命令相似,只不過能夠遞增一個雙精度浮點數

向尾部追加值:APPEND 語法:APPEND key value redis客戶端並非輸出追加後的字符串,而是輸出字符串總長度

獲取字符串長度:STRLEN 語法:STRLEN key 若是鍵不存在返回0,注意若是有中文時,一箇中文長度是3,redis是使用UTF-8編碼中文的

獲取多個鍵值:MGET 語法:MGET key [key ...] 例如:MGET key1 key2

設置多個鍵值:MSET 語法:MSET key value [key value ...] 例如:MSET key1 1 key2 "hello redis"

二進制指定位置值:GETBIT 語法:GETBIT key offset 例如:GETBIT key1 2 ,key1爲hello 返回 1,返回的值只有0或1,當key不存在或超出實際長度時爲0

                   設置二進制位置值:SETBIT 語法:SETBIT key offset value ,返回該位置的舊值

二進制是1的個數:BITCOUNT 語法:BITCOUNT key [start end] ,start 、end爲開始和結束字節

位運算:BITOP 語法:BITOP operation destkey key [key ...] ,operation支持AND、OR、XOR、NOT

偏移:BITPOS 語法:BITPOS key bit [start] [end]

列表(list)

存儲說明: 列表類型(list)能夠存儲一個有序的字符串列表,經常使用的操做是向列表兩端添加元素或者得到列表的某一個片斷,value值的列表元素只能是字符串。

數據結構: redis3.2以後使用的是quicklist實現的列表。其中quicklist是否ziplist的雙向列表。 redis查詢兩端的複雜度是O(1),中間查詢複雜度很高。

image
quicklist 的指針指向quicklistnode,其中quicklistnode就包含了ziplist, ziplist一個通過特殊處理的雙向鏈表。能夠存儲多個數據

list的函數說明:

添加左邊元素:LPUSH 語法:LPUSH key value [value ...] ,返回添加後的列表元素的總個數

添加右邊元素:RPUSH 語法:RPUSH key value [value ...] ,返回添加後的列表元素的總個數

移除左邊第一個元素:LPOP 語法:LPOP key ,返回被移除的元素值

移除右邊第一個元素:RPOP 語法:RPOP key ,返回被移除的元素值

列表元素個數:LLEN 語法:LLEN key, 不存在時返回0,redis是直接讀取現成的值,並非統計個數

獲取列表片斷:LRANGE 語法:LRANGE key start stop,若是start比stop靠後時返回空列表,0 -1 返回整個列表 正數時:start 開始索引值,stop結束索引值(索引從0開始) 負數時:例如 lrange num -2 -1,-2表示最右邊第二個,-1表示最右邊第一個

刪除指定值:LREM 語法:LREM key count value,返回被刪除的個數 ount>0,從左邊開始刪除前count個值爲value的元素 count<0,從右邊開始刪除前|count|個值爲value的元素 count=0,刪除全部值爲value的元素

索引元素值:LINDEX 語法:LINDEX key index ,返回索引的元素值,-1表示從最右邊的第一位

設置元素值:LSET 語法:LSET key index value

保留列表片斷:LTRIM 語法:LTRIM key start stop,start、top 參考lrange命令

一個列表轉移另外一個列表:RPOPLPUSH 語法:RPOPLPUSH source desctination ,從source列表轉移到desctination列表該命令分兩步看,首先source列表RPOP右移除,再desctination列表LPUSH

hash類型

存儲說明: value值是一個map結構

數據結構: map提供兩種結構來存儲,一種是hashtable、另外一種是前面講的ziplist,數據量小的時候用ziplist. 在redis中,哈希表分爲三層,分別是,源碼地址【dict.h】

對於hashmap你們可能很是熟悉了,可是redis如何實現,桶位置確認,hash碰撞和rehash的擴容呢。分析redis底層map結構:

  1. dictEntry

管理一個key-value,同時保留同一個桶中相鄰元素的指針,用來維護哈希桶的內部鏈;

typedef struct dictEntry {
void *key;
union { //由於value有多種類型,因此value用了union來存儲
void *val;
uint64_t u64;
int64_t s64;
double d;
} v;
struct dictEntry *next;//下一個節點的地址,用來處理碰撞,全部分配到同一索引的元素經過next指針連接起來造成鏈
複製代碼
  1. dictht

這個結構體就是對於桶大小和元素位置的存儲 實現一個hash表會使用一個buckets存放dictEntry的地址,通常狀況下經過hash(key)%len獲得的值就是buckets的索引,這個值決定了咱們要將此dictEntry節點放入buckets的哪一個索引裏,這個buckets實際上就是咱們說的hash表。dict.h的dictht結構中table存放的就是buckets的地址

typedef struct dictht {
dictEntry **table;//buckets的地址
unsigned long size;//buckets的大小,總保持爲 2^n
unsigned long sizemask;//掩碼,用來計算hash值對應的buckets索引
unsigned long used;//當前dictht有多少個dictEntry節點
} dictht;
複製代碼
  1. dict

這個結構體用於擴容 dictht實際上就是hash表的核心,可是隻有一個dictht還不夠,好比rehash、遍歷hash等操做,因此redis定義了一個叫dict的結構以支持字典的各類操做,當dictht須要擴容/縮容時,用來管理dictht的遷移

typedef struct dict {
dictType *type;//dictType裏存放的是一堆工具函數的函數指針,
void *privdata;//保存type中的某些函數須要做爲參數的數據
dictht ht[2];//兩個dictht,ht[0]平時用,ht[1] rehash時用
long rehashidx; //當前rehash到buckets的哪一個索引,-1時表示非rehash狀態
int iterators; //安全迭代器的計數。
}dict;
複製代碼

Hash的函數說明:

設置單個:HSET 語法:HSET key field value,不存在時返回1,存在時返回0,沒有更新和插入之分

設置多個:HMSET 語法:HMSET key field value [field value ...]

讀取單個:HGET 語法:HGET key field,不存在是返回nil

讀取多個:HMGET 語法:HMGET key field [field ...]

讀取所有:HGETALL 語法:HGETALL key,返回時字段和字段值的列表

判斷字段是否存在:HEXISTS 語法:HEXISTS key field,存在返回1 ,不存在返回0

字段不存在時賦值:HSETNX 語法:HSETNX key field value,與hset命令不一樣,hsetnx是鍵不存在時設置值

增長數字:HINCRBY 語法:HINCRBY key field increment ,返回增長後的數,不是整數時會提示錯誤

刪除字段:HDEL 語法:HDEL key field [field ...] ,返回被刪除字段的個數

只獲取字段名:HKEYS 語法:HKEYS key ,返回鍵的全部字段名

只獲取字段值:HVALS 語法:HVALS key ,返回鍵的全部字段值

字段數量:HLEN 語法:HLEN key ,返回字段總數

集合類型(set)

存儲說明:

集合類型中,每一個元素都是不一樣的,也就是不能有重複數據,同時集合類型中的數據是無序的。集合類型和列表類型的最大的區別是有序性和惟一性集合類型的經常使用操做是向集合中加入或刪除元素、判斷某個元素是否存在。因爲集合類型在redis內部是使用的值爲空的散列表(hashtable),因此這些操做的時間複雜度都是O(1).

數據結構:

Set在的底層數據結構以intset或者hashtable來存儲。當set中只包含整數型的元素時,採用intset來存儲,不然,採用hashtable存儲,可是對於set來講,該hashtable的value值用於爲NULL。經過key來存儲元素,hashtable取key的複雜度是O(1)的。

Set的函數說明:

添加元素:SADD 語法:SADD key member [member ...] ,向一個集合添加一個或多個元素,由於集合的惟一性,因此添加相同值時會被忽略。                 返回成功添加元素的數量。                
刪除元素:SREM 語法:SREM key member [member ...] 刪除集合中一個或多個元素,返回成功刪除的個數。

獲取所有元素:SMEMBERS 語法:SMEMBERS key ,返回集合所有元素

值是否存在:SISMEMBER 語法:SISMEMBER key member ,若是存在返回1,不存在返回0

差運算:SDIFF 語法:SDIFF key [key ...] ,例如:集合A和集合B,差集表示A-B,在A裏有的元素B裏沒有,返回差集合;多個集合(A-B)-C

交運算:SINTER    語法:SINTER key [key ...],返回交集集合,每一個集合都有的元素

並運算:SUNION       語法:SUNION key [key ...],返回並集集合,全部集合的元素

集合元素個數:SCARD 語法:SCARD key ,返回集合元素個數

                   彈出元素:SPOP 語法:SPOP key [count] ,由於集合是無序的,因此spop會隨機彈出一個元素

有序集合

儲存說明:

有序集合類型,顧名思義,和前面講的集合類型的區別就是多了有序的功能在集合類型的基礎上,有序集合類型爲集合中的每一個元素都關聯了一個分數,這使得咱們不只能夠完成插入、刪除和判斷元素是否存在等集合類型支持的操做,還能得到分數最高(或最低)的前N個元素、得到指定分數範圍內的元素等與分數有關的操做。雖然集合中每一個元素都是不一樣的,可是他們的分數卻能夠相同

數據結構: zset類型的數據結構就比較複雜一點,內部是以ziplist或者skiplist+hashtable來實現,這裏面最核心的一個結構就是skiplist,也就是跳躍表,跳躍表是實現有序集合的核心,跳躍表的設計思路和方法本人目前也未融會貫通,後續算法博客補上.

image

zset的函數說明:

添加集合元素:ZADD 語法:ZADD key [NX|XX] [CH] [INCR] score member [score member ...],不存在添加,存在更新。

獲取元素分數:ZSCORE 語法:ZSCORE key member ,返回元素成員的score 分數

元素小到大:ZRANGE 語法:ZRANGE key start top [WITHSCORES] ,參考LRANGE ,加上withscores 返回帶元素,即元素,分數 當分數同樣時,按元素排序

元素大到小:ZREVRANGE 語法:ZREVRANGE key start [WITHSCORES] ,與zrange區別在於zrevrange是從大到小排序

指定分數範圍元素:ZRANGEBYSCORE 語法:ZRANGEBYSCORE key min max [WITHSCORE] [LIMIT offest count]返回從小到大的在min和max之間的元素,(符號表示不包含,例如:80-100,(80 100,withscore返回帶分數limit offest count向左偏移offest個元素,並獲取前count個元素

指定分數範圍元素:ZREVRANGESCORE 語法:ZREVRANGEBYSCORE key max min [WITHSCORE] [LIMIT offest count]與zrangebyscore相似,只不過該命令是從大到小排序的。

增長分數:ZINCRBY 語法:ZINCRBY key increment member ,注意是增長分數,返回增長後的分數;若是成員不存在,則添加一個爲0的成員。

91Code-就要編碼,關注公衆號獲取更多內容!

在這裏插入圖片描述
相關文章
相關標籤/搜索