Redis

Redis 描述
Redis Redis是一個開源的使用C語言編寫、支持網(wǎng)絡(luò)、可基于內(nèi)存亦可持久化的日志型寄雀、Key-Value數(shù)據(jù)庫

數(shù)據(jù)類型

/*
 * SDS
 */
struct sdshdr {
    int len;
    int free;
    char buf[]; 
};

String 描述
String 采用SDS結(jié)構(gòu)進行存儲
sds Redis在為一個字符串創(chuàng)建一個sds 對象時,通常會申請比字符串長度更長的字節(jié)數(shù)組盐肃,Redis將字符串保存進這個數(shù)組,同時在len這個變量保存字符串的長度权悟,再用free這個變量保存buf尚未使用的字節(jié)數(shù)量
內(nèi)存分配 通過申請更多的內(nèi)存砸王,減少字符串修改時內(nèi)存的分配次數(shù)
二進制安全 C字符串不能包含空字符,因為先被程序讀入的空字符會被誤認為字符串的結(jié)束峦阁,只能保存純文本數(shù)據(jù)谦铃,sds 長度是根據(jù)len決定的,即使內(nèi)容中含有空字符串榔昔,也對數(shù)據(jù)的完整性也沒有任何影響
鏈表 描述
單鏈表 鏈表中的數(shù)據(jù)是以結(jié)點來表示的驹闰,每個結(jié)點的構(gòu)成:元素(數(shù)據(jù)元素的映象) + 指針(指示后繼元素存儲位置),元素就是存儲數(shù)據(jù)的存儲單元撒会,指針就是連接每個結(jié)點的地址數(shù)據(jù)
優(yōu)點 任意位置添加刪除元素的都非常的快
缺點 查找方便嘹朗,不適合隨機查找
雙鏈表 結(jié)點即要保存到下一個元素的指針,還要保存一個上一個元素的指針
typedef struct listNode {
    // 前置節(jié)點
    struct listNode *prev;
    // 后置節(jié)點
    struct listNode *next;
    // 節(jié)點的值
    void *value;
} listNode;
image.png
壓縮列表 描述
ziplist 壓縮列表是列表诵肛、哈希的底層實現(xiàn)之一屹培,壓縮列表可以包含多個節(jié)點,每個節(jié)點保存一個字節(jié)數(shù)組或者整數(shù)值
image.png
壓縮列表節(jié)點 描述
previous_entry_length 記錄了壓縮列表中前一個節(jié)點的長度
encoding 數(shù)據(jù)類型以及長度
content 節(jié)點值
List 總結(jié)
list list = 壓縮列表 或者 雙鏈表怔檩,雙鏈表廣泛運用在List/發(fā)布與訂閱/慢查詢/監(jiān)控器等
/*
 * 字典
 */
typedef struct dict {
    dictType *type;
    void *privdata;
    // 哈希表褪秀,每個字典包含兩個table
    //一般情況下字典只使用ht[0]這個哈希表,ht[1]只會在對哈希表進行rehash時才會使用
    dictht ht[2];    
    int rehashidx; 
    int iterators; 
} dict;

typedef struct dictht {
    dictEntry **table;  // 哈希表數(shù)組 ,存儲dictEntry
    unsigned long size;
    unsigned long sizemask;
    unsigned long used;
} dictht;
/*
 * hash表節(jié)點
 */
typedef struct dictEntry {
    void *key;  // 鍵
    union {   // 值
        void *val;
        uint64_t u64;
        int64_t s64;
    } v;
    struct dictEntry *next;  // 指向下個哈希表節(jié)點薛训,形成鏈表
} dictEntry
hash 描述
哈希算法 當(dāng)要將一個新的鍵值對添加到字典里面時媒吗,程序會根據(jù)鍵計算出哈希值和索引值,然后再根據(jù)索引值將新鍵值對放到哈希表數(shù)組指定的索引上
鍵沖突 兩個不同的鍵值對(key相同覆蓋乙埃,不同放入鏈表)闸英,計算出的哈希值和索引值是一樣的锯岖,使用鏈地址法:每個hash節(jié)點都有一個next指針,指向下一個元素存儲位置自阱,形成一個單鏈表(取值時直接比較key是否相等)
字典 每個字典包含兩張哈希表數(shù)組,一般情況下字典只使用ht[0]這個哈希表嚎莉,ht[1]只會在對哈希表進行rehash時才會使用
rehash 哈希表擴展或者收縮時米酬,將現(xiàn)有哈希表的所有鍵值對rehash到另外一張哈希表沛豌。但是這個rehash動作并不是一次性完成的,而是分多次漸進式完成的(鍵值對過多時赃额,一次性rehash肯定會消耗服務(wù)器大量的計算資源)
/*
 * 整數(shù)集合
 */
