Redis學習筆記(十七) 集群(上)

来源:https://www.cnblogs.com/xtt321/archive/2020/06/09/13081491.html
-Advertisement-
Play Games

Redis集群是Redis提供的分散式資料庫方案,集群通過分片來進行數據共用,並提供複製和故障轉移操作。 一個Redis集群通常由多個節點組成,在剛開始的時候每個節點都是相互獨立的,他們處於一個只包含自己的集群當中,我們通過使用CLUSTER MEET命令將節點連接到一起,構成一個包含多節點的集群。 ...


Redis集群是Redis提供的分散式資料庫方案,集群通過分片來進行數據共用,並提供複製和故障轉移操作。

一個Redis集群通常由多個節點組成,在剛開始的時候每個節點都是相互獨立的,他們處於一個只包含自己的集群當中,我們通過使用CLUSTER MEET命令將節點連接到一起,構成一個包含多節點的集群。

 

集群的數據結構:

clusterNode結構保存了一個節點的當前狀態,比如節點創建時間、節點名稱、節點當前的配置紀元、節點的ip埠。每個節點都會使用一個clusterNode結構記錄自己的狀態,併為集群中的所有其他節點都創建一個相應的clusterNode結構。

struct clusterNode{
//創建節點的時間
mstime_t ctime;
//節點的名稱,由40個十六進位字元組成
char name[REDIS_C:USTER_NAMELEN]
//節點標識(標識節點的角色以及節點目前狀態)
inf flags;
//節點當前的配置紀元
uint64_t configEpochl;
//節點的ip地址
char ip;
//節點的埠號
int port;
//保存連接節點所需要的有關信息
clusterLink *link;
}
typedef struct clusterLink{
//連接的創建時間
mstime_t ctime;
//TCP  套接字描述
int fd;
//輸出緩衝區,保存著等待發送給其他節點的消息
sds sndbuf;
//輸入緩衝區,保存著從其他節點接收到的消息
sds rcvbuf;
//與這個連接相關聯的節點,如果沒有的話為NULL
struct clusterNode *node;
} clusterLink;

每個節點都保存著一個clusterState結構,這個結構記錄了在當前節點的視角下,集群目前所處的狀態,

typedef struct clusterState{
//指向當前節點的指針
clusterNode *myself;
//集群當前的配置紀元,用於實現故障轉移。
uint64_t currentEpoch;
//集群當前的狀態:線上或下線
int state;
//集群中至少處理著一個槽的節點數量
int size;
//集群節點名單(包括myself節點) 
//字典的鍵為節點的名稱,字典值為節點對應的clusterNode結構
dict *node;
} clusterState;

槽指派:

Redis集群通過分片的方式來保存資料庫中的鍵值對:集群的整個資料庫被分成16348個槽,資料庫中的每個鍵都屬於16384個槽的其中一個,集群中的每個節點可以處理0個最多16384個槽。

使用cluster meet 命令將節點連接到集群裡面後,這時集群仍處於下線狀態,因為集群中的節點沒有處理任何槽

通過使用cluster addslots < slot > 命令,可以為節點分配槽

記錄節點的槽指派信息:

clusterNode 結構的slots屬性和numslot屬性記錄了節點負責處理那些槽:

struct clusterNode{
unsigned char slots[16348/8];
int numslots;
};

同時,節點會將自己的slots數組通過消息發送給集群中的其他節點,以此來告知其他節點自己目前負責處理那些槽。

clusterState結構中的slots數組記錄了集群中所有16384個槽的指派信息。

typedef struct clusterState{
clusterNode *slots[16384];
}clusterState;

clusterState.slots是為了更快的定位槽所在的節點O(i)。

clusterNode.slots 當程式需要將某個節點的槽指派信息通過消息發送給其他節點時,程式只需要將相應節點的clusterNode.slots數組整個發送過去就可以,clusterState.slots記錄了集群中所有的槽指派訊息,而clusterNode.slots只記錄了當前節點的槽指派信息。

當客戶端向節點發送與資料庫鍵有關的命令時,接收命令的節點會計算出命令要處理的資料庫鍵屬於哪個槽,並檢查這個槽是否指派給了自己:

如果鍵所在的槽正好是指派給了當前節點,那麼節點直接執行這個命令;如果鍵所在的槽並沒有指派給當前節點,那麼節點會向客戶端返回一個MOVED錯誤,指引客戶端轉向到正確節點,並再次發送之前想要執行的命令。

