Redis

數據結構與對象

數據類型 能夠存儲的值 操做
String 字符串、整數或浮點型 對整個字符串或者字符串的
對整數和浮點數執行自增或自減操做
List 列表 從兩端壓入或者彈出元素
對單個或者多個元素進行修剪、只保留一個範圍內的元素
Set 無序集合 添加、獲取、移除單個元素
檢查一個元素是否存在於集合中
計算交集、並集、差集
從集合裏面隨機獲取元素
HASH 包含鍵值對的無序散列表 添加、獲取、移除單個鍵值對
獲取全部鍵值對
檢查某個鍵是否存在
ZSET 有序集合 添加、獲取、刪除元素
根據分值範圍或者成員來獲取元素、計算一個鍵的排名

String

字符串結構

struct sdshdr{
    //記錄buf數組中已使用字節的數量
    int len;
    //記錄buf數組中未使用的數量
    int free;
    //字節數組,用於保存字符串
    char buf[];
}

常見操做

127.0.0.1:6379> set hello world
OK
127.0.0.1:6379> get hello
"world"
127.0.0.1:6379> del hello
(integer) 1
127.0.0.1:6379> get hello
(nil)
127.0.0.1:6379>

應用場景

String是最經常使用的一種數據類型,普通的key/value存儲均可以歸爲此類,value其實不只是String,也能夠是數字:好比想知道何時封鎖一個IP地址(訪問超過幾回)。INCRBY命令讓這些變得很容易,經過原子遞增保持計數。redis

LIST

數據結構

typedef struct listNode{
    //前置節點
    struct listNode *prev;
    //後置節點
    struct listNode *next;
    //節點的值
    struct value;
}

常見操做

> lpush list-key item
(integer) 1
> lpush list-key item2
(integer) 2
> rpush list-key item3
(integer) 3
> rpush list-key item
(integer) 4
> lrange list-key 0 -1
1) "item2"
2) "item"
3) "item3"
4) "item"
> lindex list-key 2
"item3"
> lpop list-key
"item2"
> lrange list-key 0 -1
1) "item"
2) "item3"
3) "item"

應用場景

Redis list的應用場景很是多,也是Redis最重要的數據結構之一。
咱們能夠輕鬆地實現最新消息排行等功能。
Lists的另外一個應用就是消息隊列,能夠利用Lists的PUSH操做,將任務存在Lists中,而後工做線程再用POP操做將任務取出進行執行。數據庫

HASH

數據結構

dictht是一個散列表結構,使用拉鍊法保存哈希衝突的dictEntry。數組

typedef struct dictht{
    //哈希表數組
    dictEntry **table;
    //哈希表大小
    unsigned long size;
    //哈希表大小掩碼,用於計算索引值
    unsigned long sizemask;
    //該哈希表已有節點的數量
    unsigned long used;
}

typedef struct dictEntry{
    //鍵
    void *key;
    //值
    union{
        void *val;
        uint64_tu64;
        int64_ts64;
    }
    struct dictEntry *next;
}

Redis的字典dict中包含兩個哈希表dictht,這是爲了方便進行rehash操做。在擴容時,將其中一個dictht上的鍵值對rehash到另外一個dictht上面,完成以後釋放空間並交換兩個dictht的角色。服務器

typedef struct dict {
    dictType *type;
    void *privdata;
    dictht ht[2];
    long rehashidx; /* rehashing not in progress if rehashidx == -1 */
    unsigned long iterators; /* number of iterators currently running */
} dict;

rehash操做並非一次性完成、而是採用漸進式方式,目的是爲了不一次性執行過多的rehash操做給服務器帶來負擔。數據結構

漸進式rehash經過記錄dict的rehashidx完成,它從0開始,而後沒執行一次rehash例如在一次 rehash 中,要把 dict[0] rehash 到 dict[1],這一次會把 dict[0] 上 table[rehashidx] 的鍵值對 rehash 到 dict[1] 上,dict[0] 的 table[rehashidx] 指向 null,並令 rehashidx++。性能

在 rehash 期間,每次對字典執行添加、刪除、查找或者更新操做時,都會執行一次漸進式 rehash。ui

採用漸進式rehash會致使字典中的數據分散在兩個dictht中,所以對字典的操做也會在兩個哈希表上進行。
例如查找時,先從ht[0]查找,沒有再查找ht[1],添加時直接添加到ht[1]中。spa

常見操做

> hset hash-key sub-key1 value1
(integer) 1
> hset hash-key sub-key2 value2
(integer) 1
> hset hash-key sub-key1 value1
(integer) 0
> hgetall hash-key
1) "sub-key1"
2) "value1"
3) "sub-key2"
4) "value2"
> hdel hash-key sub-key2
(integer) 1
> hdel hash-key sub-key2
(integer) 0
> hget hash-key sub-key1
"value1"
> hgetall hash-key
1) "sub-key1"
2) "value1"

SET