typedef struct intset {   
    uint32_t encoding;
    uint32_t length;
    int8_t contents[]; // 保存元素的數(shù)組
} intse

無序集合 描述
set 使用了intset和hashtable兩種數(shù)據(jù)結(jié)構(gòu)存儲的
整數(shù)集合 intset存儲條件:①結(jié)合對象保存的所有元素都是整數(shù)值②集合對象保存的元素數(shù)量不超過512個; 整數(shù)集合數(shù)組元素從小到大有序地排列加派,并且數(shù)組中不包含任何重復(fù)項
跳躍表性質(zhì)
由很多層結(jié)構(gòu)組成
每一層都是一個有序的鏈表
最底層(Level 1)的鏈表包含所有元素
如果一個元素出現(xiàn)在 Level i 的鏈表中,則它在 Level i 之下的鏈表也都會出現(xiàn)
每個節(jié)點包含兩個指針跳芳,一個指向同一鏈表中的下一個元素芍锦,一個指向下面一層的元素
image.png
typedef struct zskiplistNode {
    //層
    struct zskiplistLevel {
        struct zskiplistNode *forward;//前進指針
        unsigned int span;//跨度
    } level[];
    struct zskiplistNode *backward; //后退指針
    double score; //分值
    robj *obj; //成員對象
} zskiplistNode;

typedef struct zskiplist {
    struct zskiplistNode *header, *tail;  //表頭節(jié)點和表尾節(jié)點
    unsigned long length;  //表中節(jié)點的的數(shù)量
    int level;  //表中層數(shù)最大的節(jié)點層數(shù)
} zskiplist;
有序集合 描述
zset 跳躍表或者壓縮列表

內(nèi)存回收

typedef struct redisObject {
    // ...
    // 引用計數(shù)
    int refcount;
    // ...
} robj;
內(nèi)存回收
Redis 構(gòu)建了一個由引用計數(shù)實現(xiàn)的內(nèi)存回收機制,通過這一機制飞盆,程序可以通過跟蹤對象的引用技術(shù)信息娄琉,在適當(dāng)?shù)臅r候自動釋放對象并進行內(nèi)存回收

對象共享

對象共享
Redis 在初始化服務(wù)器時,會創(chuàng)建一萬個字符串對象吓歇,這些對象包含了 0 到 9999 的所有整數(shù)值孽水。當(dāng)服務(wù)器需要用到值為 0 到 9999 的字符串對象時,服務(wù)器就會使用這些共享對象城看。此外每被一個建引用對象的引用計數(shù)加一

redis數(shù)據(jù)庫

redis數(shù)據(jù)庫 描述
redisServer Redis是一個字典結(jié)構(gòu)的存儲服務(wù)器女气,默認支持16個數(shù)據(jù)庫
redisClient 可以指向不同數(shù)據(jù)庫,達到切換目標數(shù)據(jù)庫的目的
redisDb dict保存所有的鍵值對测柠,每一個建都是字符串炼鞠,每一個值都可以是任意Redis基本類型
struct redisServer {
    redisDb *db; //一個數(shù)組,保存著服務(wù)器中的所有數(shù)據(jù)庫
    int dbnum;  //根據(jù)dbnum屬性創(chuàng)建服務(wù)器的數(shù)據(jù)庫數(shù)量,默認16
};

typedef struct redisClient {
    redisDb *db;  //這個屬性指向了redisDb數(shù)組的其中一個元素
} redisClient;

typedef struct redisDb {
    dict *dict;     //屬于redisDb *db數(shù)組結(jié)構(gòu)轰胁, 保存所有的鍵值對
} redisDb;

建過期

建過期 描述
expires 過期字典谒主,鍵指向dict的某一個鍵值對,值保存過期時間
過期時間查詢 過期時間減去當(dāng)前時間得到鍵剩余時間:TTL(秒為單位返回鍵的剩余生存時間) /PTTL(毫秒為單位返回鍵的剩余生存時間)
過期鍵判斷 當(dāng)前時間戳跟過期時間戳比較赃阀, 當(dāng)前時間戳大于過期時間戳代表過期
typedef struct redisDb {
    dict *expires;   //過期字典瘩将,保存鍵過期時間  
} redisDb;

過期建刪除

刪除策略 描述
定時刪除 在設(shè)置鍵的過期時間的同時,創(chuàng)建一個定時器(timer)凹耙,讓定時器在鍵的過期時間來臨時姿现,立即執(zhí)行對鍵的刪除操作
惰性刪除(對于CPU是最友好的) 放任鍵過期不管,但是每次從鍵空間中獲取鍵時肖抱,都檢查取得的鍵是否過期备典,如果過期的話,就刪除該鍵意述;如果沒有過期提佣,就返回該鍵
定期刪除 每隔一段時間吮蛹,程序就對數(shù)據(jù)庫進行一次檢查,刪除里面的過期鍵拌屏。至于要刪除多少過期鍵潮针,以及要檢查多少個數(shù)據(jù)庫,則由算法決定

RDB/AOF過期鍵處理

過期鍵處理 描述
生成RDB 執(zhí)行SAVE命令或者BGSAVE命令所產(chǎn)生的新RDB文件不會包含已經(jīng)過期的鍵
載入RDB 服務(wù)器開啟了RDB 功能的情況倚喂,主服務(wù)器啟動時每篷,會檢查所有鍵并忽略過期鍵,從服務(wù)器啟動時無論是否過期都會載入RDB(主從同步時端圈,從庫RDB會被清空)
重寫AOF BGREWRITEAOF:重寫AOF文件不會包含已經(jīng)過期的鍵
AOF持久化運行模式 當(dāng)一個鍵被惰性或者定期刪除焦读,服務(wù)器會追加一條DEL命令到現(xiàn)有AOF文件的末尾,顯式地刪除過期鍵

RDB

RDB 描述
RDB RDB用于保存和還原所有字典的鍵值對
SAVE 由服務(wù)器進程直接操作舱权,阻塞其他命令
BGSAVE 服務(wù)器子進程操作矗晃,不會阻塞
自動間隔保存 redis容許用戶手動配置save選項,當(dāng)滿足條件時宴倍,自動觸發(fā)BGSAVE 命令
dirty計數(shù)器 后數(shù)據(jù)庫每修改一次dirty屬性自增1,執(zhí)行save或者bgsave操作命令之后清空零
lastsave 記錄上一次成功執(zhí)行save或者bgsave操作命令的時間
檢查保存條件是否滿足 周期性檢查dirty屬性和lastsave屬性是否滿足了savparam條件张症,滿足就執(zhí)行BGSAVE
struct redisServer{
    struct saveparam *saveparams;  //記錄保存條件的數(shù)組
};
/** redis容許用戶手動配置save選項,當(dāng)滿足條件時鸵贬,自動觸發(fā)BGSAVE 命令 */
struct savparam{
    time_t seconds;  //秒數(shù)
    int changes;  //修改數(shù)
};
struct redisServer{
    long long dirty;   //修改計數(shù)器
    time_t lastsave;  //上一次執(zhí)行保存操作的時間
}; 


AOF

AOF 描述
AOF 保存Redis服務(wù)器所執(zhí)行的寫命令來記錄數(shù)據(jù)庫狀態(tài)的
命令追加 服務(wù)器在執(zhí)行完一個寫入命令之后俗他,會以協(xié)議格式將被執(zhí)行的寫入命令追加到服務(wù)器狀態(tài)的aof_buf緩存區(qū)的末尾(如:set 命令)
文件寫入與同步 服務(wù)器每次結(jié)束一個事件循環(huán)之前, 它都會調(diào)用flushAppendOnlyFile函 數(shù)恭理, 考慮是否需要將aof_buf緩沖區(qū)中的內(nèi)容寫人和保存到AOF文件里面
文件載入與還原 因為AOF文件里面包含了重建數(shù)據(jù)庫狀態(tài)所需的所有寫命令拯辙,所以服務(wù)器只要讀人并重新執(zhí)行一遍AOF文件里面保存的寫命令, 就可以還原服務(wù)器關(guān)閉之前的數(shù)據(jù)庫狀態(tài)
struct redisServer{
    sds aof_buf;   // aof 緩存區(qū)
}:
image.png

image.png

事件

事件 描述
事件驅(qū)動 Redis服務(wù)器是一個事件驅(qū)動器颜价,服務(wù)器需要處理以下兩類事件:文件事件與時間事件
文件事件 通過I/O多路復(fù)用程序來同時監(jiān)聽多個套接字對應(yīng)分配處理事件
文件事件原理 基于Reactor模式
時間事件 Redis時間事件分為兩大類:定時事件與周期性事件
時間事件原理 Redis服務(wù)器會將所有的時間事件放入到一個鏈表涯保,每當(dāng)時間事件執(zhí)行器運行時,它就遍歷整個鏈表周伦,查找所有已經(jīng)到達的時間事件,并調(diào)用相應(yīng)的事件處理器