節點使用以下演算法來計算給定鍵key屬於哪個槽:

def slot_number(key):
return CRC16(key) & 16383

當節點計算出鍵所屬的槽i之後,節點就會檢查自己在clusterState.slots數組中的項i,判斷所在的槽是否由自己負責:如果clusterState.slots[i]等於clusterState.myself,那麼說明槽i由當前節點負責,節點可以執行客戶端發送的命令;反之節點會根據slusterState.slots[i]指向的clusterNode結構所記錄的節點IP和埠號,向客戶端返回MOVED錯誤指引客戶端轉向至再處理槽i的節點。

MOVED錯誤的格式為:MOVED < slot > <ip>:<port>

當客戶端接收到節點返回的MOVED錯誤時,客戶端根據MOVED錯誤提供的IP地址和埠號,轉向至負責處理槽slot的節點,並向該節點重新發送之前想要執行的命令。一個集群客戶端通常會與集群中的多個節點創建套接字連接,而所謂的節點轉向實際上就是換一個套接字來發送命令。

集群模式的redis-cli 客戶端在接收到MOVED錯誤時,並不會列印出MOVED錯誤,而是根據MOVED錯誤自動進行節點轉向,並列印出轉向信息,所以我們時看不見節點返回的MOVED錯誤。

節點和單機伺服器在資料庫方面的一個區別時,節點只能使用0號資料庫,而單機Redis伺服器則沒有這一限制。除了將鍵值對保存在資料庫裡面之外,節點還會用clusterState結構中slots_to_keys跳躍表來保存槽和鍵之間的關係:

typedef struct clusterState{
zskiplist *slots_to_keys;
} clusterState;

slots_to_keys跳躍表每個節點的分值score都是一個槽號,而每個節點的成員(member)都是一個資料庫鍵:每當節點往資料庫中添加一個新的鍵值對時,節點就會將這個鍵以及鍵的槽號關聯到slots_to_keys跳躍表;當節點刪除資料庫中的每個鍵值對時,節點就會在slots_to_keys跳躍表解除被刪除鍵與槽號的關聯。

通過在slots_to_keys跳躍表中記錄各個資料庫鍵所屬的槽,節點可以很方便地對屬於某個或某些槽的所有資料庫鍵進行批量操作。

Redis集群的重新分片操作可以將任意數量已經指派給某個節點(源節點)的槽改為指派給另一個節點,並且相關槽所屬的鍵值對也會從源節點被移動到目標節點。重新分派操作可以線上進行,在重新分片的過程中,集群不需要下線,並且源節點和目標節點都可以繼續處理命令請求。

Redis集群的重新分片操作是由Redis的集群管理軟體redis-trib負責執行的,Redis提供了進行重新分片所需要的所有命令,而redis-trib則通過源節點和目標節點發送命令來進行重新分片操作。

1)redis-trib對目標節點發送CLUSTER SETSLOT < slot > IMPORTING <source_id >命令,讓目標節點準備好從源節點導入屬於槽slot的鍵值對。

2)redis-trib對CLUSTER SETSLOT< slot > MIGATING < target_id > 命令,讓源節點準備好將屬於槽slot的鍵值對遷移至目標節點。

3)redis-trib向源節點發送CLUSTER GETKEYSINGSLOT < slot > < count > 獲得最多count 個屬於槽slot的鍵值對的鍵名。

4)對於步驟3獲得的鍵名,redis-trib都向源節點發送一個MIGRATE < target_ip > < target_port > < key_name > 0 <timeout> 命令,將被選中的鍵原子地從源節點遷移至目標節點。

5)重覆 3,4步驟,直到所有鍵值對都被遷移至目標節點。

6)redis-trib向集群中的任意一個節點發送CLUSTER SETSLOT < slot > NODE < target_id > 命令,將槽slot指派給目標節點,這一指派信息通過消息發送至整個集群,最終集群中的所有節點都會直到槽slot已經指派給了目標節點。

當客戶端向源節點發送一個與資料庫鍵有關的命令,並且命令要處理的資料庫鍵恰好就屬於正在被遷移的槽時:源節點會先在自己的資料庫里查找指定的鍵,如果找到的話,就直接執行客戶端發送的命令;相反,如果源節點沒能在自己的資料庫里找到指定的鍵,那麼這個鍵有可能已經被遷移到目標節點,源節點向客戶端返回一個ASK錯誤,指引客戶端轉向正在導入槽的目標節點,並再次發送之前想要執行的命令。

