12.24 Redis 數據結構 線程模型 持久化 內存淘汰 分佈式詳細總結

簡介

Redis 是一個開源的,內存中的數據結構存儲系統,它可以用作數據庫、緩存和消息中間件。 它支持多種類型的數據結構,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 與範圍查詢, bitmaps, hyperloglogs 和 地理空間(geospatial) 索引半徑查詢等。 Redis 內置了 複製(replication),LUA腳本(Lua>

為什麼使用緩存服務器

緩存是高併發場景下提高熱點數據訪問性能的一個有效手段,在開發項目時會經常使用到。

緩存的類型分為:本地緩存分佈式緩存多級緩存

本地緩存 就是在進程的內存中進行緩存,比如我們的 JVM 堆中,本地緩存是內存訪問,沒有遠程交互開銷,性能最好,但是受限於單機容量,一般緩存較小且無法擴展。

分佈式緩存一般都具有良好的水平擴展能力,對較大數據量的場景也能應付自如。缺點就是需要進行遠程請求,性能不如本地緩存。

為了平衡這種情況,實際業務中一般採用多級緩存,本地緩存只保存訪問頻率最高的部分熱點數據,其他的熱點數據放在分佈式緩存中。

Redis & Memcached

  • 數據結構:Memcached只支持簡單的key/value數據結構,不像Redis可以支持豐富的數據類型。
  • 持久化:Memcached無法進行持久化,數據不能備份,只能用於緩存使用,且重啟後數據全部丟失。
  • 多線程:Redis 使用單線程反而避免了多線程的頻繁上下文切換問題,預防了多線程可能產生的競爭問題。 Memcache 存在著支持併發性不好、可運維性欠佳、原子性操作不夠、在誤操作時產生數據不一致等問題。 由於 Redis 只使用單核,而 Memcached 可以使用多核,所以 Redis 在存儲小數據時比 Memcached 性能更高。而在 100k 以上的數據中,Memcached 性能要高於 Redis,雖然 Redis 最近也在存儲大數據的性能上進行優化,但是比起 Memcached,還是稍有遜色。
  • 分佈式:Redis原生支持集群模式,Memcached沒有原生的集群模式。 Redis 支持通過Replication進行數據複製,通過master-slave機制,可以實時進行數據的同步複製,支持多級複製和增量複製,master-slave機制是Redis進行HA的重要手段。

線程模型

Redis 數據結構 線程模型 持久化 內存淘汰 分佈式詳細總結

Redis 內部使用文件事件處理器 file event handler,這個文件事件處理器是單線程的,所以 Redis 才叫做單線程的模型。它採用 IO 多路複用機制同時監聽多個 Socket,根據 Socket 上的事件來選擇對應的事件處理器進行處理。


文件事件處理器的結構包含 4 個部分:

  • 多個 Socket
  • IO 多路複用程序
  • 文件事件分派器
  • 事件處理器(連接應答處理器、命令請求處理器、命令回覆處理器)

多個 Socket 可能會併發產生不同的操作,每個操作對應不同的文件事件,但是 IO 多路複用程序會監聽多個 Socket,會將 Socket 產生的事件放入隊列中排隊,事件分派器每次從隊列中取出一個事件,把該事件交給對應的事件處理器進行處理。

為什麼Redis單線程也能效率這麼高?

  • 完全基於內存,絕大部分請求是純粹的內存操作,非常快速。它的數據存在內存中,類似於HashMapHashMap 的優勢就是查找和操作的時間複雜度都是O(1);
  • 採用單線程,避免了不必要的上下文切換和競爭條件,也不存在多進程或者多線程導致的切換而消耗 CPU,不用去考慮各種鎖的問題,不存在加鎖釋放鎖操作,沒有因為可能出現死鎖而導致的性能消耗;
  • 使用多路I/O複用模型,非阻塞IO;
  • Redis 直接自己構建了 VM 機制 ,因為一般的系統調用系統函數的話,會浪費一定的時間去移動和請求;

數據結構

基本:StringHashListSetSortedSet

進階:HyperLogLog、Geo、Pub/Sub、bitmaps

高級:BloomFilter

基本

String:存儲簡單的對象序列化字符串,應用場景:緩存熱點數據、計數器、會話token

Hash:保存無嵌套的對象屬性

List:列表,應用場景:簡單消息隊列、分頁

Set:無序集合,自動去重,應用場景:共同好友

Sorted Set:有序集合,自動去重,應用場景:排行榜、微博熱搜

進階

Geo:可以用來保存地理位置,並作位置距離計算或者根據半徑計算位置等。 應用場景:附近的人

Pub/Sub:訂閱/發佈,應用場景:簡單消息隊列

HyperLogLog:用來做基數統計的算法 ,比如數據集 {1, 3, 5, 7, 5, 7, 8}, 那麼這個數據集的基數集為 {1, 3, 5 ,7, 8}, 基數(不重複元素)為5。 基數統計就是在誤差可接受的範圍內,快速計算基數。 應用場景:日活躍用戶

Bitmap:支持按bit位來存儲信息,等同於byte數組,計數效率高,應用場景:日活躍用戶、布隆過濾器


Redis 數據結構 線程模型 持久化 內存淘汰 分佈式詳細總結

ps:HyperLogLog只需要用12K內存就可以統計2^64個不同元素的基數

bitmaps存儲一億用戶需要12.5M內存

高級

BloomFilter

布隆過濾器可以用於檢索一個元素是否在一個集合中。它的優點是空間效率和查詢時間都遠遠超過一般的算法,缺點是有一定的誤識別率和刪除困難。 存在誤判,可能要查到的元素並沒有在容器中,但是hash之後得到的k個位置上值都是1。如果bloom filter中存儲的是黑名單,那麼可以通過建立一個白名單來存儲可能會誤判的元素。刪除困難。一個放入容器的元素映射到bit數組的k個位置上是1,刪除的時候不能簡單的直接置為0,可能會影響其他元素的判斷。

布隆過濾器的原理是,當一個元素被加入集合時,通過K個散列函數將這個元素映射成一個位數組中的K個點,把它們置為1。檢索時,我們只要看看這些點是不是都是1就(大約)知道集合中有沒有它了:如果這些點有任何一個0,則被檢元素一定不在;如果都是1,則被檢元素很可能在。這就是布隆過濾器的基本思想。

Bloom Filter跟單哈希函數Bit-Map不同之處在於:Bloom Filter使用了k個哈希函數,每個字符串跟k個bit對應。從而降低了衝突的概率。

Redis 數據結構 線程模型 持久化 內存淘汰 分佈式詳細總結

應用場景:允許一定誤差的大數據去重(舉個栗子:黑名單、推薦和瀏覽歷史去重)


底層數據結構

SDS

Redis 用SDS(Simple Dynamic String)來保存字符串,SDS還被用作緩衝區(buffer)AOF模塊中的AOF緩衝區。

<code>struct sdshdr {  
// buf 中已佔用空間的長度
int len;

// buf 中剩餘可用空間的長度
int free;

// 數據空間
char buf[];
}; /<code>

使用SDS的好處:

  • 便於獲取字符串長度
  • 杜絕緩衝區溢出
  • 減少修改字符串時帶來的內存重分配次數

鏈表

List的底層實現之一就是鏈表

<code>typedef struct listNode{
struct listNode *prev;
struct listNode * next;
void * value;
}

/<code>


Redis 數據結構 線程模型 持久化 內存淘汰 分佈式詳細總結


  • 雙端:鏈表節點帶有prev 和next 指針,獲取某個節點的前置節點和後置節點的時間複雜度都是O(N)
  • 無環:表頭節點的 prev 指針和表尾節點的next 都指向NULL,對立案表的訪問時以NULL為截止
  • 表頭和表尾:因為鏈表帶有head指針和tail 指針,程序獲取鏈表頭結點和尾節點的時間複雜度為O(1)
  • 長度計數器:鏈表中存有記錄鏈表長度的屬性 len
  • 整數集合

    整數集合是集合(set)的底層實現之一,當一個集合中只包含整數,且這個集合中的元素數量不多時,redis就會使用整數集合intset作為集合的底層實現。

    <code>typedef struct intset{
    //編碼方式
    uint32_t enconding;
    // 集合包含的元素數量
    uint32_t length;
    //保存元素的數組
    int8_t contents[];
    }
    複製代碼/<code>

    整數集合的底層實現為數組,這個數組以有序,無重複的範式保存集合元素,在有需要時,程序會根據新添加的元素類型改變這個數組的類型。

    字典

    字典,又稱為符號表(symbol table)、關聯數組(associative array)或映射(map),是一種用於保存鍵值對的抽象數據結構。類似HashMap,當發生哈希衝突時,採用頭插法向單向鏈表表頭插入元素。


    Redis 數據結構 線程模型 持久化 內存淘汰 分佈式詳細總結

    rehash的時候將ht[0]數據重新分配到ht[1]中,將ht[0]釋放,將ht[1]設置成ht[0],最後為ht[1]分配一個空白哈希表。


    Redis 數據結構 線程模型 持久化 內存淘汰 分佈式詳細總結

    然而在實際開發過程中,rehash 操作並不是一次性、集中式完成的,而是分多次、漸進式地完成的。


    漸進式rehash 的詳細步驟:

    1、為ht[1] 分配空間,讓字典同時持有ht[0]和ht[1]兩個哈希表

    2、在字典中維持一個索引計數器變量rehashidx,並將它的值設置為0,表示rehash 開始

    3、在rehash 進行期間,每次對字典執行CRUD操作時,程序除了執行指定的操作以外,還會將ht[0]中的數據rehash 到ht[1]表中,並且將rehashidx加1

    4、當ht[0]中所有數據轉移到ht[1]中時,將rehashidx 設置成-1,表示rehash 結束

    採用漸進式rehash 的好處在於它採取分而治之的方式,避免了集中式rehash 帶來的龐大計算量。

    跳錶

    跳錶(skiplist)是一種有序數據結構,它通過在每個節點中維持多個指向其他節點的指針,從而達到快速訪問節點的目的。跳躍表是一種隨機化的數據,跳躍表以有序的方式在層次化的鏈表中保存元素,效率和平衡樹媲美 ——查找、刪除、添加等操作都可以在對數期望時間下完成,並且比起平衡樹來說,跳錶的實現要簡單直觀得多。

    Redis 只在兩個地方用到了跳錶,一個是實現有序集合鍵,另外一個是在集群節點中用作內部數據結構

    Redis 數據結構 線程模型 持久化 內存淘汰 分佈式詳細總結

    跳錶數據結構其實相當於給原始鏈表加上多級索引


    Redis 數據結構 線程模型 持久化 內存淘汰 分佈式詳細總結

    ps: 跳錶是通過隨機函數來維護“平衡性”。當我們往跳錶中插入數據的時候,我們可以通過一個隨機函數,來決定這個結點插入到哪幾級索引層中,比如隨機函數生成了值K,那我們就將這個結點添加到第一級到第K級這個K級索引中。

    Redis 數據結構 線程模型 持久化 內存淘汰 分佈式詳細總結

    持久化

    RDB做鏡像全量持久化,AOF做增量持久化。因為RDB會耗費較長時間,不夠實時,在停機的時候會導致大量丟失數據,所以需要AOF來配合使用。

    RDB

    RDBRedis的性能影響非常小,是因為在同步數據的時候他只是fork了一個子進程去做持久化的,fork是指redis通過創建子進程來進行RDB操作,cow指的是copy on write,子進程創建後,父子進程共享數據段,父進程繼續提供讀寫服務,寫髒的頁面數據會逐漸和子進程分離開來。

    RDB在數據恢復時比AOF快,因為數據文件小,每條記錄只保存了一次,AOF一條記錄可能保存多次操作記錄。RDB文件的存儲格式和Redis數據在內存中的編碼格式是一致的,不需要再進行數據編碼工作,所以在CPU消耗上要遠小於AOF日誌的加載。

    缺點:快照截屏間隔可能較久,如果採用RDB進行持久化,服務掛掉可能造成更多數據的丟失;在生成快照時如果文件很大可能導致客戶端卡頓

    SAVE命令由服務器進程直接執行保存操作,會阻塞服務器。BGSAVE命令由子進程執行保存操作,不會阻塞服務器。

    服務器狀態中會保存所有用save選項設置的保存條件,當任意一個保存條件被滿足時,服務器會自動執行BGSAVE命令。

    AOF

    根據默認配置,RDB 五分鐘一次生成快照,但是 AOF 是一秒一次去通過一個後臺的線程fsync操作,那最多丟這一秒的數據。

    AOF在對日誌文件進行操作的時候是以 append-only 的方式去寫的,他只是追加的方式寫數據,自然就少了很多磁盤尋址的開銷了,寫入性能驚人,文件也不容易破損。

    AOF的日誌是通過一個叫 非常可讀 的方式記錄的,這樣的特性就適合做 災難性數據誤刪除 的緊急恢復了,比如公司的實習生通過

    flushall 清空了所有的數據,只要這個時候後臺重寫還沒發生,你馬上拷貝一份 AOF 日誌文件,把最後一條 flushall 命令刪了就完事了。

    缺點:一樣的數據,AOF 文件比 RDB 還要大;AOF開啟後,Redis支持寫的QPS會比RDB支持寫的要低,因為每秒異步刷新一次日誌

    AOF文件通過保存所有修改數據庫的寫命令請求來記錄服務器的數據庫狀態;命令請求會先保存到AOF緩衝區裡面,之後再定期寫入並同步到AOF文件。

    AOF重寫 首先從數據庫中讀取鍵現在的值,然後用一條命令去記錄鍵值對,代替之前記錄這個鍵值對的多條命令 ,產生一個新的AOF文件,新AOF文件和原AOF保存的數據庫狀態一樣,但體積更小;

    在執行BGREWRITEAOF命令時,Redis會維護一個AOF重寫緩衝區,該緩衝區會在子進程創建新的AOF文件期間,記錄服務器執行的所有寫命令。當子進程完成創建新AOF文件之後,服務器會將重寫緩衝區中的所有內容追加到新的AOF文件的末尾。最後,服務器用新的AOF文件替換舊的AOF文件,以此來完成AOF文件重寫操作。

    配置項

    no-appendfsync-on-rewrite

    是否在後臺寫時阻塞,默認值no(表示阻塞寫操作)。no表示新的主進程的set操作會被阻塞掉,而yes表示新的主進程的set不會被阻塞,待整個後臺寫完成之後再將這部分set操作同步到aof文件中。但這可能會存在數據丟失的風險(機率很小),如果對性能有要求,可以設置為yes,僅在後臺寫時會異步處理命令。

    auto-aof-rewrite-percentage

    AOF文件的體積比上一次重寫之後的增長比例,假設用戶對Redis設置了配置選項auto-aof-rewrite-percentage 100,那麼當AOF文件的體積比上一次重寫之後的文件大小大了至少一倍(100%)的時候,Redis將執行BGREWRITEAOF命令。

    auto-aof-rewrite-min-size

    觸發AOF文件重寫的最小的文件大小,即最開始AOF文件必須要達到這個文件大小時才觸發重寫,後面的每次重寫就不會根據這個變量了(根據上一次重寫完成之後的大小) 。

    內存淘汰

    過期策略

    Redis鍵的過期策略,是有定期刪除+惰性刪除兩種。

    定期好理解,默認100ms就 隨機 抽一些設置了過期時間的key,去檢查是否過期,過期了就刪了。

    惰性刪除,查詢時再判斷是否過期,過期就刪除鍵不返回值。

    內存淘汰機制

    當新增數據發現內存達到限制時,Redis觸發內存淘汰機制。

    配置項

    maxmemory

    配置Redis存儲數據時指定限制的內存大小,比如100m。當緩存消耗的內存超過這個數值時, 將觸發數據淘汰。該數據配置為0時,表示緩存的數據量沒有限制, 即LRU功能不生效。64位的系統默認值為0,32位的系統默認內存限制為3GB。

    maxmemory_policy

    觸發數據淘汰後的淘汰策略

    • no-eviction:當內存限制達到並且客戶端嘗試執行會讓更多內存被使用的命令返回錯誤(大部分的寫入指令,但DEL和幾個例外)
    • allkeys-lru: 嘗試回收最少使用的鍵(LRU),使得新添加的數據有空間存放。
    • volatile-lru: 嘗試回收最少使用的鍵(LRU),但僅限於在過期集合的鍵,使得新添加的數據有空間存放。
    • allkeys-lfu: 嘗試回收最近最不常用的鍵(LFU),使得新添加的數據有空間存放。
    • volatile-lfu: 嘗試回收最近最不常用的鍵(LFU),但僅限於在過期集合的鍵,使得新添加的數據有空間存放。
    • allkeys-random: 回收隨機的鍵使得新添加的數據有空間存放。
    • volatile-random: 回收隨機的鍵使得新添加的數據有空間存放,但僅限於在過期集合的鍵。
    • volatile-ttl: 回收在過期集合的鍵,並且優先回收存活時間(TTL)較短的鍵,使得新添加的數據有空間存放。

    maxmemory_samples

    隨機採樣的精度,也就是隨即取出key的數目。該數值配置越大, 越接近於真實的LRU算法,但是數值越大,相應消耗也變高,對性能有一定影響,樣本值默認為5。

    近似LRU算法

    真實LRU算法需要一個雙向鏈表來記錄數據的最近被訪問順序,比較耗費內存。

    Redis 通過對少量鍵進行取樣,然後回收其中的最久未被訪問的鍵。通過調整每次回收時的採樣數量maxmemory-samples,可以實現調整算法的精度。

    Redis 的鍵空間是放在一個哈希表中的,要從所有的鍵中選出一個最久未被訪問的鍵,需要另外一個數據結構存儲這些源信息,這顯然不划算。最初,Redis只是隨機的選3個key,然後從中淘汰,後來算法改進到N個key的策略,默認是5個。

    Redis 3.0之後又改善了算法的性能,會提供一個待淘汰候選key的pool,裡面默認有16個key,按照空閒時間排好序。更新時從Redis鍵空間隨機選擇N個key,分別計算它們的空閒時間 idle,key只會在pool不滿或者空閒時間大於pool裡最小的時,才會進入pool,然後從pool中選擇空閒時間最大的key淘汰掉。

    Redis為什麼不使用真實的LRU實現是因為這需要太多的內存。不過近似的LRU算法(approximated LRU)對於應用而言應該是等價的。


    Redis 數據結構 線程模型 持久化 內存淘汰 分佈式詳細總結

  • 淺灰色帶是已經被回收的對象。
  • 灰色帶是沒有被回收的對象。
  • 綠色帶是被添加的對象。
  • LRU實現的理論中,我們希望的是,在舊鍵中的第一半將會過期。RedisLRU算法則是概率的過期舊的鍵。
  • 分佈式

    Redis支持三種分佈式部署的方式:主從複製、哨兵模式、集群模式

    主從複製

    Redis 數據結構 線程模型 持久化 內存淘汰 分佈式詳細總結

    工作方式

    Redis可以使用主從同步,從從同步。第一次同步時,主節點做一次bgsave,並同時將後續修改操作記錄到內存buffer,待完成後將RDB文件全量同步到複製節點,複製節點接受完成後將RDB鏡像加載到內存。加載完成後,再通知主節點將期間修改的操作記錄同步到複製節點進行重放就完成了同步過程。後續的增量數據通過AOF日誌同步即可,有點類似數據庫的binlog。

    優點

    可以進行讀寫分離,分擔了主服務器讀操作的壓力

    缺點

    Redis不具備自動容錯和恢復功能,主機從機的宕機都會導致前端部分讀寫請求失敗,較難支持在線擴容,在集群容量達到上限時在線擴容會變得很複雜。

    哨兵模式

    Redis 數據結構 線程模型 持久化 內存淘汰 分佈式詳細總結

    當主服務器中斷服務後,可以將一個從服務器升級為主服務器,以便繼續提供服務,但是這個過程需要人工手動來操作。 為此,Redis 2.8中提供了哨兵工具來實現自動化的系統監控和故障恢復功能。

    哨兵的作用就是監控Redis系統的運行狀況。它的功能包括以下兩個。

    (1)監控主服務器和從服務器是否正常運行。 (2)主服務器出現故障時自動將從服務器轉換為主服務器。

    工作方式

    Sentinel是Redis的高可用性(HA)解決方案,由一個或多個Sentinel實例組成的Sentinel系統可以監視任意多個主服務器,以及這些主服務器屬下的所有從服務器,並在被監視的主服務器進行下線狀態時,自動將下線主服務器屬下的某個從服務器升級為新的主服務器,然後由新的主服務器代替已下線的主服務器繼續處理命令請求。

    Redis提供的sentinel(哨兵)機制,通過sentinel模式啟動redis後,自動監控master/slave的運行狀態,基本原理是:心跳機制+投票裁決,每個sentinel只有一次選舉的機會,當主庫出現故障,哨兵會投票從庫中選出一個承擔主庫的任務,剩下的還是從庫

    優點

    • 可以進行讀寫分離,分擔了主服務器讀操作的壓力
    • 主從可以自動切換,可用性更高

    缺點

    • Redis較難支持在線擴容,在集群容量達到上限時在線擴容會變得很複雜

    集群模式

    redis集群是一個由多個主從節點群組成的分佈式服務器群,它具有複製、高可用和分片特性。Redis集群不需要sentinel哨兵也能完成節點移除和故障轉移的功能。需要將每個節點設置成集群模式,這種集群模式沒有中心節點,可水平擴展,據官方文檔稱可以線性擴展到上萬個節點(官方推薦不超過1000個節點)。redis集群的性能和高可用性均優於之前版本的哨兵模式,且集群配置非常簡單。

    集群模式有以下幾個特點:

    • 由多個Redis服務器組成的分佈式網絡服務集群;
    • 集群之中有多個Master主節點,每一個主節點都可讀可寫;
    • 節點之間會互相通信,兩兩相連;
    • Redis集群無中心節點。

    優點

    • 在哨兵模式中,仍然只有一個Master節點。當併發寫請求較大時,哨兵模式並不能緩解寫壓力。 我們知道只有主節點才具有寫能力,那如果在一個集群中,能夠配置多個主節點,緩解寫壓力,redis-cluster集群模式能達到此類要求。
    • 在Redis-Cluster集群中,可以給每一個主節點添加從節點,主節點和從節點直接遵循主從模型的特性。 當用戶需要處理更多讀請求的時候,添加從節點可以擴展系統的讀性能。

    故障轉移

    Redis集群的主節點內置了類似Redis Sentinel的節點故障檢測和自動故障轉移功能,當集群中的某個主節點下線時,集群中的其他在線主節點會注意到這一點,並對已下線的主節點進行故障轉移。 集群進行故障轉移的方法和Redis Sentinel進行故障轉移的方法基本一樣,不同的是,在集群裡面,故障轉移是由集群中其他在線的主節點負責進行的,所以集群不必另外使用Redis Sentinel。

    集群分片策略

    常見的集群分片算法有:一般哈希算法、一致性哈希算法以及Hash Slot算法,Redis採用的是Hash Slot

    一般哈希算法

    計算方式:hash(key)%N

    缺點:如果增加一個redis,映射公式變成了 hash(key)%(N+1)

    ​ 如果一個redis宕機了,映射公式變成了 hash(key)%(N-1)

    ​ 在以上兩種情況下,幾乎所有的緩存都失效了。

    一致性哈希算法

    先構造出一個長度為2^32整數環,根據節點名稱的hash值(分佈在[0,2^32-1])放到這個環上。現在要存放資源,根據資源的Key的Hash值(也是分佈在[0,2^32-1]),在環上順時針的找到離它最近的一個節點,就建立了資源和節點的映射關係。

    優點:一個節點宕機時,上面的數據轉移到順時針的下一個節點中,新增一個節點時,也只需要將部分數據遷移到這個節點中,對其他節點的影響很小

    刪除一個節點

    Redis 數據結構 線程模型 持久化 內存淘汰 分佈式詳細總結

    新增節點

    Redis 數據結構 線程模型 持久化 內存淘汰 分佈式詳細總結

    缺點:由於數據在環上分佈不均,可能存在某個節點存儲的數據比較多,那麼當他宕機的時候,會導致大量數據湧入下一個節點中,把另一個節點打掛了,然後所有節點都掛了

    改進:引進了虛擬節點的概念,想象在這個環上有很多“虛擬節點”,數據的存儲是沿著環的順時針方向找一個虛擬節點,每個虛擬節點都會關聯到一個真實節點

    Redis 數據結構 線程模型 持久化 內存淘汰 分佈式詳細總結

    ash Slot算法

    Redis採用的是Hash Slot分片算法,用來計算key存儲位置的。集群將整個數據庫分為16384個槽位slot,所有key-value數據都存儲在這些slot中的某一個上。一個slot槽位可以存放多個數據,key的槽位計算公式為:slot_number=CRC16(key)%16384,其中CRC16為16位的循環冗餘校驗和函數。

    客戶端可能會挑選任意一個redis實例去發送命令,每個redis實例接收到命令,都會計算key對應的hash slot,如果在本地就在本地處理,否則返回moved給客戶端,讓客戶端進行重定向到對應的節點執行命令

    注意事項

    過期時間的設置

    如果大量的key過期時間設置的過於集中,到過期的那個時間點,Redis可能會出現短暫的卡頓現象。嚴重的話會出現緩存雪崩,我們一般需要在時間上加一個隨機值,使得過期時間分散一些。

    電商首頁經常會使用定時任務刷新緩存,可能大量的數據失效時間都十分集中,如果失效時間一樣,又剛好在失效的時間點大量用戶湧入,就有可能造成緩存雪崩。

    緩存雪崩:大量緩存的key同時失效,同時大批量的請求落到了數據庫上,數據庫扛不住掛了。(處理方法:失效時間加上一個隨機值,避免同時失效)

    緩存穿透:用戶不斷訪問緩存和數據庫都沒有的數據。(處理方式:請求參數校驗,將查詢不到數據的key放到緩存中,value設為null)

    緩存擊穿:對於熱點數據,如果一直有高併發的請求,剛好緩存失效,這時大量的請求就會落在數據庫上(設置熱點期間不過期)

    keys缺陷

    Redis的單線程的。keys指令會導致線程阻塞一段時間,線上服務會停頓,直到指令執行完畢,服務才能恢復。 使用scan指令可以無阻塞的提取出指定模式的key列表,但是會有一定的重複概率,在客戶端做一次去重就可以了,但是整體所花費的時間會比直接用keys指令長 。

    疑問補充

    Redis字典漸進式擴容

    雖然redis實現了在讀寫操作時,輔助服務器進行漸進式rehash操作,但是如果服務器比較空閒,redis數據庫將很長時間內都一直使用兩個哈希表。所以在redis週期函數中,如果發現有字典正在進行漸進式rehash操作,則會花費1毫秒的時間,幫助一起進行漸進式rehash操作

    持久化

    Redis持久化的數據庫文件即是RDB文件,如果開啟了AOF,數據則持久化在AOF文件中

    為什麼哈希槽是16384個

    Redis 數據結構 線程模型 持久化 內存淘汰 分佈式詳細總結

    正常的心跳包攜帶節點的完整配置,可以用冪等方式替換舊節點以更新舊配置。 這意味著它們包含原始形式的節點的插槽配置,它使用帶有16k插槽只需要2k空間,但使用65k插槽時將使用高達8k的空間。 2、同時,由於其他設計權衡,Redis Cluster不太可能擴展到超過1000個主節點。因此,16k處於正確的範圍內,以確保每個主站有足夠的插槽,最多1000個主節點,但足夠小的數字可以輕鬆地將插槽配置傳播為原始位圖。



    分享到:


    相關文章: