<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Redis上篇--分析

      Redis上篇--解析

      本文大部分知識整理自網上,在正文結束后都會附上參考地址。如果想要深入或者詳細學習可以通過文末鏈接跳轉學習。

      1. 基本介紹

      Redis 是一個開源的、高性能的 內存鍵值數據庫,Redis 的鍵值對中的 key 就是字符串對象,而 value 就是指Redis的數據類型,可以是String,也可以是List、Hash、Set、 Zset 的數據類型。Redis通常被用作數據庫、緩存、消息中間件和實時數據處理引擎。它以速度極快、支持豐富的數據結構而聞名,是現代應用架構中非常流行的組件。

      它的核心特點我們需要了解一下:

      1. 內存存儲 (In-Memory):
        • 數據主要存儲在內存 (RAM) 中,這是 Redis 速度驚人的根本原因(讀寫操作通常在微秒級別)。
        • 它也提供可選的持久化機制,可以將數據異步或同步保存到磁盤,防止服務器重啟后數據丟失。
      2. 豐富的數據結構 (Data Structures):
        • 不僅僅是簡單的 Key-Value 字符串!Redis 支持多種高級數據結構:
          • Strings: 最基本類型,可以存儲文本、數字、二進制數據(如圖片片段)。
          • Lists: 有序的元素集合,可在頭部或尾部插入/刪除,適合實現隊列、棧、時間線。
          • Sets: 無序的唯一元素集合,支持交集、并集、差集等操作,適合標簽、共同好友。
          • Sorted Sets (ZSets): 帶分數的有序唯一元素集合,元素按分數排序,完美適用于排行榜、優先級隊列。
          • Hashes: 存儲字段-值對的集合,非常適合表示對象(如用戶信息:field: name, value: "Alice"; field: age, value: 30)。
          • Bitmaps / HyperLogLogs / Geospatial Indexes: 特殊用途的數據結構,用于位操作、基數統計(去重計數)、地理位置計算等。
      3. 高性能與低延遲:
        • 內存訪問 + 單線程架構 (核心命令執行是單線程,避免了鎖競爭) + 高效的網絡 I/O 模型 (epoll/kqueue) 使其擁有極高的吞吐量和極低的延遲。
      4. 持久化 (Persistence):
        • RDB (Redis Database File): 在指定時間間隔生成整個數據集的內存快照。恢復快,文件緊湊。適合備份和災難恢復。
        • AOF (Append-Only File): 記錄所有修改數據庫狀態的命令。更安全(最多丟失一秒數據),文件可讀性強,但文件通常更大,恢復可能比 RDB 慢??梢酝瑫r開啟或選擇其一。
      5. 原子操作與事務:
        • 所有單條命令的執行都是原子的。
        • 支持簡單的事務 (MULTI/EXEC),可以將一組命令打包執行(但不支持回滾 - 命令語法錯誤會導致整個事務不執行,運行時錯誤不影響其他命令執行)。
        • Lua 腳本: 可以執行復雜的、需要多個命令且保證原子性的操作。

      其實還有像發布訂閱、集群架構本節就不贅述了。

      典型應用場景

      1. 緩存 (Caching): 最常見的用途。將頻繁訪問的熱點數據(如數據庫查詢結果、頁面片段、會話信息)存儲在 Redis 中,顯著減輕后端數據庫壓力,提升應用響應速度。
      2. 會話存儲 (Session Store): 存儲用戶會話信息,易于在多服務器或微服務架構中實現會話共享。
      3. 排行榜/計數器 (Leaderboards / Counters): 利用 Sorted Sets 可以非常高效地實現實時排行榜。利用 INCR 等命令實現高并發下的計數器(如點贊數、瀏覽量)。
      4. 實時系統 (Real-time Systems):
        • 消息隊列 (Message Queue): 利用 Lists 或 Streams (一種更強大的持久化消息隊列數據結構) 實現簡單的消息隊列。
        • 實時分析: 處理實時事件流(如用戶活動跟蹤、監控數據)。
      5. 地理空間應用 (Geospatial): 存儲地理位置坐標,執行附近位置查詢、距離計算等。
      6. 速率限制 (Rate Limiting): 限制用戶 API 調用頻率或操作次數。
      7. 分布式鎖 (Distributed Lock): 利用 Redis 的原子操作實現簡單的跨進程/跨機器的互斥鎖。
      // 對應的數據類型作用場景:
      String可以用來做緩存、計數器、限流、分布式鎖、分布式Session等。
      Hash可以用來存儲復雜對象。List可以用來做消息隊列、排行榜、計數器、最近訪問記錄等。
      Set可以用來做標簽系統、好友關系、共同好友、排名系統、訂閱關系等。
      Zset可以用來做排行榜、最近訪問記錄、計數器、好友關系等。
      Geo可以用來做位置服務、物流配送、電商推薦、游戲地圖等。
      HyperLogLog可以用來做用戶去重、網站UV統計、廣告點擊統計、分布式計算等。
      Bitmaps可以用來做在線用戶數統計、黑白名單統計、布隆過濾器等。
      

      看了這么大幾點,就可以知道Redis相當牛逼了。都說Redis快,僅僅是因為內存操作嗎?接下來看一下它為什么這么快!

      2. '快'的原因

      Redis 可以達到極高的性能(官方測試讀速度約 11 萬次 / 秒,寫速度約 8 萬次 / 秒),快自然有快的道理

      2.1 內存

      基于內存操作

      Redis將所有數據存儲在內存中,避免了傳統數據庫的磁盤I/O瓶頸,內存的讀寫速度遠高于磁盤,這使得Redis能夠實現超高的響應速度。

      節選一下別人的對比:內存的讀寫速度,和磁盤讀寫速度的對比

      • 最快情況下, 固態 硬盤 速度,大致是 內存速度的 百分之一,
      • 最慢情況下, 機械 硬盤 速度,大致是 內存速度的 萬分之一,

      內存讀寫速度可以達到每秒數百GB,在微秒級別,而磁盤(特別機械硬盤) 讀寫速度通常只有數十MB,在毫秒級別, 是數千倍的差距。

      對比與傳統的關系型數據庫比如說MySQL,需要從磁盤加載數據到內存緩沖區才能操作,Redis不需要這個步驟,就避免了磁盤 I/O 的延遲。

      +++

      2.2 高性能數據結構

      高效的數據結構

      我們都知道Redis向我們用戶提供了value為string, list, hash, set, zset五種基本數據類型來使用,還有幾種高級的數據結構例如geo, bitmap, hyperloglog。本文就只看基本的數據類型了。

      本節分析一下底層實現,這些數據類型底層實現有如下這么些:

      sds( 簡單動態字符串)

      ziplist(壓縮列表)

      linkedlist(雙端鏈表)

      hashtable(字典)

      skiplist(跳表)

      這些底層結構能夠在內存中高效地存儲和操作數據,為Redis的快速性能提供了堅實的基礎。這里附上別人的圖:【來自參考1】

      2.2.1 sds

      首先就是大家最為熟知的string類型了:它的底層實現是基于sds的。在這之前,我們需要知道這樣一件事,Redis中所有數據均通過redisObject結構體封裝

      typedef struct redisObject {
          unsigned type:4;        // 數據類型(如String、List)
          unsigned encoding:4;    // 編碼方式(int/embstr/raw)
          unsigned lru:24;        // LRU緩存淘汰信息
          int refcount;           // 引用計數(用于共享和內存回收)
          void *ptr;              // 指向實際數據的指針
      } robj;
      /*
      type:標識數據類型(String固定為OBJ_STRING)。
      encoding:決定ptr指向的數據結構,String有三種可能編碼:
      OBJ_ENCODING_INT:整數類型。
      OBJ_ENCODING_EMBSTR:短字符串(≤44字節)。
      OBJ_ENCODING_RAW:長字符串(>44字節)
      */
      

      當前字符串的值可表示為64位有符號整數 long (-92233720368547758079223372036854775807 很大就是了),表示為int編碼,直接存儲整數

      如果不能表示為整數,字符串長度 ≤44字節的時候,為EMBSTR編碼:連續內存的短字符串,此時,redisObjectSDS分配在單塊連續內存中,這樣可以減少內存碎片,提升CPU緩存命中率。redisObject固定占16字節,SDS頭部(sdshdr8)占3字節(len、alloc、flags各1字節),總內存分配單元為64字節(Redis內存分配器jemalloc的最小單位),所以剩余空間:64 - 16 - 3 - 1(結束符\0) = 44字節。

      如果超過了44字節,redisObjectSDS兩次分配內存(不連續),ptr指向獨立的SDS結構。

      那么這個SDS(Simple Dynamic String)到底是什么個情況呢?SDS是Redis自定義的動態字符串結構,解決了C原生字符串的缺陷(緩沖區溢出、長度計算O(n)、二進制不安全)

      struct __attribute__((__packed__)) sdshdr8 {
          uint8_t len;        // 已用長度  1字節 
          uint8_t alloc;      // 總分配容量(不包括頭部和\0)  1字節
          unsigned char flags;// 標識SDS類型(sdshdr8/16/32/64)  1字節
          char buf[];         // 實際數據(柔性數組)
      };
      

      基于這種結構,相比于c語言的字符串,我們可以O(1)復雜度獲取字符串長度:直接讀取len字段;C語言字符串是使用char數組存儲,以'\0'作為字符串結束,比如字符串”Redis“在C語言中存儲結構就是這個樣子的:

      Redis'\0' 
      

      C語言字符串這種特殊規定,就導致無法存儲特殊字符。如果某個字符串中間包含'\0'字符,讀取字符串的時候就無法讀取到完整字符,遇到'\0'就結束了,此外呢,C字符串不記錄自身的長度,每次增長或縮短一個字符串,都要對底層的字符數組進行一次內存重分配操作。如果在 append 操作之前沒有通過內存重分配來擴展底層數據的空間大小,就會產生緩存區溢出;如果進行 trim 操作之后沒有通過內存重分配來釋放不再使用的空間,就會產生內存泄漏。

      而Redis的這種結構就很好了,二進制安全,依賴len而非\0判斷結束,可存儲圖片等二進制數據;

      另外還涉及到擴容問題,Redis的SDS中,如果新增的拼接字符串長度小于未使用空間,就不用擴容了;

      此外,惰性空間釋放:縮短字符串時不立即回收內存,只是簡單的修改sdshdr 頭中的 Len 字段就可以了。

      2.2.2 zipList

      Redis的壓縮列表(ziplist)是一種極致內存優化的緊湊型數據結構,用于在小數據量場景下高效存儲列表、哈希和有序集合。它通過精巧的設計實現了O(1)頭部操作和高效內存利用,是Redis早期核心數據結構之一(Redis 7.0后逐漸被listpack替代,但理解其設計仍有重要意義)

      // ziplist的數據結構
      typedef struct {
          uint32_t zlbytes;   // 4字節	整個壓縮列表占用的內存字節數(uint32_t)
          uint32_t zltail;    // 最后一個entry的偏移量(實現O(1)尾部訪問)
          uint16_t zllen;     // entry數量(當≥65535時需遍歷計算)
          entry* entries;     // 實際存儲的節點列表
          uint8_t  zlend;     // 結束標志(0xFF)
      } ziplist;
      // 其結點的數據結構
      struct entry {
          uint8_t prevlen;  // 前驅節點長度(1或5字節)
          uint8_t encoding; // 數據編碼方式(字節數組或整數)
          optional uint8_t data[]; // 實際數據
      };
      

      壓縮列表以一種緊湊的方式存儲數據,將多個元素緊密地排列在一起,節省了存儲空間。在壓縮列表中,相鄰的元素可以共享同一個內存空間。這里附上【尼恩】的示意圖:

      他的優點:緊湊存儲,無額外指針(相比鏈表節省 20%-30% 內存);通過 zltail 快速定位尾部,支持 O(1) 時間的尾插/尾刪;

      但是,插入/刪除需移動后續節點,時間復雜度 O(N);會有連鎖更新風險。

      Redis 的壓縮列表(Ziplist)與傳統雙向鏈表在數據結構設計、性能和應用場景上存在如下差異:

      第一,從結構設計上來說

      特性 壓縮列表(Ziplist) 傳統雙向鏈表
      存儲方式 連續內存塊,通過偏移量定位節點 離散內存塊,每個節點包含前驅/后繼指針
      節點結構 無指針,包含 prevlen(前驅長度)+ encoding(編碼類型)+ 數據內容 包含前驅指針、后繼指針及數據內容
      頭部元數據 zlbytes(總字節數)、zltail(尾節點偏移)、zllen(節點數量)、zlend(結束符) 通常僅記錄頭尾指針和節點數量
      內存布局 緊湊存儲,無額外指針開銷 邏輯上是相鄰的

      第二,內存效率對比

      維度 壓縮列表 雙向鏈表
      內存占用 極低(無指針,變長編碼優化) 較高(每個節點需 2 個指針,占 16 字節)
      空間利用率 高(緊湊存儲減少碎片) 低(易產生內存碎片)
      適用數據規模 小數據場景(元素數量 ≤ 512,單元素 ≤ 64 字節) 大數據場景(無嚴格限制)

      第三,操作性能對比

      操作類型 壓縮列表 雙向鏈表
      隨機訪問 O(n)(需遍歷節點) O(n)(需遍歷指針鏈)
      頭尾插入/刪除 O(1)(通過 zltail 快速定位) O(1)(直接操作頭尾指針)
      中間插入/刪除 O(n)(需移動后續節點,可能觸發連鎖更新) O(n)(需遍歷到節點位置,但指針操作快)

      2.2.3 雙向鏈表

      Redis中的雙端鏈表是一種優化后的數據結構,專門用于存儲有序的元素集合。Redis雙端鏈表具備雙向鏈接的特性,即每個節點都包含指向前一個節點和后一個節點的指針。

      這里附上別人的Redis雙向鏈表的示意圖:

      可以看到每個節點包含 前驅指針后繼指針數據值,支持從頭部或尾部向中間遍歷;頭節點的 prev 和尾節點的 next 均指向 NULL,避免循環引用;List結構中還有長度字段len 屬性直接記錄節點數,避免遍歷統計;還存有頭指針、尾指針,方便從頭或者尾部開始遍歷鏈表。

      操作 時間復雜度 說明
      頭部插入/刪除 O(1) 直接調整頭指針及相鄰節點指針
      尾部插入/刪除 O(1) 同上
      按索引訪問 O(n) 需從頭或尾遍歷(平均一半節點)
      按值查找 O(n) 順序遍歷,無哈希索引
      遍歷全部節點 O(n) 需訪問每個節點

      再在這里與2.2.3小節的壓縮列表對比一下:

      場景 雙向鏈表 壓縮列表
      大型列表 ? 穩定O(1)操作 ? 插入可能觸發O(n2)連鎖更新
      小型列表 ? 內存開銷大 ? 內存節省80%+
      頻繁頭尾操作 ? 直接指針修改 ? 尾部快,頭部需移動數據
      中間位置修改 ? O(1)指針操作 ? O(n)數據移動
      二進制安全 ? 無特殊限制 ? 支持
      內存碎片 ? 高(節點離散分配) ? 極低(連續內存)

      2.2.4 漸進式擴容 雙哈希結構

      通過Redis源碼,我們可以看到dict的定義如下:

      typedef struct dict {
          dictType *type;     // 類型特定函數
          void *privdata;     // 私有數據
          dictht ht[2];       // 雙哈希表(用于漸進式rehash)
          long rehashidx;     // rehash進度索引
      } dict;
      
      typedef struct dictht {
          dictEntry **table;      // 桶數組
          unsigned long size;     // 桶數量
          unsigned long sizemask; // size-1(用于位運算)
          unsigned long used;     // 已用節點數
      } dictht;
      
      typedef struct dictEntry {
          void *key;              // 鍵(SDS)
          union {                 // 值(聯合體)
              void *val;
              uint64_t u64;
              int64_t s64;
          } v;
          struct dictEntry *next; // 鏈地址法解決沖突
      } dictEntry;
      

      從上述結構體我們可以推斷出其具體結構:

      可以看到,redis處理哈希沖突的方式是鏈地址法,當多個鍵值對映射到同一個哈希表數組索引時,這些鍵值對會以鏈表的形式存儲,鏈表的每個節點包含鍵值對。(這種查找插入的速度都不慢,hash表的數據結構我這里就不解釋了,我們知道Redis的hash表如上圖所示就行了)

      操作 平均復雜度 最壞復雜度 場景
      HSET/HGET O(1) O(n) 哈希沖突嚴重
      HGETALL O(n) O(n) 全量遍歷
      HDEL O(1) O(n) 需鏈表刪除

      隨著數據量的增長,Redis 的哈希表需要擴容存儲能力。但擴容操作本身可能會非常耗時,導致服務阻塞。所以就有了上面的ht[2]這個東西了??!

      為了在擴容過程中避免阻塞服務,Redis 設計了雙哈希表結構 dict.ht,其中包含兩個哈希表:

      • ht[0]:主哈希表,用于存儲當前所有數據,并處理客戶端的讀寫請求。
      • ht[1]:備用哈希表,用于擴容操作。

      擴容的流程大概如下:

      當哈希表負載因子超過閾值(元素數/桶數)≥ 1 且未執行 BGSAVE/BGREWRITEAOF,或負載因子 ≥ 5 時,觸發擴容。Redis 會創建一個容量為原表兩倍的新哈希表(ht[1]),并通過分批次遷移數據實現無阻塞擴容。具體步驟為:

      首先,初始化新表:分配 ht[1] 的內存空間,設置其 sizemaskused 字段,將舊表(ht[0])的 rehashidx 置為 0,標記擴容開始;

      其次,漸進遷移:處理客戶端請求時,遷移 ht[0] 中 rehashidx 對應的一個哈希桶的所有鍵值對到 ht[1],并遞增 rehashidx,在這個過程中,查詢操作就同時搜索 ht[0]ht[1],新增操作直接寫入 ht[1],刪除/更新操作如果所在桶若未遷移,在 ht[0] 執行;若已遷移則在 ht[1] 執行。

      同時呢,還會有定時輔助遷移:即使無操作,Redis 也會在 serverCron 中觸發 1ms 的遷移任務,每次最多遷移 10 個桶,確??臻e時完成擴容;

      最后完成收尾:當 ht[0] 的所有數據遷移完成后,釋放其內存,將 ht[1] 設為新的 ht[0],并重置 rehashidx 為 -1。

      2.2.5 跳躍表

      跳躍表(Skip List)是一種基于有序鏈表的隨機化數據結構,通過多層索引實現高效查找、插入和刪除操作,平均時間復雜度為 O(log n)。Redis 的有序集合(Sorted Set)就是采用跳躍表作為其核心數據結構。那么它長什么樣子呢

      跳表的做法就是給鏈表做索引,而且是分層索引,可以有多層,層級越多占用 的空間肯定是越多的;

      跳表通過維護多級索引,每個級別的索引都是原始鏈表的子集,用于快速定位元素。

      每個節點在不同級別的索引中都有一個指針,通過這些指針,可以在不同級別上進行快速查找,從而提高了查找效率。

      比如說在上面的圖中,查找元素8,就可以按照下面的順序去查找:

      只用找1 5 7 8,就可以了。

      可以很直觀地看到查找算法看起來挺簡單的,難點就是插入、刪除元素的時候,索引該如何去維護。跳躍表實現見后續文章吧,本文只做Redis數據結構的簡要概括。下面附上一張Redis中skipList的數據結構,來自參考3:

      header:指向跳躍表的表頭節點

      tail:指向跳躍表的表尾節點

      level:記錄目前跳躍表內,層數最大的那個節點層數(表頭節點的層數不計算在內)

      length:記錄跳躍表的長度,也就是跳躍表目前包含節點的數量(表頭節點不計算在內)

      同時在跳躍表中,score值有序

      特性 經典跳躍表 Redis 跳躍表
      排序依據 單鍵值 分值(score)+成員(ele)
      跨度設計 有(支持排名計算)
      遍歷方向 單向 雙向鏈表,方便以倒序方式獲取一個范圍內的元素。
      頭節點 僅存指針 存儲最大層數
      層數上限 無硬性限制 固定 32 層

      Redis 為什么采用跳躍表而不用平衡樹?【copy自參考3】

      • 從內存占用上來比較,跳表比平衡樹更靈活一些。平衡樹每個節點包含 2 個指針(分別指向左右子樹),而跳表每個節點包含的指針數目平均為 1/(1-p),具體取決于參數 p 的大小。如果像 Redis里的實現一樣,取 p=1/4,那么平均每個節點包含 1.33 個指針,比平衡樹更有優勢。
      • 在做范圍查找的時候,跳表比平衡樹操作要簡單。在平衡樹上,我們找到指定范圍的小值之后,還需要以中序遍歷的順序繼續尋找其它不超過大值的節點。如果不對平衡樹進行一定的改造,這里的中序遍歷并不容易實現。而在跳表上進行范圍查找就非常簡單,只需要在找到小值之后,對第 1 層鏈表進行若干步的遍歷就可以實現。
      • 從算法實現難度上來比較,跳表比平衡樹要簡單得多。平衡樹的插入和刪除操作可能引發子樹的調整,邏輯復雜,而跳表的插入和刪除只需要修改相鄰節點的指針,操作簡單又快速。

      2.3 單線程、多路復用

      Redis 的單線程設計是其高性能的核心支柱,但它并非字面意義上的“只有一個線程”。Redis 的工作線程(主線程)串行處理所有客戶端命令,但存在輔助線程處理異步任務

      為什么堅持核心單線程呢?這可能是一種取舍,如果是多線程的話,需要考慮 共享數據結構需加鎖(如 Mutex)、線程上下文切換需要消耗 CPU 周期、線程安全編程難度高一些。

      如果采用單線程的話,天然無鎖,可以保證操作的原子性;因為是單線程嘛,所以就沒有縣城上下文切換了;代碼就更簡單易懂了,也容易維護嘛。

      單線程肯定會有不足的:比如說執行了慢命令,(如 KEYS *)會阻塞所有后續請求;單線程無法充分利用多核cpu。

      所以可以得出:CPU 并不是Redis的瓶頸 → 避免鎖/切換開銷 → 單線程更高效

      因為Redis使用內存存儲數據,所以數據訪問非常迅速,不會成為性能瓶頸。此外,Redis的數據操作大多數都是簡單的鍵值對操作,不包含復雜計算和邏輯,因而CPU開銷很小。相反,Redis的瓶頸在于內存的容量和網絡的帶寬,這些問題無法通過增加CPU核心來解決。

      Redis 6.x開始引入了多線程, 但是多線程僅僅是在 處理網絡IO,Redis 核心命令執行依然是單線程,確保性能和一致性。

      +++

      那么,現在說一下Redis 的網絡 I/O 處理,采用 事件驅動的 Reactor 模式,結合 I/O 多路復用技術漸進式多線程優化

      Redis 采用 Reactor 模式作為網絡模型的基礎架構,在這一模式下,Redis 通過一個主事件循環(Event Loop) 持續監聽并分發網絡事件。

      首先,事件分發器:基于 I/O 多路復用技術(如 Linux 的 epoll)實現,負責監控所有客戶端連接的 Socket 文件描述符(FD);

      然后,事件處理器:為不同事件(如連接、讀、寫)綁定對應的回調函數。例如:連接事件觸發 accept 處理器,創建新客戶端連接;讀事件觸發命令請求處理器,解析并執行 Redis 命令;寫事件觸發響應回復處理器,將結果返回客戶端。

      通過 I/O 多路復用,單一線程可同時監聽數萬個 Socket,僅當 Socket 真正發生讀寫事件時才觸發回調,避免了線程空轉和阻塞,這種設計使得 Redis 在單線程下仍能高效處理高并發請求,尤其適合內存操作快速完成的場景

      盡管單線程模型簡化了數據一致性管理,但網絡 I/O 瓶頸在高并發場景下逐漸顯現。為此,Redis 從 6.0 版本開始引入漸進式多線程優化:新增的 I/O 線程僅負責網絡數據的讀取與發送,而命令解析與數據操作仍由主線程單線程執行,這種設計確保了核心數據操作的原子性,避免多線程競爭。

      主要流程:

      1. 主線程接收新連接,將 Socket 分配至全局隊列;
      2. I/O 線程池并行讀取請求數據并解析為命令(若啟用 io-threads-do-reads),或并行發送響應結果;
      3. 主線程按順序執行所有命令,再將結果寫入緩沖區供 I/O 線程發送
      【用戶可通過 io-threads 參數設置線程數(建議為 CPU 核數的 1~1.5 倍),并通過 io-threads-do-reads 控制是否啟用讀并行化,
          在高并發網絡場景下,此優化可提升吞吐量 40%~50%,同時避免核心邏輯的鎖競爭】
      

      2.4 異步持久化機制

      單機的Redis速度已經獨步天下了,倘若遇到系統錯誤,導致Redis應用程序中斷了,由于數據是在內存里面,那不就全部丟失了嗎?閣下該如何應對!這就需要 說到Redis的持久化機制了

      Redis的持久化機制包含RDBAOF兩種方式,其核心設計原則是最大化性能,因此持久化操作本質是異步的(主線程非阻塞);

      • 首先說一下RDB(Redis Database):

      它是將內存中的數據以二進制格式生成全量快照(Snapshot),寫入 dump.rdb 文件,通過 fork 子進程完成持久化,主進程繼續處理請求,僅 fork 操作短暫阻塞(約 1-100ms)。那么其觸發方式是什么樣子的呢?

      可以自動觸發(默認異步),在配置文件里面配置 save m n:如 save 900 1 表示 900 秒內至少 1 次鍵修改時觸發;從節點全量復制時自動觸發。

      也可以手動觸發,就需要命令的形式了,SAVE:同步阻塞主線程,生成快照(不推薦生產環境使用);BGSAVE:異步生成快照,通過子進程完成(默認方式)。

      這種方式快速生成快照,對性能影響較小,此外呢,文件體積較小,適合備份和災難恢復。但是,如果是 Redis 服務器在兩次快照之間崩潰,可能會丟失部分數據

      • 第二種方式AOF(Append-Only File)

      它是將 Redis 執行的所有寫命令(如SET、INCR)追加到日志文件(默認名為appendonly.aof),同時在AOF 文件過大時,通過BGREWRITEAOF命令對日志進行瘦身(合并重復命令):創建一個新的AOF文件來替代現有的AOF文件,新舊兩個文件所保存的數據庫狀態是相同的,但 新 AOF文件 去掉 老的 冗余命令,通常體積會較舊AOF文件小很多,達到壓縮 AOF 文件體積的目的。

      重寫瘦身觸發方式:【1】手動:BGREWRITEAOF 命令?!?】自動:滿足 auto-aof-rewrite-percentage(默認 100%)和 auto-aof-rewrite-min-size(默認 64MB)條件時觸發。

      這個重寫操作是異步的嗎?Redis是利用子線程進行復制拷貝,總結來說就是 一個拷貝,兩處日志。?復制過程 不會卡主線程?,整個過程是讓子進程干活,主線程繼續服務用戶。兩處日志分別指:【1】主線程正常處理新操作,把命令記錄到? AOF 緩沖區 ,異步刷新到 原來的AOF日志?里(比如每秒刷一次磁盤)? 【2】同時,新操作還會被額外記錄到? AOF重做緩沖區?,等小弟整理完舊日志后,這些新操作會被追加到新的AOF文件里,保證數據不丟失?

      那么AOF這種方式的異步點在哪里呢?

      寫操作:主線程將命令追加到 aof_buf 內存緩沖區(非阻塞)

      刷盤策略:根據配置異步刷盤

      appendfsync always   # 同步寫盤(強一致,性能差)
      appendfsync everysec # 每秒異步刷盤(推薦-默認)
      appendfsync no       # 依賴操作系統刷盤
      

      這種持久化方式數據安全性高(最多丟失 1 秒數據),支持命令級恢復,但是文件體積大,恢復速度慢,因為是很多命令嘛。

      那么Redis是采用哪種方式呢?是同時開啟 RDB 和 AOF喔,利用 RDB 的快速恢復能力和 AOF 的數據安全性,重啟時,優先加載RDB恢復數據,再重放AOF增量操作。

      end. 參考

      1. https://mp.weixin.qq.com/s/pFwnTOQSovy_nMrg0QQk-Q 【尼恩---Redis 為啥那么快?怎么實現 100W并發?說出 這 6大架構,面試官跪 了】
      2. http://www.rzrgm.cn/yidengjiagou/p/17239149.html為什么Redis不直接使用C語言的字符串?
      3. https://mp.weixin.qq.com/s?__biz=MzkxNzIyMTM1NQ==&mid=2247501801&idx=1&sn=36ec0db469080065aac9ff6f15900f08&scene=21#wechat_redirect 【尼恩-跳躍表】
      posted @ 2025-06-18 11:07  別來無恙?  閱讀(30)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 妺妺窝人体色WWW看人体| 色综合天天综合天天更新| 狠狠亚洲色一日本高清色| 中国猛少妇色xxxxx| 亚洲精品区二区三区蜜桃| 日韩美女视频一区二区三区| 久久99久国产精品66| 亚洲国产精品高清久久久| 天堂av资源在线免费| 午夜性爽视频男人的天堂| 扒开女人内裤猛进猛出免费视频| 色99久久久久高潮综合影院| 国产成人精品永久免费视频| 国产午夜福利精品视频| 日韩精品人妻中文字幕| 成人亚洲欧美一区二区三区 | 国产AV巨作丝袜秘书| 午夜福利在线观看6080| 国产网红女主播精品视频| 精品嫩模福利一区二区蜜臀| 国产精品中文字幕av| 中文字幕无码乱码人妻系列蜜桃| 老熟妇欲乱一区二区三区| 午夜高清福利在线观看| 国产无套内射普通话对白| 精品国产熟女一区二区三区| 国产成人午夜福利院| 女人18片毛片60分钟| 免费无遮挡无码视频网站| 亚洲国产午夜精品福利| 成年性午夜免费视频网站| 国产综合色在线精品| 中文字幕乱码一区二区免费| 色偷偷www.8888在线观看| av午夜福利一片免费看久久| 无码精品人妻一区二区三区中| 熟女人妇 成熟妇女系列视频| 午夜好爽好舒服免费视频| 亚欧美日韩香蕉在线播放视频| 丰城市| 国产精品久久无中文字幕|