亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

分布式Redis深度歷險-Cluster

發布時間:2020-08-07 12:25:17 來源:網絡 閱讀:464 作者:Java筆記丶 欄目:編程語言

本文為分布式Redis深度歷險系列的第三篇,主要內容為Redis的Cluster,也就是Redis集群功能。

Redis集群是Redis官方提供的分布式方案,整個集群通過將所有數據分成16384個槽來進行數據共享。

?

集群基礎實現

一個集群由多個Redis節點組成,不同的節點通過CLUSTER MEET命令進行連接:

CLUSTER MEET <ip> <port>

收到命令的節點會與命令中指定的目標節點進行握手,握手成功后目標節點會加入到集群中,看個例子,圖片來自于Redis的設計與實現:

分布式Redis深度歷險-Cluster

分布式Redis深度歷險-Cluster

分布式Redis深度歷險-Cluster

分布式Redis深度歷險-Cluster

分布式Redis深度歷險-Cluster

?

槽分配

一個集群的所有數據被分為16384個槽,可以通過CLUSTER ADDSLOTS命令將槽指派給對應的節點。當所有的槽都有節點負責時,集群處于上線狀態,否則處于下線狀態不對外提供服務。

clusterNode的位數組slots代表一個節點負責的槽信息。

struct?clusterNode?{


????unsigned?char?slots[16384/8];?/*?slots?handled?by?this?node?*/

????int?numslots;???/*?Number?of?slots?handled?by?this?node?*/

????...
}

看個例子,下圖中1、3、5、8、9、10位的值為1,代表該節點負責槽1、3、5、8、9、10。

每個Redis Server上都有一個ClusterState的對象,代表了該Server所在集群的信息,其中字段slots記錄了集群中所有節點負責的槽信息。

typedef?struct?clusterState?{

????//?負責處理各個槽的節點
????//?例如?slots[i]?=?clusterNode_A?表示槽?i?由節點?A?處理
????//?slots[i]?=?null?代表該槽目前沒有節點負責
????clusterNode?*slots[REDIS_CLUSTER_SLOTS];

}

?

槽重分配

可以通過redis-trib工具對槽重新分配,重分配的實現步驟如下:

  1. 通知目標節點準備好接收槽

  2. 通知源節點準備好發送槽

  3. 向源節點發送命令:CLUSTER GETKEYSINSLOT <slot> <count>從源節點獲取最多count個槽slot的key

  4. 對于步驟3的每個key,都向源節點發送一個MIGRATE <target_ip> <target_port> <key_name> 0 <timeout>?命令,將被選中的鍵原子的從源節點遷移至目標節點。

  5. 重復步驟3、4。直到槽slot的所有鍵值對都被遷移到目標節點

  6. 將槽slot指派給目標節點的信息發送到整個集群。

在槽重分配的過程中,槽中的一部分數據保存著源節點,另一部分保存在目標節點。這時如果要客戶端向源節點發送一個命令,且相關數據在一個正在遷移槽中,源節點處理步驟如圖:
分布式Redis深度歷險-Cluster

當客戶端收到一個ASK錯誤的時候,會根據返回的信息向目標節點重新發起一次請求。

ASK和MOVED的區別主要是ASK是一次性的,MOVED是永久性的,有點像Http協議中的301和302。

?

一次命令執行過程

我們來看cluster下一次命令的請求過程,假設執行命令?get testKey

  1. cluster client在運行前需要配置若干個server節點的ip和port。我們稱這些節點為種子節點。

  2. cluster的客戶端在執行命令時,會先通過計算得到key的槽信息,計算規則為:getCRC16(key) & (16384 - 1),得到槽信息后,會從一個緩存map中獲得槽對應的redis server信息,如果能獲取到,則調到第4步

  3. 向種子節點發送slots命令以獲得整個集群的槽分布信息,然后跳轉到第2步重試命令

  4. 向負責該槽的server發起調用
    server處理如圖:
    分布式Redis深度歷險-Cluster

  5. 客戶端如果收到MOVED錯誤,則根據對應的地址跳轉到第4步重新請求,

  6. 客戶段如果收到ASK錯誤,則根據對應的地址跳轉到第4步重新請求,并在請求前帶上ASKING標識。

以上步驟大致就是redis cluster下一次命令請求的過程,但忽略了一個細節,如果要查找的數據鎖所在的槽正在重分配怎么辦?

?

Redis故障轉移

疑似下線與已下線

集群中每個Redis節點都會定期的向集群中的其他節點發送PING消息,如果目標節點沒有在有效時間內回復PONG消息,則會被標記為疑似下線。同時將該信息發送給其他節點。當一個集群中有半數負責處理槽的主節點都將某個節點A標記為疑似下線后,那么A會被標記為已下線,將A標記為已下線的節點會將該信息發送給其他節點。

比如說有A,B,C,D,E 5個主節點。E有F、G兩個從節點。
當E節點發生異常后,其他節點發送給A的PING消息將不能得到正常回復。當過了最大超時時間后,假設A,B先將E標記為疑似下線;之后C也會將E標記為疑似下線,這時C發現集群中由3個節點(A、B、C)都將E標記為疑似下線,超過集群復制槽的主節點個數的一半(>2.5)則會將E標記為已下線,并向集群廣播E下線的消息。

?

選取新的主節點

當F、G(E的從節點)收到E被標記已下線的消息后,會根據Raft算法選舉出一個新的主節點,新的主節點會將E復制的所有槽指派給自己,然后向集群廣播消息,通知其他節點新的主節點信息。

選舉新的主節點算法與選舉Sentinel頭節點的過程很像:

  1. 集群的配置紀元是一個自增計數器,它的初始值為0.

  2. 當集群里的某個節點開始一次故障轉移操作時,集群配置紀元的值會被增一。

  3. 對于每個配置紀元,集群里每個負責處理槽的主節點都有一次投票的機會,而第一個向主節點要求投票的從節點將獲得主節點的投票。

  4. 檔從節點發現自己正在復制的主節點進入已下線狀態時,從節點會想集群廣播一條CLUSTER_TYPE_FAILOVER_AUTH_REQUEST消息,要求所有接收到這條消息、并且具有投票權的主節點向這個從節點投票。

  5. 如果一個主節點具有投票權(它正在負責處理槽),并且這個主節點尚未投票給其他從節點,那么主節點將向要求投票的從節點返回一條CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK消息,表示這個主節點支持從節點成為新的主節點。

  6. 每個參與選舉的從節點都會接收CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK消息,并根據自己收到了多少條這種消息來同濟自己獲得了多少主節點的支持。

  7. 如果集群里有N個具有投票權的主節點,那么當一個從節點收集到大于等于N/2+1張支持票時,這個從節點就會當選為新的主節點。

  8. 因為在每一個配置紀元里面,每個具有投票權的主節點只能投一次票,所以如果有N個主節點進行投票,那么具有大于等于N/2+1張支持票的從節點只會有一個,這確保了新的主節點只會有一個。

  9. 如果在一個配置紀元里面沒有從節點能收集到足夠多的支持票,那么集群進入一個新的配置紀元,并再次進行選舉,知道選出新的主節點為止。

?

Redis常用分布式實現方案

最后,聊聊redis集群的其他兩種實現方案。

client做分片

客戶端做路由,采用一致性hash算法,將key映射到對應的redis節點上。
其優點是實現簡單,沒有引用其他中間件。
缺點也很明顯:是一種靜態分片方案,擴容性差。

Jedis中的ShardedJedis是該方案的實現。

proxy做分片

該方案在client與redis之間引入一個代理層。client的所有操作都發送給代理層,由代理層實現路由轉發給不同的redis服務器

分布式Redis深度歷險-Cluster

其優點是: 路由規則可自定義,擴容方便。
缺點是: 代理層有單點問題,多一層轉發的網絡開銷

?


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

武乡县| 射阳县| 奇台县| 新民市| 武汉市| 堆龙德庆县| 阿克苏市| 武义县| 黑水县| 滁州市| 韶山市| 永胜县| 平顺县| 曲麻莱县| 荔波县| 福贡县| 定南县| 乌兰察布市| 渭源县| 井冈山市| 伊春市| 肇庆市| 平陆县| 青海省| 余姚市| 望城县| 五台县| 阿拉善左旗| 漯河市| 盐源县| 吴川市| 靖边县| 南木林县| 鹰潭市| 全南县| 绍兴县| 嘉定区| 平邑县| 宝应县| 汪清县| 尼木县|