在3.0的版本中,服務(wù)器只有一個serverCron的時間事件
1.更新服務(wù)器的各類統(tǒng)計信息速侈,比如時間倚搬、內(nèi)存占用,數(shù)據(jù)庫占用情況等;
2.清理數(shù)據(jù)庫中過期的鍵值空間馒闷;
3.關(guān)閉和清理實現(xiàn)的客戶端連接航揉;
4.嘗試進行AOF或RDB持久化操作尤蛮;
5.如果是主服務(wù)器,會定期的對從服務(wù)器進行同步;
6.如果處于集群模式,對集群定期的進行同步和連接測試

image.png

Redis單線程

Redis單線程 描述
Redis服務(wù)器 服務(wù)器狀態(tài)結(jié)構(gòu)使用clients鏈表連接多個客戶端狀態(tài),新添加的客戶端狀態(tài)會被放到鏈表末尾
struct redisServer {
    list *clients;  //一個鏈表,保存所有的客戶端狀態(tài)
};

Redis是單線程的,為何不利用多個CPU ?
官方解釋:CPU通常Redis的瓶頸,瓶頸一般是內(nèi)存或網(wǎng)絡(luò)IO。

訂閱頻道

訂閱頻道 描述
SUBSCRIBE 訂閱頻道,將客戶端添加到鏈表的末尾
PUBLISH 發(fā)送消息到頻道
UNSUBSCRIBE 它從 pubsub_channels 字典的給定頻道(鍵)中乃沙, 刪除關(guān)于當(dāng)前客戶端的信息
struct redisServer {
    dict *pubsub_channels;  //鍵代表被訂閱的頻道, 值代表鏈表,保存了所有訂閱這個頻道的客戶端
};

def SUBSCRIBE(client, channels):  //偽代碼
    #遍歷所有輸入頻道
    for channel in channels:
        # 將客戶端添加到鏈表的末尾
        redisServer.pubsub_channels[channel].append(client)

def PUBLISH(channel, message):  //偽代碼
    # 遍歷所有訂閱頻道 channel 的客戶端
    for client in server.pubsub_channels[channel]:
        # 將信息發(fā)送給它們
        send_message(client, message)

訂閱評定與訂閱模式

客戶端A發(fā)送消息給news.it頻道,客戶端C、客戶端D同樣受到消息(PUBLISH 命令發(fā)送信息到某個頻道時,訂閱頻道客戶端 與 匹配訂閱模式的的客戶端同樣受到信息)

image.png

訂閱模式

訂閱模式 描述
SUBSCRIBE 訂閱模式
PUNSUBSCRIBE 程序會刪除 redisServer.pubsub_patterns 鏈表中, 所有和被退訂模式相關(guān)聯(lián)的 pubsubPattern 結(jié)構(gòu)
struct redisServer {
    list *pubsub_patterns;  //一個鏈表
};

typedef struct pubsubPattern {
    redisClient *client;  //訂閱模式的客戶端
    robj *pattern;  //訂閱的模式
} pubsubPattern;

def PUBLISH(channel, message):   //完整的PUBLISH偽代碼
    # 遍歷所有訂閱頻道 channel 的客戶端
    for client in server.pubsub_channels[channel]:
        # 將信息發(fā)送給它們
        send_message(client, message)
    # 取出所有模式托嚣,以及訂閱模式的客戶端
    for pattern, client in server.pubsub_patterns:
        # 如果 channel 和模式匹配
        if match(channel, pattern):
            # 那么也將信息發(fā)給訂閱這個模式的客戶端
            send_message(client, message)

事物