clusterState結構的importing_slots_from 數組記錄了當前節點正在從其他節點導入的槽:

typedef struct clusterState{
clusterNode *importing_slots_from[16384];
} clusterState;

如果 importing_slots_from[i]的值不為NULL,而是指向一個clusterNode結構,那麼標識當前節點正在從clusterNode所標識的節點導入槽i

clusterState結構migrating_slots_to數組記錄了當前節點正在遷移至其他節點的槽:

typedef struct clusterState{
clusterNode *migratubg_slots_to[16384];
}clusterState;

如果migrating_slots_to[i]的值不為NULL,而是指向一個clusterNode結構,那麼表示當前節點正在將槽i遷移至clusterNode所標識的節點。

 

ASK錯誤與MOVED錯誤的區別:

MOVED錯誤代表槽的負責權已經從一個節點轉移到另一個節點:在客戶端收到槽i的MOVED錯誤之後,客戶端每次遇到關於槽i的命令請求時,都可以直接將命令請求發送至MOVED錯誤所指向的節點,因為該節點就是目前負責槽i的節點。

ASK錯誤只是兩個節點在遷移槽的過程中使用的一種臨時措施。ASK錯誤的轉向不會對客戶端今後發送關於槽i的命令請求產生任何影響,客戶端仍然會將關於槽i的命令請求發送至目前負責處理槽i的節點。


每天學一點,總會有收穫。

 

說明:尊重作者知識產權,文中內容參考《Redis設計與實現》,僅在此做學習與大家分享。


 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 《ASP.NET 框架應用程式實戰》 [作者] (中) 李發陵 冷亞洪[出版] 清華大學出版社[版次] 2017年01月 第1版[印次] 2017年01月 第1次 印刷[定價] 47.00元 【第02章】 (P023) 目前, ASP.NET MVC 4 已內置於 Visual Studio 201 ...
  • 1、引導界面美化 下載grub主題 https://www.gnome-look.org/browse/cat/109/order/latest/ https://www.pling.com/s/Gnome/browse/cat/109/order/latest/ 隨便下一個主題 配置主題 cd / ...
  • 1、應啟用安全審計功能,審計覆蓋到每個用戶,對重要的用戶行為和重要安全事件進行審計 方案: 在管理工具打開本地安全策略,打開路徑:安全設置\本地策略\審核策略,將全部審核策略配置為:成功,失敗。包括審核策略更改、審核對象訪問、審核進程跟蹤、審核目錄服務訪問、審核賬戶登陸事件、審核特權使用、審核系統事 ...
  • 大家好,我是良許。 在 Linux 下,重命名一個文件,我們通常是使用 mv 命令,一般是這樣操作的: $ mv file1.txt file2.txt 這樣重命令的方式當然是可以,但有個弊端就是你需要輸入兩次文件名。文件名比較短還好,一旦比較長的話,輸兩次會很讓人崩潰的。 本文就介紹幾種更高效的文 ...
  • 記憶體在人工智慧解決方案(例如機器學習)的培訓和實施中均扮演著關鍵角色。這也是創建諸如5G之類的高級網路技術的要求,這將需要在網路邊緣以及在端點處進行處理和存儲以實現IoT和其他應用程式。 如今大多數高性能記憶體都是易失性的,這意味著當設備斷電時,存儲在記憶體中的所有內容都會丟失。但是記憶體會消耗很多功率, ...
  • Autohotkey是一款輕量小眾但高效免費開源的windows熱鍵腳本語言,游戲操縱、滑鼠操作、鍵盤快捷重定義,快捷短語等等,只有你想不到,沒有它做不到,神器中的神器呀,相見恨晚。 ...
  • 1. Kubernetes是什麼 Kubernetes中文版資料 Kubernetes是容器集群管理系統,是一個開源的平臺,可以實現容器集群的自動化部署、自動擴縮容、維護等功能。 通過Kubernetes我們可以: 快速部署應用 快速擴展應用 無縫對接新的應用功能 * 節省資源,優化硬體資源的使用 ...
  • 為什麼要用索引? 一般的應用系統,讀寫比例在10:1左右,插入操作和一般的更新操作很少出現性能問題,在生產環境中,我們遇到最多的,也是最容易出問題的,還是一些複雜的查詢操作,因此對查詢語句的優化顯然是重中之重。說起加速查詢,就不得不提到索引了。 索引是什麼? 索引在MySQL中也叫做“鍵”,是存儲引 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...