企業級NoSQL數據庫Redis

1.瀏覽器緩存過期機制

1.1 最后修改時間 last-modified

瀏覽器緩存機制是優化網頁加載速度和減少服務器負載的重要手段。以下是關于瀏覽器緩存過期機制、Last-ModifiedETag 的詳細講解:

一、Last-Modified 頭部

  • 定義Last-Modified 表示服務器上資源的最后修改時間。

  • 作用:用于資源的條件請求,幫助瀏覽器判斷緩存的資源是否是最新的。

  • 工作流程

    1. 瀏覽器第一次請求資源時,服務器返回資源內容和 Last-Modified 時間。

    2. 下次請求同一資源時,瀏覽器發送 If-Modified-Since 頭部,值為之前的 Last-Modified 時間。

    3. 服務器比較資源的當前修改時間與 If-Modified-Since的值:

      • 如果資源未修改,返回 304 Not Modified,瀏覽器繼續使用緩存。
      • 如果資源已修改,返回新的資源內容和更新后的 Last-Modified 時間。
  • 示例

Last-Modified: Wed, 21 Oct 2023 07:28:00 GMT

二、ETag 頭部

  • 定義ETag(Entity Tag)是服務器為資源生成的唯一標識符,通常是資源內容的哈希值或版本號。

  • 作用:比 Last-Modified 更加精確,用于驗證資源是否變化。

  • 工作流程

    1. 瀏覽器第一次請求資源時,服務器返回資源內容和 ETag 值。

    2. 下次請求同一資源時,瀏覽器發送 If-None-Match 頭部,值為之前的 ETag

    3. 服務器比較當前資源的 ETagIf-None-Match的值:

      • 如果 ETag 未變化,返回 304 Not Modified,瀏覽器繼續使用緩存。
    • 如果 ETag 變化,返回新的資源內容和新的 ETag 值。
  • 示例

ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"

五、Last-Modified vs ETag

  • 精確度
    • Last-Modified 僅記錄最后修改時間,可能無法檢測到在同一秒內的多次修改。
    • ETag 通常基于內容的哈希值,能夠更精確地檢測到任何變化。
  • 性能
  • 生成 ETag 可能需要更多的計算資源,尤其是在大規模資源或高頻請求的情況下。
  • Last-Modified 相對簡單,性能開銷較小。
  • 使用場景
    • 對于靜態資源,ETag 更加適用。
    • 對于動態資源,可以結合 Last-Modified 和其他緩存策略使用。

六、最佳實踐

  1. 合理設置緩存策略
    • 對于不經常變化的靜態資源,設置較長的 max-age 以充分利用緩存。
    • 對于經常變化的資源,使用較短的 max-age 或結合驗證機制。
  2. 使用 ETagLast-Modified
    • 同時使用兩者可以提供更可靠的緩存驗證,但需注意服務器的性能開銷。
  • 如果服務器性能有限,可以選擇只使用其中一個。
  1. 版本化資源
    • 通過在資源URL中包含版本號(如 style.v1.css),可以在資源更新時強制瀏覽器下載新版本,避免緩存問題。

七、總結

瀏覽器緩存機制通過多種HTTP頭部字段控制資源的緩存和過期,Last-ModifiedETag 是其中重要的驗證手段。合理配置這些頭部字段,可以顯著提升網頁性能,優化用戶體驗,同時有效管理服務器資源。

第一次訪問

image-20241216144110944

第二次訪問

image-20241216144252162

1.2 Etag 標記

但是如果訪問的時間一樣的,怎么辦?If-Modefied精確到的是秒,要知道的是,計算機一秒中可以干好多事的,比如一秒中修改上千次的圖片

# 使用 touch 模擬訪問時間是一樣的(移走1.jpeg,在重新上傳一張圖片,重命名為1.jpeg)
[root@Rocky9.4 html]#touch -t 202407020931.48 1.jpeg

第一次訪問

第一次訪問是由于我將時間設置成一樣了,但是因為服務器返回的Etag是新的,而瀏覽器保存的還是舊的,所以Etag不一致,所以返回狀態碼是200

image-20241216143352281

第二次訪問

第二次訪問,Etag也統一了,所以返回了狀態碼304

image-20241216145149331

1.3 過期時間 expires 和 Cache-Control

一、瀏覽器緩存機制概述

瀏覽器緩存通過在本地存儲網頁資源(如HTML、CSS、JavaScript、圖片等),避免每次訪問網頁時都從服務器重新下載這些資源,從而加快頁面加載速度,提高用戶體驗,同時減少服務器帶寬的使用。

明白了,你希望更詳細地了解瀏覽器緩存中的 ExpiresCache-Control 頭部,以及它們之間的關系和具體應用。以下是更深入的講解:

二、Expires 頭部

1. 定義與作用
  • Expires 是一個HTTP響應頭,用于指定資源的絕對過期時間。它告訴瀏覽器在指定的時間之前,可以直接從緩存中使用該資源,而無需向服務器重新請求。
2. 格式
  • Expires 的值是一個絕對的HTTP日期和時間,格式為:Wdy, DD Mon YYYY HH:MM:SS GMT

示例

Expires: Wed, 21 Oct 2025 07:28:00 GMT
3. 使用場景
  • 適用于靜態資源,如圖片、CSS、JavaScript文件,這些資源不經常變化。
  • 適合設置較長的緩存時間,減少瀏覽器對服務器的請求頻率,提升加載速度。
4. 缺點
  • 使用絕對時間,可能受客戶端和服務器時間不同步的影響。
  • 當資源更新時,若不改變 Expires,可能導致瀏覽器繼續使用過期的緩存,出現內容不一致的問題。

三、Cache-Control 頭部

1. 定義與作用
  • Cache-Control 是一個更為靈活和強大的HTTP響應頭,用于控制緩存策略。它可以替代或補充 Expires 頭部,提供更精確的緩存控制。
2. 常用指令
  • max-age=秒數:指定資源在多少秒內被認為是新鮮的。max-age 的優先級高于 Expires

示例

Cache-Control: max-age=3600
  • no-cache:資源必須在使用前重新驗證(即使資源沒有過期)。

示例

Cache-Control: no-cache
  • no-store:禁止任何形式的緩存,既不存儲請求信息,也不存儲響應信息。

示例

Cache-Control: no-store
  • public:響應可被任何緩存區緩存,包括瀏覽器和中間緩存(如CDN)。

示例

Cache-Control: public
  • private:響應僅為單個用戶緩存,不能被共享緩存(如CDN)緩存。

示例

Cache-Control: private
  • must-revalidate:一旦資源過期,必須向服務器驗證其有效性。

示例

Cache-Control: must-revalidate
  • proxy-revalidate:與 must-revalidate 類似,但僅適用于共享緩存。

示例

Cache-Control: proxy-revalidate
3. 使用場景
  • 動態資源:可以靈活設置緩存策略,如需要頻繁更新但又希望利用緩存提升性能的資源。
  • 細粒度控制:通過組合多個指令,實現更復雜的緩存策略。
4. 與 Expires 的關系
  • 優先級:當同時存在 Cache-Control: max-ageExpires 時,Cache-Control 優先級更高。
  • 推薦使用:現代瀏覽器和服務器更推薦使用 Cache-Control,因為它更靈活且不依賴絕對時間。

四、ExpiresCache-Control 的對比

特性ExpiresCache-Control
類型絕對時間相對時間及其他緩存指令
格式HTTP日期格式指令列表
優先級低于 Cache-Control高于 Expires
靈活性較低,只有一個絕對過期時間高,可以組合多種指令控制緩存行為
推薦使用場景主要用于向后兼容舊瀏覽器現代Web應用的首選緩存控制方式

五、實際應用示例

1. 設置長時間緩存(適用于不經常變化的靜態資源)
Cache-Control: public, max-age=31536000
Expires: Wed, 21 Oct 2025 07:28:00 GMT
  • 解釋:資源可以被公共緩存(如CDN)緩存,且在1年內(31536000秒)不需要重新驗證。
2. 設置短時間緩存,需重新驗證(適用于可能會頻繁更新的資源)
Cache-Control: no-cache
  • 解釋:瀏覽器每次使用緩存前必須向服務器驗證資源是否有更新。
3. 禁止緩存(適用于敏感數據)
Cache-Control: no-store
  • 解釋:禁止任何形式的緩存,確保每次請求都從服務器獲取最新數據。

六、結合 ETagLast-Modified 使用緩存驗證

即使設置了 Cache-ControlExpires,瀏覽器在某些情況下仍可能需要驗證緩存資源的有效性。此時,ETagLast-Modified 提供了有效的驗證機制:

  • ETag:提供資源的唯一標識符,確保緩存的資源與服務器上的一致。
  • Last-Modified:記錄資源的最后修改時間,供瀏覽器進行條件請求。

示例

Cache-Control: max-age=3600, must-revalidate
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
Last-Modified: Wed, 21 Oct 2023 07:28:00 GMT

七、最佳實踐

  1. 優先使用 Cache-Control
  • 由于其靈活性和優先級,現代Web開發中應優先配置 Cache-Control 頭部。
  1. 合理設置 max-age
  • 根據資源的更新頻率,合理設置緩存時間。靜態資源可以設置較長時間,動態資源設置較短時間或不緩存。
  1. 結合使用 ETagLast-Modified
  • 提供雙重驗證機制,確保緩存的資源始終是最新的。
  1. 版本化靜態資源
  • 通過在資源URL中添加版本號(如 style.v1.css),確保資源更新時瀏覽器能夠獲取到最新版本,避免緩存問題。
  1. 使用CDN
  • 配合緩存頭部,利用內容分發網絡(CDN)提升全球范圍內的資源加載速度,并有效管理緩存策略。

八、總結

  • ExpiresCache-Control 都用于控制資源的緩存和過期,但 Cache-Control 提供了更高的靈活性和優先級。
  • ETagLast-Modified 是用于緩存驗證的強大工具,確保瀏覽器使用最新的資源。
  • 最佳實踐 是結合使用這些HTTP頭部,合理設置緩存策略,提升Web應用的性能和用戶體驗。

1.4 CDN

CDN(內容分發網絡,Content Delivery Network)是一種通過將內容復制并緩存到全球多個地理位置的服務器上,從而加速用戶訪問速度的技術。它主要的目的是提高網站或應用的性能、穩定性、可擴展性,同時減少服務器負載和帶寬消耗。

一、CDN的工作原理

CDN的核心思想是將網站的靜態資源(如HTML文件、CSS文件、JavaScript、圖片、視頻等)緩存到分布在全球的邊緣服務器(Edge Servers)上。當用戶請求訪問某個資源時,CDN會根據用戶的地理位置,選擇距離用戶最近的服務器提供資源,從而減少加載時間和提高訪問速度。

1. 資源分發與緩存
  • 資源分發:當你將資源上傳到CDN服務時,CDN提供商會將這些內容分發到位于世界各地的數據中心。
  • 緩存:CDN的服務器會將常用的靜態內容緩存到本地存儲中,當有新的請求時,如果內容已經存在并且沒有過期,則直接返回緩存的內容。
2. 邊緣服務器與原始服務器
  • 邊緣服務器(Edge Server):這些是部署在全球各地的服務器,負責將資源提供給終端用戶。用戶訪問時,通常會被路由到離他們最近的邊緣服務器,以減少延遲。
  • 原始服務器(Origin Server):原始服務器是網站的源服務器,存儲網站的所有內容。如果CDN的邊緣服務器沒有緩存某個請求的內容,它會從原始服務器獲取并返回給用戶。
3. 緩存策略

CDN通常會使用一些緩存策略來決定哪些內容需要緩存,以及緩存多久。常見的緩存策略包括:

  • 緩存時間(TTL,Time to Live):決定緩存的有效期。例如,靜態資源如圖片、CSS文件可能會緩存較長時間,而動態內容可能緩存較短時間。
  • 緩存控制(Cache-Control):通過設置HTTP頭來控制緩存行為(如 max-ageno-cache)。
  • 動態內容緩存:CDN一般針對動態內容(如用戶特定數據、實時信息)使用不同的緩存策略,可能會使用“按需緩存”或“低過期時間”的方式進行處理。
4. 智能路由與負載均衡

CDN通常會根據多個因素(如地理位置、網絡負載、帶寬等)選擇最優的邊緣服務器來響應用戶請求。這一過程稱為智能路由或負載均衡。通過此方式,CDN能夠確保用戶始終通過最快的路徑獲取到資源。

二、CDN的優勢

  1. 提高加載速度
    • 減少延遲:通過將內容分發到全球多個節點,用戶總是能夠從離自己最近的節點獲取資源,從而大幅減少延遲,提高加載速度。
    • 更高的可用性:通過分布式緩存,用戶能夠在多個服務器之間獲取資源,即使某個服務器出現故障,也不會影響服務的可用性。
  2. 減輕原始服務器負載
    • CDN緩存了大量靜態內容,減少了原始服務器的直接負擔,降低了帶寬使用和處理請求的壓力。
  3. 提升網站的可擴展性
    • CDN幫助網站應對流量激增,能夠在不同地區和時段自動調整資源的分配和流量管理,提供更好的擴展性。
  4. 增強網站的安全性
    • DDoS防護:許多CDN提供DDoS攻擊防護,能夠通過分布式架構分擔攻擊流量,從而減輕原始服務器的壓力。
    • SSL加密:CDN服務提供SSL證書支持,幫助加密數據傳輸,提升安全性。
  5. 節省帶寬成本
    • 通過減少從原始服務器到客戶端的流量,CDN有助于降低帶寬費用,尤其是對于全球性網站。
  6. 高可用性和容錯性
    • CDN通過將資源緩存到多個節點,提升了資源的冗余度。在某個節點出現故障時,流量可以被自動引導到其他正常工作的節點,保證網站的高可用性。

三、CDN的類型

  1. 靜態內容CDN
    • 主要緩存靜態內容,如圖片、JavaScript文件、CSS文件等。通過將這些內容緩存到多個位置,能夠加速資源加載速度。
  2. 動態內容CDN
    • 動態內容指的是根據用戶請求生成的內容,比如數據庫查詢結果或用戶個性化信息。動態內容通常不緩存,但現代CDN提供商提供了對動態內容的優化方案,通過智能緩存策略加速動態內容的加載。
  3. 直播和視頻流CDN
    • 專門用于視頻流、直播視頻內容的傳輸,優化了大帶寬視頻數據的分發和傳輸。常見的技術包括流媒體協議如 HLS(HTTP Live Streaming)和 DASH(Dynamic Adaptive Streaming over HTTP)。
  4. 邊緣計算CDN
    • 這種類型的CDN不僅提供緩存功能,還支持在邊緣服務器上執行計算任務。它能夠在靠近用戶的地方處理請求,提高性能和降低延遲。

四、CDN的工作流程

  1. 資源上傳到CDN
    • 將網站的靜態資源上傳到CDN供應商的服務器。資源可能會分發到多個全球節點進行緩存。
  2. 用戶請求訪問資源
    • 用戶訪問網頁時,瀏覽器向CDN發起請求。CDN會根據用戶的地理位置,智能選擇離用戶最近的服務器響應請求。
  3. 緩存命中與未命中
    • 如果邊緣服務器已緩存該資源(緩存命中),CDN直接返回緩存的內容。
    • 如果緩存過期或沒有緩存該資源(緩存未命中),CDN會向原始服務器請求資源,并將返回的資源緩存起來供后續用戶使用。
  4. 返回資源給用戶
    • 一旦緩存的資源通過CDN的邊緣節點返回給用戶,用戶的瀏覽器會在本地緩存該資源,下次訪問時,直接從瀏覽器本地獲取。

五、CDN的服務提供商

目前,全球有多個主要的CDN服務提供商,最知名的包括:

  1. Cloudflare
    • 提供免費和收費的CDN服務,支持全球分布的邊緣節點,提供DDoS防護和Web應用防火墻(WAF)。
  2. Akamai
    • 全球領先的CDN供應商,服務覆蓋范圍廣,適用于大規模企業和高流量網站,提供強大的內容加速和安全功能。
  3. Amazon CloudFront
    • AWS提供的CDN服務,能夠與AWS的其他服務(如S3、EC2等)無縫集成,提供高可擴展性和靈活性。
  4. Fastly
    • 以高性能為特點,支持即時緩存清除和高效的動態內容傳輸,適用于對延遲要求極高的應用。
  5. KeyCDN
    • 提供較為簡單和成本效益高的CDN解決方案,適用于中小型網站。

六、CDN的優化策略

  1. 合理設置緩存過期時間
    • 根據內容的更新頻率,合理設置緩存過期時間(TTL),避免緩存過期導致頻繁訪問原始服務器。
  2. 使用分布式緩存
    • 利用CDN的全球節點分布,將內容緩存到多個節點,從而提供更好的負載均衡和冗余。
  3. 壓縮和優化內容
    • 對資源進行壓縮(如圖片、CSS、JavaScript等),減少傳輸的數據量,提高加載速度。
  4. 結合HTTPS加密
    • 使用CDN的SSL證書加密功能,為網站提供HTTPS支持,提升數據傳輸的安全性。

七、總結

CDN是一種通過將網站內容分發到全球多個節點,減少延遲、提高加載速度、減輕服務器負載的技術。它不僅能加速資源的交付,還能提高網站的安全性、可用性和可擴展性。隨著互聯網應用的增長,CDN已成為優化網站性能和提供全球用戶良好體驗的重要工具。

1.4.1 用戶請求CDN流程

用戶請求CDN資源的流程可以分為幾個步驟。這個流程涉及到用戶如何向CDN發起請求,CDN如何決定從哪個服務器提供資源,以及緩存如何影響響應時間。以下是詳細的用戶請求CD能資源的流程:

一、請求流程概述

  1. 用戶發起請求:用戶的瀏覽器或應用程序向服務器請求某個資源(如圖片、CSS、JavaScript文件等)。
  2. DNS解析:請求首先通過DNS解析,將資源的域名解析為CDN的IP地址。
  3. 路由到CDN邊緣節點:用戶的請求被路由到距離用戶最近的CDN邊緣節點。
  4. 邊緣節點緩存檢查:CDN的邊緣節點檢查緩存中是否已有該資源。
  5. 緩存命中或未命中:根據緩存的情況,決定是直接返回緩存的內容,還是從源服務器獲取最新的資源。
  6. 返回資源給用戶:資源通過邊緣節點傳輸給用戶,用戶的瀏覽器接收并展示。

二、詳細步驟

1. 用戶發起請求

用戶在瀏覽器中輸入網址或點擊鏈接時,瀏覽器會發起HTTP請求來請求某個資源。這些資源通常是靜態文件,如HTML、CSS、JavaScript文件,或者圖片、視頻等媒體文件。

例如,用戶請求資源:https://www.example.com/images/logo.png

2. DNS解析

用戶請求的域名(如 www.example.com)會通過DNS解析,轉化為一個IP地址。通常,這個域名已經指向CDN提供商的域名解析系統。

  • 傳統方式:直接訪問原始服務器的IP。
  • CDN方式:DNS解析返回的是CDN邊緣服務器的IP,而不是源服務器的IP。

CDN提供商通常會在多個地理位置部署多個邊緣節點(edge node),當請求發起時,DNS會返回離用戶最近的CDN邊緣節點的IP地址,確保請求被路由到最近的服務器。

3. 請求被路由到CDN邊緣節點

DNS解析完成后,瀏覽器向CDN的邊緣節點發送請求。CDN邊緣節點是部署在全球各地的服務器,它們緩存了資源內容,能夠快速響應用戶請求。

CDN邊緣節點的選擇通常由以下因素決定:

  • 地理位置:用戶的IP地址與邊緣節點的地理位置之間的距離,盡可能選擇距離用戶最近的節點。
  • 網絡負載:當前邊緣節點的負載情況。如果某個節點過載,CDN會選擇其他負載較低的節點。
4. 邊緣節點緩存檢查

邊緣節點收到請求后,會檢查緩存中是否已有該資源。這一步稱為緩存命中檢查

  • 緩存命中:如果邊緣節點緩存中已經存在該資源,并且資源沒有過期,則直接從緩存中讀取并返回給用戶。
  • 緩存未命中:如果緩存中沒有該資源,或者資源已經過期,則會將請求轉發給源服務器(origin server)。
5. 緩存命中或未命中
  • 緩存命中:如果資源已經存在并且有效,CDN會直接將緩存的資源返回給用戶。這是加速訪問的關鍵步驟,因為用戶不需要訪問源服務器,節省了時間和帶寬。

    例如,若用戶請求 https://www.example.com/images/logo.png,CDN的邊緣節點可能已經緩存了這個文件,且TTL(過期時間)沒有到期,此時CDN直接返回文件。

  • 緩存未命中:如果緩存中沒有該資源,或者緩存的資源已經過期,CDN會向源服務器發起請求以獲取資源。

6. 從源服務器獲取資源

當緩存未命中時,CDN邊緣節點會向原始服務器(origin server)請求該資源。此時,源服務器會根據請求返回最新的資源,并且將該資源緩存到邊緣節點,以供下次請求使用。

  • 資源返回后,CDN會緩存到邊緣節點并設置適當的緩存過期時間(TTL)。這意味著下一次請求時,邊緣節點可以直接返回緩存的內容,而不需要再訪問源服務器。
7. 返回資源給用戶

無論是緩存命中還是從源服務器獲取資源,最終,CDN的邊緣節點會把響應數據返回給用戶的瀏覽器。用戶的瀏覽器從CDN邊緣節點接收到資源,并進行展示。

8. 瀏覽器緩存

在資源返回給瀏覽器后,瀏覽器也會根據響應頭(如 Cache-ControlExpires 等)進行本地緩存,以便在下一次訪問時直接從本地緩存中獲取資源,而不再發送請求到CDN或源服務器。

三、緩存策略與內容更新

CDN中的緩存策略非常關鍵,它決定了緩存內容的過期時間、更新方式以及緩存策略的靈活性。

  1. TTL(Time to Live,生存時間)
    • 每個緩存的資源都會設置一個TTL,TTL指定了該資源在CDN邊緣節點緩存的有效期。TTL過期后,緩存的內容會被認為是過期的,需要重新向源服務器請求內容。
  2. 緩存清除
    • 主動清除:CDN提供商允許通過管理控制臺或API來主動清除緩存中的某些資源。這對于資源更新頻繁或緊急更新的情況非常重要。
    • 自動清除:當資源的TTL到期時,CDN會自動清除緩存并向源服務器請求新的內容。
  3. 緩存驗證
    • 使用 ETagLast-Modified 等HTTP頭部字段,CDN可以驗證緩存是否有效。即使TTL未到期,CDN也可以通過向源服務器發送條件請求(If-None-MatchIf-Modified-Since)來判斷緩存是否需要更新。

四、CDN的優勢

  1. 減少延遲:用戶總是能從離自己最近的邊緣服務器獲取資源,減少了傳輸延遲。
  2. 提高可用性:即使源服務器宕機,CDN仍可以從其他節點提供緩存的內容,保持服務可用。
  3. 減輕源服務器負擔:通過緩存大量請求,CDN能夠減輕源服務器的負載,減少帶寬消耗。
  4. 提高網站性能:加速資源加載,提升用戶體驗,尤其是對于全球用戶。

五、CDN請求流程示意圖

 用戶請求 --> DNS解析 --> CDN邊緣節點 --> 緩存檢查 -->|                          |                        |緩存命中                     緩存未命中                  ||                          |                        |返回緩存的資源             從源服務器請求資源            ||                          |                        |
返回給用戶的資源             緩存資源并返回給用戶        |

六、總結

  1. CDN工作流程:CDN通過將資源分發到多個邊緣節點,利用智能路由、緩存和負載均衡技術,將資源快速交付給用戶,減少延遲,提高網站性能。
  2. 緩存命中與未命中:CDN根據緩存策略決定是否直接返回緩存的內容,或者向源服務器請求更新內容。
  3. 瀏覽器與CDN緩存:瀏覽器本地緩存和CDN的緩存共同工作,確保資源加載更快,減少重復請求。

CDN在提高網站性能、增強網站可用性、降低帶寬消耗等方面發揮了重要作用,是現代Web應用不可或缺的組成部分。

image-20241217113705693

1.4.2 CDN分層緩存

CDN(Content Delivery Network,內容分發網絡)的分層緩存(Layered Caching)是指通過多級緩存架構有效提升內容分發效率的一種策略。在CDN中,請求的內容通常會經過多個層級的緩存節點,以實現更佳的性能和資源利用率。整個流程通常可以分為以下幾個層次:

  1. L1 邊緣節點緩存(Edge Cache)
    這是離用戶最近的一層緩存節點。當用戶向CDN請求內容時,邊緣節點首先檢查本地緩存是否已存有該內容。若存在并未過期,便直接從該節點返回內容給用戶,降低傳輸延遲,提高用戶體驗;若緩存中無此內容或內容已過期,則向上層的緩存節點或源站請求。
  2. L2 區域或中間層緩存(Mid-Tier/Regional Cache)
    當邊緣節點未能在本地拿到所需內容時,會將請求向上層的區域緩存節點發出。區域緩存通常位于更靠近源站的核心網絡,儲存那些在一定時間窗口內被多個邊緣節點重復請求的內容。通過在此層進行緩存,CDN減少了向源站多次重復請求同一內容的頻率。這一層有助于將熱門內容在更廣的地理范圍內進行共享,降低源站負載,并減少跨區域的回源請求延遲。
  3. 源站(Origin Server)
    當所有中間層緩存與邊緣緩存均無請求內容時,才會到達最終的源站。源站是內容的原始出處,CDN會從這里獲取最新版本的內容,然后將其分發給請求用戶,并在適當的層級緩存節點中儲存副本,以便滿足未來類似請求。

分層緩存的工作原理

以下是一個典型的用戶請求過程:

  1. 用戶訪問網站,請求某個資源(例如一張圖片)。
  2. 用戶的DNS解析請求將用戶導向離他最近的L1邊緣節點。
  3. L1節點檢查自身是否緩存了該資源。
    • 如果,則直接將資源返回給用戶,請求結束。這稱為“緩存命中”。
    • 如果沒有,則L1節點向其上層的L2區域節點發起請求。
  4. L2節點執行相同的檢查,查看自身是否緩存了該資源。
    • 如果,則將資源返回給L1節點,L1節點再將其返回給用戶。同時,L1節點也會緩存該資源,以便下次相同的請求可以直接命中。
    • 如果沒有,則L2節點繼續向上,向源站發起請求。
  5. 源站將資源返回給L2節點,L2節點再返回給L1節點,L1節點最終返回給用戶。L1和L2節點都會緩存該資源。

分層緩存的優勢

  • 減輕源站壓力: 通過多層緩存,大部分用戶請求都可以在L1或L2節點得到滿足,大大減少了回源站的請求數量,從而減輕了源站的負載。
  • 提高緩存命中率: 分層結構使得更常用的內容可以緩存在更靠近用戶的L1節點上,從而提高整體的緩存命中率,減少用戶訪問延遲。
  • 降低網絡擁塞: 由于大量請求在CDN內部完成,減少了跨區域和跨運營商的網絡傳輸,有助于緩解網絡擁塞。
  • 更好的可擴展性: 分層結構使得CDN系統更容易擴展,可以通過增加L1和L2節點來應對不斷增長的用戶訪問量。

分片緩存(Chunked Caching)

在某些情況下,CDN還會使用分片緩存技術,將大文件(例如視頻文件)分割成多個小片段(chunks),然后分別緩存這些片段。當用戶請求文件時,CDN只需傳輸用戶需要的片段,而不是整個文件。這對于提高大文件傳輸效率和支持流媒體播放非常有用。

總結

CDN分層緩存是一種有效的提高網站性能和用戶體驗的技術。通過合理地組織和管理多層緩存節點,CDN可以更好地分配資源,提高緩存命中率,并減輕源站的壓力。

2.Redis 安裝及連接

Redis簡介
Redis(Remote Dictionary Server)是一個開源的內存數據結構存儲系統,可以用作數據庫、緩存和消息隊列中間件。它以Key-Value形式存儲數據,提供多種數據結構和豐富的功能特性。Redis的核心價值在于高速訪問、簡單的數據操作模型以及豐富的數據結構支持,使其在需要快速讀寫、實時計算和高并發的場景中表現突出。

Redis的主要特性

  1. 內存存儲
    Redis將數據存儲在內存中,從而達到非常高的訪問速度(讀寫操作通常在微秒級別)。這使其在對實時性要求高的場景(如會話存儲、實時排行、實時計數器等)表現優異。

  2. 多種數據結構支持
    相較于傳統的Key-Value存儲僅支持字符串,Redis支持多種豐富的數據結構類型,這些數據結構以簡單命令即可操作:

    • String(字符串):最基礎的數據結構,可存儲普通字符串、數字、二進制數據。
    • Hash(哈希):類似于Key-Value映射的集合,可方便存儲對象屬性并對屬性進行增刪改操作。
    • List(列表):雙端鏈表實現,支持從頭尾插入、彈出元素,可用來實現消息隊列、任務列表等功能。
    • Set(集合):無序集合結構,支持求交集、并集和差集等集合運算,常用于去重、標簽管理。
    • Sorted Set(有序集合):每個元素會關聯一個分數(score),Redis會根據分數對元素進行排序,可用于排行榜、延時隊列等場景。
    • Bitmap(位圖)、HyperLogLogGeo(地理位置)等特殊數據類型:滿足統計計數、地理位置查詢等特殊需求。
  3. 持久化能力
    雖然Redis是內存數據庫,但它并非易失性存儲。Redis提供兩種持久化機制,讓數據在斷電后仍能恢復:

    • RDB(Redis Database Backup):定時生成內存快照并持久化到磁盤,恢復速度快,數據略有延遲。
    • AOF(Append Only File):將每次寫操作以日志的形式追加到文件中,數據恢復更為完整,可根據策略對AOF文件進行定期重寫壓縮。

    可以根據業務需求選擇合適的持久化方案,或同時開啟RDB和AOF實現數據安全與高效率的折中。

  4. 高可用與分布式
    Redis提供主從復制(Master-Slave Replication)實現數據的多份冗余,主節點負責寫操作,從節點同步主節點的數據,提供讀取分流和故障切換。當主節點出現故障時,可手動或借助Redis Sentinel(哨兵)實現自動故障轉移。
    對于更大規模的數據集與訪問壓力,Redis Cluster可以將數據分片至多個節點,提升整體存儲能力和吞吐性能。

  5. 事務支持
    Redis提供簡單的事務機制(MULTI/EXEC命令),可以將一組操作打包,保證這些操作的順序性和原子性。雖然不支持復雜的回滾功能,但事務可以確保一組命令要么都執行要么都不執行。

  6. Lua腳本擴展
    Redis內置了Lua解釋器,用戶可以在Redis內原子執行Lua腳本,對數據進行復雜操作,而無需在客戶端與Redis之間多次往返,提高復雜操作的性能和一致性。

  7. 豐富的使用場景
    憑借高性能和多數據結構支持,Redis可廣泛應用于各種場景:

    • 緩存熱點數據(例如:熱門商品信息、用戶會話數據、應用程序配置)
    • 消息隊列與任務調度(利用List或Stream)
    • 實時統計(計數器、排行榜、實時分析)
    • 分布式鎖(利用SetNx命令實現簡單的分布式鎖機制)
  8. 簡單易用的命令行與客戶端支持
    Redis提供簡潔直觀的命令行客戶端和與主流編程語言(如Java、Python、Go、C#等)兼容的客戶端庫,降低學習成本與集成難度。


總結
Redis作為一個內存數據存儲系統,具有高性能、豐富的數據類型、靈活的持久化策略以及高可用性架構支持。它在高并發、低延遲與實時處理場景中得到廣泛應用,已成為構建現代互聯網應用的重要基礎組件。

image-20241218093552202

2.1 dnf 安裝 Redis

# Rocky 9.4 由系統源提供
[root@redis1.xyy.org ~]#dnf info redis
Name         : redis
Version      : 6.2.7
Release      : 1.el9
Architecture : x86_64
Size         : 1.3 M
Source       : redis-6.2.7-1.el9.src.rpm
Repository   : appstream
Summary      : A persistent key-value database
URL          : https://redis.io
License      : BSD and MIT
Description  : Redis is an advanced key-value store. It is often referred to as a data: structure server since keys can contain strings, hashes, lists, sets and: sorted sets.:: You can run atomic operations on these types, like appending to a string;: incrementing the value in a hash; pushing to a list; computing set: intersection, union and difference; or getting the member with highest: ranking in a sorted set.:: In order to achieve its outstanding performance, Redis works with an: in-memory dataset. Depending on your use case, you can persist it either: by dumping the dataset to disk every once in a while, or by appending: each command to a log.:: Redis also supports trivial-to-setup master-slave replication, with very: fast non-blocking first synchronization, auto-reconnection on net split: and so forth.:: Other features include Transactions, Pub/Sub, Lua scripting, Keys with a: limited time-to-live, and configuration settings to make Redis behave like: a cache.:: You can use Redis from most programming languages also.[root@Rocky9.4 ~]## CentOS 7由 epel 源提供
[root@CentOS7 ~]#yum info redis
Name        : redis
Arch        : x86_64
Version     : 3.2.12
Release     : 2.el7
Size        : 1.4 M
Repo        : installed
From repo   : epel
Summary     : A persistent key-value database
URL         : http://redis.io
License     : BSD[root@redis1.xyy.org ~]#dnf install redis
[root@redis1.xyy.org ~]#systemctl enable --now redis
[root@redis1.xyy.org ~]#pstree -p | grep redis|-redis-server(4237)-+-{redis-server}(4238)|                    |-{redis-server}(4239)|                    |-{redis-server}(4240)|                    `-{redis-server}(4241)
[root@redis1.xyy.org ~]#
[root@redis1.xyy.org ~]#redis-cl
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> INFO Server
# Server
redis_version:6.2.7
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:ec192bdd77ecd321
redis_mode:standalone
os:Linux 5.14.0-427.13.1.el9_4.x86_64 x86_64
arch_bits:64
monotonic_clock:POSIX clock_gettime
multiplexing_api:epoll
atomicvar_api:c11-builtin
gcc_version:11.3.1
process_id:4237
process_supervised:systemd
run_id:37144e0c3a2930dac6148605d26afae8ee4d38ba
tcp_port:6379
server_time_usec:1734486571682241
uptime_in_seconds:37314
uptime_in_days:0
hz:10
configured_hz:10
lru_clock:6433323
executable:/usr/bin/redis-server
config_file:/etc/redis/redis.conf
io_threads_active:0
127.0.0.1:6379>

2.2 編譯安裝 Redis

從 Redis 官方下載地址 獲取穩定版壓縮包,如 redis-7.4.0.tar.gz

image-20241218102907079
# 1.創建 Redis 用戶(不需要登錄權限,只是用于運行 Redis 服務以提高安全性)
useradd -r -s /sbin/nologin redis# 2.獲取源碼包
wget https://download.redis.io/releases/redis-7.4.0.tar.gz# 3.解壓并進入源碼目錄
tar xf redis-7.4.0.tar.gz
cd redis-7.4.0# 4.開始編譯(在某些發行版下可開啟 USE_SYSTEMD=yes 選項,以生成可與 systemd 交互的可執行文件。)
make -j $(nproc) USE_SYSTEMD=yes# 5.安裝到指定位置
make PREFIX=/apps/redis install# 6.建立軟鏈接(方便在命令行中使用redis-server、redis-cli)
ln -s /apps/redis/bin/redis-* /usr/bin/# 7.創建所需目錄
mkdir -p /apps/redis/{etc,log,data,run}# 8.拷貝源碼目錄中自帶redis.conf,拷貝到配置目錄:
cp redis.conf /apps/redis/etc/# 9.redis.conf:修改關鍵配置
#bind:改為 0.0.0.0 或保留默認看實際需要;
#requirepass:設置 Redis 密碼,如 requirepass 123456;
#dir:RDB/快照文件存放目錄,一般設為 /apps/redis/data;
#logfile:日志文件路徑,如 /apps/redis/log/redis-6379.log;
#pidfile:pid 文件路徑,如 /apps/redis/run/redis-6379.pid;
sed -i -e 's/bind 127.0.0.1/bind 0.0.0.0/' \-e "/# requirepass/a requirepass 123456" \-e "/^dir .*/c dir /apps/redis/data/" \-e "/^logfile .*/c logfile /apps/redis/log/redis-6379.log" \-e "/^pidfile .*/c pidfile /apps/redis/run/redis-6379.pid" \/apps/redis/etc/redis.conf# 10.設置文件權限
chown -R redis:redis /apps/redis# 11.內核與系統參數優化(不優化會有告警)# 11.1 調整內核參數
vim /etc/sysctl.conf
net.core.somaxconn = 1024
vm.overcommit_memory = 1sysctl -p# 11.2 禁用透明大頁(THP)
echo never > /sys/kernel/mm/transparent_hugepage/enabled
# 可以寫入啟動腳本(如 /etc/rc.local 或 /etc/rc.d/rc.local)以在重啟后繼續生效。# 12.創建Systemd服務并啟動
# CentOS/Rocky:/usr/lib/systemd/system/redis.service
# Ubuntu:/lib/systemd/system/redis.service(或 /etc/systemd/system/redis.service)
[Unit]
Description=Redis persistent key-value database
After=network.target[Service]
ExecStart=/apps/redis/bin/redis-server /apps/redis/etc/redis.conf --supervised systemd
ExecStop=/bin/kill -s QUIT $MAINPID
# 啟動notify一定要編譯了 USE_SYSTEMD=yes,否則啟動服務有問題
Type=notify
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755[Install]
WantedBy=multi-user.target# 13.刷新并啟動服務
systemctl daemon-reload
systemctl enable --now redis
systemctl status redis# 14.查看Redis版本或者信息
redis-server -v
# 查看服務信息
redis-cli -a 123456 INFO Server
# 測試插入和查詢數據
redis-cli -a 123456 set mykey "Hello World"
redis-cli -a 123456 get mykey
#! /bin/bash
#-----------------------------------------------------
#Author:            XingYuyu
#Date:              2024-08-12
#Blog:              http://8.141.4.74
#Filename:          install_redis.sh
#Description:       [Online Install Redis for Rocky Linux ,Ubuntu,CentOS ]
#-----------------------------------------------------
VERSION=redis-7.4.0
PASSWORD=123456
INSTALL_DIR=/apps/redisos_type() {awk -F'[ "]' '/^NAME/{print $2}' /etc/os-release
}color() {RES_COL=80MOVE_TO_COL="echo -en \e[${RES_COL}G"SETCOLOR_SUCCESS="echo -en \e[1;32m"SETCOLOR_FAILURE="echo -en \e[1;31m"SETCOLOR_WARNING="echo -en \e[1;33m"SETCOLOR_NORMAL="echo -en \e[0m"echo -n "$1" && $MOVE_TO_COLecho -n "["if [ $2 = "success" -o $2 = "0" ]; then${SETCOLOR_SUCCESS}echo -n $"  OK  "elif [ $2 = "failure" -o $2 = "1" ]; then${SETCOLOR_FAILURE}echo -n $"FAILED"else${SETCOLOR_WARNING}echo -n $"WARNING"fi${SETCOLOR_NORMAL}echo -n $"]"echo
}install_redis() {wget https://download.redis.io/releases/${VERSION}.tar.gz || {color "Redis 源碼下載失敗" 1exit}tar xf ${VERSION}.tar.gzcd ${VERSION}CPUS=lscpu | awk '/^CPU\(s\)/{print $2}'make -j $CPUS USE_SYSTEMD=yes PREFIX=${INSTALL_DIR} install && color "Redis 編譯安裝完成" 0 || {color "Redis 編譯安裝失敗" 1exit}ln -s ${INSTALL_DIR}/bin/redis-* /usr/bin/mkdir -p ${INSTALL_DIR}/{etc,log,data,run}cp redis.conf ${INSTALL_DIR}/etc/sed -i -e 's/bind 127.0.0.1/bind 0.0.0.0/' -e "/# requirepass/a requirepass $PASSWORD" -e "/^dir .*/c dir ${INSTALL_DIR}/data/" -e "/^logfile .*/c logfile ${INSTALL_DIR}/log/redis-6379.log" -e "/^pidfile .*/c pidfile ${INSTALL_DIR}/run/redis-6379.pid" ${INSTALL_DIR}/etc/redis.confif id redis &>/dev/null; thencolor "Redis 用戶已經存在,無需創建" 0elseuseradd -r -s /sbin/nologin rediscolor "Redis 用戶創建成功" 0fichown -R redis.redis ${INSTALL_DIR}cat >>/etc/sysctl.conf <<EOF
net.core.somaxconn = 1024
vm.overcommit_memory = 1
EOFsysctl -pif [ `os_type` == "Ubuntu" ];thencat >> /lib/systemd/system/rc-local.service <<EOF
[Install]
WantedBy=multi-user.target
EOFecho '#!/bin/bash' > /etc/rc.localecho 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' >>/etc/rc.localchmod +x /etc/rc.local/etc/rc.local# Ubuntu 的service文件放在/lib/systemd/system/下或者/etc/systemd/system/下不能放在/usr/lib/下cat > /lib/systemd/system/redis.service <<EOF
[Unit]
Description=Redis persistent key-value database
After=network.target[Service]
ExecStart=${INSTALL_DIR}/bin/redis-server ${INSTALL_DIR}/etc/redis.conf --supervised systemd
ExecStop=/bin/kill -s QUIT \$MAINPID
Type=notify
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755[Install]
WantedBy=multi-user.target
EOFelseecho 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' >>/etc/rc.d/rc.localchmod +x /etc/rc.d/rc.local/etc/rc.d/rc.localcat > /usr/lib/systemd/system/redis.service <<EOF
[Unit]
Description=Redis persistent key-value database
After=network.target[Service]
ExecStart=${INSTALL_DIR}/bin/redis-server ${INSTALL_DIR}/etc/redis.conf --supervised systemd
ExecStop=/bin/kill -s QUIT \$MAINPID
Type=notify
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755[Install]
WantedBy=multi-user.targetEOFfisystemctl daemon-reloadsystemctl enable --now redis &>/dev/nullsystemctl is-active redis &> /dev/null && color "Redis 服務啟動成功,Redis信息如下:" 3 || { color "Redis 啟動失敗" 1 ;exit; }#sleep 5redis-cli -a $PASSWORD INFO Server 2>/dev/null
}install_CentOS7() {. /etc/init.d/functions# jemalloc-devel依賴于epel源yum -y install epel-release && yum -y install gcc jemalloc-devel systemd-devel || {color "安裝軟件包失敗,請檢查網絡配置" 1exit}rpm -q wget &>/dev/null || yum -y install wget &>/dev/nullwget https://download.redis.io/releases/${VERSION}.tar.gz || {action "Redis 源碼下載失敗" falseexit}tar xf ${VERSION}.tar.gzcd ${VERSION}CPUS=lscpu | awk '/^CPU\(s\)/{print $2}'make -j $CPUS USE_SYSTEMD=yes PREFIX=${INSTALL_DIR} install && action "Redis 編譯安裝完成" || {action "Redis 編譯安裝失敗" falseexit}ln -s ${INSTALL_DIR}/bin/redis-* /usr/bin/mkdir -p ${INSTALL_DIR}/{etc,log,data,run}cp redis.conf ${INSTALL_DIR}/etc/sed -i -e 's/bind 127.0.0.1/bind 0.0.0.0/' -e "/# requirepass/a requirepass $PASSWORD" -e "/^dir .*/c dir ${INSTALL_DIR}/data/" -e "/^logfile .*/c logfile ${INSTALL_DIR}/log/redis-6379.log" -e "/^pidfile .*/c pidfile ${INSTALL_DIR}/run/redis-6379.pid" ${INSTALL_DIR}/etc/redis.confif id redis &>/dev/null; thenaction "Redis 用戶已經存在" falseelseuseradd -r -s /sbin/nologin redisfichown -R redis.redis ${INSTALL_DIR}cat >>/etc/sysctl.conf <<EOF
net.core.somaxconn = 1024
vm.overcommit_memory = 1
EOFsysctl -pecho 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' >>/etc/rc.d/rc.localchmod +x /etc/rc.d/rc.local/etc/rc.d/rc.localcat >/usr/lib/systemd/system/redis.service <<EOF
[Unit]
Description=Redis persistent key-value database
After=network.target[Service]
ExecStart=${INSTALL_DIR}/bin/redis-server ${INSTALL_DIR}/etc/redis.conf --supervised systemd
ExecReload=/bin/kill -s HUP \$MAINPID
ExecStop=/bin/kill -s QUIT \$MAINPID
Type=notify
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755[Install]
WantedBy=multi-user.targetEOFsystemctl daemon-reloadsystemctl enable --now redis &>/dev/nullsystemctl is-active redis &> /dev/null && ${COLOR}"Redis 服務啟動成功,Redis信息如下:"${END} || { ${COLOR}"Redis 啟動失敗"${END};exit; }#sleep 5redis-cli -a $PASSWORD INFO Server 2>/dev/null
}install_Ubuntu() {apt -y install make gcc libjemalloc-dev libsystemd-dev || {color "安裝軟件包失敗,請檢查網絡配置" 1exit}install_redis
}install_Rocky() {# jemalloc-devel依賴于epel源yum -y install epel-release && yum -y install gcc jemalloc-devel systemd-devel || {color "安裝軟件包失敗,請檢查網絡配置" 1exit}rpm -q wget &>/dev/null || yum -y install wget &>/dev/nullinstall_redis
}if [ $(os_type) == 'CentOS' ]; theninstall_CentOS7
elif [ $(os_type) == 'Rocky' ]; theninstall_Rocky
elif [ $(os_type) == 'Ubuntu' ]; theninstall_Ubuntu
elsecolor "未識別的操作系統" 1
fi

2.3 連接到 Redis

2.3.1 客戶端連接到 Redis

1.本機無密碼連接

redis-cli

2.跨主機無密碼連接

redis-cli -h HOSTNAME/IP -p PORT

3.跨主機密碼連接

redis-cli -h HOSTNAME/IP -p PORT -a PASSWORD

2.3.2 程序連接 Redis

redis 支持多種開發語言訪問

https://redis.io/docs/latest/develop/clients/

image-20241218152549416

shell 腳本寫入數據到 Redis

#!/bin/bashNUM=100
PASS=123456for i in `seq $NUM`; doredis-cli -h 127.0.0.1 -a "$PASS" --no-auth-warning set key${i} value${i}echo "key${i} value${i} 寫入完成"
doneecho "$NUM 個key寫入到Redis完成"

3.Redis 的多實例

在生產環境中,為了更好地利用資源、實現多租戶隔離或分離不同業務的數據與配置,運維人員往往會在一臺服務器上運行多個 Redis 實例。Redis 的多實例部署并非Redis內建的特性,而是通過為每個實例指定獨立的配置文件、獨立的運行端口與數據目錄來實現的。以下是關于Redis多實例的詳細講解:

為什么需要多實例

  1. 資源隔離與多租戶支持
    在某些場景下,不同的業務線或不同的用戶需要獨立的Redis服務,以免數據和性能相互影響。多實例可以為每個業務運行獨立的Redis,保證數據和訪問流量的隔離。
  2. 不同的配置要求
    某些業務可能需要不同的持久化策略(RDB或AOF)、內存管理策略或安全設置。多實例部署允許針對每個實例使用單獨的配置文件,從而靈活定制每個實例的行為。
  3. 更好地利用硬件資源
    一臺物理機/虛擬機的CPU、內存、網絡資源較為充裕時,可以在同一臺機器上運行多個Redis實例,充分利用硬件資源。尤其在內存較大時,不同實例分別作為緩存、隊列、會話存儲使用,可以最大化硬件利用率。

配置多實例的關鍵點

  1. 獨立的配置文件
    每個實例都需要一個獨立的配置文件(例如 redis-6379.conf, redis-6380.conf)。
    在配置文件中需要注意如下參數:

    • port:每個實例必須使用不同的端口,如6379、6380、6381等。
    • pidfile:每個實例需要獨立的PID文件,如 /var/run/redis_6379.pid/var/run/redis_6380.pid
    • logfile:為每個實例指定獨立的日志文件,如 /var/log/redis_6379.log/var/log/redis_6380.log
    • dir:為每個實例指定獨立的數據目錄,如 /var/lib/redis/6379//var/lib/redis/6380/,確保RDB或AOF文件不沖突。
    • daemonize yes:通常在生產中,多實例都以守護進程方式后臺運行。利用 systemd 的進程監督能力,即使用 --supervised systemd 參數時,必須將 daemonize 設為 no。如果將 daemonize 設為 yes,則與 systemd 的監督模式相矛盾,導致 Redis 無法正常通過 systemd 進行管理和監控。
  2. 獨立的啟動命令
    啟動時為每個實例指定相應的配置文件。常用命令形式:

    redis-server /path/to/redis-6379.conf
    redis-server /path/to/redis-6380.conf
    

    確保每個實例正常監聽自己的端口并使用自己的配置。

  3. 服務管理與守護進程
    為每個實例創建單獨的systemd服務文件或init腳本,方便運維管理。如在systemd中創建 /etc/systemd/system/redis@6379.serviceredis@6380.service 等文件,然后通過 systemctl start redis@6379 啟動指定實例。

  4. 安全與訪問控制
    確保為每個實例設置合理的訪問控制,如 bind參數、protected-mode設置、requirepass或ACL策略。多實例運行時應確保不同實例的數據和訪問策略獨立,避免安全隱患。

  5. 監控與報警
    多實例運行時需要對每個實例分別進行監控,收集其內存使用、連接數、QPS、延遲、慢查詢等指標,并對異常情況及時報警。

舉例:多實例文件組織形式

/etc/redis/
├─ redis-6379.conf
├─ redis-6380.conf
└─ redis-6381.conf/var/lib/redis/
├─ 6379/
│  ├─ dump.rdb
│  └─ appendonly.aof
├─ 6380/
│  ├─ dump.rdb
│  └─ appendonly.aof
└─ 6381/├─ dump.rdb└─ appendonly.aof/var/log/
├─ redis_6379.log
├─ redis_6380.log
└─ redis_6381.log

總結

Redis多實例部署是通過為每個實例提供獨立的端口、獨立的配置文件以及數據和日志目錄來實現的。這種方式在同一臺服務器上實現了靈活的資源分配和多租戶支持。通過精心配置和管理,運維人員能夠同時運行多個Redis實例,為不同應用提供高效、獨立而又經濟實惠的內存數據存儲服務。

案例:以編譯安裝為例實現 Redis 多實例

# 生成的文件列表
[root@Rocky9.4 ~]#ll /apps/redis/
total 0
drwxr-xr-x 2 redis redis 134 Dec 17 23:22 bin
drwxr-xr-x 2 redis redis  22 Dec 18 20:04 data
drwxr-xr-x 2 redis redis  24 Dec 18 20:04 etc
drwxr-xr-x 2 redis redis  28 Dec 17 23:22 log
drwxr-xr-x 2 redis redis  28 Dec 18 20:04 run[root@Rocky9.4 redis]#tree /apps/redis/
/apps/redis/
├── bin
│   ├── redis-benchmark
│   ├── redis-check-aof -> redis-server
│   ├── redis-check-rdb -> redis-server
│   ├── redis-cli
│   ├── redis-sentinel -> redis-server
│   └── redis-server
├── data
│   ├── dump-6379.rdb
│   ├── dump-6380.rdb
│   └── dump-6381.rdb
├── etc
│   ├── redis_6379.conf
│   ├── redis_6380.conf
│   ├── redis_6381.conf
│   └── redis.conf
├── log
│   ├── redis-6379.log
│   ├── redis-6380.log
│   └── redis-6381.log
└── run├── redis-6379.pid├── redis-6380.pid└── redis-6381.pid5 directories, 19 files# 配置文件需要修改的地方
vim /apps/redis/etc/redis_6379.conf
bind 0.0.0.0 -::1
port 6379
daemonize no
pidfile /apps/redis/run/redis-6379.pid
logfile /apps/redis/log/redis-6379.log
# 寫入數據的時候,并且滿足save才會生產dump-6379.rdb這個文件
dbfilename dump-6379.rdb
dir /apps/redis/data/
# 3600秒,寫一次數據 300秒,100次數據,60秒,10000次數據 滿足就會備份,為了更快的看到效果可以更改,例如:save 60 1
save 3600 1 300 100 60 10000
appendfilename "appendonly-6379.aof"vim /apps/redis/etc/redis_6380.conf
bind 0.0.0.0 -::1
port 6380
daemonize no
pidfile /apps/redis/run/redis-6380.pid
logfile /apps/redis/log/redis-6380.log
dbfilename dump-6380.rdb
dir /apps/redis/data/
save 3600 1 300 100 60 10000
appendfilename "appendonly-6380.aof"vim /apps/redis/etc/redis_6381.conf
bind 0.0.0.0 -::1
port 6381
daemonize no
pidfile /apps/redis/run/redis-6381.pid
logfile /apps/redis/log/redis-6381.log
dbfilename dump-6381.rdb
dir /apps/redis/data/
save 3600 1 300 100 60 10000
appendfilename "appendonly-6381.aof"# 創建service文件
# 1./usr/lib/systemd/system/redis6379.service
[Unit]
Description=Redis persistent key-value database
After=network.target[Service]
ExecStart=/apps/redis/bin/redis-server /apps/redis/etc/redis_6379.conf --supervised systemd
ExecStop=/bin/kill -s QUIT $MAINPID
Type=notify
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755[Install]
WantedBy=multi-user.target[root@Rocky9.4 ~]## 2./usr/lib/systemd/system/redis6380.service
[Unit]
Description=Redis persistent key-value database
After=network.target[Service]
ExecStart=/apps/redis/bin/redis-server /apps/redis/etc/redis_6380.conf --supervised systemd
ExecStop=/bin/kill -s QUIT $MAINPID
#Type=notify
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755[Install]
WantedBy=multi-user.target[root@Rocky9.4 ~]## 3./usr/lib/systemd/system/redis6381.service
[Unit]
Description=Redis persistent key-value database
After=network.target[Service]
ExecStart=/apps/redis/bin/redis-server /apps/redis/etc/redis_6381.conf --supervised systemd
ExecStop=/bin/kill -s QUIT $MAINPID
#Type=notify
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755[Install]
WantedBy=multi-user.target
[root@Rocky9.4 ~]#systemctl daemon-reload
systemctl enable --now redis6379.service redis6380.service redis6381.service
# 這里有個問題,通過二進制安裝好的Redis,start的時候用tab鍵無法補全

4.Redis 持久化

Redis 是一個基于內存的數據結構存儲系統,但它提供了多種持久化機制,可以將內存中的數據保存到磁盤中,從而在 Redis 重啟或服務器宕機后依然能夠恢復數據。Redis 主要提供了兩種持久化方式:RDB(Redis Database)AOF(Append Only File)。這兩種方式可以單獨使用,也可以配合使用,具體選擇取決于業務需求(對數據一致性、寫入性能、磁盤空間等的不同要求)。

4.1 RDB(Redis Database)

RDB 方式是 Redis 最早的持久化模式,即在某個時間點對內存數據做快照,并保存到一個 .rdb 文件中

4.1.1 RDB 的工作機制

方法1:

SAVE 命令是“阻塞式”保存,Redis 不會創建子進程,而是直接由主進程把內存數據寫到 RDB 文件里。

[root@Rocky9.4 redis]#( redis-cli -a 123456 save & );pstree -p | grep redis-server;ls /apps/redis/data/ -lh
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.|-redis-server(28847)-+-{redis-server}(28854)|                     |-{redis-server}(28855)|                     |-{redis-server}(28856)|                     |-{redis-server}(28857)|                     `-{redis-server}(28858)
total 180M
-rw-r--r-- 1 redis redis 180M Dec 23 18:48 dump_6379.rdb
-rw-r--r-- 1 redis redis  48K Dec 23 21:45 temp-28847.rdb

使用 python 腳本存入一千萬條數據,再進行備份看到下面的現象

# 這個需要使用pip install redis來安裝redis包
import redispool=redis.ConnectionPool(host="10.0.0.41",port=6379,password="123456")
r=redis.Redis(connection_pool=pool)
for i in range(10000000):r.set("k%d" % i,"v%d" % i)data=r.get("k%d" % i)print(data)

image-20241223215647425

方法2:

BGSAVE 才是“后臺”保存,Redis 會 fork 一個子進程來完成 RDB 持久化,主進程繼續對外提供服務。

[root@Rocky9.4 data]#redis-cli -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> bgsave
Background saving started
127.0.0.1:6379># 生產臨時文件,fork 子進程 pid是920,從temp-920.rdb也可以看出是進程920在備份
[root@Rocky9.4 data]#pstree -p | grep redis-server;ls /apps/redis/data/ -lh|-redis-server(638)-+-redis-server(920)|                   |-{redis-server}(666)|                   |-{redis-server}(667)|                   |-{redis-server}(668)|                   |-{redis-server}(669)|                   `-{redis-server}(671)
total 128M
-rw-r--r-- 1 redis redis 67M Dec 24 14:43 temp-920.rdb
# 備份結束以后,將文件重命名
[root@Rocky9.4 data]#pstree -p | grep redis-server;ls /apps/redis/data/ -lh|-redis-server(638)-+-{redis-server}(666)|                   |-{redis-server}(667)|                   |-{redis-server}(668)|                   |-{redis-server}(669)|                   `-{redis-server}(671)
total 180M
-rw-r--r-- 1 redis redis 180M Dec 24 14:43 dump_6379.rdb# 也可以查看日志
[root@Rocky9.4 data]#tail -f ../log/redis-6379.log
# bgsave的日志,會顯示出具體的子進程編號
638:M 24 Dec 2024 15:15:14.746 * Background saving started by pid 1037
1037:C 24 Dec 2024 15:15:22.016 * DB saved on disk
1037:C 24 Dec 2024 15:15:22.026 * Fork CoW for RDB: current 0 MB, peak 0 MB, average 0 MB
638:M 24 Dec 2024 15:15:22.095 * Background saving terminated with success# save的日志
638:M 24 Dec 2024 15:20:09.364 * DB saved on disk

image-20241224150259770

方法3:

Redis 會在配置文件中設置觸發 RDB 生成快照的條件,典型配置示例:

save 900 1   # 在900秒內(15分鐘)至少有1個鍵發生變動,則觸發保存快照
save 300 10  # 在300秒內(5分鐘)至少有10個鍵發生變動,則觸發保存快照
save 60 10000# 在60秒內(1分鐘)至少有10000個鍵發生變動,則觸發保存快照# 上面是之前老版本的寫法,寫在新版本的寫法:
save 3600 1 300 100 60 10000

觸發快照后,Redis 通過fork 出一個子進程,子進程負責將內存數據寫入臨時的 RDB 文件;父進程繼續處理客戶端請求,因此在快照生成的過程中,Redis 仍然能夠服務讀寫請求。

當子進程將數據寫完后,會原子性地用臨時文件替換原先的 RDB 文件,以確保在替換前的 RDB 文件依然可用。這個和bgsave的模式是一樣的.

4.1.2 RDB 的優點

  1. 性能開銷小:由于生成快照時是通過 fork 子進程來執行,主進程只需做少量工作,對性能影響較小。
  2. 適合做冷備:如果業務允許一定程度的數據丟失(因為 RDB 只能反映生成快照時的數據狀態),那么 RDB 非常簡潔且容易做冷備份與全量備份。
  3. 啟動速度快:從 RDB 文件進行數據恢復時,因為只是加載一個快照文件,啟動速度通常比較快。

4.1.3 RDB 的缺點

  1. 可能丟失數據:快照通常并不會很頻繁地生成(除非你把 save 指令配置得極短,這會帶來極大的性能損耗),所以在兩次快照之間發生的數據寫操作可能會丟失。
  2. fork 開銷:在大數據量時執行 fork 操作需要分配子進程的內存頁表,會有一定系統開銷,且寫入 .rdb 文件時也會消耗 I/O 資源。

4.2 AOF(Append Only File)

從 Redis 7.0.0開始以及之后的版本中,AOF(Append Only File)機制經過優化,引入了基礎 RDB 文件和增量 AOF 文件的組合方式。這種設計有助于提高 AOF 的管理效率和數據恢復的速度。().

AOF 是另一種持久化方式,它會將每次寫操作以命令的形式追加到一個文件中(默認叫 appendonly.aof),從而實現數據的保存。

4.2.1 AOF 的工作機制

  • 寫命令追加:Redis 會把收到的每條寫命令,用 Redis 協議格式(Redis Serialization Protocol)記錄到 AOF 文件的末尾。
  • AOF 刷盤策略:Redis 提供了多種 AOF 同步策略(即何時將命令真正寫到磁盤),通過 appendfsync參數控制:
    1. appendfsync always:每次有寫操作時都同步寫入磁盤,最安全但最慢。
    2. appendfsync everysec:每秒將緩存中的寫命令同步寫到磁盤,默認配置,在系統斷電時最多丟失1秒的數據
    3. appendfsync no:由操作系統決定何時同步寫到磁盤,性能最高,安全性最低。
  • AOF 重寫(Rewrite):隨著大量寫操作的發生,AOF 文件會越來越大,因此需要對 AOF 文件進行“重寫壓縮”。
    • Redis 會 fork 出子進程,把內存中的數據以最精簡的命令集合重新寫到一個新文件中。
    • 重寫過程中,主進程持續將新的寫操作命令追加到一個緩沖區,待子進程重寫完成后,再將這些命令同步到新文件末尾,最后原子地替換舊 AOF 文件。

4.2.2 AOF 的優點

  1. 數據安全:AOF 可以配置成每次寫操作都寫入磁盤(always),或者至少每秒寫一次(everysec),相比 RDB,數據丟失的風險會小得多。
  2. 日志記錄:AOF 文件是按命令記錄的文本文件,人為可讀,并且在出現緊急情況時可以對其進行分析或修復(比如手動刪除錯誤指令)。

4.2.3 AOF 的缺點

  1. 文件體積大:和 RDB 相比,AOF 文件會更大,尤其是在沒有做 AOF 重寫的情況下。
  2. 寫性能影響:如果采用最安全的 appendfsync always 模式,那么每次寫操作都要同步到磁盤,會帶來明顯的性能損耗。
  3. 恢復速度:AOF 重放所有寫命令來恢復數據,可能比載入一個完整的 RDB 文件更慢。

4.3 如何選擇 RDB 和 AOF

  1. 只用 RDB
    • 對數據一致性要求不高,能容忍幾分鐘的數據丟失,且更傾向于更好的寫性能。
    • 能夠定期手動備份 RDB 文件,或者通過復制等方式冗余數據。
  2. 只用 AOF
    • 對數據安全性要求更高,不能容忍太多數據丟失,希望可以在秒級甚至實時上落盤。
    • 愿意投入更多的磁盤性能和空間成本,接受 AOF 重放帶來的恢復速度影響。
  3. RDB + AOF 同時使用(較推薦)
    • 大多數生產環境下,往往兩者結合使用,Redis 啟動時優先載入 AOF 文件(更完整),如果 AOF 文件不存在或不可用才載入 RDB 文件。
    • 可以在保證數據安全的同時,也能定期生成快照,便于快速恢復或冷備份。

4.4 AOF相關配置

[root@Rocky9.4 etc]#vim /apps/redis/etc/redis_6379.conf
# 啟用 AOF 持久化,通過config命令開啟,防止數據清空 config set appendonly yes
appendonly yes
# AOF 文件的名稱
appendfilename "appendonly-6379.aof"
# 新版本專門為aof增加了一個目錄,這個目錄是在$dir下創建的
appenddirname "appendonlydir"# AOF 同步策略
# always: 每個寫命令都同步到磁盤
# everysec: 每秒同步一次
# no: 讓操作系統決定何時同步
appendfsync everysec# 數據目錄
dir /apps/redis/data/# AOF 重寫的策略
# 例如,當 AOF 文件大小增長到上一個重寫后的大小的 100% 時觸發重寫
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb# 查看備份的目錄
[root@Rocky9.4 data]#tree
.
├── appendonlydir
│   ├── appendonly-6379.aof.1.base.rdb
│   ├── appendonly-6379.aof.1.incr.aof
│   └── appendonly-6379.aof.manifest
├── dump-6379.rdb
├── dump-6380.rdb
└── dump-6381.rdb1 directory, 6 files
[root@Rocky9.4 data]#pwd
/apps/redis/data
[root@Rocky9.4 data]#

根據業務需求選擇合適的同步策略:

  • always:適用于對數據安全性要求極高的場景,但性能開銷較大。
  • everysec:默認策略,適用于大多數場景,平衡了性能和數據安全性。
  • no:適用于對性能要求極高且可以容忍數據丟失的場景。

在 Redis 7.4 中,AOF(Append Only File)持久化機制引入了更為復雜和高效的文件結構,以提高數據持久性和恢復速度。您在 appendonlydir 目錄下看到的以下幾個文件:

基礎 RDB 文件: appendonly-6379.aof.1.base.rdb      180M
增量 AOF 文件: appendonly-6379.aof.1.incr.aof      56
清單文件: 	   appendonly-6379.aof.manifest        98

這些文件分別代表了 Redis 7.4 中 AOF 持久化機制的新特性和結構。下面將詳細解釋每個文件的含義及其作用。

1. appendonly-6379.aof.1.base.rdb(180M)

作用

  • 這是一個 基礎 RDB 快照 文件。它包含了在某個時間點上 Redis 數據庫的完整狀態。
  • 作為 AOF 持久化的一部分,Redis 7.4 結合了 RDB 和 AOF 的優點,通過基礎 RDB 文件和增量 AOF 文件來實現高效的數據持久化和恢復。

優點

  • 快速恢復:通過加載 RDB 快照,Redis 可以快速恢復到某個時間點的狀態,而無需重放所有 AOF 命令。
  • 減少文件大小:基礎 RDB 文件存儲了數據的全量快照,后續的增量 AOF 文件只記錄自快照以來的變化,避免了 AOF 文件過大的問題。

2. appendonly-6379.aof.1.incr.aof(56)

作用

  • 這是一個 增量 AOF 文件,記錄了自基礎 RDB 快照以來的所有寫操作命令(如 SET, HSET, LPUSH 等)。
  • 增量 AOF 文件用于補充基礎 RDB 快照,確保在恢復時可以通過重放這些命令來達到最新的數據狀態。

優點

  • 高效寫入:相比傳統 AOF 記錄所有寫操作,增量 AOF 只記錄快照之后的變化,減少了磁盤寫入量。
  • 靈活管理:可以定期生成新的基礎 RDB 快照,并清理舊的增量 AOF 文件,優化存儲空間。

3. appendonly-6379.aof.manifest(98)

作用

  • 這是一個 清單文件(Manifest File),用于管理和跟蹤基礎 RDB 文件與對應的增量 AOF 文件之間的關系。
  • 該文件記錄了哪些增量 AOF 文件對應于哪個基礎 RDB 文件,確保在數據恢復時能夠正確地加載和重放命令。

優點

  • 數據一致性:通過清單文件,Redis 可以準確地知道需要加載哪些文件來恢復數據,避免數據不一致的問題。
  • 自動管理:清單文件幫助 Redis 自動管理文件的生命周期,如刪除過期的增量 AOF 文件,維護持久化目錄的整潔。

二、Redis 7.4 AOF 持久化機制的改進

Redis 7.4 引入了 混合持久化(Hybrid Persistence) 機制,將 RDB 和 AOF 結合起來,以充分利用兩者的優勢:

  1. 基礎 RDB + 增量 AOF
    • 定期生成基礎 RDB 快照,作為持久化的基準點。
    • 記錄基礎 RDB 之后的所有寫操作到增量 AOF 文件中,確保數據的實時性和持久性。
  2. 高效恢復
    • 在恢復數據時,Redis 首先加載基礎 RDB 文件,快速恢復到某個時間點的狀態。
    • 然后重放對應的增量 AOF 文件,達到最新的數據狀態。
  3. 優化存儲和性能
    • 通過將持久化過程分為全量快照和增量記錄,減少了 AOF 文件的大小和重寫開銷。
    • 提高了持久化和恢復的效率,降低了對系統性能的影響。

三、如何管理這些文件

1. 自動管理

Redis 7.4 會自動生成和管理這些文件,包括:

  • 生成基礎 RDB 文件:根據配置的策略(如 AOF 重寫觸發條件),定期生成新的基礎 RDB 文件。
  • 記錄增量 AOF:在基礎 RDB 文件生成后,開始記錄新的寫操作到增量 AOF 文件中。
  • 更新清單文件:確保清單文件準確反映當前的持久化文件結構。

2. 手動管理

雖然 Redis 會自動管理這些文件,但您仍可以進行一些手動操作以優化或排查問題:

  • 觸發 AOF 重寫:可以使用 BGREWRITEAOF 命令手動觸發 AOF 重寫,生成新的基礎 RDB 文件和增量 AOF 文件。
  • 備份持久化文件:定期備份 appendonlydir 目錄下的所有持久化文件(包括 .rdb, .aof, .manifest)以防止數據丟失。
  • 監控文件大小:監控各類持久化文件的大小,確保磁盤空間充足,并根據需要調整持久化策略。

四、配置示例

在 Redis 配置文件 (redis.conf) 中,相關配置可能如下:

# 啟用 AOF 持久化
appendonly yes# AOF 文件的名稱
appendfilename "appendonly.aof"# AOF 同步策略
appendfsync everysec# 混合持久化配置
# 具體配置項可能因 Redis 版本而異,請參考官方文檔

注意:Redis 7.4 的混合持久化機制可能引入了新的配置選項,請務必參考 Redis 官方文檔 以獲取最新和詳細的配置說明。

五、總結

Redis 7.4 在 AOF 持久化機制上引入了基礎 RDB 文件、增量 AOF 文件和清單文件的結構,通過混合持久化機制,結合了 RDB 和 AOF 的優勢,實現了高效、可靠的數據持久化和快速恢復。這些文件的存在確保了 Redis 在高負載和大數據量的場景下,能夠保持數據的完整性和系統的高可用性。

理解和正確管理這些持久化文件,對于保障 Redis 數據的安全性和系統的穩定性至關重要。建議定期備份持久化文件,并監控文件的大小和系統性能,以確保 Redis 實例的健康運行。

4.5 AOF rewrite 重寫

appendonly-6379.aof.1.base.rdb:基礎 RDB 快照文件。

appendonly-6379.aof.1.incr.aof:增量 AOF 文件,記錄自基礎快照以來的所有寫命令。

appendonly-6379.aof.manifest:清單文件,管理基礎 RDB 文件與增量 AOF 文件的關系。

4.5.1 基礎 RDB 文件與增量 AOF 文件的工作機制

  1. 基礎 RDB 文件 (appendonly-6379.aof.1.base.rdb)
  • 作用:保存某一時間點的數據庫完整狀態,相當于一個 RDB 快照。
  • 更新條件:當進行 AOF 重寫(AOF Rewrite)操作時,Redis 會生成一個新的基礎 RDB 文件。此操作可以自動觸發,也可以手動執行。
  1. 增量 AOF 文件 (appendonly-6379.aof.1.incr.aof)
  • 作用:記錄自上一個基礎 RDB 快照以來的所有寫命令(增量操作)。
  • 更新方式:在 Redis 運行過程中,所有寫操作都會被追加到當前的增量 AOF 文件中。
  1. 清單文件 (appendonly-6379.aof.manifest)
  • 作用:跟蹤和管理基礎 RDB 文件與增量 AOF 文件之間的關系,確保在數據恢復時能夠正確加載基礎快照并應用增量命令。

4.5.2 增量備份的工作原理與配置

增量備份主要依賴于基礎 RDB 文件和增量 AOF 文件的組合。通過這種方式,你可以在保持高效的同時,實現數據的持續備份。

增量備份的工作流程

  1. 基礎快照生成:
    • 當執行 AOF 重寫操作時,Redis 會生成一個新的基礎 RDB 文件,記錄當前數據庫的完整狀態。
  2. 記錄增量操作:
    • 在基礎快照生成后,所有新的寫操作會被記錄到新的增量 AOF 文件中。
  3. 管理文件關系:
    • 清單文件 (appendonly-6379.aof.manifest) 記錄了當前使用的基礎 RDB 文件和對應的增量 AOF 文件,確保數據恢復時能夠正確加載。

4.5.3 參數配置

[root@redis.xyy.org ~]#vim /apps/redis/etc/redis.conf
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble yes
aof-timestamp-enabled no

以下是這些參數的詳細解釋及其在增量備份中的作用:

appendonly yes:啟用 AOF 持久化。

appendfilename "appendonly.aof":指定 AOF 文件名。

appendfsync everysec:每秒執行一次 FSYNC 操作,平衡性能與持久性。

  1. no-appendfsync-on-rewrite no
    • 解釋:當設置為 yes 時,Redis 在執行 AOF 重寫期間會停止執行 FSYNC 操作,從而提高性能;設置為 no 則不會停止 FSYNC
    • 建議:默認情況下建議保持 no,確保數據的持久性,尤其在對數據一致性要求較高的場景。
  2. auto-aof-rewrite-percentage 100
    • 解釋:定義 AOF 文件增長的比例,達到此比例后觸發 AOF 重寫。100 表示當當前 AOF 文件大小是上一次重寫后的大小的 2 倍時觸發重寫(增長了 100%)。
    • 建議:根據實際數據寫入量和系統性能調整此值。較低的比例會更頻繁地進行重寫,但可能影響性能;較高的比例則減少重寫頻率,但可能導致 AOF 文件過大。
  3. auto-aof-rewrite-min-size 64mb
    • 解釋:設置 AOF 重寫的最小觸發文件大小。只有當 AOF 文件大小超過 64MB 且增長比例達到 auto-aof-rewrite-percentage 時,才會觸發重寫。
    • 建議:確保設置一個合理的最小值,以避免頻繁的小規模重寫,影響性能。
  4. aof-load-truncated yes
    • 解釋:當 AOF 文件不完整或被截斷時,是否允許 Redis 加載這些文件。yes 表示允許加載,并盡可能恢復數據。
    • 建議:在生產環境中建議設置為 no,以避免加載損壞的數據。如果設置為 yes,需要確保有其他數據恢復機制,以防止數據丟失。
  5. aof-use-rdb-preamble yes
    • 解釋:在 AOF 文件開頭包含一個 RDB 快照的前導數據(preamble)。這有助于加快數據加載速度。
    • 建議:默認建議保持 yes,提高數據恢復的效率。
  6. aof-timestamp-enabled no
    • 解釋:是否在 AOF 文件中記錄命令的時間戳。no 表示不記錄,yes 表示記錄。
    • 建議:通常設置為 no,除非你有特定需求需要記錄時間戳。
# 通過 bgrewriteaof 手動觸發重寫機制
[root@Rocky9.4 data]#redis-cli -a 123456 bgrewriteaof;pstree -p | grep redis ;ll appendonlydir/ -h
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
Background append only file rewriting started|-redis-server(22944)-+-redis-server(23325)|                     |-{redis-server}(22946)|                     |-{redis-server}(22947)|                     |-{redis-server}(22948)|                     |-{redis-server}(22949)|                     `-{redis-server}(22950)
total 180M
-rw-r--r-- 1 redis redis 180M Dec 28 23:25 appendonly.aof.1.base.rdb
-rw-r--r-- 1 redis redis 719K Dec 29 23:04 appendonly.aof.1.incr.aof
-rw-r--r-- 1 redis redis    0 Dec 29 23:08 appendonly.aof.2.incr.aof
-rw-r--r-- 1 redis redis  132 Dec 29 23:08 appendonly.aof.manifest[root@Rocky9.4 data]#ll appendonlydir/
total 183420
-rw-r--r-- 1 redis redis 187817903 Dec 29 23:08 appendonly.aof.2.base.rdb
-rw-r--r-- 1 redis redis         0 Dec 29 23:08 appendonly.aof.2.incr.aof
-rw-r--r-- 1 redis redis        88 Dec 29 23:08 appendonly.aof.manifest
[root@Rocky9.4 data]#

5.Redis 常用命令

5.1 ACL 控制

user <username> [on|off] [>password] [~pattern] [+permissions] [-permissions]

命令權限(+ / - / ~ / allcommands / nocommands)

  • +<command>:允許執行某個命令(如 +get, +set
  • -<command>:禁止執行某個命令
  • allcommands:允許執行所有命令
  • nocommands:禁止執行所有命令
  • ~<pattern>:這是匹配命令子令(SUBCOMMANDS),也可以通過 +<command>|subcommand 的形式添加特定子命令權限

onoff:啟用或禁用用戶。

>password:設置用戶的密碼,可以有多個密碼。

~pattern:指定用戶可以訪問的鍵的模式(可選)。

+permissions-permissions:授予或撤銷用戶的權限,可以使用命令類別或具體命令。

# 假設您希望創建一個名為 alice 的用戶,設置密碼為 123456,并且授予她所有權限但禁用 FLUSHALL 命令。可以按照以下方式配置:
[root@Rocky9.4 etc]#vim redis_6379.conf
user alice on >123456 ~* +@all -FLUSHALL -FLUSHDB
user default on >123456 ~* +@all +get +set -FLUSHALL -FLUSHDB -keys -config
# 重啟服務
systemctl restart redis
# 連接到Redis
[root@Rocky9.4 etc]#redis-cli -u redis://alice:123456@127.0.0.1:6379
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> FLUSHALL
(error) NOPERM User alice has no permissions to run the 'flushall' command
127.0.0.1:6379> exit

Key 權限(~ / %)

  • ~<pattern>:允許對匹配 <pattern> 的 key 進行讀寫操作
  • &<pattern>:只讀訪問(7.0+ 里對 key 權限有進一步細分,比如讀寫分離,會使用 % 符號來區分寫權限)
  • %<pattern>:只寫訪問(這是 Redis 7.0+ 擴展的語法,用于區分只寫權限)
  • allkeys / nokeys:允許/禁止訪問所有 key

解釋:

  • user alice:定義用戶名為 alice
  • on:啟用該用戶。
  • >123456:設置用戶的密碼為 123456
  • ~*:允許用戶訪問所有鍵。
  • +@all:授予用戶所有命令權限。
  • -FLUSHALL -FLUSHDB:撤銷 FLUSHALLFLUSHDB 命令的權限,防止用戶執行這些危險命令。
# 默認用戶去掉flushall 和 flushdb
user default on >123456 &logs:* ~* +@all -FLUSHALL -FLUSHDB# 動態管理 ACL
# 1.ACL List(查看當前所有用戶配置的詳細信息,包括用戶名稱、密碼哈希、權限列表、key patterns 等。)
[root@Rocky9.4 etc]#redis-cli -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> acl list
1) "user alice on sanitize-payload #87b9b7660e9fe77503b14eb6da0277151e031aad3a88a1673b798d8443af242b resetchannels -@all"
2) "user default on sanitize-payload #8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92 ~* resetchannels &logs:* +@all -flushall -flushdb"
127.0.0.1:6379># 2.ACL GETUSER <username>(獲取指定用戶的ACL信息)
127.0.0.1:6379> ACL GETUSER alice1) "flags"2) 1) "on"2) "sanitize-payload"3) "passwords"4) 1) "87b9b7660e9fe77503b14eb6da0277151e031aad3a88a1673b798d8443af242b"5) "commands"6) "-@all"7) "keys"8) ""9) "channels"
10) ""
11) "selectors"
12) (empty array)
127.0.0.1:6379># 3.ACL SETUSER <username> [規則 ...](更新(創建或修改)用戶的權限規則)
ACL SETUSER bob on >bob_password +get +set -FLUSHALL -FLUSHDB  ~bob:*
ACL SETUSER bob on:啟用 bob
>bob_password:設置 bob 的密碼
+get +set:允許 bob 執行 get、set 命令
~bob:*:只允許 bob 訪問前綴為 bob: 的 key# 4.ACL DELUSER <username> [<username> ...](刪除用戶及其權限配置)
ACL DELUSER alice
ACL DELUSER bob# 5.ACL SAVE(將內存中的 ACL 配置寫回到 aclfile(如果在配置文件中指定了 aclfile 路徑的話)中。默認不寫入 redis.conf,如果希望保存到文件,需要先在 redis.conf 中指定:)
注意:在redis.conf中配置aclfile,就不能同時配置user alice...,必須要將配置寫入到aclfile,并且還要將這個文件手動創建出來,服務才會重啟成功
aclfile /path/to/aclfile.conf

5.2 INFO

作用:查看 Redis 服務器的各種統計信息和狀態,例如內存使用情況、復制狀態、連接數、持久化信息、keyspace 信息等。

使用示例

127.0.0.1:6379> INFO keyspace
# Keyspace
db0:keys=10000001,expires=0,avg_ttl=0,subexpiry=0
127.0.0.1:6379>127.0.0.1:6379> info server
# Server
redis_version:7.4.1
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:a9a1c6875521b0ad
redis_mode:standalone
os:Linux 5.14.0-427.13.1.el9_4.x86_64 x86_64
arch_bits:64
monotonic_clock:POSIX clock_gettime
multiplexing_api:epoll
atomicvar_api:c11-builtin
gcc_version:11.5.0
process_id:9692
process_supervised:no
run_id:83d8b9655623d6edaf809f8a7456e68179e9de91
tcp_port:6379
server_time_usec:1735883510494144
uptime_in_seconds:6113
uptime_in_days:0
hz:10
configured_hz:10
lru_clock:7830262
executable:/apps/redis/bin/redis-server
config_file:/apps/redis/etc/redis_6379.conf
io_threads_active:0
listener0:name=tcp,bind=0.0.0.0,bind=-::1,port=6379
127.0.0.1:6379>

Redis 會返回一個多段文本,包含大量信息,可按模塊劃分(server、clients、memory、persistence、stats、replication、cpu、cluster、keyspace 等)。

常用操作

  • INFO memory:只查看和內存相關的信息。
  • INFO replication:只查看主從復制(replication)相關信息。
  • INFO server: 查看server的相關信息
  • INFO cluster: 查看集群的信息
  • INFO keyspace: 查看數據庫的信息,有多少鍵.

5.3 SELECT

作用:切換 Redis 的邏輯數據庫(DB)。Redis 默認有 16 個邏輯數據庫,編號 0 到 15(可通過 databases 配置修改)。

使用示例

127.0.0.1:6379> SELECT 1
OK
127.0.0.1:6379[1]>    # 命令提示符會顯示當前已在 DB1

注意點

  • Redis 集群模式下通常只能使用 DB 0,不支持多 DB 切換。
  • 切換數據庫僅對當前連接有效,斷開后重新連接默認仍進入 DB 0。

5.4 KEYS

作用:列出匹配給定模式(pattern)的所有 Key。常用模式如 KEYS user:*

使用示例

127.0.0.1:6379> KEYS *
1) "foo"
2) "bar"
3) "user:1001"

注意點

  • 不要在生產環境中頻繁使用 KEYS 命令,因為它會對整個 keyspace 做遍歷,耗時且阻塞服務器,容易導致性能問題,最好使用acl禁用keys*。
  • 生產中更常用 SCAN 命令以非阻塞(游標)方式遍歷 key。

5.5 BGSAVE

作用:在后臺(異步)執行一次 RDB 快照,將當前數據集保存到磁盤(默認文件名 dump.rdb,可在 redis.conf 中配置)。

使用示例

127.0.0.1:6379> BGSAVE
Background saving started

執行后會立即返回,Redis 會在后臺完成 RDB 持久化。

常用場景

  • 手動觸發一次快照,做數據備份。
  • 結合 save 配置自動觸發也可以,但在現代 Redis 版本中,很多人更傾向于 AOF 或混合持久化。

5.6 DBSIZE

作用:返回當前所選數據庫(DB)中 key 的數量。

使用示例

127.0.0.1:6379> DBSIZE
(integer) 10000001
127.0.0.1:6379>

表示當前 DB 里有 一千萬 個 key。

注意點

  • DBSIZE 是一個簡單計數,不涉及 keys 的遍歷,因此非常高效。
  • 如果想知道所有 DB 的 key 數量,可以逐一 SELECT 0~15 執行 DBSIZE,或者用 INFO keyspace 查看。

5.7 FLUSHDB

作用:清空當前數據庫(DB)的所有 Key(只影響您當前選擇的 DB)。

使用示例

127.0.0.1:6379> FLUSHDB
OK

如果在 DB0 執行,會清空 DB0;在 DB1 執行會清空 DB1。

風險與注意

  • 不可逆,會刪除當前 DB 中的全部數據!
  • 可在正式執行前先確認 SELECT 到了正確的 DB,避免誤刪。

5.8 FLUSHALL

作用:清空 所有 DB 的所有 Key(默認 16 個數據庫都會被清空)。

使用示例

127.0.0.1:6379> FLUSHALL
OK

風險與注意

  • FLUSHDB 更危險,一旦執行,會導致 Redis 整個實例所有 DB 數據被清空。
  • 一般不建議在生產環境使用,務必謹慎操作!

5.9 SHUTDOWN

作用:關閉 Redis 服務器。執行后,會嘗試做一次持久化(若配置了 RDB/AOF),然后退出進程。

使用示例

127.0.0.1:6379> SHUTDOWN

連接會立即斷開,Redis 服務停止。

注意點

  • 如果想避免保存數據(即不再進行 RDB/AOF 落盤),可加選項 SHUTDOWN NOSAVE
  • 如果只想保存數據而不關閉,可以執行 SAVEBGSAVE

5.10 SCAN

在 Redis 中,SCAN 命令是一種基于游標(cursor)**的迭代查詢方式,能夠**分批且非阻塞地遍歷數據庫中的 Key(或集合、哈希、ZSet 等),避免像 KEYS * 這樣一次性掃描全部 Key 導致大規模阻塞的問題。下面介紹一下 SCAN 的核心概念、使用方法以及與 KEYS 的區別。

一、為什么要用 SCAN?

  1. KEYS 的缺點
    • KEYS pattern 命令會一次性遍歷所有 Key,并返回所有匹配的結果。
    • 在 Key 數量很大的情況下(幾百萬上千萬),一次掃描會造成主線程阻塞,期間無法處理其他請求,導致服務卡頓甚至超時。
    • 因為 Redis 是單線程架構,這種大規模阻塞會嚴重影響線上業務。
  2. SCAN 的優點
    • 將大范圍掃描拆分成多次小范圍掃描,每次只返回一部分數據。
    • 采用“游標(Cursor)+ 增量遍歷”的模式,每掃描一部分,Redis 就返回一個新的 Cursor,并在響應中包含本次掃描到的部分數據。
    • 用戶可以根據返回的 Cursor 繼續下一次掃描,直到 Cursor 回到 0 表示掃描結束。
    • 相比 KEYSSCAN 對服務器的阻塞時間更短,也更可控。

二、SCAN 的基本用法

2.1 命令格式

SCAN cursor [MATCH pattern] [COUNT count]
  • cursor:游標,初次調用時通常傳 0,表示從頭開始掃描。
  • MATCH pattern:可選,用于過濾匹配的 Key 模式(如 MATCH user:*)。如果不指定 MATCH,則返回的 Key 不做任何模式過濾(會返回所有 Key 的子集)。
  • COUNT count:可選,用于指定每次掃描希望返回的 Key 數量。并非嚴格保證返回固定數量,而是“期望值”,Redis 可能實際返回多于或少于這個數的 key。

初次調用

127.0.0.1:6379> SCAN 0 COUNT 10
1) "13107200"
2)  1) "k4533779"2) "k252114"3) "k933235"4) "k3676789"5) "k2576537"6) "k7573677"7) "k5285770"8) "k2267950"9) "k2473601"10) "k4433328"
  • 返回結果中的第一個元素 "13107200" 是新的游標值,下次掃描時要用它。
  • 第二個數組是本次掃描到的一批 Key(例如 5~10 個)。

后續調用

127.0.0.1:6379> SCAN 13107200 COUNT 10
1) "4456448"
2)  1) "k1450912"2) "k9102989"3) "k6829708"4) "k3410677"5) "k2513869"6) "k9564207"7) "k7683296"8) "k2951179"9) "k6113726"10) "k8041825"
127.0.0.1:6379>
  • 繼續用上一次返回的游標 13107200 作為本次調用的游標;
  • Redis 返回游標 “4456448” 和新的 Key 列表。

三、SCAN 與其他相關命令

SCAN:遍歷數據庫中的 Key。

SSCAN:遍歷 Set 中的元素。

HSCAN:遍歷 Hash 中的 field-value 對。

ZSCAN:遍歷 Sorted Set 中的 member-score 對。

它們用法相似,都是 SCAN cursor [MATCH pattern] [COUNT count] 的形式,只是操作的數據結構不同。例如:

HSCAN myhash 0 MATCH field:* COUNT 10

四、SCAN vs. KEYS

  • 性能:
    • KEYS 命令會阻塞 Redis 直到掃描完所有 Key;
    • SCAN 采用增量掃描,每次只處理一部分,能把阻塞時間分散到多個小的時間片,對線上性能影響更小。
  • 用法:
    • KEYS 適合在測試小規模場景下調試時使用,方便一次性獲取所有匹配 key;
    • 生產環境中強烈推薦使用 SCAN,能避免大規模阻塞。
  • 一致性:
    • KEYS 在那一刻會返回快照式的所有 Key;
    • SCAN 可能會出現漏掃或重復,尤其當 Key 動態變化時。但大多數情況下,這種不完全一致性是能接受的(可額外在應用層做去重處理)。

6.Redis 數據類型

6.1 字符串(string)類

6.1.1 String 的存儲特點

  • 存儲內容:可以是文本(如 "Hello")、數字(如 "123")、二進制文件(如圖片、音頻等),只要單個值不超過 512 MB 即可。
  • 內存開銷:小字符串采用 SDS(Simple Dynamic String) 結構存儲,Redis 會根據實際值大小自動選擇合適的底層結構,避免頻繁的內存分配。
  • 常用場景:
    • 緩存網頁內容、配置、令牌、session 信息、計數器等;
    • 存儲對象的序列化結果,比如 JSON、Protobuf 等;
    • 計數統計,利用 INCR/DECR 等快速自增自減

6.1.2 常見的操作命令

6.1.2.1 設置與獲取
6.1.2.1.1 SET
  • 作用:設置 key 的值。如果 key 已存在,會被覆蓋;如果 key 不存在,則創建一個新的 key。

  • 基本語法:

    SET <key> <value>
    
  • 示例:

    SET user:1001 "Alice"
    GET user:1001  # 返回 "Alice"
    
  • 擴展參數:

    • EX seconds:設置過期時間(秒)。

    • PX milliseconds:設置過期時間(毫秒)。

    • NX:只有當 key 不存在時才執行設置。

    • XX:只有當 key 存在時才執行設置。

    • 例如:

      SET mykey "Hello" EX 10 NX
      

      表示僅當 mykey不存在時,才設置值為 "Hello"并自動在 10 秒后過期。

6.2.2.1.2 GET
  • 作用:獲取 key 的字符串值。

  • 示例:

    GET mykey
    

    若 key 存在,則返回對應的值;若 key 不存在,返回 nil

6.2.2.1.3 MSET / MGET
  • MSET:同時設置多個 key-value 對。

    MSET k1 "v1" k2 "v2" k3 "v3"
    

    一次性寫入多對數據,減少多次網絡往返。

  • MGET:批量獲取多個 key 的值。

    MGET k1 k2 k3
    

    返回一個數組,如 [v1, v2, v3],不存在的 key 會以 nil 對應。

6.2.2.1.4 SETNX / SETXX(或結合 SET 命令的 NX / XX 參數)
  • SETNX:Set if Not eXists,只在 key 不存在時設置成功。等價于 SET key value NX
  • SETXX:Set if eXists,只在 key 存在時設置成功。等價于 SET key value XX
6.1.2.2 數值操作

Redis 支持對字符串值進行數字自增自減操作(前提是該字符串能被解析為整數或浮點數)。

6.1.2.2.1 INCR / DECR
  • INCR :將 key 的值自增 1。如果 key 不存在,則先初始化為 0 再自增。

  • DECR :將 key 的值自減 1。

  • 示例:

    SET counter 10
    INCR counter      # counter = 11
    DECR counter      # counter = 10
    
  • 注意:若 value 不是一個整數字符串,例如 "Hello"1.5,執行 INCR/DECR 會報錯 (ERR value is not an integer)。

6.1.2.2.2 INCRBY / DECRBY
  • 作用:一次性加/減指定數值。

    INCRBY <key> <increment>
    DECRBY <key> <decrement>
    
  • 示例:

    SET counter 100
    INCRBY counter 50   # counter = 150
    DECRBY counter 20   # counter = 130
    
6.1.2.2.3 INCRBYFLOAT
  • 作用:對浮點數進行加法操作。

    SET price 12.5
    INCRBYFLOAT price 0.7  # price = 13.2
    
  • 使用場景:計量或需要小數的場景,如金額、溫度等。

6.1.2.3 部分字符串操作
6.1.2.3.1 APPEND
  • 作用:向指定 key 的現有值 追加 一段字符串。如果 key 不存在,就相當于 SET

  • 示例:

    SET greeting "Hello"
    APPEND greeting ", Redis!"
    GET greeting        # "Hello, Redis!"
    
6.1.2.3.2 GETRANGE (舊命令:SUBSTR)
  • 作用:獲取字符串中指定區間(基于下標)的子串,區間含左右邊界,支持負索引(-1 表示最后一個字符)。

  • 語法:

    GETRANGE <key> <start> <end>
    
  • 示例:

    SET greeting "Hello, Redis!"
    GETRANGE greeting 0 4    # 返回 "Hello"
    GETRANGE greeting -6 -2  # 返回 "Redis" 中的一部分, 要根據實際字符串判斷
    

    注意字符串 "Hello, Redis!"的長度和下標分布,從 0 到 12。

6.1.2.3.3 SETRANGE
  • 作用:在指定偏移量開始處,用給定值覆蓋或插入到現有字符串里。若偏移量超過當前字符串長度,中間會填充空字節(\x00)。

  • 示例:

    SET mykey "Hello World"
    SETRANGE mykey 6 "Redis"  # 原字符串第 6 位開始覆蓋,"Hello Redis"
    GET mykey  # "Hello Redis"
    
6.1.2.3.4 STRLEN
  • 作用:返回字符串值的長度(字節數)。

  • 示例:

    SET name "Alice"
    STRLEN name    # 返回 5
    
6.1.2.4 過期與生命周期管理

盡管不是 String 專有命令,但實際中常和 String 配合使用:

  • EXPIRE :為 key 設置過期時間(單位秒)。到期后 key 會被自動刪除。
  • TTL :查看 key 剩余存活時間。
  • PERSIST :移除 key 的過期時間,使 key 變為永久存在。

也可在 SET 命令時直接附帶 EXPX 參數來設置過期時間。

6.1.2.5 高級應用:Bit 操作

Redis 還提供了對 String 值執行位操作(bitwise)的命令,如 SETBIT, GETBIT, BITCOUNT, BITOP 等,能在每個位上進行讀寫、計數或邏輯運算。

  • SETBIT :將字符串第 offset 位設置為 value (0 或 1)。
  • GETBIT :獲取 offset 位置的位值。
  • BITCOUNT [start end]:統計字符串指定區間內值為 1 的位數。
  • BITOP AND/OR/XOR [… ]:對多個 key 對應的位進行邏輯運算,并將結果存儲到 destkey

這些命令常用于**實現位圖(bitmap)**功能,比如用戶簽到、活躍狀態等布爾屬性的存儲。

6.1.2.6 小結 & Best Practices
  1. 最常用的操作
    • SET / GET:基礎讀寫;
    • MSET / MGET:批量讀寫;
    • INCR / DECR / INCRBYFLOAT:實現計數器或數值操作;
    • APPEND / GETRANGE / SETRANGE:在字符串上做增改或截取;
    • EXPIRE / SET ... EX:配合過期管理。
  2. 注意字符串與數值
    • 只有當字符串能被解析為整數或浮點數時,INCR/DECR/INCRBYFLOAT 才能工作,否則會報錯;
    • 若您頻繁進行數值操作,不要在中間手動 GET 并轉回數字,以免造成競態。直接用原子操作(INCR…)更可靠。
  3. 內存與大小限制
    • Redis 默認可存儲最大 512MB 的值,但太大的值會帶來內存和網絡傳輸負擔,不建議把超大文件直接放 Redis。
    • 建議拆分或使用外部文件存儲(OSS、S3、NFS),Redis 中只存元數據或指針。
  4. 使用過期策略
    • 若用 Redis 做緩存,通常會為 key 設置過期時間,避免數據無限堆積或過期失效。
  5. Bit 操作
    • 高級玩法,能有效利用 Redis 做位圖統計,如用戶行為打點、日活統計等,但要注意數據結構設計和偏移量計算。
# 設置值,并設置有效期(s)--10秒過期,也可以通過SETEX來直接設置
set title study ex 10 # 存在title,不變,不存在設置成ceo
127.0.0.1:6379> SETNX title ceo
(integer) 1# 批量設置--mset/mget
127.0.0.1:6379> mset name xingyuyu age 18 gender femal title cto
OK
127.0.0.1:6379> mget name age
1) "xingyuyu"
2) "18"
127.0.0.1:6379>

6.2 哈希(Hash)

在 Redis 中,Hash(哈希) 是一種將多個字段(field)映射到同一個 key 下的數據結構。換句話說,Redis 的 Hash 類似一個小型的 key-value 表,表里的 “行” 只有一條,但這條“行”有許多字段(field)。它非常適合用來存儲和讀取類似對象、用戶資料、配置項等場景。下面將按照前面類似的步驟,講解 Hash 的基本概念、常用操作以及使用場景與注意事項。


6.2.1 Redis Hash 的存儲與特點

  1. 內部結構
    • 小規模的哈希對象(字段數量較少時),Redis 會采用一種緊湊的數據結構(ziplist 或 listpack)來節省內存。
    • 當字段數量或字段長度變大時,會轉換成真正的哈希表(Hashtable)。
    • 這對我們是透明的,Redis 會自動處理。但它解釋了為什么 Hash 往往在小規模場景下特別高效。
  2. 數據特征
    • Key:在 Redis 層面標識一個哈希對象的名稱(如 user:1001)。
    • Fields 和 Values:在哈希對象內部,每個 field 都擁有一個獨立的 value。不同 field 之間互不干擾,但都屬于同一個 key 的管理之下。
    • 字段唯一:同一個哈希鍵下的 field 名稱是不能重復的,若重復則會更新原有值。
  3. 常用場景
    • 存儲用戶信息(字段:username、email、age 等);
    • 緩存一條記錄或配置,這些記錄可有多個屬性;
    • 減少 key 數量(相比將每個屬性單獨存為一個 String key,這時可以把多個屬性存在一個哈希 key 中)。

6.2.2 Hash 的常見操作命令

6.2.2.1 基礎增刪改查
6.2.2.1.1 HSET / HGET
  • HSET

    • 作用:向 hash 里設置(或更新)一個字段的值。如果字段不存在,就創建;若存在,就覆蓋。

    • 語法:

      HSET <key> <field> <value> [<field2> <value2> ...]
      
    • 示例:

      HSET user:1001 name "Alice" age "20"
      

      user:1001不存在,Redis 會創建一個新的哈希;并設置字段 name="Alice"age="20"

  • HGET

    • 作用:獲取 hash 表中某個字段的值。

    • 語法:

      HGET <key> <field>
      
    • 示例:

      HGET user:1001 name
      # 返回 "Alice"
      
6.2.2.1.2 HMSET / HMGET
  • HMSET(在新版本 Redis 中 HSET <key> <field> <value> ... 已經可以替代,HMSET 舊命令仍兼容)

    • 作用:同時設置多個字段值,和 HSET 的多字段形式一致。

    • 示例:

      HMSET user:1001 city "Beijing" gender "female"
      
  • HMGET

    • 作用:一次性獲取多個字段的值。

    • 示例:

      HMGET user:1001 name age city
      # 返回一個數組 ["Alice", "20", "Beijing"]
      
6.2.2.1.3 HGETALL / HKEYS / HVALS
  • HGETALL

    • 作用:獲取 hash 中所有字段和對應值,以 field-value 對數組返回。

    • 示例:

      HGETALL user:1001
      # 可能返回 ["name","Alice","age","20","city","Beijing","gender","female"]
      
  • HKEYS

    • 作用:只返回所有字段(field)的列表。
  • HVALS

    • 作用:只返回所有字段的值列表。
  • 這三種命令在字段很多時,一次性返回也會占用較多資源,生產環境可考慮 HSCAN(分批掃描)以避免阻塞。

6.2.2.1.4 HDEL
  • 作用:刪除哈希表中的一個或多個字段。

  • 語法:

    HDEL <key> <field1> [field2 ...]
    
  • 示例:

    HDEL user:1001 age
    # 移除 "age" 字段
    
6.2.2.1.5 HEXISTS
  • 作用:檢查哈希表中指定字段是否存在。

  • 示例:

    HEXISTS user:1001 name
    # 若存在則返回 1,否則返回 0
    

6.2.2.2 數值操作(原子自增自減)

如果哈希字段的值可以解析為數字(整數或浮點數),Redis 提供了原子增量命令:

6.2.2.2.1 HINCRBY
  • 作用:對 hash 某個字段的值執行加法(整數)。

  • 語法:

    HINCRBY <key> <field> <increment>
    
  • 示例:

    HINCRBY user:1001 login_count 1
    # 將 user:1001 哈希表里 login_count 字段值 +1
    
  • 注意:若字段不存在,會先初始化為 0,再進行加法。如果原來是非數字值,會報錯。

6.2.2.2.2 HINCRBYFLOAT
  • 作用:對 hash 字段的值執行浮點加法。

  • 語法:

    HINCRBYFLOAT <key> <field> <increment>
    
  • 示例:

    HINCRBYFLOAT product:2001 price 9.99
    # 如果 price="100.0",則更新后 price="109.99"
    

6.2.2.3 Hash 掃描(HSCAN)
  • HSCAN

    • SCAN 類似,用于分批遍歷一個哈希表,避免 HGETALL 在字段太多時造成阻塞。

    • 用法:

      HSCAN <key> <cursor> [MATCH pattern] [COUNT count]
      
    • 示例(偽代碼):

      cursor = 0
      do {response = HSCAN user:1001 cursor MATCH "f*"cursor = response[0]        # 新游標fields = response[1]        # 字段值對# ...處理 fields ...
      } while (cursor != 0)
      
    • 這樣可以一口氣分多次小范圍返回,不會阻塞 Redis 主線程太久。


6.2.3 Hash 的使用場景

  1. 用戶配置、信息
    • user:1001 存放 name、email、age、login_count 等多個字段;
    • 避免把每個字段都做一個單獨的 String key。
  2. 數據對象緩存
    • 例如商品信息 product:2001,其中字段 price、title、stock 等;
    • 更新時只需改對應字段,不必覆蓋整個對象;
    • 還能減小內存,因為小哈希在 Redis 內部可用緊湊結構存儲。
  3. 記錄統計量
    • 可以在 Hash 中存放各種計數器字段(點擊量、點贊量、回復數等),通過 HINCRBY 實現原子自增。
    • 一個大對象的多種統計值都集中在同一個 hash key 下,管理更方便。
  4. 減少 key 的數量
    • 在某些業務場景中,為了避免 key 過多帶來的管理壓力,把多個相關字段匯總到同一個 Hash key 下會簡化命名空間;
    • 但要注意單個哈希不宜過大,否則一次獲取全部字段仍可能帶來性能開銷。

6.2.4 常見注意事項 & Best Practices

  1. 單個 Hash 不宜過度膨脹
    • 雖然 redis.conf 里會控制 ziplist/listpack 的一些大小閾值,但如果字段規模過大,一次性 HGETALL 會占用大量內存帶寬;
    • 對于超大哈希(上百萬字段),謹慎使用或考慮拆分、使用 HSCAN 分批遍歷。
  2. 字段值只能是字符串
    • Redis Hash 的 value 最終以字符串形式存儲(即使是數字,也保存為字符串);
    • 若要存儲復雜對象,可以序列化后放進字段值,如 JSON 或 MsgPack,更新局部字段可能就需要再解析 JSON。
  3. 過期和生命周期
    • Redis 只能對整個 Hash key 設置過期時間(如 EXPIRE user:1001 3600),無法對 Hash 里某個字段單獨設置過期。
    • 若只想讓特定字段有失效時間,需要業務層邏輯配合。
  4. Hash vs. String
    • 如果只有一個字段,使用 String 即可;
    • 如果對象字段較多或需要一起管理,Hash 更方便,也可能更省內存(對小字段場景)。
  5. Hash vs. Set、ZSet
    • Hash 專注于“字段-值”映射的結構,字段之間無順序,主要用于描述對象屬性;
    • Set/ZSet 更側重“集合”或“排序”語義;
    • 業務邏輯決定選擇。
  6. HXxx 命令的性能
    • 在絕大多數情況下都為 O(1) 或 O(N)(N 為字段數)的操作,和內部哈希表實現相關。
    • 大量字段更新時,也要留意操作分散性,別在高并發下對同一個大哈希做高頻更新——可能會增大鎖競爭(Redis 單線程)。

6.2.5 小結

Redis Hash 提供了緊湊且靈活的 “字段-值” 結構,適合存儲類似對象、配置、多字段記錄等。它的核心命令可總結為:

  1. 增改
    • HSET / HMSET:設置或更新字段
    • HINCRBY / HINCRBYFLOAT:對數值字段原子自增
  2. 查詢
    • HGET / HMGET:獲取單個或多個字段值
    • HGETALL:獲取全部字段和值
    • HKEYS / HVALS:只獲取字段 / 值列表
    • HEXISTS:判斷字段是否存在
    • HLEN:獲取字段總數
  3. 刪除
    • HDEL:刪除一個或多個字段
  4. 掃描
    • HSCAN:分批遍歷所有字段
  5. 其他
    • EXPIRE / TTL 等只能針對整個 key,不支持單字段到期

合理使用 Hash,可以有效減少 key 數量,提升空間利用率,且讓數據結構更加接近業務對象形態。結合其他 Redis 數據類型(如 List、Set、ZSet)能夠構建出更豐富的業務邏輯與功能。

  • HSET <key> <field> <value>:設置 hash 表中的 field 字段值。
  • HGET <key> <field>:獲取 hash 表中 field 字段值。
  • HMGET / HMSET:批量操作多個字段。
  • HGETALL <key>:獲取 hash 的所有字段和值。
  • HDEL <key> <field>:刪除指定字段。

6.3 列表(List)

在 Redis 中,List(列表) 是一個非常常用的數據類型,用來存儲一個按插入順序排序的字符串列表。它本質上可被視作一個雙端隊列,允許在隊列頭(left)或隊列尾(right)進行插入、彈出等操作。


6.3.1 List 的存儲與特點

  1. 存儲結構:在內部,Redis 為 List 使用了一種類似雙端鏈表QuickList(在較新的版本中)來維護元素。
  2. 數據特征:
    • 有序:按插入順序保存元素,可在頭/尾插入或彈出。
    • 元素類型:每個元素都是一個字符串,可以是文本、JSON、二進制等,長度最大可達 512MB(與普通 String 的限制相同)。
  3. 常用場景:
    • 實現消息隊列 / 任務隊列(如生產者-消費者模型)。
    • 記錄最新的操作日志或信息(用 LPUSH + LTRIM 維護一個固定長度)。
    • 需要按順序遍歷、插入、或彈出的場景。

6.3.2 List 的常見操作命令

Redis 提供了多種與 List 交互的命令,下面分門別類介紹。

6.3.2.1 插入與彈出
6.3.2.1.1 LPUSH / RPUSH
  • LPUSH [element …]:在列表頭部插入一個或多個元素。新的元素會排在最前面。
  • RPUSH [element …]:在列表尾部插入一個或多個元素。新的元素會排在最后面。

示例

LPUSH mylist "world"
LPUSH mylist "hello"
# mylist = ["hello", "world"]RPUSH mylist "!"
# mylist = ["hello", "world", "!"]

mylist 不存在時,會先創建一個空列表再插入。

6.3.2.1.2 LPOP / RPOP
  • LPOP :移除并返回列表頭部的第一個元素。
  • RPOP :移除并返回列表尾部的最后一個元素。

示例

LPOP mylist    # 返回 "hello",mylist 變為 ["world", "!"]
RPOP mylist    # 返回 "!", mylist 變為 ["world"]
6.3.2.1.3 LINSERT
  • LINSERT BEFORE|AFTER
  • 作用:在列表中的某個“現有元素”前或后,插入一個新元素。
  • 如果 pivot 不存在,命令返回 -1;如果 key 不存在或列表為空,返回 0。

示例

# mylist = ["hello", "world"]
LINSERT mylist BEFORE "world" "there"
# mylist = ["hello", "there", "world"]

6.3.2.2 獲取與查看列表內容
6.3.2.2.1 LRANGE
  • LRANGE :返回列表在指定區間內的所有元素,包含左右邊界。

  • 下標可以是正數,0 表示第一個元素,1 表示正數第二個,以此類推。

  • 下標可以為負數,-1 表示最后一個元素,-2 表示倒數第二個,以此類推。

  • 示例:

    # mylist = ["hello", "world", "!"]
    LRANGE mylist 0 -1   # 返回所有元素 ["hello","world","!"]
    LRANGE mylist 0 1    # 返回 ["hello","world"]
    
6.3.2.2.2 LINDEX
  • LINDEX :根據索引獲取列表中的單個元素。

  • index 可為正數(從頭開始 0 表示第一個)或負數(-1 表示最后一個)。

  • 示例:

    # mylist = ["hello", "world", "!"]
    LINDEX mylist 0   # 返回 "hello"
    LINDEX mylist -1  # 返回 "!"
    
6.3.2.2.3 LLEN
  • LLEN :返回列表的長度(元素個數)。

  • 若 key 不存在,則返回 0;若 key 的類型不是 list,則報錯。

  • 示例:

    # mylist = ["hello","world","!"]
    LLEN mylist   # 返回 3
    

6.3.2.3 修改與截取
6.3.2.3.1 LSET
  • LSET :將列表中下標為 index 的元素設置為新的 element

  • 若索引越界或列表不存在,會返回錯誤。

  • 示例:

    # mylist = ["hello","world","!"]
    LSET mylist 1 "Redis"
    # mylist 變為 ["hello", "Redis", "!"]
    
6.3.2.3.2 LTRIM
  • LTRIM :對列表進行修剪,只保留指定區間的元素,區間外的全部刪除。

  • 注意截取的是保留區間,而非刪除區間。

  • 示例:

    # mylist = ["hello","Redis","!"]
    LTRIM mylist 0 1
    # 只保留下標 0 到 1 的元素,mylist = ["hello","Redis"]
    
6.3.2.3.3 LREM
  • LREM :按 count 的值移除指定元素:

    • count > 0:從頭到尾,刪除最多 count 個等于 element 的元素;
    • count < 0:從尾到頭,刪除最多 |count| 個等于 element 的元素;
    • count = 0:刪除所有等于 element 的元素。
  • 示例:

    # mylist = ["hello","world","hello","Redis"]
    LREM mylist 1 "hello"
    # 只從頭到尾刪除 1 個 "hello" -> mylist = ["world","hello","Redis"]
    LREM mylist 0 "hello"
    # 再把剩余的 "hello" 都刪掉 -> mylist = ["world","Redis"]
    

6.3.2.4 隊列 & 阻塞操作
6.3.2.4.1 RPOPLPUSH
  • RPOPLPUSH :

    • source 列表的尾部彈出一個元素,并將該元素插入到 destination 列表的頭部;
    • 返回彈出的元素值。
  • 可把它當作右彈左推的隊列操作,適用于在多個隊列之間傳遞消息。

  • 示例:

    # list1 = ["job1","job2","job3"]
    # list2 = ["x","y"]
    RPOPLPUSH list1 list2 
    # -> 返回 "job3"
    # list1 = ["job1","job2"]
    # list2 = ["job3","x","y"]
    
6.3.2.4.2 BLPOP / BRPOP
  • BLPOP [key2 …] :

    • 從左側彈出第一個非空列表的頭元素;如果所有列表都為空,則阻塞等待,直到有新元素插入或達到超時。
    • 如果超時,返回 nil
  • BRPOP 類似,但從右側彈出。

  • 常用場景:消息隊列或任務隊列中,消費者阻塞等待任務的到來。

  • 示例:

    BLPOP list1 list2 30
    # 優先檢查 list1 是否有元素,如果空,再檢查 list2
    # 如果都為空,則最多阻塞 30 秒,期間如果有新元素插入便立即返回
    

    LPOP/RPOP:如果列表為空,會立即返回 nil,不會阻塞。

    BLPOP/BRPOP:如果列表為空,會阻塞等待(直到超時或有新數據),適合任務隊列實時消費場景。


6.3.3 List 的使用場景

  1. 消息/任務隊列
    • 生產者使用 LPUSH/RPUSH 將任務入隊;
    • 消費者使用 BLPOP/BRPOP 阻塞式彈出任務進行處理;
    • 實現簡單可靠的異步隊列機制。
  2. 最新消息/日志列表
    • 使用 LPUSH 不斷往頭部插入最新的消息;
    • 配合 LTRIM mylist 0 99 等截取操作,保留最近 100 條;
    • 方便快速獲取最新信息,同時限制長度防止無限膨脹。
  3. 數據分頁或流式讀取
    • 可以用 List 存儲一批數據,使用 LRANGE 分段獲取;
    • 但要注意大規模數據可能導致內存占用多,可分而治之或考慮其他結構。
  4. Rotating Queue
    • 使用 RPOPLPUSH 在多個隊列之間轉移數據,實現輪轉或多隊列消費等策略。

6.3.4 常見注意事項 & Best Practices

  1. 避免存放超大量元素
    • 雖然 List 可存數百萬個元素,但一次 LRANGE 全量拉取也會占用大量內存和帶寬。
    • 如果只需要最新部分數據,建議使用 LTRIM 保留一定區間,或按業務邏輯拆分存儲。
  2. 使用阻塞命令需注意
    • BLPOP/BRPOP 在等待時會占用一個連接。如果連接數有限或網絡環境復雜,需要注意不要同時有太多阻塞請求。
  3. List 并非隨機訪問結構
    • 只能通過索引下標進行有限的隨機訪問(LINDEX),或是依賴 LRANGE 全面遍歷。
    • 若需要頻繁隨機讀寫中間元素或多字段操作,或許 Hash/Set 等其他結構更合適。
  4. 使用場景決定操作端
    • 對于隊列場景,一般約定一端入隊另一端出隊,避免混用增刪端,以形成一致的 FIFO(或 LIFO)順序。
    • 對于日志場景,通常是 LPUSH + LTRIM,永遠從頭部插入最新消息。
  5. Watch out for LRANGE large ranges
    • 盡管 Redis 的 List 操作性能較優,但一次性獲取幾百萬條也會造成阻塞和內存壓力。
    • 生產環境中可以 LRANGE key start end 分段獲取,或設計合理的數據拆分。

6.3.5 小結

List 在 Redis 中是一個強大且靈活的數據結構,可滿足多種順序場景需求,包括消息隊列最新列表雙端隊列等。其核心操作可以概括為:

  1. 頭/尾插入LPUSHRPUSH
  2. 頭/尾彈出LPOPRPOP
  3. 讀取區間LRANGE、查看長度:LLEN
  4. 阻塞彈出BLPOPBRPOP(常用于隊列)
  5. 部分修改LSETLTRIMLREM
  6. 多隊列轉移RPOPLPUSH

在實際業務中,通過合理地選用這些操作并結合過期策略或其他結構(例如存儲 ID 在 List 中、實際數據放在 Hash 或 String 里),可以構建高效的隊列模型、實時日志系統或其他順序相關的功能。

6.4 集合(Set)

在 Redis 中,Set(集合) 類型用于存儲一組不重復的字符串元素,和我們熟悉的數學集合很類似。Redis 提供了豐富的命令來操作集合,包括添加、刪除、判斷成員以及集合之間的交并差運算等。下面將按照類似前面介紹的風格,詳細講解 Set 的基本概念、常用命令以及使用場景和最佳實踐。


6.4.1 Redis Set 的存儲與特點

  1. 內部結構
    • Redis 使用類似哈希表(Hash Table)來存儲 Set 中的元素,每個元素都是一個獨立的字符串,并且不允許重復
    • 如果嘗試將相同的元素多次添加到同一個 Set,只有第一次會生效,后續重復添加不會改變集合狀態,也不會報錯。
  2. 數據特征
    • 元素無序:Redis 不保證插入順序,也不能通過索引下標來獲取或遍歷。
    • 元素唯一:同一個元素在集合中只會出現一次。
    • 高效查找:Set 中的元素查找、添加、刪除通常是 O(1) 平均復雜度(哈希表機制)。
  3. 常用場景
    • 存儲好友列表、標簽列表、不重復的元素集合;
    • 取交集、并集、差集,做共同好友、共同興趣、共同標簽分析等;
    • 去重功能(快速判斷某元素是否已經存在);
    • 隨機獲取、抽獎(SRANDMEMBERSPOP)等場景。

6.4.2 Set 的常見操作命令

6.4.2.1 添加、刪除、判斷成員
6.4.2.1.1 SADD
  • 作用:向集合添加一個或多個元素,如果元素已存在則跳過,不影響集合。

  • 語法:

    SADD <key> <member1> [member2 ...]
    
  • 返回值:實際被添加進集合的新元素數量。

  • 示例:

    SADD myset "apple"
    SADD myset "banana" "orange"
    # 如果 myset 之前不存在,會創建并插入元素。
    # 如果 "apple" 已存在,再次插入不會重復。
    
6.4.2.1.2 SREM
  • 作用:刪除集合中指定的一個或多個元素。

  • 語法:

    SREM <key> <member1> [member2 ...]
    
  • 返回值:被成功移除的元素數量。

  • 示例:

    SREM myset "banana"  # 從 myset 移除 "banana"
    
6.4.2.1.3 SISMEMBER
  • 作用:判斷某個元素是否為集合成員。

  • 語法:

    SISMEMBER <key> <member>
    
  • 返回值:1 表示是集合成員,0 表示不是或不存在。

  • 示例:

    SISMEMBER myset "apple"
    # 若 myset 包含 "apple" 則返回 1,否則返回 0
    

6.4.2.2 獲取、查看和隨機操作
6.4.2.2.1 SMEMBERS
  • 作用:返回集合中的所有元素。

  • 示例:

    SMEMBERS myset
    # 比如返回 ["apple","orange","grape"]
    
  • 注意:

    • 如果集合元素非常多,一次性返回也會占用較多內存和帶寬;
    • 生產環境中若集合規模龐大,可以考慮使用 SSCAN 命令分批次掃描(類似于 SCAN)。
6.4.2.2.2 SCARD
  • 作用:返回集合中的元素數量。

  • 示例:

    SCARD myset  # 返回例如 3
    
6.4.2.2.3 SPOP
  • 作用:隨機移除并返回集合中的一個或多個元素(默認 1 個)。

  • 語法:

    SPOP <key> [count]
    
  • 示例:

    SPOP myset
    # 隨機彈出一個元素,并將其從 myset 中移除。
    SPOP myset 2
    # 隨機彈出 2 個元素,返回數組,并同時從集合刪除它們。
    
  • 應用場景:抽獎、隨機發放獎品、隨機推薦等。

6.4.2.2.4 SRANDMEMBER
  • 作用:隨機獲取集合中的一個或多個元素,但不會將其從集合中刪除(和 SPOP 區別在于是否刪除)。

  • 語法:

    SRANDMEMBER <key> [count]
    
  • 示例:

    SRANDMEMBER myset
    # 隨機返回一個元素,不會刪除
    SRANDMEMBER myset 2
    # 隨機返回 2 個元素(可能包含重復,Redis < 3.2 不同版本實現略有區別)
    

    在 Redis 3.2+,如果 count 為正,則返回不重復的元素;如果 count 為負,則可能返回重復的元素。可查閱對應版本文檔以確認。


6.4.2.3 集合運算(交集、并集、差集)

Redis 提供了三個重要的集合運算命令:SINTERSUNIONSDIFF。配合這些命令,能快速做聚合分析,如“共同好友”、“共同興趣標簽”等場景。

6.4.2.3.1 SINTER / SINTERSTORE
  • SINTER:求一個或多個集合的交集。

    SINTER <key1> [key2 ... keyN]
    

    返回所有在這些集合中都存在的元素。

  • SINTERSTORE:將交集結果直接存儲到另一個集合。

    SINTERSTORE <destination> <key1> [key2 ... keyN]
    
  • 示例:

    # set1 = {"apple","banana","orange"}
    # set2 = {"banana","orange","grape"}
    SINTER set1 set2
    # 返回 {"banana","orange"}SINTERSTORE set3 set1 set2
    # set3 將變成 {"banana","orange"}
    
6.4.2.3.2 SUNION / SUNIONSTORE
  • SUNION:求并集,返回任意集合里出現過的所有元素(去重)。

    SUNION <key1> [key2 ... keyN]
    
  • SUNIONSTORE:把并集結果存儲到 destination

  • 示例:

    SUNION set1 set2
    # 返回 {"apple","banana","orange","grape"}
    SUNIONSTORE set4 set1 set2
    # set4 = {"apple","banana","orange","grape"}
    
6.4.2.3.3 SDIFF / SDIFFSTORE
  • SDIFF:求差集,返回在第一個集合里而不在其他集合中的元素。

    SDIFF <key1> [key2 ... keyN]
    
  • SDIFFSTORE:將差集結果存儲到 destination

  • 示例:

    SDIFF set1 set2
    # 返回 {"apple"} (set1 - set2)
    SDIFFSTORE set5 set1 set2
    # set5 = {"apple"}
    

6.4.2.4 其他常用或補充命令
  1. MOVE (Redis 6.2 以前版本僅對 key 生效,對 Set 結構可以使用 SPOP + SADD 或 SRANDMEMBER + SADD 的方式來“移動”元素到另一個集合)。
  2. RENAME (對整個 key 進行重命名,不僅是 Set 類型才有,不過僅限 key 級別操作,不是移動元素)。
  3. SSCAN (類似 SCAN,可分批掃描大集合,語法:SSCAN key cursor [MATCH pattern] [COUNT count]),在集合規模很大的情況下比一次性 SMEMBERS 友好,避免阻塞。

6.4.3 使用場景

  1. 去重功能
    • 將數據插入 Set 并檢查返回值或 SISMEMBER 判斷重復。
    • 例如:用戶簽到(只需保存用戶 ID,保證每個用戶只簽到一次)。
  2. 社交場景
    • 用戶關注列表、好友列表都可以用 Set 表示;
    • 求共同好友:SINTER userA:friends userB:friends
    • 計算關注量:SCARD user:followers,判斷是否互相關注:SISMEMBER user:followers otherUserID 等。
  3. 標簽或權限管理
    • 每個用戶的標簽是一個 Set 或每個標簽對應一個 Set。可通過集合運算來靈活地求交集或并集。
  4. 隨機抽取、抽獎
    • SRANDMEMBER 隨機選取;如需“抽完就移除”,可用 SPOP
  5. 去除重復消息 / 數據過濾
    • 在大量數據處理中,可把已處理過的標記存進 Set,若再次出現,表明是重復,跳過即可。

6.4.4 常見注意事項 & Best Practices

  1. Set 元素數量過多
    • SMEMBERS 會把所有元素一次性返回,可能導致內存和帶寬的壓力;
    • 建議使用 SSCAN 分批遍歷;或在設計上拆分成多個小集合,避免單個 Set 過大。
  2. 大小限制
    • 單個 Set 理論上可存放多達數億個元素(只要內存足夠);但操作如交集并集也會消耗相應資源,需評估性能和內存。
  3. 不要濫用 Set 做有序需求
    • Set 是無序的,若需要按照分數、排名等有序排序,應該考慮使用 Sorted Set (ZSet)
    • 若需要按插入順序遍歷或常做 FIFO/LIFO,List 或 Stream 更適合。
  4. 集合運算開銷
    • SINTER, SUNION, SDIFF 等運算在集合很大時也可能比較耗時,尤其當參與運算的集合規模都非常龐大時。
    • 若是在線查詢,需要注意別在關鍵路徑上做大規模集合運算,以免阻塞 Redis 主線程。可以在業務層緩存結果,或在后端服務分層處理。
  5. 過期策略
    • Redis 不支持對 Set 中的單個元素設置過期,但可以對整個 key 設置過期時間(EXPIRE key seconds)。
    • 若需要對其中的部分元素做時間控制,可能需要別的結構或自行管理。

6.4.5 小結

Set 在 Redis 中是一個非常基礎且強大的數據結構,最顯著的特點是:

  • 元素唯一無序快速判重
  • 提供交集、并集、差集等集合運算;
  • 適合去重、好友列表、標簽管理、抽獎等常見場景。

其核心命令可以簡要歸納為:

  1. 添加 / 刪除:
    • SADD / SREM
  2. 查詢:
    • SMEMBERS(全量),SISMEMBER(單一判斷),SCARD(數量)
    • SSCAN(分批掃描)
  3. 隨機:
    • SPOP(隨機彈出并刪除),SRANDMEMBER(隨機獲取不刪除)
  4. 集合運算:
    • SINTER, SUNION, SDIFF 以及對應的 STORE 版本
  5. 其他:
    • SMOVE(已棄用命令,Redis 版本里沒有 SMOVE 可以用 SPOP+SADD 替代),LTRIM 不適用于 Set,SSCAN 用于分批遍歷等。

只要掌握這些命令和組合應用,就能應對大部分業務中需要“去重、隨機、集合運算”的需求。在實際開發中,還要結合 Redis 的內存管理、過期策略及安全控制,來達成高性能又可靠的 Set 使用方案。

6.5 有序集合(ZSet)

在 Redis 中,有序集合(Sorted Set)是一種在集合基礎上,為每個成員額外關聯一個分數(score)的數據結構,常被縮寫為 ZSet。它的特點是:元素不允許重復,但可以按照分數進行排序。Redis 提供了一系列針對有序集合的操作命令,方便我們在排行榜、排名查詢、區間篩選、限時排序等場景中使用。


6.5.1 ZSet 的存儲與特點

  1. 內部結構
    • Redis 使用一種結合了 跳表(Skiplist) + 哈希表(Hashtable) 的結構來存儲 ZSet。
    • 跳表可以讓我們在 O(log N) 的復雜度下進行有序操作(如范圍查找、排序等),哈希表負責快速定位元素。
  2. 數據特征
    • 元素唯一:和 Set 一樣,每個 ZSet 里元素(member)是唯一的。
    • 分數(score)可以重復:不同的 member 可以擁有相同的分數,但是 member 自身不能重復。
    • 按分數排序:Redis 可以根據 score 值對元素進行從小到大的排序,也可以支持倒序操作。
  3. 常用場景
    • 排行榜:比如按積分、熱度、時間戳等排序;
    • 時間序列:score 代表時間戳,按時間順序進行查詢或截取;
    • 帶權重的列表:以 score 作為優先級或權重值,隨時能快速獲取指定排名或分數區間的元素。

6.5.2 有序集合 ZSet 的常見命令

6.5.2.1 添加、更新、刪除元素
6.5.2.1.1 ZADD
  • 作用:向有序集合中添加一個或多個 member,并設置它們的分數 score。若 member 已存在則更新其 score。

  • 語法:

    ZADD <key> [NX|XX] [CH] [INCR] <score1> <member1> [<score2> <member2> ...]
    
  • 常用選項:

    • NX:僅當 member 不存在時才添加;
    • XX:僅當 member 已存在時才更新;
    • CH:返回被修改的成員數量(包括 score 發生變動的情況);
    • INCR:對給定 member 的分數執行加法操作,而不是直接設置分數。
  • 示例:

    ZADD leaderboard 100 "playerA"
    ZADD leaderboard 200 "playerB" 150 "playerC"
    # 如果 playerA 已存在,則其 score 會被更新為 100
    
6.5.2.1.2 ZREM
  • 作用:從有序集合中刪除指定元素,支持刪除多個。

  • 語法:

    ZREM <key> <member1> [member2 ...]
    
  • 示例:

    ZREM leaderboard "playerC"
    # 刪除 "playerC" 這個 member
    
6.5.2.1.3 ZINCRBY
  • 作用:對指定 member 的分數進行增量操作(加上給定的數值)。

  • 語法:

    ZINCRBY <key> <increment> <member>
    
  • 示例:

    ZINCRBY leaderboard 50 "playerA"
    # playerA 的分數在原來的基礎上 +50
    
  • 注意:如果 member 不存在,會先以 score=0 創建該 member,再加上 increment。


6.5.2.2 按序查詢、獲取排名
6.5.2.2.1 ZRANGE / ZREVRANGE
  • 作用:按 score 升序(ZRANGE)或降序(ZREVRANGE)獲取指定索引區間內的元素。

  • 語法:

    ZRANGE <key> <start> <stop> [WITHSCORES]
    ZREVRANGE <key> <start> <stop> [WITHSCORES]
    
  • 示例:

    ZRANGE leaderboard 0 -1        # 返回所有成員,按分數升序
    ZRANGE leaderboard 0 2 WITHSCORES  # 返回前三名,同時顯示分數
    ZREVRANGE leaderboard 0 2 WITHSCORES # 返回分數最高的三名
    
  • 索引區間:

    • 0 表示第一個元素(最小或最大的視升序/降序而定),-1 表示最后一個元素;
    • 依次類推,startstop 可以是正負索引。
6.5.2.2.2 ZRANGEBYSCORE / ZREVRANGEBYSCORE
  • 作用:按 score 值進行范圍查詢,返回分數在 [min, max](或 [max, min])區間內的 member 列表。

  • 語法:

    ZRANGEBYSCORE <key> <min> <max> [WITHSCORES] [LIMIT offset count]
    ZREVRANGEBYSCORE <key> <max> <min> [WITHSCORES] [LIMIT offset count]
    
  • 說明:

    • ZRANGEBYSCORE leaderboard 100 200:獲取 score 處于 100~200 范圍內的所有成員,按升序。
    • ZREVRANGEBYSCORE leaderboard 200 100:同樣的分數區間,但按分數從高到低排序。
    • LIMIT offset count:可對結果做分頁或截取。
    • +inf-inf:可用于表示無窮大和無窮小;(100 表示大于 100 而不是大于等于(帶括號表示排除)。
6.5.2.2.3 ZRANGEBYLEX / ZRANGEBYDICT(Redis 6.2+ 支持),與按 Member 字典序相關
  • 在某些場景下可以按 Member 的字典序,而非 score 進行范圍查詢;這是比較少用的操作,了解即可。
6.5.2.2.4 ZRANK / ZREVRANK
  • 作用:獲取某個 member 在有序集合中的排名(下標)。

  • 語法:

    ZRANK <key> <member>
    ZREVRANK <key> <member>
    
  • 返回值:

    • 若 member 存在,返回其以 0 開始的排名;
    • 若不存在,返回 nil
  • 舉例:

    ZRANK leaderboard "playerA"
    # 返回 playerA 在升序下的名次(0 表示 score 最小的那個,數值越大表示分數更高的排名)
    ZREVRANK leaderboard "playerA"
    # 返回 playerA 在降序下的名次(0 表示分數最高的)
    
6.5.2.2.5 ZCARD / ZCOUNT
  • ZCARD:返回有序集合的基數(元素總數)。

    ZCARD <key>
    
  • ZCOUNT:統計指定 score 區間內的元素數量。

    ZCOUNT <key> <min> <max>
    

    例如:ZCOUNT leaderboard 100 200 返回分數在 [100,200] 的元素數。


6.5.2.3 刪除和范圍操作
6.5.2.3.1 ZREM、ZREM_RANGE_BY_SCORE、ZREM_RANGE_BY_RANK
  • ZREM:前面提過,按 member 刪除指定元素。

  • ZREMRANGEBYSCORE:刪除score在給定區間內的所有元素。

    ZREMRANGEBYSCORE <key> <min> <max>
    # 如 ZREMRANGEBYSCORE leaderboard 0 100  -> 刪除 score <= 100 的所有元素
    
  • ZREMRANGEBYRANK:按排名下標區間刪除元素。

    ZREMRANGEBYRANK <key> <start> <stop>
    # 如 ZREMRANGEBYRANK leaderboard 0 9  -> 刪除排在前 10 名的元素
    
6.5.2.3.2 ZINTERSTORE / ZUNIONSTORE / ZDIFFSTORE (Redis 6.2+)

和普通 Set 類似,Redis 也提供了對 ZSet 的交集、并集、差集運算,但是會對 score 做相應的合并或計算。常見的是 ZINTERSTOREZUNIONSTORE

  • ZINTERSTORE:計算給定的一個或多個有序集合的交集,將結果存儲到新集合中,并根據每個元素在各集合中的 score 值執行相應的加權或求和。
  • ZUNIONSTORE:并集操作,score 同樣可以加權或求和。

示例:

ZADD zset1 1 "a" 2 "b"
ZADD zset2 2 "a" 3 "c"ZINTERSTORE out 2 zset1 zset2 WEIGHTS 2 3
# 這里 2 表示有 2 個集合,WEIGHTS 2 3 分別表示 zset1 的 score 乘以2, zset2 的 score 乘以3
# "a" 在 zset1 score=1, zset2 score=2
# 計算交集則 "a" 存在于兩個集合中,score = 1*2 + 2*3 = 2 + 6 = 8
# "b" 只在 zset1, "c" 只在 zset2,故它們不在交集里
# out = {"a":8}

注意:Redis 7.0+ 也引入了 ZDIFFSTORE(差集),不過在實際中用得相對少一些。


6.5.3 常見使用場景

  1. 排行榜
    • 例如游戲積分榜、電商熱賣榜、點贊數排行等;
    • 可以通過 ZADD 不斷更新用戶的分數,然后使用 ZREVRANGEZREVRANK 獲取某人排行或前 N 名;
    • ZINCRBY 用于積分累加,ZRANK / ZREVRANK 用于查詢當前名次。
  2. 實時排序
    • 每次用戶操作(點贊、查看、消費等)都可以更新其相關分數;
    • 通過按分數的正序或倒序可實現某些實時刷新排名的功能,比如直播間送禮排行榜、產品熱度排名等。
  3. 延時隊列 / 時間調度
    • 把 future task 存成 (score=執行時間, member=任務ID),利用 ZRANGEBYSCORE 查詢到期任務,進行處理后刪除;
    • 可以替代一些簡單的定時任務邏輯。
  4. 時間序列
    • 以時間戳作為 score,member 是事件或數據 ID;
    • 使用 ZRANGEBYSCOREZREVRANGEBYSCORE 在一定時間范圍內獲取數據。

6.5.4 注意事項 & Best Practices

  1. score 的精度
    • Redis score 本質是一個雙精度浮點數(double),盡量避免過于依賴小數精度(有時可能出現浮點誤差)。
    • 如果分數是整數,推薦直接用整數(如 123456)或用一個長整型來表達時間戳/分值以減小誤差。
  2. ZADD 頻繁更新
    • 更新分數只需再次執行 ZADD <key> <score> <member>,若 member 存在則覆蓋;或 ZINCRBY 增量更新。
    • 頻繁更新大規模 ZSet 時要注意是否會帶來內存或操作耗時,畢竟跳表需要維護順序。
  3. 排行榜前 N vs. 全量遍歷
    • ZRANGE key 0 9ZREVRANGE key 0 9:獲取前 10 名或后 10 名非常高效;
    • 如果要獲取所有成員(百萬級)并排序,返回時就會產生大流量,占用 Redis 線程,對性能影響較大。
    • 可以考慮分頁或分段查詢:ZREVRANGE key start end,或者用 ZRANGEBYSCORE + LIMIT 進行分頁,不過也要注意性能。
  4. 刪除操作
    • ZREM 只針對指定 member;
    • 對于區間刪除(score 范圍或排名范圍)可使用 ZREMRANGEBYSCOREZREMRANGEBYRANK
    • 這些批量刪除操作會在一定程度上阻塞 Redis 主線程,規模很大時也需注意分拆或異步管理。
  5. 內存占用
    • ZSet 同時維持哈希表 + 跳表結構,會比普通 Set 消耗更多內存;
    • 大量 ZSet 時需考慮內存大小、持久化和主從復制對性能的影響。
  6. 過期策略
    • Redis 不支持對 ZSet 的單個 member設置過期,只能對整個 key 設置過期;
    • 如果需要對某些分數或元素做定期清理,可以定時執行 ZREMRANGEBYSCORE 或業務邏輯判斷后刪除。

6.5.5 小結

有序集合(ZSet)是 Redis 中一個非常重要的高級數據結構,結合了“集合去重”與“分數排序”的優勢,能在很多排行榜調度排序場景下大顯身手。

其核心命令可簡要概括為:

  1. 增、刪、改、查
    • ZADD:添加/更新元素
    • ZREM:刪除指定元素
    • ZINCRBY:分數自增
    • ZRANK / ZREVRANK:查看排名(索引位置)
    • ZCARD:ZSet 大小
  2. 獲取數據
    • ZRANGE / ZREVRANGE:按索引區間獲取排序結果
    • ZRANGEBYSCORE / ZREVRANGEBYSCORE:按分數區間獲取
    • ZCOUNT:分數區間計數
  3. 范圍刪除
    • ZREMRANGEBYSCOREZREMRANGEBYRANK
  4. 交并集操作
    • ZINTERSTORE / ZUNIONSTORE:對多個 ZSet 做交集 / 并集,score 可以加權合并

掌握了這些命令及應用思路,就能靈活地在Redis中構建實時排行榜、延時隊列、時間序列、計分系統等功能。配合其他類型(String、Hash、Set 等)的混合使用,可以構建出更豐富、更高效的 Redis 數據模型來滿足不同業務需求。

6.7 時間復雜度

在 Redis 中(以及更多計算機科學領域),我們常用 Big-O 表示法(如 O(1)、O(log N)、O(N) 等)來衡量算法或操作的時間復雜度,它代表了輸入規模增大時,操作耗時的增長趨勢。下面我們分幾個層面來理解:

6.7.1 什么是 O(1) 和 O(log N)?

  1. O(1)(常數時間):
    • 表示無論數據規模 N N N 多大,操作所需的時間都近似于一個常數,與 N N N 無關。
    • 例如,用哈希表(Hash Table)查詢一個元素的平均時間復雜度是 O(1):查找過程可在常數時間內完成。
    • 當然這是平均情況。哈希表在最壞情況下(沖突嚴重)可能退化到 O(N);但在良好散列和低沖突的場景下可視為 O(1)。
  2. O(log N)(對數時間):
    • 表示操作所需時間隨數據規模 N N N 的增加按照對數規律增長。對數函數增長速度比線性函數慢得多,所以當 N N N 很大時,O(log N) 算法仍然比較高效。
    • 例如,用平衡二叉搜索樹跳表(Skiplist)B+樹等結構進行插入、查找、刪除,通常都能在 O(log N) 時間內完成。
    • Redis 的**有序集合(ZSet)**內部默認用“跳表 + 哈希表”來存儲:
      • 跳表部分提供按分數排序、區間查詢等有序操作的能力(O(log N));
      • 哈希表部分用來快速定位元素是否存在(O(1) 平均情況)。

6.7.2 為何跳表的有序操作是 O(log N)?

跳表(Skiplist) 是一種隨機化的數據結構,結構上類似多層鏈表,每一層都跳過一些節點,以加速查找、插入和刪除。

  • 在理想狀態下,每向上走一層,節點數量就減少一半;
  • 因此要找到某個元素或一個分數區間時,只需從高層往低層“逐漸逼近”,訪問的節點數大約是 log ? 2 N \log_2{N} log2?N量級;
  • 整體上插入、刪除、查找等操作都能保持在 O(log N) 水平。

舉個形象的例子:

  • 在一個排好序的很長的鏈表中,如果只能一格一格往后找,那么查找就是 O(N)。
  • 但如果你先在“頂層鏈表”里,隔幾個節點就有一個索引,可以快速跳過若干節點;再往下一層,更密集的索引幫助你再定位……如此層層逼近目標,就能極大縮短“跳”的次數,這就是為什么能夠得到 O(log N) 的時間復雜度。

6.7.3 為何哈希表的操作是 O(1)(平均情況)?

哈希表(Hash Table) 通過哈希函數把鍵(Key)映射到一個桶(bucket)或槽(slot)里,理論上可以直接通過哈希函數一次定位到存儲位置。

  • 在沖突不多、散列均勻的情況下,查找、插入、刪除操作只需要常數步(O(1))就能完成;
  • 這是因為無論有多少數據(N 很大),哈希函數的計算和一次到位的尋址,都不太依賴 N 的規模;
  • 不過,如果哈希沖突非常多或散列不均,最壞情況可能要在某個桶里的鏈表挨個遍歷(O(N)),但平均來說,好的哈希設計能讓大部分操作維持在 O(1)。

6.7.4 Redis 中具體體現

  1. ZSet 的跳表部分
    • 當我們需要“根據分數范圍取某些元素”或“得到某個分數在有序集合中的排名”時,就需要依賴有序結構(跳表)來進行區間遍歷或排名查找,復雜度約為 O(log N)(有序查找、插入、刪除)或 O(log N + M)(找出 M 個結果)。
    • 例如命令 ZRANGEBYSCOREZREVRANGEBYSCORE 就是利用跳表快速定位到指定分數區間的起始位置,然后順序掃描出結果。
  2. ZSet 的哈希表部分
    • 當我們執行 “給某個元素設置分數” 或 “查一個元素在不在這個 ZSet 里” 時,可先通過哈希表在 O(1) 平均時間內找到該元素;如果更新分數,則跳到跳表對應位置更新節點;
    • 這樣就兼顧了快速定位(哈希表)和有序操作(跳表)。
  3. Hash(哈希)類型SetHashMap 等其他結構:
    • 也都基于哈希表,插入、查詢、刪除的平均復雜度是 O(1)。
  4. ListStream
    • 大部分情況下是 O(1) 地在頭尾插入或彈出(LPUSH、LPOP、RPUSH、RPOP),但隨機訪問或索引查找時就需要 O(N)(鏈表或類似結構需遍歷)。

6.7.5 如何理解這些復雜度?

  • Big-O 并非絕對耗時:它只描述增長趨勢,并不意味著一旦是 O(log N) 就一定比 O(1) 慢,或者 O(N) 就一定比 O(log N) 慢;在小規模數據時,常數和常數因子也會很重要。
  • 平均 vs. 最壞:哈希表的 O(1) 通常指平均復雜度;跳表/樹型結構的 O(log N) 指大多數情況下都會如此,但在極端情況下也可能退化。
  • 選擇合適的數據結構:如果你需要有序查詢范圍操作排名等功能,就需要跳表/樹這樣支持排序的結構(ZSet)。如果只是key -> value 快速查詢(比如 Set/Hash),哈希表就足夠好,簡單粗暴且平均 O(1)。

6.7.6 小結

  • O(1):操作耗時不隨著數據規模變化而顯著增長,是平均情況下哈希表操作最有吸引力的特征。
  • O(log N):跳表、平衡樹等結構能實現高效的有序操作。隨著 NN 增大,耗時按照 級別增長,比 O(N) 好很多,但比 O(1) 大。
  • Redis ZSet 內部“跳表 + 哈希表”的組合可以理解為:
    • 哈希表提供快速定位(O(1) 平均)
    • 跳表提供有序操作(O(log N))
    • 二者互補,使得 ZSet 在“既需要有序,又要能快速查某元素”的場景中表現優異。

這些就是常見的時間復雜度概念和在 Redis 內部的具體落地。當在應用層設計數據結構或分析 Redis 性能時,理解這些復雜度有助于我們選擇合適的操作提前預估可能的開銷

6.7 消息隊列

在消息隊列或者消息傳遞領域,一般會提到 兩種常見的消息模式

  1. 生產者-消費者(Producer-Consumer)
  2. 發布-訂閱(Publisher-Subscriber,Pub/Sub)

6.7.1 生產者-消費者(Producer-Consumer)

6.7.1.1 模式概念
  • 生產者(Producer):負責發送消息或任務到隊列(Queue)中。
  • 消費者(Consumer):從隊列中取出消息或任務并進行處理。

常見的形態是“消息隊列”:生產者把消息投遞到隊列,消費者從隊列里取出并消費,最終隊列中存儲的是待處理的消息。

6.7.1.2 工作流程
  1. 生產者將消息發送到消息隊列;
  2. 消息隊列負責臨時存儲這些消息,充當緩沖區;
  3. 消費者從隊列中輪詢或阻塞獲取消息(通常是 FIFO,先進先出 first in,first out),然后執行處理;
  4. 處理完畢后,消息即被標記為消費完成或從隊列移除。
6.7.1.3 主要特點
  1. 解耦:生產者和消費者可以異步運行,生產者發送后就可以繼續處理其他任務,不用等待消費者處理完成。
  2. 緩沖:消息隊列在生產者和消費者之間提供了一個緩沖池,能應對突發的高并發或流量不均衡,避免直接把壓力傳遞給消費者。
  3. 可靠性(可選):大多數消息隊列中間件(RabbitMQ、Kafka、RocketMQ 等)會提供持久化、確認(ACK)機制來保證消息不丟失。
  4. 競爭消費:通常一個隊列可被多個消費者并行消費,每條消息只會被其中一個消費者處理一次,適合“任務分發”或“分布式工作池”模式。
6.7.1.4 典型應用場景
  • 異步任務處理:如發送短信、郵件、圖像處理,把耗時任務扔進隊列中,再由工作進程去處理。
  • 削峰填谷:電商大促時,訂單處理可先進入隊列以防止瞬時并發過高;消費者慢慢消化隊列里積壓的訂單。
  • 分布式系統間解耦:生產者和消費者可以各自升級或故障重啟,而不影響對方的邏輯。

6.7.2 發布-訂閱(Pub/Sub, Publisher-Subscriber)

6.7.2.1 模式概念
  • 發布者(Publisher):向某個主題或頻道(Topic/Channel)發布消息。
  • 訂閱者(Subscriber):對指定主題或頻道進行訂閱,一旦有新的消息發布,就會被推送接收到。

可以把它理解為“廣播”式:所有訂閱了某個頻道的訂閱者,在發布者推送消息后,都會各自收到一份消息。

6.7.2.2 工作流程
  1. 訂閱者先聲明對某個主題/頻道感興趣,并訂閱之;
  2. 發布者向該主題/頻道發布消息;
  3. 消息中間件負責將消息同時分發給所有已訂閱該主題/頻道的消費者;
  4. 每個訂閱者都能夠各自收到該條消息,并進行自己的處理。
6.7.2.3 主要特點
  1. 一對多:一個發布者發布的一條消息可以同時被多個訂閱者接收,這與“生產者-消費者”中單條消息只被一個消費者處理截然不同。
  2. 實時推送:當發布者有新消息時,訂閱者能立即收到;
  3. 不保證存儲(取決于實現):如果某個訂閱者離線或沒有及時消費,消息可能就錯過了(除非使用帶持久化/主題回溯的消息系統,例如 Kafka、Redis Streams 也有一定存儲能力,但傳統“Redis Pub/Sub”則不存儲歷史消息)。
  4. 松耦合:發布者不需要知道訂閱者是誰,訂閱者也不需要知道具體是哪一個發布者發的消息。它們只通過主題來“對接”。
6.7.2.4 典型應用場景
  • 廣播通知:系統中某個事件需要同時通知多個服務或模塊。
  • 實時推送:聊天房間、直播間彈幕、股票行情等,需要向所有在線訂閱者推送最新數據。
  • 異步事件總線:在微服務架構中,一些服務可能只需要監聽特定事件來觸發自己的邏輯,發布者只管發布事件,多個訂閱者各自執行不同流程。

6.7.3 對比與總結

維度生產者-消費者(消息隊列)發布-訂閱(Pub/Sub)
消息傳遞關系一對一:隊列中的一條消息只會被一個消費者處理一對多:一個消息可同時被多個訂閱者接收
消息存儲通常會存儲在隊列里,若消費者未及時消費,消息也不會丟取決于系統實現,傳統 Pub/Sub 通常不存儲歷史消息
消費模式消費者競爭消費同一個隊列;可實現分布式工作池、并行處理所有訂閱該主題的訂閱者都能各自收到一份消息,并行處理
適用場景異步處理、隊列緩沖、削峰填谷、解耦分布式任務實時廣播通知、事件訂閱、多客戶端同時接收相同消息
消息確認 & 重試通常具備ACK/重試機制,確保消息被正確處理傳統簡單 Pub/Sub 一般無重試/確認,消息分發后即丟
核心關注點可靠消費,隊列實現排隊、緩沖;保證單條消息只被處理一次消息廣播,多消費者同時收到,不保證是否被落地存儲

6.7.4 延伸與選擇

  1. 生產者-消費者主要關注:
    • 消息排隊可靠處理、可控的并發消費、處理完消息后就出隊
    • 適用于工作隊列、任務處理、訂單處理、分布式流水線等。
  2. 發布-訂閱主要關注:
    • 分發:一次消息,多個訂閱者同時收到;
    • 廣播多對多模式;
    • 適用于實時性推送、廣播通知、事件總線等。
  3. 組合使用
    • 有時一個系統中既需要排隊處理,又需要廣播通知,則會在不同子模塊選擇不同模式,或者使用支持多種模式的消息中間件(如 Kafka 既支持“訂閱分區”,也能做分布式隊列;RabbitMQ 可用交換器+隊列配合實現多播等)。
  4. 不同系統實現
    • 如 RabbitMQ、ActiveMQ、RocketMQ 更偏向隊列模型(生產者-消費者),但也能通過不同的 exchange 類型(主題交換、fanout 等)來實現類似發布-訂閱;
    • Kafka 雖然更多用于訂閱(消費者組對 Topic 的訂閱),但本質也能做隊列(同一個分區內仍是單消費者消費)。
    • Redis 的 Pub/Sub 屬于較簡單的純廣播,不存儲歷史消息,而 Redis Streams 則提供了可做隊列或訂閱的能力,也支持 Consumer Group。

6.7.5 小結

  • 生產者-消費者(消息隊列模型):
    • 核心訴求:每條消息由唯一消費者處理,注重可靠消費、解耦、延遲容忍,可以做異步處理、削峰填谷。
  • 發布-訂閱(Pub/Sub 模型):
    • 核心訴求:一次消息可同時被多個訂閱者接收,注重實時廣播、事件分發;不一定有存儲與確認機制。

兩種模式各有適用場景,在實際項目中往往結合使用,或者在同一個消息系統內使用不同的交換策略實現不同效果。選擇哪種模式取決于消息要給多少人接收、是否需要隊列緩沖、是否要落盤與確認、是否需要多對多的實時通信等業務需求。

6.7.6 Redis 實現消息隊列

在許多場景下,Redis 經常被用作輕量級的消息隊列(Message Queue),實現簡單的生產者-消費者模型或發布訂閱功能。根據 Redis 版本和需求的不同,常見的實現方式主要有:

  1. 使用 List(列表)+ 阻塞彈出:最傳統的方式,利用 LPUSH/RPUSHBLPOP/BRPOP 組合,構建簡單隊列。
  2. 使用 Redis Pub/Sub:更適合實時廣播式的消息分發,但消息不能持久化。
  3. 使用 Redis Streams(5.0+):官方推薦的現代化消息流結構,支持持久化、有序存儲、消費組、ACK 等功能,更適合復雜的消息隊列場景。

下面依次介紹各方案的特點與適用場景,并總結常見注意事項。


6.7.6.1 使用 List 構建簡單隊列
6.7.6.1.1 基本原理
  • 生產者:在列表尾部或頭部插入消息
    • 常用 LPUSH queue "message"RPUSH queue "message"
  • 消費者:使用 阻塞命令 BLPOPBRPOP 來彈出消息
    • 當隊列為空時,消費者阻塞等待,直到超時(若指定)或有新消息入隊

這樣就構成了一個FIFO(先進先出)或類似隊列的模型。例如:

# 生產者往右端插入
RPUSH task_queue "task1"
RPUSH task_queue "task2"# 消費者阻塞等待
BLPOP task_queue 0
# 如果為空,則阻塞等待;有數據就立刻返回
  • 如果需要嚴格的 FIFO,可約定同一端入隊,另一端出隊,比如:
    • 生產者使用 RPUSH
    • 消費者使用 BLPOP
    • 數據會從右端進,左端出,實現最常見的隊列順序。
6.7.6.1.2 特點與適用場景
  • 優點
    • 實現簡單,命令直觀;
    • 無需額外插件或復雜配置,適合小規模隊列或臨時需求;
    • BLPOP/BRPOP阻塞模式,避免頻繁輪詢,實時性好。
  • 缺點
    • 無內置消息確認(ACK)重試消費組等機制;如果消費者在處理后崩潰,消息就丟失了(除非自行實現“處理后寫回”流程)。
    • 不便于多消費者并行處理同一個隊列里的同一條消息,需要自己設計邏輯避免重復消費。
    • 沒有持久化機制時,Redis 重啟后現有隊列內容是否能夠完整恢復,需結合 AOF/RDB 機制進行持久化;但如果嚴格消息可靠性要求很高,Redis 并不是專業的“持久化消息隊列”解決方案(可考慮 RabbitMQ、Kafka)。

這種方式非常適合簡單任務隊列小規模異步處理

  • 例如把用戶的某些操作異步處理掉,不要求強一致或復雜消息確認;
  • 如果對消息丟失容忍度高或可以接受自己做補償機制。

6.7.6.2 使用 Redis Pub/Sub
6.7.6.2.1 基本原理
  • Redis 的 Publish/Subscribe功能實現了發布和訂閱模型:
    • 發布者通過 PUBLISH channel message 向指定頻道發送消息;
    • 訂閱者使用 SUBSCRIBE channel 監聽該頻道并實時接收消息;
  • 這是一種廣播式一對多的消息分發:只要多個訂閱者都訂閱了同一個 channel,它們都會收到發布者的消息副本。
6.7.6.2.2 特點與應用場景
  • 優點
    • 實時性好,消息一發送,所有訂閱者都能立即收到;
    • 適合推送通知類場景,比如聊天室、服務器實時事件廣播等。
  • 缺點
    • 無持久化:消息不是存儲在 Redis 中,而是一經發布即向所有訂閱者推送,如果當時訂閱者掉線或來不及處理,就會丟失。
    • 無法回放歷史消息,也沒有內置的隊列特性(排隊、確認、重試)等。

因此,Redis Pub/Sub 不大適合“傳統隊列”需求,更像實時廣播,用來做直播聊天室、在線游戲通知、事件總線等。在需要可靠消費的場景中則不合適。


6.7.6.3 使用 Redis Streams(5.0+)
6.7.6.3.1 Streams 簡介
  • Redis Streams 是 Redis 5.0 引入的新數據結構,專為消息流(log stream)設計。
  • 它既可以看作有序存儲的消息隊列,也可像 Kafka 一樣保留歷史消息,客戶端可以從指定位置開始讀取、重復讀取并標記消費進度。
6.7.6.3.2 關鍵概念
  1. Stream:按時間或插入順序將消息(Entry)排成有序隊列,每條消息帶有一個 ID(類似時間戳+序列號)。
  2. XADD:生產者向 Stream 中添加消息(XADD mystream * field1 value1 field2 value2 ...)。
  3. XREAD / XREADGROUP:消費者讀取消息,可指定從哪個 ID 開始讀,實現增量消費
  4. Consumer Group(消費者組):允許多個消費者分組消費同一個 Stream 中的數據;Redis 會自動做分配,并支持消息ACK未確認消息管理,適合多消費者并行且保證消息不會重復消費或丟失太多。
  5. XACK / XPENDING:通過ACK機制,只有消費者成功處理后才算消息被確認,從而減少消息丟失。未確認的消息可以查看和重新分配。
6.7.6.3.3 Streams 使用示例(簡化)
# 生產者
XADD mystream * sensor-id 1 temperature 30.2# 消費者(若非消費者組)
XREAD COUNT 10 STREAMS mystream 0
# 讀取 mystream 中的全部消息(從 id=0 開始)# 創建消費者組
XGROUP CREATE mystream mygroup $ MKSTREAM
# 消費者在該組內讀取
XREADGROUP GROUP mygroup consumer1 COUNT 10 STREAMS mystream >
# 讀取從上次讀取位置以后的新消息# 消費后,手動確認
XACK mystream mygroup <message-id1> <message-id2> ...
# 標記這些消息已成功處理
6.7.6.3.4 優勢與特點
  1. 可靠性:通過消費者組和 ACK 機制,避免消費者崩潰導致消息永久丟失。
  2. 多消費者并發:同一個消費者組可以有多個消費者競爭消費消息,Redis 會自動分配未被其它消費者領取的消息給它們。
  3. 消息回溯:默認消息不會自動丟棄,可以根據需要保留一定長度或時間周期,以便后續讀重或做故障回放。也可通過 MAXLEN 配置限制流長度。
6.7.6.3.5 適用場景
  • 分布式系統中需要可靠消息隊列:既要并發消費,又要防止某臺消費者掛了導致消息丟失;
  • 需要歷史消息回溯(至少在一定范圍內),比如日志、事件存檔等;
  • 相對大規模、嚴謹的異步消息處理,比 List 方案更“專業”,且支持高級特性。

6.7.6.4 選擇哪種方式?
  1. 最簡單:List + 阻塞彈出
    • 適合輕量級的單一隊列,不需要復雜確認或重復消費管理;
    • 代碼簡單易上手,如果消息丟了問題不大(或能用自定義補償),就行。
  2. Pub/Sub
    • 適合實時推送一對多通知場景,不做持久化,消息即時投遞后即丟棄;
    • 不適合需要存儲與可靠消費的排隊場景。
  3. Redis Streams
    • 適合對消息的可靠性、持久性、多消費者管理有一定要求的場景,提供近似 MQ 的能力;
    • 結構更復雜,需要掌握 XREADGROUP, XACK, XPENDING, XCLAIM 等命令;
    • 如果需要專業、超大規模的隊列并發(數十萬~百萬 QPS 級別)或高級分布式事務,可考慮專業消息系統(Kafka、RabbitMQ、RocketMQ 等);但 Redis Streams 對于中等規模的可靠隊列、實時處理依然非常合適。

6.7.6.5 常見注意事項
  1. Redis 單線程特性
    • 所有命令都在單線程內執行,若消息量巨大、消費者或生產者并發極高,可能造成阻塞。
    • Redis 6.0 引入多 I/O 線程,但命令執行依然是單線程,需根據實際場景評估性能。
  2. 持久化
    • 如果你希望消息在 Redis 重啟后保留,需要啟用 RDB / AOF 持久化,但也得考慮性能開銷數據一致性
    • 如果需要100%不丟消息,需要確保 Redis 持久化策略和硬件環境都可靠。
  3. 內存限制
    • Redis 主要在內存中操作,如果消息積壓量非常大,就可能導致內存壓力,或大量寫入也影響性能。可開啟 eviction 策略,但那會導致可能的消息丟失。
  4. 消費端處理失敗重試
    • 簡單 List 模型下,若處理失敗,需要手動將消息再 push 回隊列,或記錄日志后再做補償。
    • 使用 Streams + 消費者組可以重新分配未確認的消息(XPENDING, XCLAIM),從而實現一定程度的重試、死信隊列等機制。
  5. 吞吐 vs. 功能
    • Redis 消息隊列方式更傾向于“輕量、高速、短期緩存/隊列”場景;不提供像專業 MQ 那樣完善的路由、擴展、跨節點分布功能。
    • 如果需求簡單、無需過度擴展,Redis 夠用且非常快;若是大規模企業級 MQ 場景或需要嚴格事務和更靈活的路由策略,可考慮 RabbitMQ、Kafka、RocketMQ 等。

6.7.6.6 小結

Redis 作為內存數據庫,本身并不是專業的消息中間件,但它速度快、命令簡單,對很多輕量級消息隊列實時通知場景來說很實用:

  1. List + BLPOP / BRPOP:最經典的簡易隊列方案。適合單隊列、簡單生產-消費、對可靠性無特殊要求的場景。
  2. Pub/Sub:適合實時廣播的一對多訂閱,不保留歷史消息,也無確認機制。
  3. Redis Streams:Redis 5.0+ 官方提供的“日志流”數據結構,支持有序存儲、消費者組、ACK 確認、回溯消息等,能滿足中等規模、較高可靠性要求的消息隊列場景。

根據業務需求,選擇合適的模式和實現方式,才能在性能與可靠性之間找到平衡。對簡單場景,List 隊列最易上手;若需要相對專業的隊列功能又想依賴 Redis生態,則 Streams 是更好的選擇;若需要高可靠性和大規模分布式集群,可進一步研究專業MQ或結合 Redis 與其他系統。

7.Redis 主從復制

7.1 Redis 主從復制的基本概念

  1. 主節點(Master)與從節點(Replica)
    • 在 Redis 術語中,傳統稱呼是 MasterSlave,從 5.0 開始社區傾向使用 MasterReplica 來替代。
    • Master 負責處理寫請求,并將寫操作同步到 Replica;Replica 負責接收 Master 同步過來的數據,并對外提供讀服務(如果配置了 replica-read-only no,也可以寫,但通常不建議這樣做)。
  2. 異步復制(Asynchronous Replication)
    • Redis 的主從復制本質上是 異步復制,即 Master 在將寫操作返回給客戶端后,會在后臺將數據同步給 Replica。
    • 對于強一致性要求較高的場景,需要做額外的配置或處理(如 Wait、min-replicas-to-write 等機制)。
  3. Sentinel 與 Cluster 模式
    • Sentinel 是 Redis 提供的自動故障檢測與主從切換的工具,通過監聽主節點的健康度,來進行自動化的故障轉移。
    • Cluster 模式則是 Redis 官方推薦的多節點分片方案,同樣具備部分自動的故障轉移能力,且更適合于分布式水平擴展的場景。
    • 無論使用 Sentinel 還是 Cluster,本質上都基于主從(主備)復制來實現高可用。

7.2 Redis 主從復制的工作流程

要理解 Redis 7.4 的復制特性,我們先回顧一下 Redis 在 2.8 之后引入的 PSYNC(部分重同步) 機制,以及 6.x、7.x 中的改進。它們在底層架構上沒有根本性變化,但對復制的穩定性、內存使用和網絡消耗做了優化。

  1. 初次全量復制(Full Synchronization)
    • 當 Replica 節點第一次向 Master 發起復制請求,或者復制狀態失效(無法進行部分重同步)時,會觸發一次 “全量復制”。
    • Master 會執行以下操作:
      1. 觸發保存 RDB 文件(或者使用已有的 RDB 文件)
      2. 通過網絡將 RDB 文件發送給 Replica
      3. 在 RDB 文件發送完畢后,會將積累的增量命令(AOF 或命令緩存)發送給 Replica
    • Replica 在收到 RDB 后會先將其加載到內存,再應用后續增量命令,直到與 Master 同步到相同的 offset(復制偏移量)。
  2. 部分重同步(Partial Resynchronization)
    • 如果 Replica 與 Master 斷開連接(網絡故障、超時等)后重新連接,Replica 會把自己保存的 Replication Offset(復制偏移量)和 Replication ID(同步 ID)發送給 Master。
    • 如果 Master 還能在復制積壓緩沖區(Replication Backlog)中找到從 Replica 上次斷開后遺漏的那部分數據,就可以直接進行 “部分重同步”,只發送缺失的命令給 Replica,避免重復執行一次全量數據同步,從而減少網絡和 IO 開銷。
  3. 復制偏移量(Replication Offset)與復制緩沖區(Replication Backlog)
    • Master 在處理命令時,會維護一個全局增長的 offset,同時把最近一段時間的寫命令緩存到 Backlog
    • 當 Replica 發起 PSYNC 請求時,會帶上自己的 offset 和上一次復制的 Master Replid,Master 檢查是否能滿足部分重同步,否則只能再次進行全量復制。
  4. 主從復制的異步特性
    • Redis 復制是 異步 的,Master 在寫操作完成后就返回給客戶端,后臺才向 Replica 發送復制數據。
    • 如果需要保障數據安全(例如避免主節點宕機時數據丟失過多),需要配合 min-replicas-to-writemin-replicas-max-lag 等配置項來做一定程度的同步保障。

7.3 配置與運維要點

7.3.1 基本配置

redis.conf 或者使用 CONFIG SET 命令,可以進行以下配置來啟用和管理復制功能:

  • Master 側配置

一般情況下,主節點不需要額外做什么特殊配置,只要正常提供服務即可。

如果你為 Master 設置了訪問密碼(例如 requirepass),你需要在 Slave 端做相應的身份認證配置。

  • Slave 側配置

    replicaof <master-ip> <master-port>
    replicaof 10.0.0.42 6379
    

    或在 Redis 運行中執行:

    REPLICAOF <master-ip> <master-port>
    
  • 密碼相關

    • 如果 Master 設置了訪問密碼,需要在 Replica 配置:

      masterauth <master-password>
      masterauth 123456
      
    • Replica 自身的 requirepass 用于客戶端訪問 Replica 時的密碼,與復制用的 masterauth 并不相同。

  • 只讀模式

    • Redis 默認開啟 replica-read-only yes,從節點只接受讀請求,不允許外部寫,從而避免寫入沖突。
  • 延遲優化

    • repl-disable-tcp-nodelayclient-output-buffer-limit 以及網絡相關參數可視業務場景進行調優。
# 通過命令行直接設置(Redis的版本要保持一致,如果不一致可能會無法復制)
# 所有從節點執行
127.0.0.1:6379> REPLICAOF 10.0.0.42 6379
127.0.0.1:6379> CONFIG SET masterauth 123456
# slave1 從節點狀態
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:10.0.0.42
master_port:6379
master_link_status:up
master_last_io_seconds_ago:4
master_sync_in_progress:0
slave_read_repl_offset:64185
slave_repl_offset:64185
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:8ba3aa667f0d3e54f4c6499d4d42ce0f68ccce8f
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:64185
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:962
repl_backlog_histlen:63224
127.0.0.1:6379># slave2 從節點狀態
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:10.0.0.42
master_port:6379
master_link_status:up
master_last_io_seconds_ago:6
master_sync_in_progress:0
slave_read_repl_offset:2109
slave_repl_offset:2109
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:8ba3aa667f0d3e54f4c6499d4d42ce0f68ccce8f	<-- 主節點的 replid
master_replid2:0000000000000000000000000000000000000000 <-- 備用 replid
master_repl_offset:2109
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:738
repl_backlog_histlen:1372
127.0.0.1:6379># 主節點狀態
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=10.0.0.40,port=6379,state=online,offset=1045,lag=0
slave1:ip=10.0.0.41,port=6379,state=online,offset=1045,lag=0
master_failover_state:no-failover
master_replid:8ba3aa667f0d3e54f4c6499d4d42ce0f68ccce8f
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:1045
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:6
repl_backlog_histlen:1040
127.0.0.1:6379>

role:slave:本實例是從節點。

master_link_status:up:當前和主節點連接正常。

master_last_io_seconds_ago:8:上一次從主節點收到數據到現在,已經過了 8 秒。

master_sync_in_progress:0:表示目前沒有在做全量復制或同步過程;如果在進行全量同步,會顯示 1。

slave_read_repl_offset、slave_repl_offset:該從節點當前已讀取/執行到的復制偏移量。

master_replid:主節點的復制 ID。

master_replid2:備用 ID,默認是全 0,如果沒有經歷故障轉移或者沒有開啟相關功能,通常不會被使用。

master_repl_offset:主節點上的全局復制偏移量。

repl_backlog_*:與復制積壓緩沖區的狀態相關。

connected_slaves:0:因為這是一個從節點,不會再帶其他從節點,所以其下級從節點數量是 0。

7.3.2 宕機與故障恢復

  • 斷電 / 宕機后再次啟動
    • 如果 Replica 的偏移量信息仍然保留,且 Master 的 backlog 中還包含所需的增量數據,則會觸發 部分重同步;否則進行 全量同步
    • 需要重點關注磁盤剩余空間、內存容量以及網絡帶寬,避免在高并發或超大 RDB 傳輸時給系統帶來風險。
  • 監控與告警
    • 建議通過INFO replication監控以下指標:
      • role:節點角色(master / replica)
      • connected_slaves:當前連接的從節點數量
      • repl_backlog_activerepl_backlog_size 和 backlog 的使用情況
      • master_link_status:從節點與主節點的連接狀態(up / down)
      • master_sync_in_progress:從節點是否在進行同步
    • 結合其他監控系統(如 Prometheus + Grafana)將復制狀態可視化,便于及時發現問題。
  • 手動故障轉移
    • 如果使用 Sentinel,可以在主節點故障時自動提升某個從節點為新主節點。
    • 如果沒有使用 Sentinel 或集群,需要手動執行 REPLICAOF NO ONE 將某個從節點晉升為主節點,并重新配置其他節點的復制指向。

7.3.3 性能調優

  • 減小全量復制的概率
    • 適度增大 repl-backlog-size,讓主節點可以保存更多增量命令,減少重連后出現 “無法部分重同步” 的情況。
    • 優化網絡狀況,縮短復制延遲,降低 Replica 失聯幾率。
  • 合理使用磁盤復制(Diskless Replication)
    • 若磁盤 IO 壓力較大或者環境允許,可以打開 repl-diskless-sync yes
    • 在大規模場景下需要評估內存峰值,避免產生過大的內存消耗導致 OOM。
  • 多副本策略
    • 如果業務有嚴格的數據安全需求,可以多實例部署,從節點數量增加后,通過 min-replicas-to-writemin-replicas-max-lag 機制做一定程度的 “半同步”(寫安全)保護。
    • 但要注意過多 Replica 也會加大主節點帶寬壓力和內存開銷。

7.4 主從復制故障恢復

如何在 Redis 中手動配置 主從復制(Master-Replica) 以及在 Master 節點故障后如何手動將 Slave(Replica) 提升為新的主節點的整個過程。

  • 純手動配置
  • 基于 Sentinel 的自動/半自動故障轉移。

Master 節點故障 & 手動提升 Slave

Master 節點 “掛了” 或出現嚴重故障,需要將 Slave 節點變成新的 Master,這個過程稱為 故障轉移主從切換

  1. 確定 Master 已不可用
  • 通過監控、日志或運維工具確認 Master 節點宕機,或者無法在短時間內修復。
  1. 在 Slave 上停止復制,提升為主
  • 登錄到 Slave 節點:
redis-cli -h 10.0.0.40 -p 6379
  • 執行:
REPLICAOF NO ONE

此命令會讓當前節點放棄做從節點的角色,成為一個“獨立”的主節點,今后寫入將直接在這個節點生效。

  • (可選)如果原本 Master 設置了密碼,而當前節點也需要對客戶端進行認證,可在 redis.conf 中設置 requirepass new-password,或者用 CONFIG SET requirepass new-password
  1. 檢查新的 Master 狀態
  • 再次執行 INFO replication,應當看到 role: master,且 connected_slaves: 0
  • 測試寫入:
SET new_test_key "i_am_new_master"
GET new_test_key

如果返回正確,說明新的 Master 工作正常

  1. 其他節點(如果有多個)重新指向新的 Master
  • 如果原來還有其他從節點,需要將它們也切換到指向新的 Master:
redis-cli -h <other-slave-ip> -p 6379 REPLICAOF 10.0.0.40 6379
  • 如果之前沒有設置 Sentinel 或自動化腳本,需要一臺臺手動執行。

使用 Sentinel 自動化或半自動化故障轉移

如果你覺得 純手動 的方式在生產環境不夠及時或存在人工失誤的風險,Redis 提供了 Sentinel 組件,能夠實現自動或半自動的故障檢測與主從切換。

1. Sentinel 的工作原理簡述
  • Sentinel 進程會不斷地監控主服務器和從服務器的健康狀態。
  • 當 Sentinel 認為主服務器處于宕機狀態(經過若干次判斷確認),它會在剩余的 Sentinel 進程間通過投票確定是否真的故障。
  • 一旦確認 Master 故障,Sentinel 會將某一臺 Slave(Replica)提升為新的 Master,并向其他從節點發布更新,指向新的 Master。
  • 客戶端可以通過 Sentinel 獲取最新的 Master 信息,從而始終向正確的主節點發送寫請求。
2. Sentinel 配置示例

假設有三臺機器部署了三個 Sentinel 實例(一般生產環境要有奇數個 Sentinel,至少 3 個)。這里簡單示范一個 Sentinel 的配置文件(sentinel.conf)核心片段:

port 26379# 監控指定Master:<MasterName> <ip> <port> <quorum>
# quorum 是判斷宕機所需要的最少 Sentinel 同意票數
sentinel monitor mymaster 192.168.1.10 6379 2# 如果 Master 設置了密碼,請使用:
sentinel auth-pass mymaster <master-password># 故障轉移時新 Master 的復制配置
sentinel config-epoch mymaster 0# 開啟通知腳本(可選),當故障轉移時執行某些通知動作
# sentinel notification-script mymaster /var/redis/scripts/notify.sh# 故障轉移后執行的腳本(可選),比如更改應用配置
# sentinel reconfig-script mymaster /var/redis/scripts/reconfig.sh# 指定檢測 Master、Slave、Sentinel 的周期、超時時間等
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
  • 啟動 Sentinel:
redis-sentinel /path/to/sentinel.conf
  • 通過 redis-cli -p 26379 SENTINEL mastersSENTINEL slaves mymaster 可以查看當前 Sentinel 監控到的主從信息。

  • 一旦主節點故障,Sentinel 會經過判定和投票,將一個 Slave 自動提升為 Master 并更新集群拓撲

提示:如果希望在故障時人工確認后再切換,也可以結合腳本,讓 Sentinel 先發出通知,運維手動執行 SENTINEL failover mymaster 命令觸發故障轉移,這就變成了“半自動化”方案。

在 Redis 的主從復制機制中,主要存在兩種數據同步方式:全量復制(Full Resynchronization)**和**增量復制(Partial Resynchronization)。下面從原理和流程兩方面進行介紹。


7.5 全量復制(Full Resynchronization)

當從節點(Slave)第一次連接到主節點(Master),或者因網絡抖動、斷線導致主從復制狀態不一致且無法通過增量復制來追趕時,就需要執行全量復制。

1. 觸發條件

  1. 從節點首次連接主節點:新的從節點剛剛啟動或沒有復制狀態,需要獲取主節點的全部數據。
  2. 斷線后 backlog 不足:如果從節點斷線時間較久,主節點的復制積壓緩沖區(replication backlog)已經覆蓋了所需的數據增量,無法完成增量復制,就會觸發全量復制。

2. 流程概述

  1. 從節點向主節點發送 PSYNC 命令
    • 當從節點第一次連接主節點或者復制信息不一致時,會發送形如 PSYNC ? -1 的命令,表示需要進行全量復制。
    • 如果主節點發現這是一個無法進行部分復制的請求(要么是第一次連接,要么 backlog 中無對應 offset),則返回 FULLRESYNC <runid> <offset>,表示將進入全量復制過程。
  2. 主節點執行快照(RDB)并發送給從節點
    • 主節點接收到從節點的全量復制請求后,會 fork() 出一個子進程執行 BGSAVE,生成一份 RDB 快照文件。
    • 在生成 RDB 的過程中,主節點會將新寫入操作(增量數據)放入一個緩沖區(復制緩沖 buffer)中。
    • RDB 文件準備好后,主節點會通過套接字把 RDB 文件發送給從節點。
  3. 從節點加載 RDB
    • 從節點接收到 RDB 文件后,會先清空現有數據,再將 RDB 文件中的數據加載到內存,完成數據的“快照恢復”。
  4. 傳輸增量指令
    • 當從節點完成 RDB 加載后,主節點會將全量復制期間緩沖的寫操作(AOF 同步流或復制緩沖區)一并發送給從節點,從節點會依次執行這些命令,以使數據最終與主節點保持同步。
  5. 切換到命令持續復制
    • 全量復制完成后,從節點會正式進入主從復制狀態,此后主節點會將后續的寫命令以“命令流”的形式持續發給從節點,從節點實時執行,實現最終一致。

7.6 增量復制(Partial Resynchronization)

增量復制也稱為部分重同步,當從節點與主節點之間出現短暫斷線或從節點本身保持了“復制偏移量”并且主節點保存了足夠的“復制積壓緩沖區”(replication backlog)時,就能通過增量復制快速“追上”主節點的寫操作。

1. 基本概念

  • runid:每個 Redis 實例都有一個唯一運行 ID,用于在從節點追蹤主節點身份時識別主節點。
  • 復制偏移量(offset):主節點給自己的每條寫命令分配一個遞增的 offset,從節點通過上報自身已復制的 offset 來確定需要補齊的數據量。
  • 復制積壓緩沖區(replication backlog):主節點中用環形緩沖區存儲最近一段時間的寫操作(命令流),以便斷線的從節點在恢復連接后,可以從 backlog 補齊這段期間內缺失的指令,而無需執行全量復制。

2. 流程概述

  1. 從節點向主節點發送 PSYNC <master_runid> <offset>
    • 從節點在斷線重連后,會攜帶上一次記錄的主節點 runid 和復制 offset,向主節點請求進行部分復制。
  2. 主節點檢查復制 backlog
    • 主節點對比從節點發來的 offset 與自身維護的 backlog:
      1. 如果 offset 在 backlog 的可用范圍內(即主節點仍然保留了這部分寫命令),則可以進行部分復制。
      2. 如果 offset 不在 backlog 范圍內(丟失了更多數據或主節點 runid 發生變化),則需要轉為全量復制。
  3. 執行增量復制
    • 如果符合條件,主節點會從 backlog 中取出從節點所缺失的寫命令,依次發送給從節點。
    • 從節點依次執行這些指令,完成數據追趕。
  4. 持續復制
    • 當 backlog 的數據補齊后,從節點就和主節點重新保持一致,進入正常的命令流復制階段。

3. 全量復制與增量復制的聯系

  • 全量復制是一個“重置性”的過程,通常會帶來較大開銷:
    • 主節點需要生成 RDB 文件;
    • 傳輸大量數據;
    • 從節點需要清空內存重新加載 RDB。
  • 增量復制則更輕量:
    • 只要復制偏移量還在主節點的 backlog 范圍內,從節點只需接收并執行缺失的指令即可,無需加載全部數據。

Redis 會盡量通過增量復制來節省資源,只有當增量復制無法滿足需求時才會降級為全量復制。


4. 總結

  1. 全量復制
    • 適用于從節點初次連接主節點、從節點斷線過久導致 backlog 覆蓋或主節點重啟導致 runid 變化的情形。
    • 流程是:從節點請求 →主節點生成 RDB 并發送 → 從節點加載 RDB →同步增量數據。
  2. 增量復制
    • 從節點在與主節點短暫斷線且 backlog 尚在有效范圍時使用。
    • 流程是:從節點攜帶 offset 請求 →主節點對比 offset 與 backlog → 如果在有效范圍則只發送缺失命令流并執行。

在實際生產環境中,通過合理設置 repl-backlog-size 和其他相關配置,可以最大限度地使用增量復制,從而降低全量復制帶來的開銷和對集群性能的影響。

以下內容基于 Redis 經典(單機版)主從結構(非 Cluster 模式)進行講解,涵蓋了 Redis 主從同步的完整過程,包括初次連接、全量復制、增量復制、日常同步四個階段。希望能幫助你更系統地理解 Redis 的主從同步機制。


7.7 主從同步完整過程

1. 主從復制的基本原理

Redis 主從結構中,主節點(Master) 負責處理寫操作,并將數據變化(命令流)傳播給 從節點(Slave)

  • 主節點:只讀/讀寫皆可(視具體配置而定),但通常在生產環境下只對外提供寫操作;
  • 從節點:只讀,避免寫與主節點寫沖突;從節點的作用通常是分擔讀壓力或在主節點出現故障時快速接管。

Redis 的復制主要通過以下關鍵要素來維持同步:

  1. 復制偏移量(offset)
    • 主節點會為自己發送的每一條數據(寫命令)維護一個全局遞增的 offset;
    • 從節點也會維護自身已經復制到的 offset;
    • 雙方通過對比 offset 來確定是否有數據缺失、是否需要補齊。
  2. 運行 ID(runid)
    • 每個 Redis 進程在啟動時都會生成一個唯一標識 runid;
    • 從節點會記錄和識別當前所連主節點的 runid,用以區分不同的主節點。
  3. 復制積壓緩沖區(replication backlog)
    • 在主節點上維護的一個環形緩沖區,用于緩存最近一段時間的寫操作(命令流);
    • 當從節點短暫斷線后重連,如果缺失的部分數據仍在該緩沖區內,就可以直接通過此緩沖區補齊,免去全量復制帶來的開銷。

2. 從節點啟動時的主從同步流程

當一個新的從節點啟動,或一個斷線已久的從節點重新加入時,通常會經歷一個 “全量復制” 的過程來獲取主節點上的全部數據,再進入持續增量復制階段。

2.1 從節點與主節點的初始握手
  1. 從節點配置了 slaveof <master-host> <master-port>(或 replicaof <master-host> <master-port>)后,在啟動時會嘗試向主節點發起連接;
  2. 從節點發送 PING:在正式開始復制前,從節點通常會先與主節點進行一次簡單的“心跳”請求(PING),以檢測網絡和鑒定主節點是否可訪問;
  3. 主節點返回 PONG:若主節點可訪問,會回復 PONG,握手階段成功。
2.2 觸發全量復制(Full Resynchronization)

在握手完成后,從節點會向主節點發送 PSYNC ? -1 命令,意即“我沒有任何已知的 offset,也不知道你的 runid,需要進行一次全量復制”。

  • 如果主節點檢測到從節點的請求無法進行部分(增量)復制(因為是新加入或 backlog 不可用),則會返回 FULLRESYNC <master_runid> <offset> 表示需要進行全量復制。
  • 從節點收到 FULLRESYNC 后,會記錄下主節點的 runid 和 offset(從節點此時的本地 offset 也將重置)。
2.3 主節點生成 RDB 并發送
  1. 主節點執行 BGSAVE
    • 主節點 fork() 出子進程將內存快照保存為 RDB 文件;
    • 在生成 RDB 過程中,主節點還會將新產生的寫命令存儲到 復制緩沖區(或稱 “復制積壓緩沖區 + 額外 buffer”)里,以便后續給從節點補充“快照生成階段”遺漏的寫操作;
  2. 主節點將 RDB 文件通過網絡發送給從節點
    • 當子進程完成 RDB 文件的生成后,主節點會把 RDB 文件直接通過 socket 流方式發送給從節點(而不一定是先存盤再讀取,這在高版本 Redis 中是可配置/可優化的)。
2.4 從節點加載 RDB
  1. 清空本地數據
    • 為確保和主節點數據完全一致,從節點會先清空內存中的舊數據;
  2. 加載 RDB 文件
    • 從節點將接收到的 RDB 文件內容直接寫到內存中,恢復成與主節點一致的數據狀態。
2.5 傳輸并執行增量指令
  • 在 RDB 傳輸和加載的這段時間里,主節點不斷有新的寫命令被執行,這些命令被存儲在主節點的復制緩沖區;
  • 從節點加載完 RDB 后,主節點會把復制緩沖區中的所有新寫命令發送給從節點;
  • 從節點按順序執行這些寫命令,讓自身的數據狀態追趕到主節點當前最新狀態。
2.6 進入持續復制階段
  • 完成上述過程后,主從數據一致;
  • 主節點針對后續所有寫操作(命令流)會實時發送給從節點,從節點也會實時執行這些操作,使得主從數據保持同步。

小結:當從節點第一次連到主節點或斷線時間過久時,就會觸發這樣一次較為消耗資源的 全量復制


3. 日常短暫斷線時的增量同步流程

在大多數情況下,Redis 會盡量通過 增量復制(Partial Resynchronization) 來同步,以避免全量復制帶來的大規模數據傳輸和主節點磁盤/CPU開銷。增量復制發生在:

  • 從節點與主節點的網絡出現短暫斷線;
  • 主節點重啟后 runid 不變(2.8+ 的 “主節點部分重同步” 場景,但如果重啟后 runid 改變則無法增量);
  • 主節點保存了足夠的 backlog 數據。
3.1 觸發增量復制

當從節點重新連上主節點后,會發送命令:

PSYNC <master_runid> <offset>
  • 其中 <master_runid> 為從節點上一次記錄的主節點 runid;
  • <offset> 為從節點已復制到的最后一個字節/命令偏移量。
3.2 主節點判斷能否增量

主節點收到上述請求后,會根據以下條件判斷:

  1. runid 是否匹配
    • 如果從節點攜帶的 runid 和主節點本身的 runid 相同,說明還是同一個主節點(或主節點重啟但 runid 復用了);如果不匹配,就必須走全量復制。
  2. offset 是否在 backlog 范圍內
    • 主節點檢查自身的 replication backlog,判斷該 offset 是否仍在 backlog 的可用范圍內:
      • 如果 backlog 中依然保存了 offset 之后所有的命令,則可以執行“增量復制”;
      • 如果已經被覆蓋(說明從節點缺失太多數據),只能退回到全量復制。
3.3 執行增量復制
  • 如果判斷可以增量:主節點就從 backlog 中取出 offset 之后的命令,發送給從節點;
  • 從節點依次執行,更新自身數據并將 offset 往前推進;
  • 當 backlog 的缺失命令全部執行完畢后,從節點與主節點再次到達一致狀態,進入正常的實時復制階段。

增量復制只需發送丟失的數據指令,不需重新加載全量數據,大大減少了網絡和 CPU 等資源的開銷。


4. 正常主從復制(持續同步)

在從節點完成全量或增量數據同步后,就進入了持續復制階段。此時,主節點對外執行的寫操作會同時復制給所有從節點,從節點實時(或在毫秒級延遲內)執行這些寫命令,保證主從數據最終一致。

這一階段包含以下細節:

  1. 命令傳播

    • 主節點每收到一條寫命令,在處理完后會將該命令寫入自己的復制流,并將其發送給所有處于“在線”狀態的從節點;
  2. 從節點應用命令

    • 從節點收到命令后,順序執行相應的寫操作,保證數據狀態與主節點同步;
  3. 心跳機制

    • 主從之間會周期性發送 REPLCONF ACK <offset> 等命令來維持心跳,并更新雙方的 offset;
  4. 故障轉移/選舉

    (如有 Sentinel 或 Redis Cluster)

    • 若主節點故障或網絡不可達,從節點可在某些機制(比如 Sentinel)下被提升為新的主節點,其他從節點改為復制這個新的主節點,實現自動故障轉移。

5. 小結

  1. 初次連接或大范圍數據丟失時,從節點會進行 全量復制
    • 主節點 BGSAVE 生成 RDB 并發送給從節點;
    • 從節點加載 RDB;
    • 同步全量復制期間主節點的增量命令;
    • 進入持續復制階段。
  2. 短暫斷線且 backlog 數據仍有效時,可以 增量復制
    • 從節點攜帶上次已知的 runid 和 offset 發起 PSYNC 請求;
    • 若 runid 相同且 offset 在 backlog 范圍內,則只需發送缺失的命令;
    • 完成缺失命令后進入持續復制階段。
  3. 持續復制階段下,主節點的所有寫操作會同時廣播給從節點,從節點實時執行,以保持與主節點數據一致。

在實際生產環境中,我們會通過合理設置 repl-backlog-size 等參數來增大 backlog 緩沖,盡可能提高增量復制的成功率,降低全量復制帶來的壓力和風險。這樣能夠使主從架構在高并發、網絡抖動等環境下更穩定地運行。

8.Redis 級聯復制

Redis 中,所謂“級聯復制”(有時也被稱作“鏈式復制”或“多級復制”),是指一個從節點(Replica)不僅可以從主節點(Master)復制數據,也可以從另一個從節點上再復制數據,從而形成一條主—從—從的“鏈式”結構。這樣做的目的通常是為了 分擔主節點的網絡負載應對跨地域/網絡層級的部署需求


一、級聯復制的基本概念

  1. 傳統主從結構

    • 典型的 Redis 主從復制拓撲是 “一主多從(Star 型)”,所有從節點都直接從主節點復制數據。
    • 優點:拓撲簡單,便于運維,主節點故障后也能較快地進行故障轉移。
    • 缺點:當從節點數量很多時,主節點的網絡帶寬和 CPU 負載壓力會增大。
  2. 級聯復制結構

    • 在級聯復制模式下,可以將一部分從節點配置為 “從節點的從節點”,即:

      Master -> Replica1 -> Replica2 -> Replica3 -> ...
      
    • 對于 Replica2 而言,它的“上游”節點就是 Replica1,Replica2 會把 Replica1 當作“Master”來復制數據;而 Replica1 實際又是 Master 的從節點。以此類推,可以形成多級 “鏈式” 復制。

  3. 適用場景

    • 跨地域/跨機房:有時希望把數據先從主機房(Master)復制到同城/同可用區的某個從節點,再從這個從節點復制到更遠的分支機房,從而減小跨地域的網絡延遲和帶寬壓力。
    • 減少 Master 壓力:當主節點帶寬或 CPU 資源較有限,而需要部署大量只讀副本,可考慮讓某些副本從“二級副本”甚至“三級副本”拉取數據。

二、Redis 級聯復制的工作原理

Redis 的主從復制是通過 PSYNC(部分重同步)機制來實現的,核心包括:

  1. 復制偏移量(Replication Offset)和主從 ID(Replication ID)
    • 每個節點都有一個不斷遞增的復制偏移量 offset,Master 在發送寫操作時更新 offset,并在 backlog 中保存一段時間的操作命令歷史。
    • 當 Replica(從節點)向上游請求同步時,會帶上自己當前的 offset 和上次復制的 Master Replid,通過這二者來判斷是否能進行部分重同步(PSYNC)還是需要全量復制。
  2. 全量復制 vs. 部分重同步
    • 當一個從節點首次連接到上游節點(不管該上游是 Master 還是另一個 Replica),若無法滿足部分同步條件,就會觸發全量復制(即發送 RDB + 后續增量命令)。
    • 后續短暫斷線重連時,如果上游節點的 backlog 還保留著從節點缺失的命令,就能走部分重同步,減少網絡和 IO 開銷。
  3. 多級復制的本質
    • 不管“上游”節點是 Master 還是另一個 Replica,對下游節點而言都是一個“發送復制數據”的源節點。Redis 內部并沒有把“從節點的從節點”當成一種特別的角色,每個 Replica 只知道自己要從“上游”拉取數據并保持同步即可。

三、Redis 級聯復制的配置步驟

假設我們有如下節點:

  • Master:IP 為 192.168.1.10,端口 6379
  • 一級從節點(Replica1):IP 為 192.168.1.11,端口 6379
  • 二級從節點(Replica2):IP 為 192.168.1.12,端口 6379

1. 配置 Master

在 Master 的 redis.conf 中,通常無需額外開啟什么。只要確保能正常對外提供服務即可。若 Master 設有密碼,則需要在從節點配置對應的 masterauth

2. 配置一級從節點(Replica1)

  • 在其 redis.conf或啟動參數中指定:

    replicaof 192.168.1.10 6379
    # 如果 Master 設置了密碼:
    masterauth <master-password>
    
  • 啟動后,Replica1 會從 Master 拉取全量數據。可通過 INFO replication 查看 master_link_status: up 即表示同步成功。

3. 配置二級從節點(Replica2)

  • 在其 redis.conf中,讓它去復制 “一級從節點(Replica1)”:

    replicaof 192.168.1.11 6379
    # 如果 Replica1 也啟用了 requirepass(對外訪問),則需要:
    masterauth <replica1-password>
    
  • 注意,這里是配置 replicaof 192.168.1.10 6379,而是指向 “一級從節點”。

  • 啟動后,Replica2 會把 Replica1 當作“Master”,向它進行全量或部分重同步。

4. 驗證級聯復制

  • 在真正的 Master 上插入一個測試 Key:

    redis-cli -h 192.168.1.10 -p 6379 SET test_key "hello_cascading"
    
  • 先在一級從節點(Replica1)驗證:

    redis-cli -h 192.168.1.11 -p 6379 GET test_key
    # 返回 hello_cascading
    
  • 再在二級從節點(Replica2)驗證:

    redis-cli -h 192.168.1.12 -p 6379 GET test_key
    # 返回 hello_cascading
    
  • 如果都能查到相同數據,說明級聯復制已生效。


四、級聯復制的優缺點

1. 優點

  1. 分擔主節點壓力
    • 如果從節點很多,都直接連到 Master,Master 的網絡帶寬和 CPU 可能吃緊。級聯后,只有一級 Replica 跟 Master 同步,其他節點從該 Replica 同步,可以顯著減輕 Master 的負載。
  2. 跨網絡 / 跨機房優化
    • 在多機房部署場景下,可以先在本地機房搭建一個從節點,再讓其他遠程機房的節點從這個本地從節點拉取數據,減少跨數據中心的網絡消耗。

2. 缺點

  1. 增加復制延遲
    • 數據從 Master 同步到 Replica1,再到 Replica2,會比直接從 Master 同步多一層延遲,且鏈越長,延遲越大。
  2. 潛在單點風險
    • 如果中間級節點(例如 Replica1)出現故障,那么它下游的所有 Replica2、Replica3 等都會無法獲取更新,需要及時重新配置或修復。
  3. 運維復雜度更高
    • 需要維護一條鏈上的健康狀況,了解每一級節點的狀態;故障轉移(故障切換)場景下也更復雜。

五、級聯復制的故障與運維要點

  1. 監控每一級節點的復制狀態
    • 使用 INFO replication 命令查看 master_link_status 是否為 up
    • 監控 rolerepl_backlog_sizemaster_sync_in_progress 以及復制偏移量。
  2. 避免鏈條過長
    • 雖然理論上可以多級復制,但一般不建議層數超過 2~3 級。過長的鏈會帶來較大的復制延遲和較高的故障風險。
  3. 自動故障轉移(Sentinel / Cluster)
    • 若要實現自動或半自動的故障轉移,可以結合 Redis Sentinel 或者 Redis Cluster。
    • 需要注意:Redis Sentinel 在做主從切換時,默認只關注“真正的 Master”與“其直連從節點”的關系;如果使用級聯復制,還需要確保 Sentinel 能正確感知到各級節點的狀態,以便在故障時進行合適的切換邏輯。
  4. 網絡與帶寬規劃
    • 在跨機房或跨網絡環境下,需要關注各個節點間的帶寬和延遲,確保不會因為網絡問題導致頻繁的復制中斷或超時。
  5. 資源使用與擴容
    • 級聯復制可以減少 Master 帶寬或 CPU 壓力,但并沒有降低整體的資源消耗,尤其在接收數據的一方(Replica1)可能會有額外的網絡 I/O 負擔。

六、總結

Redis 支持“多級”或“級聯”復制,即讓某個從節點繼續作為其他從節點的上游,從而形成一條或多條復制鏈。其核心機制與普通主從一致,都依賴 PSYNC 進行全量或部分重同步;區別只在于從節點的 “master” 變成了另一個 Replica。

  • 如何配置:在二級或更多級的從節點上,通過 replicaof <上游節點IP> <端口> 指向另一個 Replica 即可。
  • 何時使用:最常見于大規模只讀節點部署、跨機房同步、或需要減少 Master 壓力的場景;但要權衡延遲和運維復雜度。
  • 故障與運維:需要對每一級節點都進行監控,一旦上游節點掛了,下游節點也會同步中斷,需要手動或使用 Sentinel/Cluster 自動重建復制關系。

總的來說,級聯復制是 Redis 提供的一個靈活選項,但在多數常見部署中(尤其是云環境帶寬和資源充足的情況下),仍以“星型”的主從架構為主。如果確實有跨網絡或帶寬受限場景,需要謹慎設計和規劃級聯的層級、監控及故障轉移策略。

9.Redis 哨兵(Sentinel)

img

Redis Sentinel(哨兵)是 Redis 官方提供的一套高可用(High Availability)解決方案,用于監控多個 Redis 服務器實例并在主節點出現故障時進行自動故障轉移(Failover)。Sentinel 的目標是保證集群的健壯性和可用性,幫助運維人員減少手動干預。


一、核心功能

  1. 監控(Monitoring)
    Redis Sentinel 會持續監控主節點和從節點的狀態是否正常。一旦檢測到主節點無法正常響應,Sentinel 會標記該節點為主觀下線(Subjectively Down),并在多個 Sentinel 達成一致后,進一步認定其為客觀下線(Objectively Down)。
  2. 通知(Notification)
    當 Sentinel 識別到主節點宕機或故障轉移發生時,它可以通過發布訂閱頻道(Pub/Sub)、郵件、Webhook 等方式通知運維或相關組件,以方便及時處理。
  3. 自動故障轉移(Automatic Failover)
    當主節點被判定不可用時,Sentinel 會從從節點中挑選一個合適的節點將其升級為新的主節點,并重新配置其他從節點指向新的主節點,保證應用能夠繼續使用 Redis 服務。
  4. 配置提供(Configuration Provider)
    客戶端可以通過 Sentinel 獲取當前可用的主節點信息,客戶端不需要提前知道具體的主節點地址,而是直接向 Sentinel 請求,從而獲得更動態的部署方式。

二、工作原理

Sentinel 檢測到主節點出現故障后,會經歷以下幾個重要步驟:

  1. 主觀下線(Subjectively Down, SDOWN)
    • 每個 Sentinel 會定期向主從節點發送 PING 命令。
    • 如果在配置的時間(down-after-milliseconds)內沒有收到有效回復,則該 Sentinel 標記此節點為“主觀下線”。
  2. 客觀下線(Objectively Down, ODOWN)
    • 當一個 Sentinel 將主節點標記為 SDOWN 后,會詢問其他 Sentinel 是否也認為主節點不可用。
    • 如果有足夠多(達到 quorum 配置)的 Sentinel 都認為主節點已下線,則將主節點標記為“客觀下線”,確定主節點確實無法對外服務。
  3. 故障轉移選舉
    • 在檢測到主節點 ODOWN 后,Sentinel 之間會先進行一次領導者(Leader)選舉:誰來執行故障轉移。
    • 通過 Raft-like 的投票機制(基于多輪投票、配置時間限制等),選出一個 Sentinel 成為故障轉移的執行者。
  4. 晉升新主節點
    • 領導者 Sentinel 會從現有的從節點(Slave)中挑選最合適的一個(考慮 slave-priority、復制偏移量、延遲、最近是否斷線等因素)晉升為新的主節點。
    • 晉升完成后,Sentinel 會向其他從節點發送命令,將它們的復制目標指向新的主節點。
  5. 通知與更新
    • 故障轉移成功后,Sentinel 會更新自身的配置,并廣播新的主節點信息。
    • 其他非領導者 Sentinel 收到更新信息后,也會更新本地配置;客戶端如果通過 Sentinel 獲取主節點信息,也會知道新的主節點地址,從而實現自動切換。
  6. 老主節點重新上線
    • 當故障恢復后,原主節點會以從節點(Slave)身份自動加入集群,繼續對新主節點進行復制。
    • 這樣,集群又恢復到完整的主從結構,并保持高可用。

三、典型架構

通常在生產環境中,至少部署 3 個 Sentinel 節點(奇數個),奇數個是為了防止出現腦裂現象,分別監控同一個主從集群。這樣可以提高一致性和容錯能力。

  1. 主從節點(Master-Slave)
    • 至少一個主節點,若干從節點,用于數據復制和負載均衡。
  2. Sentinel 集群
    • 建議 3 個或 5 個 Sentinel,保證在出現網絡分區或單點故障時仍能做出正確決策并完成自動故障轉移。
  3. 客戶端應用
    • 客戶端可以配置通過 Sentinel 獲取主節點地址,而無需提前硬編碼主節點信息。

四、配置要點

詳細配置過程參考《Redis的一主二從三哨兵》。

sentinel.conf 或相應的配置文件中,需要定義監控的主節點信息,以及故障轉移的一些關鍵參數。

  1. 監控主節點

    sentinel monitor mymaster <master-ip> <master-port> <quorum>
    
    • mymaster:自定義的監控主節點名稱。
    • <master-ip>:主節點 IP。
    • <master-port>:主節點端口。
    • <quorum>:判斷主節點客觀下線所需的最少 Sentinel 數。
  2. 下線判定時間

    sentinel down-after-milliseconds mymaster 5000
    
    • 指定多少毫秒內未收到正常響應后,標記該主節點為“主觀下線”。
  3. 故障轉移超時

    sentinel failover-timeout mymaster 60000
    
    • 指定在執行故障轉移時,若在此時間內無法完成,Sentinel 會放棄當前故障轉移流程。
  4. 通知腳本

    sentinel notification-script mymaster /path/to/notify.sh
    
    • 在發生主節點故障或故障轉移時,Sentinel 會調用該腳本。
  5. 故障轉移腳本

    sentinel reconfig-script mymaster /path/to/reconfig.sh
    
    • 在執行故障轉移后,可運行該腳本完成額外的重新配置操作(如更新負載均衡器等)。
  6. 手動下線redis節點

[root@Rocky9.4 ~]#redis-cli -p 26379
127.0.0.1:26379> SENTINEL FAILOVER mymaster
OK
127.0.0.1:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_tilt_since_seconds:-1
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=10.0.0.40:6379,slaves=2,sentinels=3# 修改slave優先級
27.0.0.1:6379> CONFIG SET replica-priority 70
OK
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:10.0.0.41
master_port:6379
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_read_repl_offset:3991359
slave_repl_offset:3991359
slave_priority:70
......

詳細的配置參數

# 三臺機器全部這樣配置
# 源碼編譯不會在/apps/redis/etc/下生成sentinel.conf這個文件,需要從源碼里面拷貝一份
[root@redis_master redis]#cp /root/redis-7.4.1/sentinel.conf /apps/redis/etc/sentinel.conf
[root@redis_master redis]#vim /apps/redis/etc/sentinel.conf
port 26379
bind 0.0.0.0
daemonize yes
pidfile "/apps/redis/run/redis-sentinel.pid"
logfile "/apps/redis/log/sentinel_26379.log"
dir "/tmp" # 工作目錄
sentinel monitor mymaster 10.0.0.42 6379 2 # mymaster是當前一組主從復制集群的名字,sentinel可以監控多組 2代表有兩個sentinel認為宕機就可以選舉了
sentinel auth-pass mymaster 123456 # mymaster集群中master的密碼,這行一定在上面那行的下面
sentinel down-after-milliseconds mymaster 3000 #判斷mymaster集群中所有節點的主觀下線的時間,單位:毫秒,建議3000
sentinel parallel-syncs mymaster 1 #發生故障轉移后,同時向新的master同步數據的slave數量,數字越小總同步時間越長,但可以減輕新master的負載壓力
sentinel failover-timeout mymaster 180000 #所有slave指向新的master所需的超時時間,單位:毫秒 三分鐘
sentinel deny-scripts-reconfig yes # 禁止修改腳本

五、Sentinel 內部定時任務

在 Redis Sentinel 的內部實現中,有多個定時(周期性)任務來驅動上述流程。可以簡要地將其理解為以下幾個重要的“循環”或“Timer”:

  1. 定時 PING 檢測
    • Sentinel 會按照一定頻率(默認 1 秒一次,或由配置決定)向主節點、從節點以及其他 Sentinel 發送 PING 命令。
    • 若節點在 down-after-milliseconds 內沒有響應,則標記為主觀下線(SDOWN)。這是主觀下線偵測的核心機制。
  2. 定時 INFO 收集
    • Sentinel 也會周期性地向 Redis 節點發送 INFO 命令,以獲取節點版本、復制偏移量、角色(主 / 從)、所監控的其他節點信息等。
    • 這些信息有助于判斷哪個從節點最適合被晉升為新主節點(例如優先級、復制偏移量等)。
  3. Sentinel 之間的 HELLO 信息交換
    • 不同 Sentinel 之間會通過發布訂閱(__sentinel__:hello 頻道)來交換信息。
    • Sentinel 周期性地把自己監控的主從節點信息發布到頻道,同時也從頻道中接收其他 Sentinel 的信息,從而實現對集群拓撲的一致認知。
  4. 選舉與故障轉移狀態機定時檢查
    • 當 Sentinel 認為主節點客觀下線,會啟動故障轉移流程。
    • 這一流程也是通過定時任務逐步推進(如:發起投票->收集票數->如果超時則重試->成功后晉升從節點),直到完成或超時失敗。
  5. 配置文件定時保存
    • Sentinel 會在故障轉移完成后或配置更新后,異步地把最新狀態寫入到本地配置文件(如 sentinel.conf),以防止進程重啟后丟失最新的拓撲配置。

這些定時任務共同構成了 Sentinel 的“感知-決策-執行”的循環:感知節點狀態、決策是否需要故障轉移、執行切換并通知集群

六、使用與維護建議

  1. 部署建議
    • 為保證高可用,每個 Sentinel 都應該與 Redis 節點分布在不同的物理機或容器中,避免單點故障或網絡分區對可用性的影響。
    • 建議使用奇數個 Sentinel(至少 3 個),防止腦裂(split-brain)問題。
  2. 客戶端正確使用
    • 推薦客戶端直接連接 Sentinel 獲取主節點信息(通過 SENTINEL get-master-addr-by-name <master-name>)。
    • 部署應用時保證在主節點切換后,客戶端可以盡快感知到新的主節點,盡量減少服務中斷。
  3. 監控及報警
    • 時刻關注 Sentinels 自身的健康狀況:Sentinel 之間的網絡連通性、各個 Redis 節點的延遲情況等。
    • 合理設置報警機制(如日志監控、Prometheus + Grafana 監控等),在出現告警時及時排查網絡和系統問題。
  4. 版本兼容與升級
    • 不同版本的 Redis 可能在 Sentinel 功能上存在差異,部署前要查看官方文檔確認兼容性。
    • 升級 Redis 或 Sentinel 時,要先在測試環境演練并做好回滾預案。

七、總結

Redis Sentinel 通過持續監控、自動通知與故障轉移、配置中心等功能,幫助 Redis 在主從模式下實現高可用。它能最小化人工干預,確保當主節點出現故障后,系統能自動完成從節點晉升、集群重新配置等關鍵步驟,從而最大程度地保證業務的連續性。在生產環境中,合理地進行 Sentinel 部署、配合主從架構及應用配置的優化,將顯著提升整個 Redis 集群的可靠性和穩定性。

八、客戶端連接 Sentinel 工作原理

在使用 Redis Sentinel 進行高可用部署時,客戶端并不是直接去“猜”主節點(master)的地址,也不會直接同時連所有從節點(replica)來判斷誰是主節點,而是通過向 Sentinel 查詢當前可用的主節點地址,再去連接該主節點進行讀寫操作。其核心思想是“客戶端將主節點發現和故障轉移邏輯交給 Sentinel 去做”,客戶端只需要在初始化時知道一組 Sentinel 的地址,就能在主節點發生變化時自動感知并切換到新的主節點。

1. 整體流程概覽

  1. 客戶端初始化:
    客戶端會被配置好一個或多個 Sentinel 的地址列表(IP:PORT),以及一個代表“主節點名稱”(masterName)的標識。
  2. 客戶端向 Sentinel 查詢當前主節點:
    客戶端向 Sentinel 發送命令(例如 SENTINEL get-master-addr-by-name <masterName>),獲取到當前主節點的 IP 和端口。
  3. 客戶端連接 Redis 主節點:
    客戶端根據上一步返回的 IP 和端口,建立與當前主節點的連接,用于讀寫操作。
  4. Sentinel 監控和故障轉移:
    • Sentinel 在后臺持續監控 Redis 主從節點的健康狀況。如果主節點不可用,Sentinel 選舉出一個從節點晉升為新的主節點,并更新內部配置信息。
    • Sentinel 會對外暴露新的主節點信息,客戶端再次通過 Sentinel 查詢(或在連接異常時重新查詢),就能拿到新主節點的地址。
  5. 客戶端重新連接:
    如果客戶端在使用過程中發現原主節點斷開(網絡異常、超時等),會再去詢問 Sentinel 最新的主節點地址,從而與新主節點建立連接,實現故障恢復和高可用。

通過以上步驟,Redis 集群在后端完成了主從切換和故障轉移,而客戶端只需要確保能訪問至少一個存活的 Sentinel,就可以拿到最新的主節點地址,從而無需關心后端節點的實際變化。


2. 工作原理與關鍵機制

  1. Sentinel 的監控機制:
    • 每個 Sentinel 節點都會與主從節點(以及其他 Sentinel)定期進行 PING 通信,用于確認節點是否存活;
    • 當 Sentinel 判斷主節點下線(主觀下線 + 客觀下線),便會發起故障轉移流程;
    • 多個 Sentinel 通過 Raft 或者“分布式選舉協議”類似的方式,協商并最終確定一個從節點作為新的主節點。
  2. 客戶端與 Sentinel 的交互方式:
    • 當客戶端啟動時,通常會使用某些高層次的客戶端庫或連接池(如 JedisSentinelPool、Lettuce Sentinel、redisson-spring-boot-starter 等)。這些庫實現了與 Sentinel 通信的邏輯:
      1. 逐個嘗試連接配置列表中的 Sentinel;
      2. 向 Sentinel 發送“獲取主節點地址”的命令;
      3. 收到 Sentinel 返回的 (IP, PORT) 后,建立與該 IP:PORT 的 Redis 連接。
    • 在正常讀寫過程中,客戶端并不持續與 Sentinel 保持數據操作上的交互,只在連接創建或重連時才再次詢問 Sentinel。
  3. 故障轉移與主節點更新:
    • 一旦主節點發生故障,Sentinel 通過投票和選舉機制切換新的主節點;
    • Sentinel 內部會更新自己管理的“主節點信息”;
    • 客戶端如果和原主節點斷開或檢測到異常,會重新詢問 Sentinel,拿到新的主節點地址并連接。
  4. Sentinel 的高可用:
    • 生產環境中往往會部署若干個 Sentinel 進程(一般建議至少 3 個),相互之間協同監控,避免單點故障;
    • 只要客戶端能夠連上任意存活的 Sentinel,就能得到最新主節點的信息。
  5. 讀寫分離(可選)
    • 有些客戶端或框架(例如 Redisson、一些自定義的分布式緩存中間件)支持根據場景選擇讀從節點或寫主節點;
    • 但 Sentinel 默認只會向客戶端返回主節點地址(用于寫入),從節點主要用于冗余或只讀場景。
    • 如果需要讀寫分離,通常也需要客戶端自行或使用特定的代理層來管理從節點連接。

3. 總結

Redis Sentinel + 客戶端的連接工作原理可以概括為:

  1. 客戶端只關注 Sentinel,向其索取主節點地址
  2. Sentinel 負責監控 Redis 主從拓撲并在故障時進行自動化的主從切換
  3. 客戶端在連接或發生異常時,通過 Sentinel 的信息獲取新的主節點地址并自動重連

這種模式避免了客戶端自己去判斷哪個 Redis 節點是主節點,也不需要在客戶端配置中硬編碼主節點的 IP/端口,從而極大簡化了運維和故障轉移的流程,提高了系統整體的高可用性。

下面的內容將為你介紹 Redis Cluster 的實現原理,并對 Redis ClusterSentinel 在架構設計和使用場景上的差異進行說明。


10.Redis Cluster

Redis Cluster 概述

Redis Cluster 是 Redis 官方提供的分布式解決方案,能夠在多臺 Redis 節點之間實現數據分片(Sharding)和故障自動轉移(Failover),從而在高可用性和可伸縮性方面為 Redis 提供支持。與傳統的主從復制模式相比,Redis Cluster 在面對業務快速增長、數據量暴增、服務高可用需求等場景時更具優勢。

一、Redis Cluster 實現原理

Redis Cluster 是 Redis 提供的分布式解決方案,旨在解決單機 Redis 在數據量、并發量和高可用方面的瓶頸。它可以在多臺服務器之間進行數據分片(sharding),并提供一定程度的故障轉移能力。

1. 核心特性

  1. 數據分片(Sharding):
    Redis Cluster 將整個 key 空間劃分為 16384 個哈希槽(hash slot,范圍為 0~16383)。每個節點可分配到若干槽,并負責存儲該槽內的所有數據。客戶端訪問某個 key 時,通過對 key 進行 CRC16 運算并對 16384 取模來定位該 key 所在的槽位,然后直接請求對應節點。
  2. 高可用(Replica):
    • Redis Cluster 通過為每個主節點(master)配置一個或多個從節點(replica)來進行冗余備份提高可用性。
    • 當某個主節點失效時,其從節點會被自動提升為主節點(Failover)。
  3. 無中心節點:
    Redis Cluster 沒有專門的中心控制節點,集群中的每個節點既存儲數據又保存集群信息,節點之間通過 Gossip 協議(消息交換協議)定期與其他節點通信以保持拓撲更新。集群中不存在單點故障的“中心”節點,一定程度上提升了系統的健壯性。
  4. Gossip 協議 & 心跳檢測:
    • 每個節點周期性向其他節點發送 PING 消息并等待回復(PONG),通過超時判定一個節點是否下線。
    • 大多數主節點(master)同意某節點下線,才能標記該節點為 FAIL 狀態并進行故障轉移。
  5. 客戶端重定向
    • 若客戶端訪問了錯誤的槽位,集群節點會返回 MOVEDASK 重定向信息,告訴客戶端正確的節點地址。
    • 這樣客戶端可以自動重試,將請求發往正確的節點。
  6. 讀寫拆分
    在 Redis Cluster 中,客戶端的寫請求會自動發送到目標主節點,而讀請求則可以通過客戶端自行配置來從從節點進行讀取,從而減輕主節點壓力,提高整體的讀吞吐量。
  7. 線性擴展
    Redis Cluster 通過簡單地增加或減少節點,并對集群中的哈希槽重新分配(Rebalance)來實現擴展。與單節點或者簡單主從復制方式相比,Redis Cluster 可以更有效地利用多機資源,從而提高吞吐量和存儲容量。

2. Redis Cluster 的架構

一般來說,一個 Redis Cluster 至少需要 3 個主節點 來完成基本的故障自動轉移。此外,為了保證高可用,每個主節點可配置一個或多個從節點。如下是一個示例拓撲結構:

      +---------+    +---------+    +---------+| Master1 |    | Master2 |    | Master3 ||  Slot   |    |  Slot   |    |  Slot   || 0-5460  |    | 5461-10922 | | 10923-16383 |+----+----+    +----+----+    +----+----+|              |              |+v+            +v+            +v+|R|            |R|            |R|Slave1         Slave2         Slave3
  • 主節點(Master):存儲并管理哈希槽的數據,響應客戶端的讀寫請求。
  • 從節點(Slave):復制主節點的數據。當主節點發生故障時,從節點會自動升級為主節點。

  • Gossip 協議:集群節點之間通過 Gossip 協議交換彼此的心跳和槽位分配等信息,確保集群拓撲的一致性。


二、Redis Cluster 的數據分片機制

Redis Cluster 使用預先定義好的 16384 個哈希槽 來進行數據分片。

  1. 當客戶端執行 SET key value 等命令時,Redis 會先對 key 進行 CRC16 運算,然后再將結果對 16384 取模,得到對應的哈希槽號(槽 ID)。
  2. Redis 決定哪個節點負責管理這些哈希槽,進而決定數據存放在哪個節點上。
  3. 當需要進行集群擴容或縮容時,可通過 redis-cli 命令對哈希槽進行重新分配(Rebalance),盡量平衡各個節點的負載。

示意:

CRC16(key) % 16384 --> slot_id
slot_id 由哪個節點負責

四、Redis Cluster 的高可用機制

  1. 主從復制(Master-Replica Replication)
    當某個主節點不可用時,對應的從節點會在完成一定條件和集群投票后自動升級為主節點,實現故障轉移。
  2. 故障檢測(Failure Detection)
    • PFAIL(主觀下線):若節點 A 在 cluster_node_timeout 時間內沒有收到節點 B 的正確回復,節點 A 會將 B 標記為主觀下線(PFAIL)。
    • FAIL(客觀下線):若多數節點(包括 A)都認為 B 下線,則會將 B 標記為客觀下線(FAIL)。此時便會觸發故障轉移流程。
  3. 故障轉移(Failover)
    當一個主節點被客觀下線后,集群會發起選舉,等待符合條件的從節點成為新的主節點。新的主節點接管原主節點的哈希槽,并恢復對外提供讀寫服務。

二、Redis Sentinel 原理

Redis Sentinel 是針對 Redis 的高可用監控與自動故障轉移工具,更常用于單主多從架構。它本身并不提供數據分片能力,而是側重監控和故障轉移。

  1. 監控主從架構:
    Sentinel 不斷地 PING 主節點、從節點以及其他 Sentinel,以檢測節點是否存活。
  2. 主觀下線和客觀下線:
    • 當一個 Sentinel 認為主節點無法訪問,就會標記其為“主觀下線”。
    • 如果其他 Sentinel 也同意該主觀下線,則將其升級為“客觀下線”,啟動故障轉移流程。
  3. 故障轉移流程:
    • Sentinel 會通過選舉機制在剩余的從節點中選出一個最合適的“晉升為主節點”的節點。
    • 更新配置,并通知所有從節點改為復制新的主節點。
    • 這期間,會向客戶端廣播新的主節點信息。
  4. 通知客戶端
    • 客戶端(或者客戶端的連接池)只需要連接 Sentinel,而無需手動指定主節點。
    • 當主節點切換時,客戶端可以通過 Sentinel 查詢最新主節點地址,實現自動重連。
  5. Sentinel 的高可用本身
    • 通常生產環境會部署多個 Sentinel 進程,互為備份且通過投票方式確認主節點是否故障。
    • 只要有一個 Sentinel 存活,就可向客戶端提供最新的主節點信息。

三、Redis Cluster vs Sentinel 的區別

  1. 核心定位/目標
    • Redis Cluster:
      • 主要解決 數據分片(水平擴容) 的問題,同時提供基礎的高可用。
      • 適用于數據量大、吞吐量高,需要進行分布式存儲和集群擴展的場景。
    • Sentinel:
      • 主要用于 單個 Redis 主從架構的高可用;不提供數據分片功能。
      • 適用于 Redis 數據規模較小或單節點足以支撐業務,且希望在主節點故障時自動完成主從切換。
  2. 數據分布方式
    • Redis Cluster:按槽 (hash slot) 進行數據分片,支撐大數據量和高并發場景。
    • Sentinel:無分片,通常只是一主多從(或多對主從),數據在所有從節點之間完全復制。
  3. 故障轉移機制
    • Redis Cluster:節點間通過 Gossip 協議互相通信,自動判斷失效節點并進行主從切換;集群會將一部分槽轉移到新的主節點上。
    • Sentinel:Sentinel 進程會監控主從結構,通過投票對主節點下線作出判斷,再自動提拔新的從節點為主節點。
  4. 客戶端訪問模式
    • Redis Cluster:客戶端需要支持 cluster 模式,訪問時根據 key 自動定位到對應的節點,如果訪問錯誤節點需要重定向。
    • Sentinel:客戶端只需要連接 Sentinel 并獲取當下可用的主節點地址,無需關心后端的節點信息。
  5. 部署復雜度
    • Redis Cluster:需要至少 3 個主節點(加上各自從節點)才能在節點故障時正常工作,還需客戶端/應用支持;整體部署配置較為復雜,但可提供水平擴展。
    • Sentinel:在單主多從的基礎上額外部署若干個 Sentinel 進程即可,相對簡單;適合中小規模或單機足以承載的業務場景。
  6. 適用場景
    • Redis Cluster:
      • 超大規模數據存儲,需要分片擴容;
      • 希望在一套 Redis 上承載高并發、高可用且數據量較大的業務。
    • Sentinel:
      • 數據規模較小或單機可承載,重點是主從的高可用(自動切換);
      • 對運維和部署的復雜度要求較低。

四、總結

  1. Redis Cluster
    • 分布式架構:提供自動分片與基本的高可用;
    • 適合數據量大、需要負載均衡、水平擴容的場景;
    • 部署更復雜,對客戶端要求更高。
  2. Redis Sentinel
    • 監控+高可用:在單主多從的基礎上實現自動主從切換;
    • 不提供數據分片,只解決高可用;
    • 部署簡單、對客戶端改動較小,適合中小規模業務。

根據項目需求,如果您只是希望 Redis 能夠在主節點故障時自動切換到從節點,那么 Sentinel 就足夠滿足高可用需求;但如果您需要在多臺機器間分片存儲海量數據并同時兼顧高可用,則需要使用 Redis Cluster。有時也會出現 Redis Cluster + Sentinel 混合使用的場景(但更常見的是 Redis Cluster 自己負責高可用,Sentinel 僅用于傳統單體 Redis 部署)。

選擇合適的方案,才能在保證高可用的同時兼顧部署成本與運維復雜度。

11.原生命令部署 Cluster

11.1 在所有節點上安裝redis并啟動cluster功能

# 先通過腳本編譯安裝Redis,6臺Redis
node1 10.0.0.40
node2 10.0.0.41
node3 10.0.0.42
node4 10.0.0.50
node5 10.0.0.112
node6 10.0.0.113# 手動修改配置文件
bind 0.0.0.0
masterauth 123456 #建議配置,否則后期的master和slave主從復制無法成功,還需在配置
requirepass 123456
cluster-enabled yes #取消此行注釋,必須開啟集群,開啟后Redis 進程會有Cluster標識
cluster-config-file nodes-6379.conf #取消此行注釋,此為集群狀態文件,記錄主從關系即slot范圍信息,由redis cluster 集群自動創建和維護
cluster-require-full-coverage no #默認值為yes,設為no可以防止一個節點不可用導致整個cluster不可用# 修改配置文件相關設置-6臺都執行
sed -i.bak -e 's/bind 127.0.0.1/bind 0.0.0.0/' -e '/masterauth/a masterauth 123456' -e '/# requirepass/a requirepass 123456' -e '/# cluster-enabled yes/a cluster-enabled yes' -e '/# cluster-config-file nodes-6379.conf/a cluster-config-file nodes-6379.conf' -e '/cluster-require-full-coverage yes/c cluster-require-full-coverage no' /apps/redis/etc/redis.conf# 查看當前redis進程
[root@node5 ~]# ps aux | grep redis
redis      43944  0.3  0.4 134120  7952 ?        Ssl  22:09   0:08 /apps/redis/bin/redis-server 0.0.0.0:6379
root       44019  0.0  0.1   6408  2156 pts/0    S+   22:49   0:00 grep --color=auto redis# 重啟服務-6臺執行
[root@node1 ~]#systemctl restart redis
# 再次查看redis進程,發現有cluster標識
[root@node1 ~]#ps aux | grep redis
redis      22009  0.1  0.8 136680  8192 ?        Ssl  22:54   0:00 /apps/redis/bin/redis-server 0.0.0.0:6379 [cluster]
root       22033  0.0  0.2   6408  2176 pts/0    S+   22:54   0:00 grep --color=auto redis
[root@node1 ~]#

11.2 執行meet操作實現相互通信

redis-cli -h <已存在節點IP> -p <已存在節點端口> \cluster meet <新節點IP> <新節點端口>
# 如果在已存在節點ip這臺機器上執行, <已存在節點IP> -p <已存在節點端口> 這個可以省略不寫

在 Redis 集群中,使用 CLUSTER MEET 命令是為了將新節點引入到集群中,而一旦新節點被引入,它會與集群中的所有其他節點進行通信。這種通信行為是 Redis 集群設計的結果,因為 Redis 集群本質上是 全連接 的。

原因:Redis 集群的全連接機制

  1. Redis 集群中的節點相互感知:
    • 當你通過 CLUSTER MEET 命令將一個新節點(比如 10.0.0.41)引入到集群中時,這個節點會從你執行 CLUSTER MEET 的節點那里獲取集群的拓撲信息。
    • 獲取到的拓撲信息中包含了集群中所有其他節點的地址。
  2. 自動建立連接:
    • 新加入的節點會主動與集群中其他所有節點建立通信連接(包括心跳包、槽信息同步等)。
    • 同樣,其他所有節點也會與新加入的節點建立通信連接,從而形成一個全連接的網絡。
  3. 為什么其他節點之間也通信:
    • 當你通過 CLUSTER MEET 命令將多個節點加入到集群中(比如 10.0.0.4210.0.0.50),這些節點會逐步通過集群的拓撲信息互相發現對方,并建立通信連接。
    • 因此,不僅本機節點與其他節點通信,所有節點之間都會建立通信。

集群通信設計的目的

Redis 集群設計為全連接網絡,其目的是:

  1. 保證高可用性: 每個節點都能快速檢測到其他節點的狀態(通過心跳包機制),如果某個節點出現故障,集群可以迅速感知并觸發故障轉移(failover)。
  2. 槽分布同步: 每個節點都會知道集群中所有槽(slots)的分布,方便在請求轉發或槽遷移時快速找到目標節點。
  3. 數據一致性: 副本節點需要定期與主節點同步數據,而這種全連接的設計讓任何節點都能快速找到需要通信的目標節點。
[root@node1 ~]#redis-cli -a 123456 cluster nodes
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
167cc05be9ab506a5fa687e8c9dded4dc2b633a5 :6379@16379 myself,master - 0 0 0 connected# 執行meet
[root@node1 ~]#redis-cli -a 123456 --no-auth-warning cluster meet 10.0.0.41 6379
root@node1 ~]#redis-cli -a 123456 --no-auth-warning cluster meet 10.0.0.42 6379
[root@node1 ~]#redis-cli -a 123456 --no-auth-warning cluster meet 10.0.0.50 6379
[root@node1 ~]#redis-cli -a 123456 --no-auth-warning cluster meet 10.0.0.112 6379
root@node1 ~]#redis-cli -a 123456 --no-auth-warning cluster meet 10.0.0.113 6379# 查看連接情況-與其他5臺機器進行通信
[root@node1 ~]#ss -nt
State            Recv-Q            Send-Q                         Local Address:Port                          Peer Address:Port             Process            
ESTAB            0                 0                                  10.0.0.40:56390                            10.0.0.42:16379                               
ESTAB            0                 0                                  10.0.0.40:56116                           10.0.0.112:16379                               
ESTAB            0                 0                                  10.0.0.40:22                                10.0.0.1:4078                                
ESTAB            0                 0                                  10.0.0.40:16379                           10.0.0.112:55198                               
ESTAB            0                 0                                  10.0.0.40:16379                           10.0.0.113:59318                               
ESTAB            0                 0                                  10.0.0.40:16379                            10.0.0.50:42352                               
ESTAB            0                 0                                  10.0.0.40:16379                            10.0.0.41:46130                               
ESTAB            0                 0                                  10.0.0.40:35310                            10.0.0.41:16379                               
ESTAB            0                 0                                  10.0.0.40:45462                           10.0.0.113:16379                               
ESTAB            0                 0                                  10.0.0.40:16379                            10.0.0.42:38686                               
ESTAB            0                 0                                  10.0.0.40:52672                            10.0.0.50:16379                               
[root@node1 ~]#ss -nlt
State             Recv-Q            Send-Q                         Local Address:Port                          Peer Address:Port            Process            
LISTEN            0                 128                                  0.0.0.0:22                                 0.0.0.0:*                                  
LISTEN            0                 511                                  0.0.0.0:6379                               0.0.0.0:*                                  
LISTEN            0                 511                                  0.0.0.0:16379 #集群的工作端口                             0.0.0.0:*                                  
LISTEN            0                 128                                     [::]:22                                    [::]:*                                  
LISTEN            0                 511                                    [::1]:16379                                 [::]:*                                  
LISTEN            0                 511                                    [::1]:6379                                  [::]:*                                  
[root@node1 ~]## 查看cluster的所有節點相互通信
[root@node1 ~]#redis-cli -a 123456 --no-auth-warning cluster nodes
167cc05be9ab506a5fa687e8c9dded4dc2b633a5 10.0.0.40:6379@16379 myself,master - 0 0 1 connected
5b4b959cec186ee66836d176305b6db55f0ac451 10.0.0.41:6379@16379 master - 0 1736781760000 0 connected
3e9cf23bbfbcbd673d8c5b4abaf3f0e722c94b2a 10.0.0.112:6379@16379 master - 0 1736781758000 5 connected
2758daa041534a8eaef4ac279b430b0836d1e7f4 10.0.0.113:6379@16379 master - 0 1736781761000 4 connected
14468ef2bc32bcf9819b97c72c1c567916a93354 10.0.0.42:6379@16379 master - 0 1736781759894 2 connected
2d56d8d0b9ee2afce646c61577c8b622b87bafe3 10.0.0.50:6379@16379 master - 0 1736781762048 3 connected
[root@node1 ~]## 當前狀態
[root@node1 ~]#redis-cli -a 123456 --no-auth-warning cluster info
cluster_state:fail
cluster_slots_assigned:0 #無槽位分配
cluster_slots_ok:0
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6 #已知的節點有6臺
cluster_size:0
cluster_current_epoch:5
cluster_my_epoch:1
cluster_stats_messages_ping_sent:1239
cluster_stats_messages_pong_sent:1279
cluster_stats_messages_meet_sent:5
cluster_stats_messages_sent:2523
cluster_stats_messages_ping_received:1279
cluster_stats_messages_pong_received:1244
cluster_stats_messages_received:2523
total_cluster_links_buffer_limit_exceeded:0
[root@node1 ~]#

11.3 為各個master節點指派槽位范圍

方法1:手動分配槽

# 例如給新節點分配 [5461-6000] 這 540 個 slots
redis-cli -a 123456 -h <新節點IP> -p <新節點端口> cluster addslots {5461..6000}

方法2:腳本自動化分配

# 創建添加槽位的腳本(為master節點分,slave不需要,會自動同步master)
[root@node1 ~]#cat addslot.sh
#!/bin/bash
host=$1
port=$2
start=$3
end=$4
pass=123456for slot in $(seq ${start} ${end}); doecho "Adding slot: $slot"redis-cli -h ${host} -p ${port} -a ${pass} --no-auth-warning \cluster addslots ${slot}
done
[root@node1 ~]#./addslots.sh 10.0.0.40 6379 0 5460
[root@node1 ~]#./addslots.sh 10.0.0.41 6379 5461 10922
[root@node1 ~]#./addslots.sh 10.0.0.42 6379 10922 16383#查看集群信息
[root@node1 ~]#redis-cli -a 123456 --no-auth-warning cluster info
cluster_state:ok #當前 Redis 集群的整體狀態(ok:集群正常運行。fail:集群有問題(如未分配槽位,或某些節點不可用)。)
cluster_slots_assigned:16384 #分配的槽位數量,Redis 集群總共有 16384 個槽位。( 0,表示沒有分配任何槽位,這會導致 cluster_state:fail 的原因之一。)
cluster_slots_ok:16384 #狀態正常的槽位數量。
cluster_slots_pfail:0 #部分失敗(PFAIL) 的槽位數量。某些節點的狀態在短時間內沒有響應心跳,但尚未被正式標記為失敗。
cluster_slots_fail:0 #失敗(FAIL) 的槽位數量。表明某些槽的主節點已經被標記為失敗,需要手動修復。
cluster_known_nodes:6 #集群中已知的節點數量,包括主節點和從節點。
cluster_size:3 #當前集群中有幾個主節點(通常指已分配槽位的主節點數量)。
cluster_current_epoch:5 #當前集群的全局元數據版本,每當集群拓撲發生變化(如添加或刪除節點、重新分配槽位)時,此值會遞增。
cluster_my_epoch:1 #當前節點的元數據版本。通常情況下,cluster_my_epoch 反映了該節點的初始化時的分配版本。
cluster_stats_messages_ping_sent:1894 #當前節點已發送的 PING 消息數量,用于與其他節點的心跳通信。
cluster_stats_messages_pong_sent:1953 #當前節點已發送的 PONG 消息數量,用于響應其他節點的 PING 消息。
cluster_stats_messages_meet_sent:5 #當前節點已發送的 MEET 消息數量,用于引入新節點時的握手通信。
cluster_stats_messages_sent:3852 #當前節點發送的所有類型消息的總數量。
cluster_stats_messages_ping_received:1953 #當前節點收到的 PING 消息數量。
cluster_stats_messages_pong_received:1899 #當前節點收到的 PONG 消息數量。
cluster_stats_messages_received:3852 #當前節點收到的所有類型消息的總數量。
total_cluster_links_buffer_limit_exceeded:0 #集群中連接緩沖區超出限制的總次數。如果值大于 0,表示可能有性能瓶頸,需要檢查集群的網絡連接或緩沖區配置。
#查看集群節點
[root@node1 ~]#redis-cli -a 123456 --no-auth-warning cluster nodes
167cc05be9ab506a5fa687e8c9dded4dc2b633a5 10.0.0.40:6379@16379 myself,master - 0 0 1 connected 0-5460
5b4b959cec186ee66836d176305b6db55f0ac451 10.0.0.41:6379@16379 master - 0 1736782488967 0 connected 5461-10922
3e9cf23bbfbcbd673d8c5b4abaf3f0e722c94b2a 10.0.0.112:6379@16379 master - 0 1736782485000 5 connected
2758daa041534a8eaef4ac279b430b0836d1e7f4 10.0.0.113:6379@16379 master - 0 1736782486000 4 connected
14468ef2bc32bcf9819b97c72c1c567916a93354 10.0.0.42:6379@16379 master - 0 1736782486809 2 connected 10923-16383
2d56d8d0b9ee2afce646c61577c8b622b87bafe3 10.0.0.50:6379@16379 master - 0 1736782487891 3 connected
[root@node1 ~]#

若不小心分配錯了槽位,如何刪除/重新分配?

# 1.刪除槽(前提:槽內無數據或不關心數據)
# 刪除單個槽
redis-cli -h <wrong_host> -p <wrong_port> -a 123456 cluster delslots 100
# 或刪除多個槽
redis-cli -h <wrong_host> -p <wrong_port> -a 123456 cluster delslots 100 101 102#或者使用批量腳本一次性刪除整個區間:
for slot in $(seq 0 5000); doredis-cli -h <wrong_host> -p <wrong_port> -a 123456 cluster delslots ${slot}
done#重新分配到正確節點
# 到正確節點 (correct_host, correct_port) 上添加這些槽
for slot in $(seq 0 5000); doredis-cli -h <correct_host> -p <correct_port> -a 123456 cluster addslots ${slot}
done

如果槽內有數據,該怎么處理?

如果槽內已經存有鍵值數據,不能直接 delslots,否則會造成集群不一致或報錯;此時需要先將數據遷移到目標節點,然后再執行 delslots。簡要流程如下:

# 1.將槽標記為待遷移
# 在源節點上執行
redis-cli -h <src_host> -p <src_port> -a <pass> cluster setslot <slot> migrating <dest_node_id># 在目標節點執行:
redis-cli -h <dest_host> -p <dest_port> -a <pass> cluster setslot <slot> importing <src_node_id># 2.使用 migrate 命令搬移數據(在源節點上,對所有屬于該槽位的 key 執行 migrate 到目標節點;也可以用 redis-cli --cluster reshard 交互式自動遷移。或者逐條 DUMP + RESTORE 的方式遷移,也可以腳本化。)# 3.將槽標記到新節點
# 在目標節點執行:
redis-cli -h <dest_host> -p <dest_port> -a <pass> cluster setslot <slot> node <dest_node_id>
# 在源節點執行 cluster delslots <slot>(如果不再需要該槽)。# 實際生產環境 中,使用 redis-cli --cluster reshard 或 redis-cli --cluster move 命令會自動完成 importing/migrating 等過程,并避免手動操作失誤

11.4 指定各個節點的主從關系

# 通過上面cluster nodes 查看master的ID信息,執行下面操作,將對應的slave 指定相應的master節點,實現三對主從節點# master:10.0.0.40-slave:10.0.0.50(后面的ID對應的master的id,前面寫的是slave的ip)
[root@node1 ~]#redis-cli -h 10.0.0.50 -a 123456 --no-auth-warning cluster replicate 167cc05be9ab506a5fa687e8c9dded4dc2b633a5
# master:10.0.0.41-slave:10.0.0.112
[root@node1 ~]#redis-cli -h 10.0.0.112 -a 123456 --no-auth-warning cluster replicate 5b4b959cec186ee66836d176305b6db55f0ac451
# master:10.0.0.42-slave:10.0.0.13
[root@node1 ~]#redis-cli -h 10.0.0.113 -a 123456 --no-auth-warning cluster replicate 14468ef2bc32bcf9819b97c72c1c567916a93354# 查看節點間關系
[root@node1 ~]#redis-cli -a 123456 --no-auth-warning cluster nodes
167cc05be9ab506a5fa687e8c9dded4dc2b633a5 10.0.0.40:6379@16379 myself,master - 0 0 1 connected 0-5460
5b4b959cec186ee66836d176305b6db55f0ac451 10.0.0.41:6379@16379 master - 0 1736782929293 0 connected 5461-10922
3e9cf23bbfbcbd673d8c5b4abaf3f0e722c94b2a 10.0.0.112:6379@16379 slave 5b4b959cec186ee66836d176305b6db55f0ac451 0 1736782927129 0 connected
2758daa041534a8eaef4ac279b430b0836d1e7f4 10.0.0.113:6379@16379 slave 14468ef2bc32bcf9819b97c72c1c567916a93354 0 1736782930369 2 connected
14468ef2bc32bcf9819b97c72c1c567916a93354 10.0.0.42:6379@16379 master - 0 1736782928211 2 connected 10923-16383
2d56d8d0b9ee2afce646c61577c8b622b87bafe3 10.0.0.50:6379@16379 slave 167cc05be9ab506a5fa687e8c9dded4dc2b633a5 0 1736782927000 1 connected[root@node1 ~]#redis-cli -a 123456 --no-auth-warning cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3 # 3組集群
cluster_current_epoch:5
cluster_my_epoch:1
cluster_stats_messages_ping_sent:2376
cluster_stats_messages_pong_sent:2450
cluster_stats_messages_meet_sent:5
cluster_stats_messages_sent:4831
cluster_stats_messages_ping_received:2450
cluster_stats_messages_pong_received:2381
cluster_stats_messages_received:4831
total_cluster_links_buffer_limit_exceeded:0
[root@node1 ~]#

11.5 客戶端連接自動計算槽位

# 根據key計算槽位所在哪個master
[root@node1 ~]#redis-cli  -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> set class m44
(error) MOVED 7755 10.0.0.41:6379# 集群模式連接,會自動重定向寫入到計算的機器
[root@node1 ~]#redis-cli  -a 123456 -c
10.0.0.41:6379> get class
"m44"
10.0.0.41:6379> set title ceo
-> Redirected to slot [2217] located at 10.0.0.40:6379
OK
10.0.0.40:6379> set cto hello
-> Redirected to slot [7151] located at 10.0.0.41:6379
OK
10.0.0.41:6379> 

12.基于redis7.4的redis cluster部署

12.1 在所有節點上安裝redis并啟動cluster功能

# 先通過腳本編譯安裝Redis,6臺Redis
node1 10.0.0.40
node2 10.0.0.41
node3 10.0.0.42
node4 10.0.0.43
node5 10.0.0.44
node6 10.0.0.45# 手動修改配置文件
bind 0.0.0.0
masterauth 123456 #建議配置,否則后期的master和slave主從復制無法成功,還需在配置
requirepass 123456
cluster-enabled yes #取消此行注釋,必須開啟集群,開啟后Redis 進程會有Cluster標識
cluster-config-file nodes-6379.conf #取消此行注釋,此為集群狀態文件,記錄主從關系即slot范圍信息,由redis cluster 集群自動創建和維護
cluster-require-full-coverage no #默認值為yes,設為no可以防止一個節點不可用導致整個cluster不可用
cluster-node-timeout #節點之間通信超時時間。# 修改配置文件相關設置-6臺都執行
sed -i.bak -e 's/bind 127.0.0.1/bind 0.0.0.0/' -e '/masterauth/a masterauth 123456' -e '/# requirepass/a requirepass 123456' -e '/# cluster-enabled yes/a cluster-enabled yes' -e '/# cluster-config-file nodes-6379.conf/a cluster-config-file nodes-6379.conf' -e '/cluster-require-full-coverage yes/c cluster-require-full-coverage no' /apps/redis/etc/redis.conf

12.2 創建集群

# --cluster-replicas 1 意味著每個主節點會有一個從節點。
[root@node1 ~]#redis-cli -a 123456 --cluster create 10.0.0.40:6379 10.0.0.41:6379 10.0.0.42:6379 10.0.0.43:6379 10.0.0.44:6379 10.0.0.45:6379 --cluster-replicas 1
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 10.0.0.44:6379 to 10.0.0.40:6379
Adding replica 10.0.0.45:6379 to 10.0.0.41:6379
Adding replica 10.0.0.43:6379 to 10.0.0.42:6379
#  M=>master S=>slave
M: 334ecb1234284cfa2a60ced7c5a8d29f4cd5de10 10.0.0.40:6379slots:[0-5460] (5461 slots) master
M: c9b13ad218d3c8aaf62153738bb21d08a59a66c8 10.0.0.41:6379slots:[5461-10922] (5462 slots) master
M: 767c6fc628516c09dd63fe4dbdc36cecee3808b3 10.0.0.42:6379slots:[10923-16383] (5461 slots) master
S: 12b6dbf4fd222db57a57e0bbd42694377a107ca5 10.0.0.43:6379replicates 767c6fc628516c09dd63fe4dbdc36cecee3808b3
S: 5023eb920093b0da73426572ef189d98f337023e 10.0.0.44:6379replicates 334ecb1234284cfa2a60ced7c5a8d29f4cd5de10
S: 637a013fee8c69a87d4ca9d503f01d3817680f4c 10.0.0.45:6379replicates c9b13ad218d3c8aaf62153738bb21d08a59a66c8
Can I set the above configuration? (type 'yes' to accept): yes #輸入yes自動創建集群
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join>>> Performing Cluster Check (using node 10.0.0.40:6379)
M: 334ecb1234284cfa2a60ced7c5a8d29f4cd5de10 10.0.0.40:6379slots:[0-5460] (5461 slots) master #已經分配的槽位1 additional replica(s) #分了一個slave
S: 637a013fee8c69a87d4ca9d503f01d3817680f4c 10.0.0.45:6379slots: (0 slots) slave #slave沒有分配槽位replicates c9b13ad218d3c8aaf62153738bb21d08a59a66c8 #對應master的ID,也就是10.0.0.41
S: 5023eb920093b0da73426572ef189d98f337023e 10.0.0.44:6379slots: (0 slots) slavereplicates 334ecb1234284cfa2a60ced7c5a8d29f4cd5de10
S: 12b6dbf4fd222db57a57e0bbd42694377a107ca5 10.0.0.43:6379slots: (0 slots) slavereplicates 767c6fc628516c09dd63fe4dbdc36cecee3808b3
M: c9b13ad218d3c8aaf62153738bb21d08a59a66c8 10.0.0.41:6379slots:[5461-10922] (5462 slots) master1 additional replica(s)
M: 767c6fc628516c09dd63fe4dbdc36cecee3808b3 10.0.0.42:6379slots:[10923-16383] (5461 slots) master1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
[root@node1 ~]## 觀察以上結果,可以看到三組master/slave
master:10.0.0.40-->slave:10.0.0.44
master:10.0.0.41-->slave:10.0.0.45
master:10.0.0.42-->slave:10.0.0.43# 查看主從狀態
[root@node1 ~]#redis-cli -a 123456 info replication
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
# Replication
role:master
connected_slaves:1
slave0:ip=10.0.0.44,port=6379,state=online,offset=686,lag=0
master_failover_state:no-failover
master_replid:686dd579b02a3975b8c8df7e4f707dfa612519f1
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:686
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:686# 查看指定master節點的slave節點信息
[root@node3 ~]#redis-cli -a 123456 cluster nodes
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
c9b13ad218d3c8aaf62153738bb21d08a59a66c8 10.0.0.41:6379@16379 master - 0 1736845843217 2 connected 5461-10922
5023eb920093b0da73426572ef189d98f337023e 10.0.0.44:6379@16379 slave 334ecb1234284cfa2a60ced7c5a8d29f4cd5de10 0 1736845844228 1 connected
334ecb1234284cfa2a60ced7c5a8d29f4cd5de10 10.0.0.40:6379@16379 master - 0 1736845842000 1 connected 0-5460
12b6dbf4fd222db57a57e0bbd42694377a107ca5 10.0.0.43:6379@16379 slave 767c6fc628516c09dd63fe4dbdc36cecee3808b3 0 1736845842208 3 connected
767c6fc628516c09dd63fe4dbdc36cecee3808b3 10.0.0.42:6379@16379 myself,master - 0 0 3 connected 10923-16383
637a013fee8c69a87d4ca9d503f01d3817680f4c 10.0.0.45:6379@16379 slave c9b13ad218d3c8aaf62153738bb21d08a59a66c8 0 1736845841000 2 connected
[root@node3 ~]## 查看指定master節點的slave節點信息
[root@node1 ~]#redis-cli -a 123456 cluster slaves 767c6fc628516c09dd63fe4dbdc36cecee3808b3
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
1) "12b6dbf4fd222db57a57e0bbd42694377a107ca5 10.0.0.43:6379@16379 slave 767c6fc628516c09dd63fe4dbdc36cecee3808b3 0 1736845978620 3 connected"
[root@node1 ~]## 驗證集群的狀態
[root@node1 ~]#redis-cli -a 123456 cluster info
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:763
cluster_stats_messages_pong_sent:710
cluster_stats_messages_sent:1473
cluster_stats_messages_ping_received:705
cluster_stats_messages_pong_received:763
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:1473
total_cluster_links_buffer_limit_exceeded:0
[root@node1 ~]## 查看任意節點的集群狀態
[root@node1 ~]#redis-cli -a 123456 --cluster info 10.0.0.40:6379
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
10.0.0.40:6379 (334ecb12...) -> 0 keys | 5461 slots | 1 slaves.
10.0.0.41:6379 (c9b13ad2...) -> 0 keys | 5462 slots | 1 slaves.
10.0.0.42:6379 (767c6fc6...) -> 0 keys | 5461 slots | 1 slaves.
[OK] 0 keys in 3 masters.
0.00 keys per slot on average.
[root@node1 ~]#

12.3 測試寫入數據

在運行代碼之前,請確保使用以下命令安裝 redis-py-cluster

pip install redis-py-cluster

from rediscluster import RedisCluster# 定義 Redis Cluster 的啟動節點
startup_nodes = [{"host": "10.0.0.40", "port": 6379},{"host": "10.0.0.41", "port": 6379},{"host": "10.0.0.42", "port": 6379},{"host": "10.0.0.43", "port": 6379},{"host": "10.0.0.44", "port": 6379},{"host": "10.0.0.45", "port": 6379}
]# 創建 RedisCluster 連接
redis_conn = RedisCluster(startup_nodes=startup_nodes, password='123456', decode_responses=True)# 批量插入并獲取鍵值對
for i in range(0, 10000):key = 'key' + str(i)value = 'value' + str(i)redis_conn.set(key, value)  # 設置鍵值print(f'{key}: {redis_conn.get(key)}')  # 輸出鍵值對

13.cluster和–cluster

下面這兩條命令雖然都跟 Redis Cluster 相關,但它們代表了兩套不同的命令體系,用途和選項也不盡相同。可以簡單地理解為:

  1. redis-cli cluster help
    ——服務端層面的 Cluster 子命令。這些子命令本質上是向 Redis 服務端發送 CLUSTER <subcommand> 命令,由 Redis 服務端執行,幫助我們在Redis 實例內部完成各種操作(例如查看節點信息、設置 slots 等)。
  2. redis-cli --cluster help
    ——客戶端層面的 Cluster Manager 子命令。這是 Redis 命令行工具(redis-cli)提供的一個集群管理功能,通過它可以在客戶端對多個節點進行統一管理、檢查、rebalance、reshard 等高層次操作,而不需要逐節點去執行相應命令。
[root@node1 ~]#redis-cli -a 123456 --cluster help
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
Cluster Manager Commands:create         host1:port1 ... hostN:portN--cluster-replicas <arg>check          <host:port> or <host> <port> - separated by either colon or space--cluster-search-multiple-ownersinfo           <host:port> or <host> <port> - separated by either colon or spacefix            <host:port> or <host> <port> - separated by either colon or space--cluster-search-multiple-owners--cluster-fix-with-unreachable-mastersreshard        <host:port> or <host> <port> - separated by either colon or space--cluster-from <arg>--cluster-to <arg>--cluster-slots <arg>--cluster-yes--cluster-timeout <arg>--cluster-pipeline <arg>--cluster-replacerebalance      <host:port> or <host> <port> - separated by either colon or space--cluster-weight <node1=w1...nodeN=wN>--cluster-use-empty-masters--cluster-timeout <arg>--cluster-simulate--cluster-pipeline <arg>--cluster-threshold <arg>--cluster-replaceadd-node       new_host:new_port existing_host:existing_port--cluster-slave--cluster-master-id <arg>del-node       host:port node_idcall           host:port command arg arg .. arg--cluster-only-masters--cluster-only-replicasset-timeout    host:port millisecondsimport         host:port--cluster-from <arg>--cluster-from-user <arg>--cluster-from-pass <arg>--cluster-from-askpass--cluster-copy--cluster-replacebackup         host:port backup_directoryhelpFor check, fix, reshard, del-node, set-timeout, info, rebalance, call, import, backup you can specify the host and port of any working node in the cluster.Cluster Manager Options:--cluster-yes  Automatic yes to cluster commands prompts[root@node1 ~]#
[root@node1 ~]#redis-cli -a 123456 cluster help
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.1) CLUSTER <subcommand> [<arg> [value] [opt] ...]. Subcommands are:2) COUNTKEYSINSLOT <slot>3)     Return the number of keys in <slot>.4) GETKEYSINSLOT <slot> <count>5)     Return key names stored by current node in a slot.6) INFO7)     Return information about the cluster.8) KEYSLOT <key>9)     Return the hash slot for <key>.
10) MYID
11)     Return the node id.
12) MYSHARDID
13)     Return the node's shard id.
14) NODES
15)     Return cluster configuration seen by node. Output format:
16)     <id> <ip:port@bus-port[,hostname]> <flags> <master> <pings> <pongs> <epoch> <link> <slot> ...
17) REPLICAS <node-id>
18)     Return <node-id> replicas.
19) SLOTS
20)     Return information about slots range mappings. Each range is made of:
21)     start, end, master and replicas IP addresses, ports and ids
22) SHARDS
23)     Return information about slot range mappings and the nodes associated with them.
24) ADDSLOTS <slot> [<slot> ...]
25)     Assign slots to current node.
26) ADDSLOTSRANGE <start slot> <end slot> [<start slot> <end slot> ...]
27)     Assign slots which are between <start-slot> and <end-slot> to current node.
28) BUMPEPOCH
29)     Advance the cluster config epoch.
30) COUNT-FAILURE-REPORTS <node-id>
31)     Return number of failure reports for <node-id>.
32) DELSLOTS <slot> [<slot> ...]
33)     Delete slots information from current node.
34) DELSLOTSRANGE <start slot> <end slot> [<start slot> <end slot> ...]
35)     Delete slots information which are between <start-slot> and <end-slot> from current node.
36) FAILOVER [FORCE|TAKEOVER]
37)     Promote current replica node to being a master.
38) FORGET <node-id>
39)     Remove a node from the cluster.
40) FLUSHSLOTS
41)     Delete current node own slots information.
42) MEET <ip> <port> [<bus-port>]
43)     Connect nodes into a working cluster.
44) REPLICATE <node-id>
45)     Configure current node as replica to <node-id>.
46) RESET [HARD|SOFT]
47)     Reset current node (default: soft).
48) SET-CONFIG-EPOCH <epoch>
49)     Set config epoch of current node.
50) SETSLOT <slot> (IMPORTING <node-id>|MIGRATING <node-id>|STABLE|NODE <node-id>)
51)     Set slot state.
52) SAVECONFIG
53)     Force saving cluster configuration on disk.
54) LINKS
55)     Return information about all network links between this node and its peers.
56)     Output format is an array where each array element is a map containing attributes of a link
57) HELP
58)     Print this help.

一、redis-cli cluster help 及其子命令詳解

當我們執行:

redis-cli -a 123456 cluster help

-a 123456 只是指定了訪問 Redis 的密碼,與你要執行的 CLUSTER HELP 命令本身無關)

返回的內容是 Redis 服務端對外暴露的Cluster 子命令列表,即 CLUSTER <subcommand>。下面對其進行簡要說明(按照它顯示的順序):

  1. COUNTKEYSINSLOT <slot>
    • 功能:返回指定 <slot> 中包含的 key 的數量(僅當前節點存儲的部分)。
    • 用法示例CLUSTER COUNTKEYSINSLOT 1234
    • 場景:當你想知道某個 slot 上有多少 key,尤其在做 reshard 之前,想先確認數據量是多少時有用。
  2. GETKEYSINSLOT <slot> <count>
    • 功能:返回當前節點在指定 <slot> 中存儲的最多 <count> 個 key 名。
    • 用法示例CLUSTER GETKEYSINSLOT 1234 10
    • 場景:一般配合 MIGRATE 命令進行遷移時,需先找到屬于某個 slot 的具體 key。
  3. INFO
    • 功能:返回集群的總體信息,包括集群狀態(ok 或 fail)、當前集群配置紀元(epoch)等。
    • 用法示例CLUSTER INFO
  4. KEYSLOT <key>
    • 功能:計算某個 key 所對應的 hash slot 值。
    • 用法示例CLUSTER KEYSLOT mykey
    • 場景:用于測試或驗證某個 key 會被路由到哪個 slot。
  5. MYID
    • 功能:返回當前 Redis 節點在集群中的 node id。
    • 用法示例CLUSTER MYID
  6. MYSHARDID
    • 功能:返回當前節點所在的 shard 的 ID(Redis 7.0+ 出現,內部概念類似 node id,主要用于分片標識)。
    • 用法示例CLUSTER MYSHARDID
  7. NODES
    • 功能:返回當前節點所看到的整個集群拓撲配置。
    • 用法示例CLUSTER NODES
    • 返回格式:多行文本,每一行代表一個節點的信息,包括其 ID、IP、端口、flags、master/slave 關系等。
  8. REPLICAS <node-id>
    • 功能:返回指定 <node-id> 的所有從節點信息(相當于老版本命令 SLAVES <node-id>)。
    • 用法示例CLUSTER REPLICAS 07c37dfeb2352f2f2bae
  9. SLOTS
    • 功能:以區間形式返回集群中所有 slot 的分配信息,包括每個區間有哪些節點負責。
    • 用法示例CLUSTER SLOTS
  10. SHARDS
    • 功能:Redis 7.0+ 新增命令,與 SLOTS 類似,但會返回更詳細的節點信息(按 shard 分組)。
    • 用法示例CLUSTER SHARDS
  11. ADDSLOTS <slot> [<slot> ...]
    • 功能:將指定的 slot 集合分配給當前節點
    • 用法示例CLUSTER ADDSLOTS 1 2 3
  12. ADDSLOTSRANGE <start slot> <end slot> [<start slot> <end slot> ...]
    • 功能:一次性將連續區間的 slot 分配給當前節點
    • 用法示例CLUSTER ADDSLOTSRANGE 0 1000 1001 2000
  13. BUMPEPOCH
    • 功能:手動讓當前集群的配置紀元(epoch)+1,通常用于測試或特殊情況下觸發集群新的配置更新流程。
    • 用法示例CLUSTER BUMPEPOCH
  14. COUNT-FAILURE-REPORTS <node-id>
    • 功能:查看有多少節點報告了指定節點的失敗(故障)。
    • 用法示例CLUSTER COUNT-FAILURE-REPORTS 07c37dfeb2352f2f2bae
  15. DELSLOTS <slot> [<slot> ...]
    • 功能:從當前節點中刪除這些 slot 的歸屬關系(讓它處于無主狀態)。
    • 用法示例CLUSTER DELSLOTS 1 2 3
  16. DELSLOTSRANGE <start slot> <end slot> [<start slot> <end slot> ...]
    • 功能:批量刪除指定區間的 slot 歸屬關系。
    • 用法示例CLUSTER DELSLOTSRANGE 0 1000 1001 2000
  17. FAILOVER [FORCE|TAKEOVER]
    • 功能:在復制結構(主從結構)中,使當前節點從從節點晉升為主節點。
    • FORCE:強制故障轉移,哪怕主節點在線;TAKEOVER:更高優先級,會忽略部分檢查。
    • 用法示例CLUSTER FAILOVER FORCE
  18. FORGET <node-id>
    • 功能:從集群信息中“遺忘”某個節點,讓該節點從集群拓撲中移除。
    • 用法示例CLUSTER FORGET 07c37dfeb2352f2f2bae
  19. FLUSHSLOTS
    • 功能:清空當前節點對所有 slot 的歸屬信息,但并不會對集群其他節點的視圖造成影響。
    • 用法示例CLUSTER FLUSHSLOTS
  20. MEET <ip> <port> [<bus-port>]
    • 功能:讓當前節點嘗試與指定 IP 和端口的節點建立集群握手,使其加入集群。
    • 用法示例CLUSTER MEET 192.168.1.100 7001
  21. REPLICATE <node-id>
    • 功能:將當前節點設置為指定節點的從節點。
    • 用法示例CLUSTER REPLICATE 07c37dfeb2352f2f2bae
  22. RESET [HARD|SOFT]
    • 功能:重置當前節點的集群狀態。
    • SOFT:保留部分集群信息,只刪除 slots 等。
    • HARD:徹底重置,清除所有集群相關信息。
    • 用法示例CLUSTER RESET HARD
  23. SET-CONFIG-EPOCH <epoch>
    • 功能:手動設置當前節點的配置紀元值。
    • 用法示例CLUSTER SET-CONFIG-EPOCH 99
  24. SETSLOT <slot> (IMPORTING <node-id> | MIGRATING <node-id> | STABLE | NODE <node-id>)
    • 功能:設置指定 slot 的狀態,例如標記為遷入中、遷出中,或指定新的歸屬節點等。
    • 用法示例CLUSTER SETSLOT 1234 MIGRATING 07c37dfeb2352f2f2bae
  25. SAVECONFIG
    • 功能:強制保存集群配置到本地磁盤(通常是 nodes.conf 文件)。
    • 用法示例CLUSTER SAVECONFIG
  26. LINKS
    • 功能:查看當前節點與其他節點之間的網絡連接詳細信息。
    • 用法示例CLUSTER LINKS
  27. HELP
    • 功能:打印出所有可用的 CLUSTER <subcommand> 命令說明。

小結:
cluster help 列出的這些命令都屬于服務端內置的子命令,它們是針對當前連接的這個 Redis 節點,來查看或操作集群信息的。比如 ADDSLOTS/DELSLOTS 就是告訴“當前節點”去聲明釋放某些 slots 的歸屬。


二、redis-cli --cluster help 及其子命令詳解

當我們執行:

redis-cli -a 123456 --cluster help

同樣會出現一系列“Cluster Manager”命令。這些命令并不是簡單的 CLUSTER <subcommand>,而是Redis CLI 工具對集群管理封裝的一套功能。它會在客戶端跑一些邏輯,然后對多個節點發送相應的 Redis 命令,從而幫我們完成創建集群、檢查或修復集群等高級操作。

常見的子命令如下:

  1. create host1:port1 ... hostN:portN

    • 功能:在給定的若干 Redis 實例之間創建一個新的集群,并進行 slot 分配。

    • 常見選項:

      • --cluster-replicas <arg>:指定每個主節點分配多少從節點。
    • 用法示例:

      redis-cli --cluster create 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 \--cluster-replicas 1
      
  2. check <host:port>

    • 功能:檢查指定節點所在的集群是否存在配置或數據異常,例如 slot 沖突、主從同步異常等。
    • 可選--cluster-search-multiple-owners:當存在多個節點同時持有相同 slot 時,嘗試自動檢測并顯示。
  3. info <host:port>

    • 功能:顯示指定節點所在集群的整體信息,包括主從節點分布、slot 分配、可能的問題等。
    • 用法示例redis-cli --cluster info 127.0.0.1:7001
  4. fix <host:port>

    • 功能:針對檢查出的問題嘗試進行修復,比如修正 slot 的 owner、清理不正確的配置等。
    • 常見選項:
      • --cluster-search-multiple-owners:檢測并嘗試修復多個節點同時擁有同一 slot 的沖突問題。
      • --cluster-fix-with-unreachable-masters:即使主節點無法訪問,也要嘗試進行修復。
    • 用法示例redis-cli --cluster fix 127.0.0.1:7001 --cluster-search-multiple-owners
  5. reshard <host:port>

    • 功能:對集群中的 slot 進行重新分配(手動或交互式),實現數據在各節點之間重新均衡。

    • 常見選項:

      • --cluster-from <node id>:指定從哪個節點或節點集合中抽取 slot。
      • --cluster-to <node id>:指定 slot 將遷移到哪個節點。
      • --cluster-slots <個數>:要遷移多少個 slot。
      • --cluster-yes:自動確認(不再提示交互)。
      • --cluster-timeout <arg>:遷移超時設置。
      • --cluster-pipeline <arg>:遷移時使用 pipeline 發送多少個 key。
      • --cluster-replace:若目標節點已擁有該 slot 的信息,也強行替換。
    • 用法示例:

      redis-cli --cluster reshard 127.0.0.1:7001 \--cluster-from 07c37dfeb2352f2f2bae \--cluster-to 09a49dfeb2352f2f2cde \--cluster-slots 100 \--cluster-yes
      
  6. rebalance <host:port>

    • 功能:在集群中執行自動負載均衡,讓各節點的 slot 數量大體趨于平均。
    • 常見選項:
      • --cluster-weight <node1=w1...nodeN=wN>:給節點設置“權重”,使 rebalance 時并非絕對平均,而是按權重分配 slot。
      • --cluster-use-empty-masters:在 rebalance 時也會考慮那些目前沒有 slots 的主節點。
      • --cluster-timeout <arg>:操作超時。
      • --cluster-simulate:只模擬操作,并不真正執行。
      • --cluster-pipeline <arg>:遷移 key 時的 pipeline 大小。
      • --cluster-threshold <arg>:只有當節點 slot 數差異超過一定閾值才進行遷移。
      • --cluster-replace:遷移中如遇 slot 沖突允許替換。
    • 用法示例redis-cli --cluster rebalance 127.0.0.1:7001 --cluster-use-empty-masters --cluster-yes
  7. add-node new_host:new_port existing_host:existing_port

    • 功能:向已經在運行的集群中新增加一個節點(可以指定是作為從節點,或者讓它自己成為主節點)。

    • 常見選項:

      • --cluster-slave:以從節點的角色加入集群。
      • --cluster-master-id <arg>:如果要作為從節點,指明它的主節點 ID。
    • 用法示例:

      redis-cli --cluster add-node 192.168.1.100:7004 192.168.1.100:7001 \--cluster-slave \--cluster-master-id 07c37dfeb2352f2f2bae
      
  8. del-node host:port node_id

    • 功能:從集群拓撲中刪除指定 node_id 的節點。
    • 用法示例redis-cli --cluster del-node 127.0.0.1:7001 07c37dfeb2352f2f2bae
  9. call host:port command arg arg .. arg

    • 功能:對集群的所有節點(或只對主節點/從節點)執行一個自定義命令。
    • 常見選項:
      • --cluster-only-masters:只對主節點執行。
      • --cluster-only-replicas:只對從節點執行。
    • 用法示例redis-cli --cluster call 127.0.0.1:7001 CONFIG GET maxmemory --cluster-only-masters
  10. set-timeout host:port milliseconds

    • 功能:設置集群節點的 cluster-node-timeout 參數。
    • 用法示例redis-cli --cluster set-timeout 127.0.0.1:7001 2000
  11. import host:port

    • 功能:將單節點 Redis 的數據導入到指定的集群節點中。

    • 常見選項:

      • --cluster-from <arg>:源 Redis 的地址。
      • --cluster-from-user <arg> / --cluster-from-pass <arg> / --cluster-from-askpass:指定源 Redis 的認證方式。
      • --cluster-copy:復制數據而不是遷移數據。
      • --cluster-replace:如 slot 中已有 key 是否直接覆蓋。
    • 用法示例:

      redis-cli --cluster import 127.0.0.1:7001 \--cluster-from 127.0.0.1:6379 \--cluster-from-pass 123456 \--cluster-copy \--cluster-replace
      
  12. backup host:port backup_directory

    • 功能:從集群中每個節點獲取 RDB 快照并保存到本地指定目錄,做集群級的統一備份。
    • 用法示例redis-cli --cluster backup 127.0.0.1:7001 /data/redis_backups/
  13. help

    • 功能:打印出以上 Cluster Manager 命令的幫助信息。

小結:
--cluster 模式下的命令可以看作是一個“批處理管理工具”,它會自動遍歷或連接集群中多個節點執行相應操作(創建、檢查、修復、分片遷移等),簡化了人工逐個節點執行命令的麻煩。


三、兩者的主要區別與使用場景

  1. 作用層次不同
    • cluster help:側重于服務端提供的低層次操作接口,直接通過 CLUSTER <subcommand> 與 Redis 節點交互。
    • --cluster help:側重于客戶端的集群管理腳本功能,相當于在本地批量調用若干 Redis 命令來完成更復雜的集群管理操作。
  2. 使用場景不同
    • cluster help:常用于日常運維或在線查看集群狀態、slot 信息,或在做某些手動精細化操作(比如精確地給節點添加 slot、指定遷移 slot 狀態)時使用。
    • --cluster help:常用于一鍵式操作,比如:
      • 創建集群(create)
      • 自動均衡(rebalance)
      • 重分片(reshard)
      • 檢查/修復(check/fix)
      • 備份(backup)
  3. 選項涵蓋面
    • cluster help:Redis 服務端自帶,子命令相對固定,圍繞 slot 與節點元信息進行管理。
    • --cluster help:Redis CLI 擴展,提供了更多“綜合管理”選項(如一次性在多個節點執行命令、自動處理交互、自動計算 slot 分配等)。

總結

  • redis-cli cluster help 展示的是 Redis 服務端自身支持的 CLUSTER 子命令,適合對集群進行細粒度、內置命令級的操作或查詢。
  • redis-cli --cluster help 則是 Redis CLI 工具提供的高級管理命令集合,讓我們在客戶端就能對整個集群進行一站式的部署、檢查、修復、遷移、備份等操作。

在實際運維中,兩者經常是結合使用的:當需要快速創建或重分片時,用 --cluster;當需要深入到某個具體節點查看或調整 slot 時,就使用 CLUSTER <subcommand>。兩種方式熟練掌握,可以大大提升對 Redis Cluster 的管理效率和靈活度。

14.Redis cluster集群動態擴容

因公司業務發展迅猛,現有的三主三從的redis cluster架構可能無法滿足現有業務的并發寫入需求,因此公司緊急采購兩臺服務器10.0.0.46,10.0.0.47,需要將其動態添加到集群當中,但不能影響業務使用和數據丟失。

注意:生產環境一般建議master節點為奇數個,防止腦裂現象。

14.1 添加新的master節點到集群

# 首先安裝redis,再執行下面命令
[root@Rocky9 ~]# sed -i.bak -e 's/bind 127.0.0.1/bind 0.0.0.0/' -e '/masterauth/a masterauth 123456' -e '/# requirepass/a requirepass 123456' -e '/# cluster-enabled yes/a cluster-enabled yes' -e '/# cluster-config-file nodes-6379.conf/a cluster-config-file nodes-6379.conf' -e '/cluster-require-full-coverage yes/c cluster-require-full-coverage no' /apps/redis/etc/redis.conf
[root@Rocky9 ~]# systemctl restart redis
[root@Rocky9 ~]# ps aux | grep redis
redis      19937  0.3  0.8 136680  8192 ?        Ssl  16:57   0:00 /apps/redis/bin/redis-server 0.0.0.0:6379 [cluster]
root       19947  0.0  0.2   6408  2048 pts/0    S+   16:57   0:00 grep --color=auto redis
# 46加入到40所在的集群節點
[root@Rocky9 ~]# redis-cli -a 123456 --cluster add-node 10.0.0.46:6379 10.0.0.40:6379
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Adding node 10.0.0.46:6379 to cluster 10.0.0.40:6379
>>> Performing Cluster Check (using node 10.0.0.40:6379)
S: 334ecb1234284cfa2a60ced7c5a8d29f4cd5de10 10.0.0.40:6379slots: (0 slots) slavereplicates 5023eb920093b0da73426572ef189d98f337023e
M: 767c6fc628516c09dd63fe4dbdc36cecee3808b3 10.0.0.42:6379slots:[10923-16383] (5461 slots) master1 additional replica(s)
M: 5023eb920093b0da73426572ef189d98f337023e 10.0.0.44:6379slots:[0-5460] (5461 slots) master1 additional replica(s)
S: 12b6dbf4fd222db57a57e0bbd42694377a107ca5 10.0.0.43:6379slots: (0 slots) slavereplicates 767c6fc628516c09dd63fe4dbdc36cecee3808b3
M: c9b13ad218d3c8aaf62153738bb21d08a59a66c8 10.0.0.41:6379slots:[5461-10922] (5462 slots) master1 additional replica(s)
S: 637a013fee8c69a87d4ca9d503f01d3817680f4c 10.0.0.45:6379slots: (0 slots) slavereplicates c9b13ad218d3c8aaf62153738bb21d08a59a66c8
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
>>> Getting functions from cluster
>>> Send FUNCTION LIST to 10.0.0.46:6379 to verify there is no functions in it
>>> Send FUNCTION RESTORE to 10.0.0.46:6379
>>> Send CLUSTER MEET to node 10.0.0.46:6379 to make it join the cluster.
[OK] New node added correctly.# 查看集群節點,46加入了集群節點,并成為master
[root@node1 ~]#redis-cli -a 123456 cluster nodes
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
767c6fc628516c09dd63fe4dbdc36cecee3808b3 10.0.0.42:6379@16379 master - 0 1736953737000 3 connected 10923-16383
5023eb920093b0da73426572ef189d98f337023e 10.0.0.44:6379@16379 master - 0 1736953737211 7 connected 0-5460
12b6dbf4fd222db57a57e0bbd42694377a107ca5 10.0.0.43:6379@16379 slave 767c6fc628516c09dd63fe4dbdc36cecee3808b3 0 1736953736201 3 connected
c9b13ad218d3c8aaf62153738bb21d08a59a66c8 10.0.0.41:6379@16379 master - 0 1736953736000 2 connected 5461-10922
c882647e71c8f3cc1b40ea20cc242fecca371cd4 10.0.0.46:6379@16379 master - 0 1736953738220 0 connected
637a013fee8c69a87d4ca9d503f01d3817680f4c 10.0.0.45:6379@16379 slave c9b13ad218d3c8aaf62153738bb21d08a59a66c8 0 1736953736000 2 connected
334ecb1234284cfa2a60ced7c5a8d29f4cd5de10 10.0.0.40:6379@16379 myself,slave 5023eb920093b0da73426572ef189d98f337023e 0 0 7 connected

14.2 在新的master上重新分配槽位

新的node節點加入到集群之后,默認是master節點,但是沒有slots,需要重新分配。添加主機之后需要對添加至集群中的新主機重新分片,否則其他沒有分片也就無法寫入數據。

注意:重新分配槽位需要清空數據,所以需要先備份數據,擴容后再恢復數據。

# 方法1:手動分配槽(Slots),40是當前任意節點即可(40-45)
[root@Rocky9 ~]# redis-cli -a 123456 --cluster reshard 10.0.0.40:6379
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Performing Cluster Check (using node 10.0.0.40:6379)
S: 334ecb1234284cfa2a60ced7c5a8d29f4cd5de10 10.0.0.40:6379slots: (0 slots) slavereplicates 5023eb920093b0da73426572ef189d98f337023e
M: 767c6fc628516c09dd63fe4dbdc36cecee3808b3 10.0.0.42:6379slots:[0-1364],[12287-16383] (5462 slots) master1 additional replica(s)
M: 5023eb920093b0da73426572ef189d98f337023e 10.0.0.44:6379slots:[1365-6825] (5461 slots) master1 additional replica(s)
S: 12b6dbf4fd222db57a57e0bbd42694377a107ca5 10.0.0.43:6379slots: (0 slots) slavereplicates 767c6fc628516c09dd63fe4dbdc36cecee3808b3
M: c9b13ad218d3c8aaf62153738bb21d08a59a66c8 10.0.0.41:6379slots:[6826-12286] (5461 slots) master1 additional replica(s)
M: c882647e71c8f3cc1b40ea20cc242fecca371cd4 10.0.0.46:6379 #新加入的master節點已經列出來了slots: (0 slots) master
S: 637a013fee8c69a87d4ca9d503f01d3817680f4c 10.0.0.45:6379slots: (0 slots) slavereplicates c9b13ad218d3c8aaf62153738bb21d08a59a66c8
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
# 要遷移多少個槽
How many slots do you want to move (from 1 to 16384)? 4096 #新分配多少個槽位=16384/master個數
# 槽的目標節點
What is the receiving node ID? c882647e71c8f3cc1b40ea20cc242fecca371cd4 #輸入接收的master的ID(這里就是46這臺機器的ID)
Please enter all the source node IDs.Type 'all' to use all the nodes as source nodes for the hash slots.Type 'done' once you entered all the source nodes IDs.
Source node #1: all #將哪些源主機的槽位分配給新節點,all是自動在所有的redis node選擇劃分,如果是從redis cluster刪除某個主機可以使用此方式將指定主機上的槽位全部移動到別的redis主機上Ready to move 4096 slots.Source nodes: #槽的來源節點,從下面三個master上移動槽位給46M: 767c6fc628516c09dd63fe4dbdc36cecee3808b3 10.0.0.42:6379slots:[0-1364],[12287-16383] (5462 slots) master1 additional replica(s)M: 5023eb920093b0da73426572ef189d98f337023e 10.0.0.44:6379slots:[1365-6825] (5461 slots) master1 additional replica(s)M: c9b13ad218d3c8aaf62153738bb21d08a59a66c8 10.0.0.41:6379slots:[6826-12286] (5461 slots) master1 additional replica(s)Destination node: #槽的目標節點M: c882647e71c8f3cc1b40ea20cc242fecca371cd4 10.0.0.46:6379slots: (0 slots) masterResharding plan:Moving slot 0 from 767c6fc628516c09dd63fe4dbdc36cecee3808b3Moving slot 1 from 767c6fc628516c09dd63fe4dbdc36cecee3808b3
...... #這里省略類似信息Moving slot 8190 from c9b13ad218d3c8aaf62153738bb21d08a59a66c8
Do you want to proceed with the proposed reshard plan (yes/no)? yes #確認分配
......
Moving slot 8189 from 10.0.0.41:6379 to 10.0.0.46:6379: .
Moving slot 8190 from 10.0.0.41:6379 to 10.0.0.46:6379: .# 方法2:通過rebalance進行自動分配,不需要計算要分配的槽位(下面會重點講解這兩個命令的區別reshard和rebalance)
[root@Rocky9 ~]# redis-cli -a 123456 --cluster rebalance 10.0.0.40:6379 --cluster-use-empty-masters
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Performing Cluster Check (using node 10.0.0.40:6379)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
>>> Rebalancing across 4 nodes. Total weight = 4.00
Moving 1366 slots from 10.0.0.41:6379 to 10.0.0.46:6379 #從41上移動了1366個slots
###################################################################################################################################################################
......
Moving 1365 slots from 10.0.0.44:6379 to 10.0.0.46:6379 # 從44上移動了1365個slots
###################################################################################################################################################################
......
Moving 1365 slots from 10.0.0.42:6379 to 10.0.0.46:6379 #從42上移動了1365個slots
###################################################################################################################################################################
......
[root@Rocky9 ~]## 查看集群節點分配情況
[root@node1 ~]#redis-cli -a 123456 cluster nodes
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
767c6fc628516c09dd63fe4dbdc36cecee3808b3 10.0.0.42:6379@16379 master - 0 1736992172987 12 connected 12288-16383
5023eb920093b0da73426572ef189d98f337023e 10.0.0.44:6379@16379 master - 0 1736992170964 10 connected 2730-6825
12b6dbf4fd222db57a57e0bbd42694377a107ca5 10.0.0.43:6379@16379 slave 767c6fc628516c09dd63fe4dbdc36cecee3808b3 0 1736992171000 12 connected
c9b13ad218d3c8aaf62153738bb21d08a59a66c8 10.0.0.41:6379@16379 master - 0 1736992169957 11 connected 8191-12286
c882647e71c8f3cc1b40ea20cc242fecca371cd4 10.0.0.46:6379@16379 master - 0 1736992172000 13 connected 0-2729 6826-8190 12287 #槽位已經分配好了
637a013fee8c69a87d4ca9d503f01d3817680f4c 10.0.0.45:6379@16379 slave c9b13ad218d3c8aaf62153738bb21d08a59a66c8 0 1736992168000 11 connected
334ecb1234284cfa2a60ced7c5a8d29f4cd5de10 10.0.0.40:6379@16379 myself,slave 5023eb920093b0da73426572ef189d98f337023e 0 0 10 connected
[root@node1 ~]## 只查看槽位分配情況
[root@node1 ~]#redis-cli -a 123456 --cluster check 10.0.0.46:6379
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
10.0.0.46:6379 (c882647e...) -> 2506 keys | 4096 slots | 0 slaves. #4096個slots
10.0.0.44:6379 (5023eb92...) -> 2494 keys | 4096 slots | 1 slaves.
10.0.0.42:6379 (767c6fc6...) -> 2500 keys | 4096 slots | 1 slaves.
10.0.0.41:6379 (c9b13ad2...) -> 2500 keys | 4096 slots | 1 slaves.
[OK] 10000 keys in 4 masters.
0.61 keys per slot on average.
>>> Performing Cluster Check (using node 10.0.0.46:6379)
M: c882647e71c8f3cc1b40ea20cc242fecca371cd4 10.0.0.46:6379slots:[0-2729],[6826-8190],[12287] (4096 slots) master
M: 5023eb920093b0da73426572ef189d98f337023e 10.0.0.44:6379slots:[2730-6825] (4096 slots) master1 additional replica(s)
S: 334ecb1234284cfa2a60ced7c5a8d29f4cd5de10 10.0.0.40:6379slots: (0 slots) slavereplicates 5023eb920093b0da73426572ef189d98f337023e
S: 12b6dbf4fd222db57a57e0bbd42694377a107ca5 10.0.0.43:6379slots: (0 slots) slavereplicates 767c6fc628516c09dd63fe4dbdc36cecee3808b3
M: 767c6fc628516c09dd63fe4dbdc36cecee3808b3 10.0.0.42:6379slots:[12288-16383] (4096 slots) master1 additional replica(s)
M: c9b13ad218d3c8aaf62153738bb21d08a59a66c8 10.0.0.41:6379slots:[8191-12286] (4096 slots) master1 additional replica(s)
S: 637a013fee8c69a87d4ca9d503f01d3817680f4c 10.0.0.45:6379slots: (0 slots) slavereplicates c9b13ad218d3c8aaf62153738bb21d08a59a66c8
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
[root@node1 ~]#

reshard和rebalance區別:

Redis Cluster 中,reshardrebalance 都可以實現對槽(slots)的重新分配,但二者在使用場景和操作方式上有所區別:

  1. reshard
    • 命令redis-cli --cluster reshard <host>:<port>
    • 定位:手動指定要從哪些節點(源節點)移動多少個槽到目標節點。
    • 典型場景:
      • 當你想精細地控制某些節點的槽分配時,比如把部分槽從節點 A 精準地移動到節點 B,而其他節點不受影響。
      • 有些場景想只給某個新節點分配指定范圍或數量的槽,而無需動到整個集群的槽分布。
    • 操作方式:在交互式命令行中會讓你選擇:
      1. 移動多少個槽;
      2. 從哪些節點搬出槽;
      3. 把這些槽搬到哪個節點。
        然后 Redis CLI 會一步步執行遷移并進行數據復制。
  2. rebalance
    • 命令redis-cli --cluster rebalance <host>:<port>
    • 定位:自動在所有主節點之間重新平衡槽的分配,使槽盡量平均地分布在各個節點。
    • 典型場景:
      • 當新加入一個主節點,希望自動把集群里的槽分擔一部分給它,讓槽(以及數據)在所有主節點之間盡量平均。
      • 或者有些主節點負載過重,自動讓腳本來做“平均化”處理,而無需手動挑選要移動多少槽、從哪個節點移動到哪個節點。
    • 操作方式:一條命令,Redis 會掃描所有主節點的槽占用情況,嘗試讓每個節點大致擁有同樣數量的槽,并執行槽遷移和數據復制。

二者的主要區別

  1. 操作的靈活度
    • reshard:更加“手動”,可以精細化指定源節點和目標節點,以及槽的數量或范圍。適合需要對槽遷移進行自定義控制的場景。
    • rebalance:更加“自動”,Redis 自己計算出如何把槽分配得更均勻。適合大多數快速均衡場景。
  2. 使用難易程度
    • reshard:需要你逐步確認哪些節點要移動多少槽,操作繁瑣但靈活度高。
    • rebalance:一鍵式自動均衡,簡單快捷,但不能過多自定義移動細節。
  3. 應用場景
    • reshard:
      • 精確控制某些節點的負載;
      • 只想調整部分節點,而不希望影響到其他節點。
    • rebalance:
      • 新加主節點后,讓整個集群自動均衡槽分布;
      • 集群某些主節點負載嚴重不均衡,希望一鍵平衡。

總結

  • reshard:更適合精細化指定范圍單一節點的槽轉移場景。
  • rebalance:更適合全局自動化的槽再平衡場景。

在實際生產中,如果只是單純要讓新節點上線并分擔部分流量,通常用 rebalance 就夠了;如果需要對槽分配高度自定義,則可使用 reshard

14.3 為新的master添加新的slave節點

需要再向當前Redis集群中添加一個Redis單機服務器10.0.0.47,用于解決當前10.0.0.46單機的潛在宕機問題,即實現響應的高可用問題,有兩種方式:

方法1:在新節點添加到集群時,直接將之設置為slave

# 直接加為slave節點<10.0.0.47>是加入的slave節點,<10.0.0.46>是加入到的集群任意一個節點
[root@node1 ~]#redis-cli -a 123456 --cluster add-node 10.0.0.47:6379 10.0.0.46:6379 --cluster-slave --cluster-master-id c882647e71c8f3cc1b40ea20cc242fecca371cd4
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Adding node 10.0.0.47:6379 to cluster 10.0.0.46:6379
>>> Performing Cluster Check (using node 10.0.0.46:6379)
M: c882647e71c8f3cc1b40ea20cc242fecca371cd4 10.0.0.46:6379slots:[0-1364],[5461-6826],[10923-12287] (4096 slots) master
M: 5023eb920093b0da73426572ef189d98f337023e 10.0.0.44:6379slots:[1365-5460] (4096 slots) master1 additional replica(s)
S: 334ecb1234284cfa2a60ced7c5a8d29f4cd5de10 10.0.0.40:6379slots: (0 slots) slavereplicates 5023eb920093b0da73426572ef189d98f337023e
S: 12b6dbf4fd222db57a57e0bbd42694377a107ca5 10.0.0.43:6379slots: (0 slots) slavereplicates 767c6fc628516c09dd63fe4dbdc36cecee3808b3
M: 767c6fc628516c09dd63fe4dbdc36cecee3808b3 10.0.0.42:6379slots:[12288-16383] (4096 slots) master1 additional replica(s)
S: 637a013fee8c69a87d4ca9d503f01d3817680f4c 10.0.0.45:6379slots: (0 slots) slavereplicates c9b13ad218d3c8aaf62153738bb21d08a59a66c8
M: c9b13ad218d3c8aaf62153738bb21d08a59a66c8 10.0.0.41:6379slots:[6827-10922] (4096 slots) master1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
>>> Send CLUSTER MEET to node 10.0.0.47:6379 to make it join the cluster.
Waiting for the cluster to join>>> Configure node as replica of 10.0.0.46:6379.
[OK] New node added correctly.# 驗證是否成功
[root@node1 ~]#redis-cli -a 123456 cluster nodes
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
767c6fc628516c09dd63fe4dbdc36cecee3808b3 10.0.0.42:6379@16379 master - 0 1736954647000 3 connected 12288-16383
8b4c349f957e7166dc2834cc1f7109d73ee25542 10.0.0.47:6379@16379 slave c882647e71c8f3cc1b40ea20cc242fecca371cd4 0 1736954647000 8 connected #47成為了46的slave
5023eb920093b0da73426572ef189d98f337023e 10.0.0.44:6379@16379 master - 0 1736954646000 7 connected 1365-5460
12b6dbf4fd222db57a57e0bbd42694377a107ca5 10.0.0.43:6379@16379 slave 767c6fc628516c09dd63fe4dbdc36cecee3808b3 0 1736954648000 3 connected
c9b13ad218d3c8aaf62153738bb21d08a59a66c8 10.0.0.41:6379@16379 master - 0 1736954648253 2 connected 6827-10922
c882647e71c8f3cc1b40ea20cc242fecca371cd4 10.0.0.46:6379@16379 master - 0 1736954649263 8 connected 0-1364 5461-6826 10923-12287
637a013fee8c69a87d4ca9d503f01d3817680f4c 10.0.0.45:6379@16379 slave c9b13ad218d3c8aaf62153738bb21d08a59a66c8 0 1736954646000 2 connected
334ecb1234284cfa2a60ced7c5a8d29f4cd5de10 10.0.0.40:6379@16379 myself,slave 5023eb920093b0da73426572ef189d98f337023e 0 0 7 connected
meet和add-node的區別:
redis-cli --cluster add-node <new_node_host:port> <existing_node_host:port>

它其實會在內部幫你完成原生的 CLUSTER MEET <ip> <port> 操作,并且還會做一些額外的檢查和提示(比如版本兼容、集群狀態等)。也就是說:

  • redis-cli --cluster add-node ... 是一個更“高級”的封裝,一條命令即可把新節點加入集群。
  • CLUSTER MEET <ip> <port> 是 Redis Cluster 原生底層命令,屬于純手動操作方式。

二者本質上都能讓新節點與現有集群“握手”,最終效果相同。只不過,--cluster add-node 更適合對新手或追求自動化的用戶,而手動 CLUSTER MEET 方式更加原始、靈活。一般來說:

  1. 使用 --cluster add-node
    • 需要的命令更少,更自動化。
    • 如果后面還需要自動分配槽(slots),還可以直接配合 --cluster rebalance 等子命令。
  2. 使用 CLUSTER MEET
    • 需要對 Redis Cluster 有一定了解。
    • 可以配合 cluster replicate <node_id>cluster addslots 等手工方式一步步細粒度地操作。

因此,你在命令行中看到的是:

redis-cli -a 123456 --cluster add-node 10.0.0.46:6379 10.0.0.40:6379

而不是手動執行:

redis-cli -h 10.0.0.40 -p 6379 -a 123456 cluster meet 10.0.0.46 6379

方法2:先將新節點加入集群,在修改為slave

為新的master添加slave節點

# 把10.0.0.47:6379添加到集群中
[root@Rocky9 ~]# redis-cli -a 123456 --cluster add-node 10.0.0.47:6379 10.0.0.46:6379
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Adding node 10.0.0.47:6379 to cluster 10.0.0.46:6379
>>> Performing Cluster Check (using node 10.0.0.46:6379)
M: c882647e71c8f3cc1b40ea20cc242fecca371cd4 10.0.0.46:6379slots:[0-2729],[6826-8190],[12287] (4096 slots) master
M: 5023eb920093b0da73426572ef189d98f337023e 10.0.0.44:6379slots:[2730-6825] (4096 slots) master1 additional replica(s)
S: 334ecb1234284cfa2a60ced7c5a8d29f4cd5de10 10.0.0.40:6379slots: (0 slots) slavereplicates 5023eb920093b0da73426572ef189d98f337023e
S: 12b6dbf4fd222db57a57e0bbd42694377a107ca5 10.0.0.43:6379slots: (0 slots) slavereplicates 767c6fc628516c09dd63fe4dbdc36cecee3808b3
M: 767c6fc628516c09dd63fe4dbdc36cecee3808b3 10.0.0.42:6379slots:[12288-16383] (4096 slots) master1 additional replica(s)
M: c9b13ad218d3c8aaf62153738bb21d08a59a66c8 10.0.0.41:6379slots:[8191-12286] (4096 slots) master1 additional replica(s)
S: 637a013fee8c69a87d4ca9d503f01d3817680f4c 10.0.0.45:6379slots: (0 slots) slavereplicates c9b13ad218d3c8aaf62153738bb21d08a59a66c8
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
>>> Getting functions from cluster
>>> Send FUNCTION LIST to 10.0.0.47:6379 to verify there is no functions in it
>>> Send FUNCTION RESTORE to 10.0.0.47:6379
>>> Send CLUSTER MEET to node 10.0.0.47:6379 to make it join the cluster.
[OK] New node added correctly.
[root@Rocky9 ~]## 查看當前集群節點
[root@node1 ~]#redis-cli -a 123456 cluster nodes
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
767c6fc628516c09dd63fe4dbdc36cecee3808b3 10.0.0.42:6379@16379 master - 0 1736998066832 12 connected 12288-16383
8b4c349f957e7166dc2834cc1f7109d73ee25542 10.0.0.47:6379@16379 master - 0 1736998065000 0 connected #47已經加入了,但是角色是master
5023eb920093b0da73426572ef189d98f337023e 10.0.0.44:6379@16379 master - 0 1736998064814 10 connected 2730-6825
12b6dbf4fd222db57a57e0bbd42694377a107ca5 10.0.0.43:6379@16379 slave 767c6fc628516c09dd63fe4dbdc36cecee3808b3 0 1736998066000 12 connected
c9b13ad218d3c8aaf62153738bb21d08a59a66c8 10.0.0.41:6379@16379 master - 0 1736998067843 11 connected 8191-12286
c882647e71c8f3cc1b40ea20cc242fecca371cd4 10.0.0.46:6379@16379 master - 0 1736998065000 13 connected 0-2729 6826-8190 12287
637a013fee8c69a87d4ca9d503f01d3817680f4c 10.0.0.45:6379@16379 slave c9b13ad218d3c8aaf62153738bb21d08a59a66c8 0 1736998066000 11 connected
334ecb1234284cfa2a60ced7c5a8d29f4cd5de10 10.0.0.40:6379@16379 myself,slave 5023eb920093b0da73426572ef189d98f337023e 0 0 10 connected
[root@node1 ~]#

更改新節點狀態為slave:

需要手動將其指定為某個master的slave,否則其默認角色為master。

redis-cli -h <新節點IP> -p <新節點端口> \cluster replicate <目標主節點ID>
[root@Rocky9 ~]# redis-cli -a 123456 -h 10.0.0.47 -p 6379
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
10.0.0.47:6379> CLUSTER NODES
637a013fee8c69a87d4ca9d503f01d3817680f4c 10.0.0.45:6379@16379 slave c9b13ad218d3c8aaf62153738bb21d08a59a66c8 0 1736998213000 11 connected
c882647e71c8f3cc1b40ea20cc242fecca371cd4 10.0.0.46:6379@16379 master - 0 1736998213000 13 connected 0-2729 6826-8190 12287
12b6dbf4fd222db57a57e0bbd42694377a107ca5 10.0.0.43:6379@16379 slave 767c6fc628516c09dd63fe4dbdc36cecee3808b3 0 1736998214000 12 connected
334ecb1234284cfa2a60ced7c5a8d29f4cd5de10 10.0.0.40:6379@16379 slave 5023eb920093b0da73426572ef189d98f337023e 0 1736998216178 10 connected
c9b13ad218d3c8aaf62153738bb21d08a59a66c8 10.0.0.41:6379@16379 master - 0 1736998215167 11 connected 8191-12286
8b4c349f957e7166dc2834cc1f7109d73ee25542 10.0.0.47:6379@16379 myself,master - 0 0 0 connected # master
767c6fc628516c09dd63fe4dbdc36cecee3808b3 10.0.0.42:6379@16379 master - 0 1736998214000 12 connected 12288-16383
5023eb920093b0da73426572ef189d98f337023e 10.0.0.44:6379@16379 master - 0 1736998214156 10 connected 2730-6825
10.0.0.47:6379> CLUSTER REPLICATE c882647e71c8f3cc1b40ea20cc242fecca371cd4 #將其設為slave,命令格式 cluster replicate MASTERID
OK
10.0.0.47:6379> CLUSTER NODES
637a013fee8c69a87d4ca9d503f01d3817680f4c 10.0.0.45:6379@16379 slave c9b13ad218d3c8aaf62153738bb21d08a59a66c8 0 1736998293993 11 connected
c882647e71c8f3cc1b40ea20cc242fecca371cd4 10.0.0.46:6379@16379 master - 0 1736998291000 13 connected 0-2729 6826-8190 12287
12b6dbf4fd222db57a57e0bbd42694377a107ca5 10.0.0.43:6379@16379 slave 767c6fc628516c09dd63fe4dbdc36cecee3808b3 0 1736998294000 12 connected
334ecb1234284cfa2a60ced7c5a8d29f4cd5de10 10.0.0.40:6379@16379 slave 5023eb920093b0da73426572ef189d98f337023e 0 1736998291000 10 connected
c9b13ad218d3c8aaf62153738bb21d08a59a66c8 10.0.0.41:6379@16379 master - 0 1736998295006 11 connected 8191-12286
8b4c349f957e7166dc2834cc1f7109d73ee25542 10.0.0.47:6379@16379 myself,slave c882647e71c8f3cc1b40ea20cc242fecca371cd4 0 0 13 connected # 是46的slave
767c6fc628516c09dd63fe4dbdc36cecee3808b3 10.0.0.42:6379@16379 master - 0 1736998293000 12 connected 12288-16383
5023eb920093b0da73426572ef189d98f337023e 10.0.0.44:6379@16379 master - 0 1736998292982 10 connected 2730-6825
10.0.0.47:6379>

15.Redis cluster集群動態縮容

實戰案例:

由于10.0.0.46服務器使用年限已經超過三年,已經超過廠商質保期而且硬盤出現異常報警,經運維部架構師提交方案并同開發同事開會商議,決定將現有Redis集群的8臺主服務器中的master 10.0.0.46和對應的slave 10.0.0.47 臨時下線,三臺服務器的并發寫入性能足夠支出未來1-2年的業務需求。

刪除節點過程:

添加節點的時候是先添加node節點到集群,然后分配槽位,刪除節點的操作與添加節點的操作正好相反,是先將被刪除的Redis node上的槽位遷移到集群中的其他Redis node節點上,然后再將其刪除,如果一個Redis node節點上的槽位沒有完全被遷移,刪除該node的時候會提示有數據且無法刪除。

在 Redis Cluster 中,如果打算縮容(移除一個主節點),需要先把該節點上所有槽 (slots) 和數據遷移到其它主節點,然后再執行刪除操作。

15.1 遷移master的槽位至其他master節點

方法1:手動遷移

# 查看集群節點
[root@node1 ~]#redis-cli -a 123456 cluster nodes
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
767c6fc628516c09dd63fe4dbdc36cecee3808b3 10.0.0.42:6379@16379 master - 0 1737090417358 12 connected 12288-16383
8b4c349f957e7166dc2834cc1f7109d73ee25542 10.0.0.47:6379@16379 slave c882647e71c8f3cc1b40ea20cc242fecca371cd4 0 1737090416000 13 connected #要刪除的slave節點
5023eb920093b0da73426572ef189d98f337023e 10.0.0.44:6379@16379 master - 0 1737090415000 10 connected 2730-6825
12b6dbf4fd222db57a57e0bbd42694377a107ca5 10.0.0.43:6379@16379 slave 767c6fc628516c09dd63fe4dbdc36cecee3808b3 0 1737090416346 12 connected
c9b13ad218d3c8aaf62153738bb21d08a59a66c8 10.0.0.41:6379@16379 slave 637a013fee8c69a87d4ca9d503f01d3817680f4c 0 1737090418370 14 connected
c882647e71c8f3cc1b40ea20cc242fecca371cd4 10.0.0.46:6379@16379 master - 0 1737090414000 13 connected 0-2729 6826-8190 12287 #要刪除的master節點
637a013fee8c69a87d4ca9d503f01d3817680f4c 10.0.0.45:6379@16379 master - 0 1737090416000 14 connected 8191-12286
334ecb1234284cfa2a60ced7c5a8d29f4cd5de10 10.0.0.40:6379@16379 myself,slave 5023eb920093b0da73426572ef189d98f337023e 0 0 10 connected
# 查看當前狀態
[root@Rocky9 ~]# redis-cli -a 123456 --cluster check 10.0.0.46:6379
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
10.0.0.46:6379 (c882647e...) -> 2506 keys | 4096 slots | 1 slaves.
10.0.0.44:6379 (5023eb92...) -> 2494 keys | 4096 slots | 1 slaves.
10.0.0.42:6379 (767c6fc6...) -> 2500 keys | 4096 slots | 1 slaves.
10.0.0.45:6379 (637a013f...) -> 2500 keys | 4096 slots | 1 slaves.
[OK] 10000 keys in 4 masters.
0.61 keys per slot on average.
>>> Performing Cluster Check (using node 10.0.0.46:6379)
M: c882647e71c8f3cc1b40ea20cc242fecca371cd4 10.0.0.46:6379slots:[0-2729],[6826-8190],[12287] (4096 slots) master # 46master節點slot的范圍1 additional replica(s)
S: 8b4c349f957e7166dc2834cc1f7109d73ee25542 10.0.0.47:6379slots: (0 slots) slavereplicates c882647e71c8f3cc1b40ea20cc242fecca371cd4
M: 5023eb920093b0da73426572ef189d98f337023e 10.0.0.44:6379slots:[2730-6825] (4096 slots) master1 additional replica(s)
S: 334ecb1234284cfa2a60ced7c5a8d29f4cd5de10 10.0.0.40:6379slots: (0 slots) slavereplicates 5023eb920093b0da73426572ef189d98f337023e
S: 12b6dbf4fd222db57a57e0bbd42694377a107ca5 10.0.0.43:6379slots: (0 slots) slavereplicates 767c6fc628516c09dd63fe4dbdc36cecee3808b3
M: 767c6fc628516c09dd63fe4dbdc36cecee3808b3 10.0.0.42:6379slots:[12288-16383] (4096 slots) master1 additional replica(s)
S: c9b13ad218d3c8aaf62153738bb21d08a59a66c8 10.0.0.41:6379slots: (0 slots) slavereplicates 637a013fee8c69a87d4ca9d503f01d3817680f4c
M: 637a013fee8c69a87d4ca9d503f01d3817680f4c 10.0.0.45:6379slots:[8191-12286] (4096 slots) master1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.# 連接到任意集群節點,4096/3=1365(約等于)平均每個節點應該分配1365個槽位
# 1.將1365個slot從10.0.0.46移動到10.0.0.44上(這樣移動的原因是44的槽位是從[2730-6825],而46的第一部分槽位是從[0-2729],所以這樣就連續住了)
[root@Rocky9 ~]# redis-cli -a 123456 --cluster reshard 10.0.0.46:6379
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Performing Cluster Check (using node 10.0.0.46:6379)
# 分片之前會自動檢查當前集群的節點信息(包括槽位的區間,node id,槽位的個數,slave對應master)
M: c882647e71c8f3cc1b40ea20cc242fecca371cd4 10.0.0.46:6379slots:[0-2729],[6826-8190],[12287] (4096 slots) master1 additional replica(s)
S: 8b4c349f957e7166dc2834cc1f7109d73ee25542 10.0.0.47:6379slots: (0 slots) slavereplicates c882647e71c8f3cc1b40ea20cc242fecca371cd4
M: 5023eb920093b0da73426572ef189d98f337023e 10.0.0.44:6379slots:[2730-6825] (4096 slots) master1 additional replica(s)
S: 334ecb1234284cfa2a60ced7c5a8d29f4cd5de10 10.0.0.40:6379slots: (0 slots) slavereplicates 5023eb920093b0da73426572ef189d98f337023e
S: 12b6dbf4fd222db57a57e0bbd42694377a107ca5 10.0.0.43:6379slots: (0 slots) slavereplicates 767c6fc628516c09dd63fe4dbdc36cecee3808b3
M: 767c6fc628516c09dd63fe4dbdc36cecee3808b3 10.0.0.42:6379slots:[12288-16383] (4096 slots) master1 additional replica(s)
S: c9b13ad218d3c8aaf62153738bb21d08a59a66c8 10.0.0.41:6379slots: (0 slots) slavereplicates 637a013fee8c69a87d4ca9d503f01d3817680f4c
M: 637a013fee8c69a87d4ca9d503f01d3817680f4c 10.0.0.45:6379slots:[8191-12286] (4096 slots) master1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
How many slots do you want to move (from 1 to 16384)? 1365 #本次要遷移槽位的個數
What is the receiving node ID? 5023eb920093b0da73426572ef189d98f337023e #接收槽位的主節點的id
Please enter all the source node IDs.Type 'all' to use all the nodes as source nodes for the hash slots.Type 'done' once you entered all the source nodes IDs.
Source node #1: c882647e71c8f3cc1b40ea20cc242fecca371cd4 #源主節點的id
Source node #2: done #輸入doneReady to move 1365 slots.Source nodes:M: c882647e71c8f3cc1b40ea20cc242fecca371cd4 10.0.0.46:6379slots:[0-2729],[6826-8190],[12287] (4096 slots) master1 additional replica(s)Destination node:M: 5023eb920093b0da73426572ef189d98f337023e 10.0.0.44:6379slots:[2730-6825] (4096 slots) master1 additional replica(s)Resharding plan:Moving slot 0 from c882647e71c8f3cc1b40ea20cc242fecca371cd4
......Moving slot 1364 from c882647e71c8f3cc1b40ea20cc242fecca371cd4
Do you want to proceed with the proposed reshard plan (yes/no)?yes #輸入yes
Moving slot 0 from 10.0.0.46:6379 to 10.0.0.44:6379: ..
......
Moving slot 1364 from 10.0.0.46:6379 to 10.0.0.44:6379:#非交互的方式
#再將1365個slot從10.0.0.46移動到第二個master節點10.0.0.45上
[root@Rocky9 ~]# redis-cli -a 123456 --cluster reshard 10.0.0.46:6379 --cluster-slots 1365 --cluster-from c882647e71c8f3cc1b40ea20cc242fecca371cd4 --cluster-to 637a013fee8c69a87d4ca9d503f01d3817680f4c --cluster-yes# 最后的slot從10.0.0.46移動到第三個master節點10.0.0.42上
[root@Rocky9 ~]#redis-cli -a 123456 --cluster reshard 10.0.0.46:6379 --cluster-slots 1366 --cluster-from c882647e71c8f3cc1b40ea20cc242fecca371cd4 --cluster-to 767c6fc628516c09dd63fe4dbdc36cecee3808b3 --cluster-yes#確認10.0.0.46的所有slot都移走了,并且在7系列版本中master自動會變成slave,并且之前它的slave,一起變成其他master的slave
[root@node1 ~]#redis-cli -a 123456 cluster nodes
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
767c6fc628516c09dd63fe4dbdc36cecee3808b3 10.0.0.42:6379@16379 master - 0 1737093990000 17 connected 6826-8190 12287-16383
8b4c349f957e7166dc2834cc1f7109d73ee25542 10.0.0.47:6379@16379 slave 767c6fc628516c09dd63fe4dbdc36cecee3808b3 0 1737093990641 17 connected #自動切換成42的slave
5023eb920093b0da73426572ef189d98f337023e 10.0.0.44:6379@16379 master - 0 1737093991650 15 connected 0-1364 2730-6825
12b6dbf4fd222db57a57e0bbd42694377a107ca5 10.0.0.43:6379@16379 slave 767c6fc628516c09dd63fe4dbdc36cecee3808b3 0 1737093992660 17 connected
c9b13ad218d3c8aaf62153738bb21d08a59a66c8 10.0.0.41:6379@16379 slave 637a013fee8c69a87d4ca9d503f01d3817680f4c 0 1737093989000 16 connected
c882647e71c8f3cc1b40ea20cc242fecca371cd4 10.0.0.46:6379@16379 slave 767c6fc628516c09dd63fe4dbdc36cecee3808b3 0 1737093991000 17 connected #切換成42的slave
637a013fee8c69a87d4ca9d503f01d3817680f4c 10.0.0.45:6379@16379 master - 0 1737093991000 16 connected 1365-2729 8191-12286
334ecb1234284cfa2a60ced7c5a8d29f4cd5de10 10.0.0.40:6379@16379 myself,slave 5023eb920093b0da73426572ef189d98f337023e 0 0 15 connected
[root@node1 ~]#redis-cli -a 123456 --cluster check 10.0.0.40:6379
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
10.0.0.42:6379 (767c6fc6...) -> 3345 keys | 5462 slots | 3 slaves.
10.0.0.44:6379 (5023eb92...) -> 3314 keys | 5461 slots | 1 slaves.
10.0.0.45:6379 (637a013f...) -> 3341 keys | 5461 slots | 1 slaves.
[OK] 10000 keys in 3 masters.
0.61 keys per slot on average.
>>> Performing Cluster Check (using node 10.0.0.40:6379)
S: 334ecb1234284cfa2a60ced7c5a8d29f4cd5de10 10.0.0.40:6379slots: (0 slots) slavereplicates 5023eb920093b0da73426572ef189d98f337023e
M: 767c6fc628516c09dd63fe4dbdc36cecee3808b3 10.0.0.42:6379slots:[6826-8190],[12287-16383] (5462 slots) master3 additional replica(s)
S: 8b4c349f957e7166dc2834cc1f7109d73ee25542 10.0.0.47:6379slots: (0 slots) slavereplicates 767c6fc628516c09dd63fe4dbdc36cecee3808b3
M: 5023eb920093b0da73426572ef189d98f337023e 10.0.0.44:6379slots:[0-1364],[2730-6825] (5461 slots) master1 additional replica(s)
S: 12b6dbf4fd222db57a57e0bbd42694377a107ca5 10.0.0.43:6379slots: (0 slots) slavereplicates 767c6fc628516c09dd63fe4dbdc36cecee3808b3
S: c9b13ad218d3c8aaf62153738bb21d08a59a66c8 10.0.0.41:6379slots: (0 slots) slavereplicates 637a013fee8c69a87d4ca9d503f01d3817680f4c
S: c882647e71c8f3cc1b40ea20cc242fecca371cd4 10.0.0.46:6379slots: (0 slots) slavereplicates 767c6fc628516c09dd63fe4dbdc36cecee3808b3
M: 637a013fee8c69a87d4ca9d503f01d3817680f4c 10.0.0.45:6379slots:[1365-2729],[8191-12286] (5461 slots) master1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.# 查看42的主從復制情況,有三個slave
[root@node1 ~]#redis-cli -a 123456 -h 10.0.0.42 info replication
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
# Replication
role:master
connected_slaves:3
slave0:ip=10.0.0.43,port=6379,state=online,offset=488319,lag=0
slave1:ip=10.0.0.46,port=6379,state=online,offset=488319,lag=0
slave2:ip=10.0.0.47,port=6379,state=online,offset=488319,lag=1
master_failover_state:no-failover
master_replid:b4e315107bb91caf6f49e76488cf53329f776ab5
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:488319
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:488319
[root@node1 ~]#
# 查看集群情況
[root@node1 ~]#redis-cli -a 123456 -h 10.0.0.40 --no-auth-warning cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:8
cluster_size:3 #有3個主節點
cluster_current_epoch:17
cluster_my_epoch:15
cluster_stats_messages_ping_sent:135374
cluster_stats_messages_pong_sent:128159
cluster_stats_messages_fail_sent:7
cluster_stats_messages_update_sent:2
cluster_stats_messages_sent:263542
cluster_stats_messages_ping_received:128157
cluster_stats_messages_pong_received:151740
cluster_stats_messages_meet_received:2
cluster_stats_messages_fail_received:2
cluster_stats_messages_auth-req_received:1
cluster_stats_messages_update_received:1
cluster_stats_messages_received:279903
total_cluster_links_buffer_limit_exceeded:0
[root@node1 ~]#

方法2:自動遷移

[root@Rocky9 ~]# redis-cli -a 123456 --cluster rebalance 10.0.0.40:6379 --cluster-weight c882647e71c8f3cc1b40ea20cc242fecca371cd4=0 --cluster-use-empty-masters
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Performing Cluster Check (using node 10.0.0.40:6379)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
>>> Rebalancing across 4 nodes. Total weight = 3.00
Moving 1366 slots from 10.0.0.46:6379 to 10.0.0.42:6379
###################################################################################################################################################################
......
Moving 1365 slots from 10.0.0.46:6379 to 10.0.0.44:6379
###################################################################################################################################################################
......
Moving 1365 slots from 10.0.0.46:6379 to 10.0.0.45:6379
###################################################################################################################################################################
......
[root@Rocky9 ~]# redis-cli -a 123456 -h 10.0.0.40 -p 6379 cluster nodes
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
767c6fc628516c09dd63fe4dbdc36cecee3808b3 10.0.0.42:6379@16379 master - 0 1737105281417 19 connected 0-1365 12288-16383
8b4c349f957e7166dc2834cc1f7109d73ee25542 10.0.0.47:6379@16379 slave 637a013fee8c69a87d4ca9d503f01d3817680f4c 0 1737105278000 21 connected
5023eb920093b0da73426572ef189d98f337023e 10.0.0.44:6379@16379 master - 0 1737105277383 20 connected 1366-6826
12b6dbf4fd222db57a57e0bbd42694377a107ca5 10.0.0.43:6379@16379 slave 767c6fc628516c09dd63fe4dbdc36cecee3808b3 0 1737105279000 19 connected
c9b13ad218d3c8aaf62153738bb21d08a59a66c8 10.0.0.41:6379@16379 slave 637a013fee8c69a87d4ca9d503f01d3817680f4c 0 1737105280000 21 connected
c882647e71c8f3cc1b40ea20cc242fecca371cd4 10.0.0.46:6379@16379 slave 637a013fee8c69a87d4ca9d503f01d3817680f4c 0 1737105280409 21 connected
637a013fee8c69a87d4ca9d503f01d3817680f4c 10.0.0.45:6379@16379 master - 0 1737105278000 21 connected 6827-12287
334ecb1234284cfa2a60ced7c5a8d29f4cd5de10 10.0.0.40:6379@16379 myself,slave 5023eb920093b0da73426572ef189d98f337023e 0 0 20 connected
[root@Rocky9 ~]#

--cluster-weight <NodeID>=0 :將節點的權重設為 0,表示不要給它分配槽,并把它目前所有槽都遷走。

--cluster-use-empty-masters :允許將新的空節點或指定節點也被納入 rebalance 的考量之中。

在 rebalance 過程中,Redis 會把該節點上的全部槽遷移到其他主節點上(取決于當前集群狀態,可能會平均遷移到多個節點)。

15.2 從集群刪除節點

雖然槽位已經遷移完成了,但是服務器IP信息還在集群當中,因此還需要將IP信息從集群中刪除

注意:刪除服務器前,必須清除主機上面的槽位,否則會刪除失敗。

# redis-cli -a 123456 --cluster del-node 10.0.0.40:6379 <NodeID_of_46>
[root@Rocky9 ~]# redis-cli -a 123456 --cluster del-node 10.0.0.46:6379 c882647e71c8f3cc1b40ea20cc242fecca371cd4
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Removing node c882647e71c8f3cc1b40ea20cc242fecca371cd4 from cluster 10.0.0.46:6379
>>> Sending CLUSTER FORGET messages to the cluster...
>>> Sending CLUSTER RESET SOFT to the deleted node.

15.3 刪除多余的slave節點

[root@Rocky9 ~]# redis-cli -a 123456 --cluster del-node 10.0.0.47:6379 8b4c349f957e7166dc2834cc1f7109d73ee25542
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Removing node 8b4c349f957e7166dc2834cc1f7109d73ee25542 from cluster 10.0.0.47:6379
>>> Sending CLUSTER FORGET messages to the cluster...
>>> Sending CLUSTER RESET SOFT to the deleted node.# 查看集群節點(46和47都沒有了)
[root@node1 ~]#redis-cli -a 123456 cluster nodes
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
767c6fc628516c09dd63fe4dbdc36cecee3808b3 10.0.0.42:6379@16379 master - 0 1737101127000 17 connected 6826-8190 12287-16383
5023eb920093b0da73426572ef189d98f337023e 10.0.0.44:6379@16379 master - 0 1737101128171 15 connected 0-1364 2730-6825
12b6dbf4fd222db57a57e0bbd42694377a107ca5 10.0.0.43:6379@16379 slave 767c6fc628516c09dd63fe4dbdc36cecee3808b3 0 1737101127159 17 connected
c9b13ad218d3c8aaf62153738bb21d08a59a66c8 10.0.0.41:6379@16379 slave 637a013fee8c69a87d4ca9d503f01d3817680f4c 0 1737101127000 16 connected
637a013fee8c69a87d4ca9d503f01d3817680f4c 10.0.0.45:6379@16379 master - 0 1737101125139 16 connected 1365-2729 8191-12286
334ecb1234284cfa2a60ced7c5a8d29f4cd5de10 10.0.0.40:6379@16379 myself,slave 5023eb920093b0da73426572ef189d98f337023e 0 0 15 connected
[root@node1 ~]#

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/66423.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/66423.shtml
英文地址,請注明出處:http://en.pswp.cn/web/66423.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

使用Flask和Pydantic實現參數驗證

使用Flask和Pydantic實現參數驗證 1 簡介 Pydantic是一個用于數據驗證和解析的 Python 庫&#xff0c;版本2的性能有較大提升&#xff0c;很多框架使用Pydantic做數據校驗。 # 官方參考文檔 https://docs.pydantic.dev/latest/# Github地址 https://github.com/pydantic/pyd…

ScratchLLMStepByStep:訓練自己的Tokenizer

1. 引言 分詞器是每個大語言模型必不可少的組件&#xff0c;但每個大語言模型的分詞器幾乎都不相同。如果要訓練自己的分詞器&#xff0c;可以使用huggingface的tokenizers框架&#xff0c;tokenizers包含以下主要組件&#xff1a; Tokenizer: 分詞器的核心組件&#xff0c;定…

C# OpenCvSharp 部署3D人臉重建3DDFA-V3

目錄 說明 效果 模型信息 landmark.onnx net_recon.onnx net_recon_mbnet.onnx retinaface_resnet50.onnx 項目 代碼 下載 參考 C# OpenCvSharp 部署3D人臉重建3DDFA-V3 說明 地址&#xff1a;https://github.com/wang-zidu/3DDFA-V3 3DDFA_V3 uses the geometri…

從零開始學數據庫 day2 DML

從零開始學數據庫&#xff1a;DML操作詳解 在今天的數字化時代&#xff0c;數據庫的使用已經成為了各行各業的必備技能。無論你是想開發一個簡單的應用&#xff0c;還是想要管理復雜的數據&#xff0c;掌握數據庫的基本操作都是至關重要的。在這篇博客中&#xff0c;我們將專注…

Java 8 Stream API

文章目錄 Java 8 Stream API1. Stream2. Stream 的創建3. 常見的 Stream 操作3.1 中間操作3.2 終止操作 4. Stream 的并行操作 Java 8 Stream API Java 8 引入了 Stream API&#xff0c;使得對集合類&#xff08;如 List、Set 等&#xff09;的操作變得更加簡潔和直觀。Stream…

運行fastGPT 第五步 配置FastGPT和上傳知識庫 打造AI客服

運行fastGPT 第五步 配置FastGPT和上傳知識庫 打造AI客服 根據上一步的步驟&#xff0c;已經調試了ONE API的接口&#xff0c;下面&#xff0c;我們就登陸fastGPT吧 http://xxx.xxx.xxx.xxx:3000/ 這個就是你的fastGPT后臺地址&#xff0c;可以在configer文件中找到。 賬號是…

第4章 Kafka核心API——Kafka客戶端操作

Kafka客戶端操作 一. 客戶端操作1. AdminClient API 一. 客戶端操作 1. AdminClient API

【王樹森搜索引擎技術】相關性02:評價指標(AUC、正逆序比、DCG)

相關性的評價指標 Pointwise評價指標&#xff1a;Area Under the Curve&#xff08;AUC&#xff09;Pairwise評價指標&#xff1a;正逆序比&#xff08;Positive to Negative Ratio, PNR&#xff09;Listwise評價指標&#xff1a;Discounted Cumulative Gain(DCG)用AUC和PNR作…

人物一致性訓練測評數據集

1.Pulid 訓練:由1.5M張從互聯網收集的高質量人類圖像組成,圖像標題由blip2自動生成。 測試:從互聯網上收集了一個多樣化的肖像測試集,該數據集涵蓋了多種膚色、年齡和性別,共計120張圖像,我們稱之為DivID-120,作為補充資源,還使用了最近開源的測試集Unsplash-50,包含…

Android 項目依賴沖突問題:Duplicate class found in modules

問題描述與處理處理 1、問題描述 plugins {id com.android.application }android {compileSdk 34defaultConfig {applicationId "com.my.dialog"minSdk 21targetSdk 34versionCode 1versionName "1.0"testInstrumentationRunner "androidx.test.run…

計算機網絡 | 什么是公網、私網、NAT?

關注&#xff1a;CodingTechWork 引言 計算機網絡是現代信息社會的基石&#xff0c;而網絡通信的順暢性和安全性依賴于有效的IP地址管理和網絡轉換機制。在網絡中&#xff0c;IP地址起到了標識設備和進行數據傳輸的核心作用。本文將詳細討論公網IP、私網IP以及NAT轉換等網絡技…

python+django+Nacos實現配置動態更新-集中管理配置(實現mysql配置動態讀取及動態更新)

一、docker-compose.yml 部署nacos服務 version: "3" services:mysql:container_name: mysql# 5.7image: mysql:5.7environment:# mysql root用戶密碼MYSQL_ROOT_PASSWORD: rootTZ: Asia/Shanghai# 初始化數據庫(后續的初始化sql會在這個庫執行)MYSQL_DATABASE: nac…

深度學習項目--基于LSTM的火災預測研究(pytorch實現)

&#x1f368; 本文為&#x1f517;365天深度學習訓練營 中的學習記錄博客&#x1f356; 原作者&#xff1a;K同學啊 前言 LSTM模型一直是一個很經典的模型&#xff0c;這個模型當然也很復雜&#xff0c;一般需要先學習RNN、GRU模型之后再學&#xff0c;GRU、LSTM的模型講解將…

基于 WEB 開發的汽車養護系統設計與實現

標題:基于 WEB 開發的汽車養護系統設計與實現 內容:1.摘要 本文介紹了基于 WEB 開發的汽車養護系統的設計與實現。文章首先闡述了系統的背景和目的&#xff0c;即隨著汽車保有量的增加&#xff0c;汽車養護需求日益增長&#xff0c;傳統的汽車養護方式已經無法滿足人們的需求&…

GitLab集成Jira

GitLab與Jira集成的兩種方式 GitLab 提供了兩種 Jira 集成&#xff0c;即Jira議題集成和Jira開發面板集成&#xff0c;可以配置一個或者兩個都配置。 具體集成步驟可以參考官方文檔Jira 議題集成&#xff08;極狐GitLab文檔&#xff09;和Jira 開發面板集成&#xff08;極狐G…

【爬蟲】某某查cookie逆向

代碼僅供技術人員進行學習和研究使用&#xff0c;請勿將其用于非法用途或以任何方式竊取第三方數據。使用該代碼產生的所有風險均由用戶自行承擔&#xff0c;作者不對用戶因使用該代碼而造成的任何損失或損害承擔任何責任。 加密參數 加密參數主要是cookie&#xff0c;其中只有…

A5.Springboot-LLama3.2服務自動化構建(二)——Jenkins流水線構建配置初始化設置

下面我們接著上一篇文章《A4.Springboot-LLama3.2服務自動化構建(一)——構建docker鏡像配置》繼續往下分析,在自動化流水線構建過程當中的相關初始化設置和腳本編寫。 一、首先需要先安裝Jenkins 主部分請參考我前面寫的一篇文章《Jenkins持續集成與交付安裝配置》 二、…

如何設置HTTPS站點防御?

設置HTTPS站點防御涉及到多個層面的安全措施&#xff0c;包括但不限于配置Web服務器、應用安全頭信息、使用內容安全策略&#xff08;CSP&#xff09;、啟用HSTS和OCSP Stapling等。下面是一些關鍵的步驟來增強HTTPS網站的安全性&#xff1a; 1. 使用強加密協議和密鑰交換算法…

[Java]類和對象

1. 什么是類&#xff1f; 類&#xff08;Class&#xff09;是藍圖或者模板。它定義了對象的屬性和行為。 類就是一種抽象的模板&#xff0c;你可以通過它創建多個對象。類定義了對象的屬性&#xff08;變量&#xff09;和行為&#xff08;方法&#xff09;。我們可以把類理解…

win32匯編環境,窗口程序中基礎列表框的應用舉例

;運行效果 ;win32匯編環境,窗口程序中基礎列表框的應用舉例 ;比如在窗口程序中生成列表框&#xff0c;增加子項&#xff0c;刪除某項&#xff0c;取得指定項內容等 ;直接抄進RadAsm可編譯運行。重點部分加備注。 ;以下是ASM文件 ;>>>>>>>>>>>…