事物 描述
事物概念 事務(wù)提供了一種“將多個命令打包示启, 然后一次性、按順序地執(zhí)行”的機制郑诺, 并且事務(wù)在執(zhí)行的期間不會主動中斷 —— 服務(wù)器在執(zhí)行完事務(wù)中的所有命令之后轻抱, 才會繼續(xù)處理其他客戶端的其他命令
MULTI 讓客戶端從非事務(wù)狀態(tài)切換到事務(wù)狀態(tài),將這些命令全部放進一個事務(wù)隊列
事務(wù)隊列 一個數(shù)組(參數(shù):執(zhí)行的命令,命令的參數(shù)容燕,參數(shù)的個數(shù))
EXEC 服務(wù)器根據(jù)客戶端所保存的事務(wù)隊列梁呈, 以先進先出(FIFO)的方式執(zhí)行事務(wù)隊列中的命令
DISCARD 取消一個事務(wù), 清空客戶端的整個事務(wù)隊列
帶 WATCH 的事務(wù) 事務(wù)開始之前監(jiān)視任意數(shù)量的鍵: 當(dāng)調(diào)用 EXEC 命令執(zhí)行事務(wù)時蘸秘, 如果任意一個被監(jiān)視的鍵已經(jīng)被其他客戶端修改了官卡, 那么整個事務(wù)不再執(zhí)行, 直接返回失敗
watched_keys 鍵被監(jiān)視的鍵醋虏, 值則是一個鏈表寻咒, 鏈表中保存了所有監(jiān)視這個鍵的客戶端
WATCH 原理 將當(dāng)前客戶端和要監(jiān)視的鍵在 watched_keys 中進行關(guān)聯(lián)
WATCH 觸發(fā) 在任何對數(shù)據(jù)庫鍵空間進行修改的命令成功執(zhí)行之后,檢查數(shù)據(jù)庫 watched_keys 字典, 查找被修改的客戶端并打開REDIS_DIRTY_CAS 標識
WATCH 事物下 執(zhí)行 EXEC 命令 REDIS_DIRTY_CAS 標識被打開代表事務(wù)的安全性已經(jīng)被破壞颈嚼,清空清空事務(wù)隊列并返回
def execute_transaction():  //事務(wù)的整個執(zhí)行過程偽代碼
    # 創(chuàng)建空白的回復(fù)隊列
    reply_queue = []
    # 取出事務(wù)隊列里的所有命令毛秘、參數(shù)和參數(shù)數(shù)量
    for cmd, argv, argc in client.transaction_queue:
        # 執(zhí)行命令,并取得命令的返回值
        reply = execute_redis_command(cmd, argv, argc)
        # 將返回值追加到回復(fù)隊列末尾
        reply_queue.append(reply)
    # 清除客戶端的事務(wù)狀態(tài)
    clear_transaction_state(client)
    # 清空事務(wù)隊列
    clear_transaction_queue(client)
    # 將事務(wù)的執(zhí)行結(jié)果返回給客戶端
    send_reply_to_client(client, reply_queue)
typedef struct redisDb {
    dict *watched_keys;  //鍵被監(jiān)視的鍵, 值則是一個鏈表叫挟, 鏈表中保存了所有監(jiān)視這個鍵的客戶端
} redisDb;

事物

事務(wù)的 ACID 性質(zhì) 描述
原子性(Atomicity) 單個 Redis 命令的執(zhí)行是原子性的艰匙,但 Redis 事務(wù)的執(zhí)行并不是原子性的,當(dāng)事務(wù)失敗時,Redis 也不會進行任何的重試或者回滾動作
一致性(Consistency) Redis的事務(wù)并不具有一致性抹恳,①入隊錯誤(發(fā)送錯誤命令旬薯,EXEC 命令時返回拒絕執(zhí)行)②執(zhí)行錯誤(執(zhí)行過程錯誤,也不會影響后面要執(zhí)行的事務(wù)命令)③Redis 進程被終結(jié)( Redis 服務(wù)器進程在執(zhí)行事務(wù)的過程中被其他進程終結(jié)适秩,或者被管理員強制殺死且沒有采取任何持久化機制绊序,重啟之后的數(shù)據(jù)庫總是空白的)
隔離性(Isolation) Redis 是單進程程序,并且它保證在執(zhí)行事務(wù)時秽荞,不會對事務(wù)進行中斷骤公,事務(wù)可以運行直到執(zhí)行完所有事務(wù)隊列中的命令為止。因此扬跋,Redis 的事務(wù)是總是帶有隔離性的
持久性(Durability) 事務(wù)的持久性由 Redis 所使用的持久化模式?jīng)Q定

復(fù)制

復(fù)制 描述
復(fù)制 通過執(zhí)行SLAVEOF命令或設(shè)置slaveof選項阶捆,可以讓一個服務(wù)器去復(fù)制另一個服務(wù)器

舊版復(fù)制

舊版復(fù)制 描述
同步(sync) 同步操作用于將從服務(wù)器的數(shù)據(jù)庫狀態(tài)更新至主服務(wù)器當(dāng)前所處的數(shù)據(jù)庫狀態(tài)
命令傳播(command propagate) 命令傳播操作則用于在主服務(wù)器的數(shù)據(jù)庫狀態(tài)被修改,導(dǎo)致主從服務(wù)器的數(shù)據(jù)庫狀態(tài)出現(xiàn)不一致時钦听,主服務(wù)器會將自己執(zhí)行的寫命令洒试,發(fā)送給從服務(wù)器執(zhí)行