常見操做

> sadd set-key item
(integer) 1
> sadd set-key item2
(integer) 1
> sadd set-key item3
(integer) 1
> sadd set-key item
(integer) 0
> smembers set-key
1) "item2"
2) "item"
3) "item3"
> sismember set-key item4
(integer) 0
> sismember set-key item
(integer) 1
> srem set-key item
(integer) 1
> srem set-key item
(integer) 0
> smembers set-key
1) "item2"
2) "item3"

應用場景

Redis爲集合提供了求交集、並集、差集等操做,故能夠用來求共同好友等操做。操作系統

ZSET

數據結構

typedef struct zskiplistNode{
        //後退指針
        struct zskiplistNode *backward;
        //分值
        double score;
        //成員對象
        robj *obj;
        //層
        struct zskiplistLever{
            //前進指針
            struct zskiplistNode *forward;
            //跨度
            unsigned int span;
        }lever[];
    }
    
    typedef struct zskiplist{
        //表頭節點跟表尾結點
        struct zskiplistNode *header, *tail;
        //表中節點的數量
        unsigned long length;
        //表中層數最大的節點的層數
        int lever;
    }

跳躍表,基於多指針有序鏈實現,能夠看做多個有序鏈表。.net

clipboard.png

在查找時,先從上層指針開始查找,找到對應的區間以後再到下一層查找。下圖演示了查找22的過程。

clipboard.png

與紅黑樹等平衡樹相比,跳躍表具備如下優勢:

  • 插入速度很是快速,由於不須要進行旋轉等操做來維持平衡性。
  • 更容易實現。
  • 支持無鎖操做。

常見操做

> zadd zset-key 728 member1
(integer) 1
> zadd zset-key 982 member0
(integer) 1
> zadd zset-key 982 member0
(integer) 0
> zrange zset-key 0 -1
1) "member1"
2) "member0"
> zrange zset-key 0 -1 withscores
1) "member1"
2) "728"
3) "member0"
4) "982"
> zrangebyscore zset-key 0 800 withscores
1) "member1"
2) "728"
> zrem zset-key member1
(integer) 1
> zrem zset-key member1
(integer) 0
> zrange zset-key 0 -1 withscores
1) "member0"
2) "982"

應用場景

以某個條件爲權重,好比按頂的次數排序
ZREVRANGE命令能夠用來按照得分來獲取前100名的用戶,ZRANK能夠用來獲取用戶排名,很是直接並且操做容易。
Redis sorted set的使用場景與set相似,區別是set不是自動有序的,而sorted set能夠經過用戶額外提供一個優先級(score)的參數來爲成員排序,而且是插入有序的,即自動排序。

鍵的過時時間

Redis能夠爲每一個鍵設置過時時間,當鍵過時時,會自動刪除該鍵。

經過EXPIRE命令或者PEXPIRE命令,客戶端能夠以秒或者秒精度爲數據庫中的某個鍵設置生存時間(Time To Live,TTL),在通過執行的秒數或者毫秒書以後,服務器就會自動刪除生存時間爲0的鍵。

對於散列表這種容器,只能爲整個鍵設置過時時間(整個散列鍵),而不能爲鍵裏面的單個元素設置過時時間。

持久化

Redis是內存數據庫,爲了不數據意外丟失,須要將內存中的數據持久化到磁盤中。

RDB持久化

在指定的時間間隔內將內存中的數據集快照寫入磁盤,恢復時是將快照文件直接讀到內存裏。

Redis會單首創建(fork)一個子進程來進行持久化,會先將數據寫入到一個臨時文件中,待持久化過程都結束了,再用這個臨時文件替代上次持久化完成的文件。整個過程當中,主進程不進行任何IO操做,這就確保了極高的性能。若是須要進行大規模數據的恢復,且對於數據的完整性不是特別敏感,那麼RDB方式要比AOF方式更加的高效。RDB的缺點是最後一次持久化的數據可能丟失。

特色
  • 適合大規模的數據恢復
  • 對數據的完整性和一致性要求不高
  • fork的時候,內存被克隆了一份,大體2倍的膨脹須要考慮
  • 將某個時間點的全部數據都存磁盤上(壓縮後的二進制文件)。
  • 能夠將快照複製到其餘服務器從而建立具備相同數據的服務器版本。
  • 若是系統發生故障,將會丟失最後一次建立快照以後的數據。
  • 若是數據量很大,保存的快照時間較長。

AOF持久化

以日誌的形式來記錄每一個寫操做,將redis執行過的全部寫指令記錄下來(讀操做不記錄),只需追加文件不能夠改寫文件,redis啓動之初會讀取該文件重構數據,換言之,redis重啓的話就是根據日誌文件的內容從前到後執行一次以完成數據的恢復工做。

將命令添加到AOF文件的末尾。