同步過程
①從服務(wù)器向主服務(wù)器發(fā)送SYNC命令;
②收到SYNC命令的主服務(wù)器執(zhí)行BGSAVE命令朴上,在后臺生成一個RDB文件垒棋,并使用一個緩沖區(qū)記錄從現(xiàn)在開始執(zhí)行的所有寫命令;
③當(dāng)主服務(wù)器的BGSAVE命令執(zhí)行完畢時痪宰,主服務(wù)器會將BGSAVE命令生成的RDB文件發(fā)送給從服務(wù)器叼架,從服務(wù)器接收并載入這個RDB文件,將自己的數(shù)據(jù)庫狀態(tài)更新至主服務(wù)器執(zhí)行BGSAVE命令時的數(shù)據(jù)庫狀態(tài)衣撬。
④主服務(wù)器將記錄在緩沖區(qū)里面的所有寫命令發(fā)送給從服務(wù)器乖订,從服務(wù)器執(zhí)行這些寫命令,將自己的數(shù)據(jù)庫狀態(tài)更新至主服務(wù)器數(shù)據(jù)庫當(dāng)前所處的狀態(tài)具练。

新版復(fù)制

新版復(fù)制 描述
PSYNC 解決舊版在處理重復(fù)制的低效率問題乍构,分為完整重同步和部分重同步,分別用于處理初次復(fù)制(與SYNC命令一樣)和斷線后重復(fù)制

部分重同步

部分重同步 描述
部分重同步 分為三個部分:①主從服務(wù)器的復(fù)制偏移量②主服務(wù)器復(fù)制積壓緩沖區(qū)③服務(wù)器運行ID
主從服務(wù)器的復(fù)制偏移量 主從服務(wù)器會分別維護一個復(fù)制偏移量,通過對比偏移量扛点,可以知道主從服務(wù)器是否處于一致狀態(tài),不一致則執(zhí)行部分重同步
偏移量 主服務(wù)器每次向從服務(wù)器傳播N個字節(jié)的數(shù)據(jù)時哥遮,就將自己的復(fù)制偏移量的值加上N;從服務(wù)器每次收到主服務(wù)器傳播來的N個字節(jié)的數(shù)據(jù)時占键,就將自己的復(fù)制偏移量的值加上N昔善;
主服務(wù)器復(fù)制積壓緩沖區(qū) 主服務(wù)器維護一個固定長度先進先出的隊列,即為復(fù)制積壓緩沖區(qū),保存一部分最近傳播的寫命令畔乙,且為每個字節(jié)記錄相應(yīng)的復(fù)制偏移量
服務(wù)器運行ID 當(dāng)斷線重連時君仆,用來判斷從服務(wù)器與上次連接的是否為同一主服務(wù)器

sentinel

image.png
sentinel 描述
sentinel redis主從復(fù)制可將主節(jié)點數(shù)據(jù)同步給從節(jié)點,一旦主節(jié)點宕機,從節(jié)點作為主節(jié)點的備份可以隨時頂上來
啟動并初始化sentinel 初始化sentinel分別為5個步驟
①初始化服務(wù)器 Sentinel的本質(zhì)是一個運行在特殊模式下的Redis服務(wù)器返咱,不需要使用數(shù)據(jù)庫钥庇,因此不載入RDB或者AOF
②將普通 Redis 服務(wù)器使用的代碼替換成 Sentinel 專用代碼 將普通Redis服務(wù)器使用的代碼替換成Sentinel專用的代碼 ,命令表中部分命令不載入咖摹,所以sentinel 部分命令無法使用(如:鍵值對命令评姨,持久化命令,事物命令萤晴,腳本命令)
③初始化 Sentinel 狀態(tài) 保存了服務(wù)器所有和Sentinel功能有關(guān)的狀態(tài)
④根據(jù)給定的配置文件吐句, 初始化 Sentinel 的監(jiān)視主服務(wù)器列表 將sentinel狀態(tài)的 masters 屬性進行初始化,masters 里面保存的是所有被監(jiān)視的主服務(wù)器的信息以及其鍵值對應(yīng)保存的是什么內(nèi)容
⑤創(chuàng)建連向主服務(wù)器的網(wǎng)絡(luò)連接 創(chuàng)建連向被監(jiān)視主服務(wù)器的網(wǎng)絡(luò)連接店读,Sentinel將成為主服務(wù)器的客戶端嗦枢,可以向主服務(wù)器發(fā)送命令,并從命令回復(fù)中獲取相關(guān)的信息 (兩個連向主服務(wù)器的異步網(wǎng)絡(luò)連接:命令連接屯断,用于向主服務(wù)器發(fā)送命令文虏,并接收命令回復(fù),訂閱連接殖演,用于訂閱主服務(wù)器的 sentinel:hello 頻道)
獲取主服務(wù)器信息 Sentinel 默認每十秒一次氧秘,向監(jiān)視的主服務(wù)器發(fā)送 INFO 命令,并分析 INFO 命令的回復(fù)來 獲取主服務(wù)器當(dāng)前信息 以及 主服務(wù)器屬下的所有從服務(wù)器信息
獲取從服務(wù)器信息 當(dāng)Sentinel發(fā)現(xiàn)主服務(wù)器有新的服務(wù)器出現(xiàn)時趴久,除了會為這個新從服務(wù)器創(chuàng)建相應(yīng)的實例結(jié)構(gòu)之外丸相,還會創(chuàng)建連接到從服務(wù)器的命令連接和訂閱連接
Sentinel 發(fā)送與接收 在建立起訂閱連接之后 ,通過頻道向主服務(wù)器和從服務(wù)器發(fā)送和接收信息
檢測主觀下線 發(fā)送 PING 命令,并通過實例返回的 PING 命令回復(fù)來判斷實例是否在線(指的是單個 Sentinel 實例對服務(wù)器做出的下線判斷)
檢測客觀下線 當(dāng)sentinel監(jiān)視的某個服務(wù)主觀下線后朋鞍,sentinel會詢問其它監(jiān)視該服務(wù)的sentinel已添,看它們是否也認為該服務(wù)主觀下線(超過半數(shù)就為主觀下線,指的是多個 Sentinel 實例在對同一個服務(wù)器做出 SDOWN 判斷)
選舉領(lǐng)頭sentinel 當(dāng)一個主服務(wù)器被判斷為客觀下線時滥酥,監(jiān)視這個下線主服務(wù)器的各個Sentinel會進行協(xié)商,選舉出一個領(lǐng)頭Sentinel畦幢,并由領(lǐng)頭Sentinel對下線主服務(wù)器進行故障轉(zhuǎn)移操作
故障轉(zhuǎn)移 領(lǐng)頭Sentinel挑選一個狀態(tài)良好坎吻、數(shù)據(jù)完整的從服務(wù)器,然后發(fā)送 SLAVEOF no one 命令宇葱,然后將這個從服務(wù)器轉(zhuǎn)換成主服務(wù)器

集群

集群 描述
集群 Redis集群是分布式數(shù)據(jù)庫方案瘦真,通過分片來進行數(shù)據(jù)共享,并提供復(fù)制和故障轉(zhuǎn)移功能
節(jié)點 一個Redis 集群通常由多個節(jié)點組成黍瞧,每個節(jié)點都是獨立的,想要構(gòu)建成一個包含多個節(jié)點的集群诸尽,可以向一個節(jié)點發(fā)送 CLUSTER MEET <ip> <port>命令,可以讓節(jié)點與ip和port所指定的節(jié)點進行握手印颤,握手成功節(jié)點就會將ip和port指定的節(jié)點添加到當(dāng)前的集群中
啟動節(jié)點 節(jié)點的本質(zhì)還是服務(wù)器您机,服務(wù)器會根據(jù) cluster-enabled(redis.conf配置項) 配置選項來決定是否開啟集群模式
Redis集群使用分片方式保存鍵值對,整個集群分為16384 個槽,每個鍵值對都屬于槽的其中一個
槽指派 集群槽可以指派給各個節(jié)點际看, 當(dāng)數(shù)據(jù)庫中的 16384 個槽都有節(jié)點在處理時咸产,集群處于上線狀態(tài),否則仲闽,處于下線狀態(tài)
集群中的執(zhí)行命令 數(shù)據(jù)庫向節(jié)點發(fā)送鍵命令脑溢,會判斷槽是否由當(dāng)前節(jié)點,如果當(dāng)節(jié)點發(fā)現(xiàn)鍵所在的槽并非由自己負責(zé)處理的時候赖欣,就會向客戶端返回一個 MOVED 錯誤屑彻,指引客戶端轉(zhuǎn)向正在負責(zé)槽的節(jié)點 ,如果是則進行執(zhí)行
重新分片 Redis集群的重新分片操作可以將任意數(shù)量已經(jīng)指派給原本節(jié)點的槽 改為指派給目標節(jié)點顶吮,并且相關(guān)槽所屬的鍵值對也會從源節(jié)點移動到目標節(jié)點
ASK 錯誤 在重新分片期間酱酬,源節(jié)點向目標節(jié)點遷移一個槽的過程中,可能會出現(xiàn)這樣一種情況:屬于被遷移槽的一部分鍵值對保存在源節(jié)點里面云矫,而另一部分鍵值對保存在目標節(jié)點中 ------ 當(dāng)客戶端向源節(jié)點發(fā)送關(guān)于鍵key的命令膳沽,源節(jié)點先在自己的數(shù)據(jù)庫里查找這個鍵,如果找到就直接返回執(zhí)行客戶端命令让禀,如果沒找到挑社,這個鍵可能已經(jīng)被遷移到了目標節(jié)點,源節(jié)點向客戶端返回一個 ASK 錯誤巡揍,指引客戶端轉(zhuǎn)向正在導(dǎo)入槽的目標節(jié)點痛阻,并再次發(fā)送之前要執(zhí)行的命令
復(fù)制與故障轉(zhuǎn)移 Redis集群分為主節(jié)點與從節(jié)點,主節(jié)點處理槽腮敌,從節(jié)點負責(zé)復(fù)制某節(jié)點
故障檢測 集群中的每個節(jié)點都會定期地想集群中的其他節(jié)點發(fā)送 PING 消息阱当,以此來檢測對方是否在線
故障轉(zhuǎn)移 當(dāng)一個從節(jié)點發(fā)現(xiàn)自己正在復(fù)制的主節(jié)點進入了已下線狀態(tài),從節(jié)點將開始對下線主節(jié)點進行故障轉(zhuǎn)移:被選中的從節(jié)點將執(zhí)行 slaveof no one 命令糜工,成為新的主節(jié)點弊添,并將這些槽全部指派給自己,新的主節(jié)點向集群廣播一條PONG消息捌木,告訴集群中的其他節(jié)點自己成為了新的主節(jié)點