使用AOF持久化須要設置同步選項,從而確保命令何時會同步到磁盤文件上。這是由於對文件寫入並不會立馬將內容同步到磁盤上,而是先存儲到緩衝區,案後由操做系統決定何時同步到磁盤。有一喜好同步選項:

選項 同步頻率
always 每一個寫命令都同步
everysec 每秒同步一次
no 讓操做系統來決定什麼時候同步
  • always 選項會嚴重減低服務器的性能。
  • everysec 選項比較合適,能夠保證系統崩潰時只丟失一秒左右的數據,而且redis每秒執行一次同步對服務器性能幾乎沒什麼影響。
  • no 選項並不能給服務器性能帶來多大的提高,並且也會增長系統崩潰時數據丟失的數量。
特色
  • 相同數據集的數據而言AOF文件遠大於RDB文件,恢復速度慢於RDB.
  • AOF運行效率要慢於RDB,每秒同步策略效率較好,不一樣步效率和RDB相同。

事務

Redis事務指一次執行多個命令,本質是一組命令的集合,一個事物中的全部命令都會被序列化,按順序地串行執行而不是被其餘命令插入,不準加塞。一個隊列中,一次性、順序性、排他性的執行一系列命令。

常見命令

  • MULTI:標記一個事務的開始。
  • EXEC:執行全部事務塊內的命令。
  • DISCARD:取消事務,放棄執行事務塊中的全部命令。
  • WATCH key [key...]:監視一個或多個key,若是在事務執行以前這個key被其餘命令所改動,那麼事務將被打斷。
  • UNWATCH:取消WATCH命令對全部key的監視。

Redis事務執行的一些狀況:

  • 當開啓事務以後,隊列中出現命令執行錯誤時,Redis將放棄整個事務。(入列時)
  • 執行事務出現錯誤時,此時執行失敗的將會回滾,其餘命令依舊執行。

特性

  • 單獨的隔離操做:事務中的全部命令都會被序列化、按順序地執行。事務在執行過程當中,不會被其餘客戶端發送的命令請求中斷。
  • 沒有隔離級別的概念:隊列中的命令沒有提交以前都不會實際的執行,由於事務提交前任何指令都不會被實際執行。
  • 不保證原子性:redis同一個事務中若是有一條命令執行失敗,其後的命令仍然會被執行,沒有回滾。

主從複製

Redis的複製也就是咱們所說的主從複製,主機數據更新後根據配置和策略,自動同步到備機的master/slaver機制,master已寫爲主,slaver已讀爲主。

實現

  • 配置規則:配從不配主
  • 從庫配置:slaveof 主庫ip 端口,slaveof 192.168.123.100 6379。
  • 每次slaver與master斷開以後都得從新鏈接,除非寫進配置文件redis.conf
  • 使用info replication查看當前server的s-m關係。

特色

  • 一旦s-m replicaiton造成,s將共享m的全部數據,鏈接以後從頭開始複製全部數據。
  • s只有讀權限。
  • s-m數據存在必定延遲。
  • m宕機以後,從機將原地待命並保留m全部的數據(m最後一次的數據保存可能會丟失),主機從新鏈接以後與從機從新創建s-m replication關係,而且主機的新添記錄仍能同步到從機。
  • 可經過slaveof no one命令使當前數據庫中止與其餘數據的同步,轉成主數據庫。

Sentinel

Sentinel是Redis高可用的解決方案,由一個或多個Sentinel實例組成的Sentinel系統能夠監視多個主服務器,以及這些主服務器屬下的全部從服務器,並在被監視的主服務器進行下線時自動將屬下的某個從服務器升級爲新的主服務器,而後由新的主服務器代替已下線的主服務器繼續處理命令請求。

Redis提供的Sentinel(哨兵)機制,經過Sentinel模式啓動Redis後,自動監控master/slaver的運行狀態,基本原理:心跳機制和投票裁決。

  • 監控:Sentinel會不斷的檢查主服務器和從服務器是否正常。
  • 提醒:當被監控的某個Redis服務器出現問題以後,Sentinel能夠經過API向管理者或者其餘的應用程序發送通知。
  • 自動故障遷移:當一個主服務器不能正常工做時,Sentinel會開始一次自動故障操做,它會將失效的主服務器的其餘一臺從服務器升級爲新的主服務器,並讓失效的主服務器的其餘從服務器改成複製新的主服務器。當客戶端試圖鏈接失效的主服務器時,集羣也會向客戶端返回新服務器的地址,使得集羣可使用新主服務器代替失效服務器。

Sentinel主從原理

服務器與Sentinel系統

clipboard.png

主服務器下線

clipboard.png

故障轉移

clipboard.png

原來的M從新進入s-m replicaiton將自動降爲s

clipboard.png

參考

Redis設計與實現
Redis 講解系列之 Redis的持久化
Redis 講解系列之 Redis的事務
Redis 講解系列之 Redis的複製(一)
Redis 講解系列之 Redis的複製(二)

相關文章
相關標籤/搜索