redis常見問題

(一)緩存和數(shù)據(jù)庫雙寫一致性問題
(二)緩存雪崩問題
(三)緩存擊穿問題
(四)緩存的并發(fā)競爭問題

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末油坝,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子刨裆,更是在濱河造成了極大的恐慌澈圈,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件帆啃,死亡現(xiàn)場離奇詭異瞬女,居然都是意外死亡,警方通過查閱死者的電腦和手機努潘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進店門诽偷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來坤学,“玉大人,你說我怎么就攤上這事渤刃∮德停” “怎么了?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵卖子,是天一觀的道長略号。 經(jīng)常有香客問我,道長洋闽,這世上最難降的妖魔是什么玄柠? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮诫舅,結(jié)果婚禮上羽利,老公的妹妹穿的比我還像新娘。我一直安慰自己刊懈,他們只是感情好这弧,可當(dāng)我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著虚汛,像睡著了一般匾浪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上卷哩,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天蛋辈,我揣著相機與錄音,去河邊找鬼将谊。 笑死冷溶,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的尊浓。 我是一名探鬼主播逞频,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼眠砾!你這毒婦竟也來了虏劲?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤褒颈,失蹤者是張志新(化名)和其女友劉穎励堡,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體刨疼,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡泉唁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了亭畜。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片迎卤。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡拴鸵,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蜗搔,到底是詐尸還是另有隱情,我是刑警寧澤聘芜,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布缝龄,位于F島的核電站叔壤,受9級特大地震影響瞎饲,放射性物質(zhì)發(fā)生泄漏企软。R本人自食惡果不足惜饭望,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一铅辞、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧斟珊,春花似錦囤踩、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽示惊。三九已至,卻和暖如春钧汹,著一層夾襖步出監(jiān)牢的瞬間录择,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工辨宠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留货裹,地道東北人。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓赋兵,卻偏偏與公主長得像搔预,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子拯田,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,843評論 2 354

推薦閱讀更多精彩內(nèi)容

  • NOSQL類型簡介鍵值對:會使用到一個哈希表船庇,表中有一個特定的鍵和一個指針指向特定的數(shù)據(jù)鸭轮,如redis,volde...
    MicoCube閱讀 3,981評論 2 27
  • redis簡介 redis是典型的NOSQL數(shù)據(jù)庫邑蒋,也是一個高性能的key-value型數(shù)據(jù)庫按厘。通過源碼對redi...
    江北曉白閱讀 485評論 0 2
  • 數(shù)據(jù)結(jié)構(gòu)部分 字符串(SDS) 數(shù)據(jù)結(jié)構(gòu)為如下: 優(yōu)點: 可以以常數(shù)復(fù)雜度獲取字符串的長度逮京,因為記錄了字符串的長度...
    良辰美景TT閱讀 581評論 0 0
  • 基于內(nèi)存的NoSQL數(shù)據(jù)庫造虏。提供五種數(shù)據(jù)結(jié)構(gòu)的存儲。字符串陶珠、列表享钞、集合、有序集合暑脆、散列表狐肢。Redis 支持很多特性...
    韓絕交閱讀 690評論 0 1
  • 泰國為什么窮份名? 因為這個國家從來沒被侵略過。 二戰(zhàn)傾斜日本僵腺,戰(zhàn)后傾向美利堅辰如,日本繁華后又親日,中國繁華后又親中凯正。 ...
    可可西里的UFO閱讀 535評論 0 0