redis的Cluster集群學習

Share猿,一個極客共同交流學習的社區(qū)!

關鍵詞

  • cluster
  • 去中心化
  • 節(jié)點槽位
  • 網(wǎng)絡抖動
  • CRC16算法(槽位定位算法)

記錄

關于cluster

RedisCluster 是redis的親兒子,他是redis作者自己提供的redis集群解決方案。

問題

1.cluster是去中心化的集群,什么是去中心化集群?

去中心化集群指的就是各個節(jié)點之間都是平等的,而且每個節(jié)點具有高度自治的特征,節(jié)點之間相互連接通訊保持數(shù)據(jù)的一致性。我們最熟知的去中心應用比特幣系統(tǒng),就是一個去中心化的系統(tǒng)。

2.cluster為什么要將所有數(shù)據(jù)劃分為 16384 的 slots(槽位)?

2.1什么是solts(槽位,又稱為hash槽)?

通過上一節(jié)學習codies集群,我們知道codies有1024個槽位,為什么cluster集群會有這么多,什么是槽位/hash槽哪?

槽位其實就相當于我們緩存桶,16384個槽位就相當于16384個存儲數(shù)據(jù)的緩存桶,cluster集群會把這個16384個緩存桶均勻分配給集群的各個節(jié)點

節(jié)點A覆蓋0-5460;

節(jié)點B覆蓋5461-10922;

節(jié)點C覆蓋10923-16383.

當我們在集群中放置一個key-value的時候,cluster會根據(jù)CRC16(key)mod16384得出的值,該值決定我們的key-value放到哪個緩存桶里面。

當我們新增集群節(jié)點的時候,新增的集群節(jié)點會從現(xiàn)有的各個節(jié)點中獲取一部分緩存桶。

節(jié)點A覆蓋1365-5460

節(jié)點B覆蓋6827-10922

節(jié)點C覆蓋12288-16383

節(jié)點D覆蓋0-1364,5461-6826,10923-12287

看到這里,想必大家也知道什么是redis cluster的槽位,為什么cluster集群的槽位比codies多的原因。

2.2.基于上面的回答我又提出一個問題,去中心化節(jié)點是把槽位均分到各個集群節(jié)點上,假如我們其中一個節(jié)點掛了,整個集群豈不是掛了??

經(jīng)過網(wǎng)上查資料,發(fā)現(xiàn),所謂的去中心化節(jié)點準確的說應該是去中心化主節(jié)點,上面的ABC節(jié)點在部署的時候我們還要對其部署對應的從節(jié)點,這樣才能保證其中一個主節(jié)點掛了而不影響整個集群。所以cluster集群是一種:去中心化+主從的集群模式。

2.3.關于槽位定位算法

Cluster 默認會對 key 值使用 crc16 算法進行 hash 得到一個整數(shù)值,然后用這個整數(shù)值對 16384 進行取模來得到具體槽位。

Cluster 還允許用戶強制某個 key 掛在特定槽位上,通過在 key 字符串里面嵌入 tag 標記,這就可以強制 key 所掛在的槽位等于 tag 所在的槽位

3.什么是cluster跳轉(zhuǎn)?

3.1.什么是cluster的轉(zhuǎn)?

說的直白一點就是從一個節(jié)點跳到另一個集群節(jié)點。

3.2.如何跳轉(zhuǎn)?

當我們對一個集群節(jié)點發(fā)送了一個指令,發(fā)現(xiàn)該節(jié)點不存在該指令的槽位,這時它會向客戶端發(fā)送一個特殊的跳轉(zhuǎn)指令攜帶目標操作的節(jié)點地址,告訴客戶端去連這個節(jié)點去獲取數(shù)據(jù)。

GET x
-MOVED 3999 127.0.0.1:6381復制代碼

MOVED 指令的第一個參數(shù) 3999 是 key 對應的槽位編號,后面是目標節(jié)點地址。MOVED 指令前面有一個減號,表示該指令是一個錯誤消息。

客戶端收到 MOVED 指令后,要立即糾正本地的槽位映射表。后續(xù)所有 key 將使用新的槽位映射表。

4.cluster集群如何進行多個節(jié)點之間數(shù)據(jù)的遷移?

Redis Cluster 提供了工具 redis-trib 可以讓運維人員手動調(diào)整槽位的分配情況,它使用 Ruby 語言進行開發(fā),通過組合各種原生的 Redis Cluster 指令來實現(xiàn)。

redis-trib提供了UI界面方便我們的遷移,還提供了自動平衡槽位的工具,無需人工干預就能均衡集群負載。

4.1.遷移過程

從源節(jié)點獲取內(nèi)容 => 存到目標節(jié)點 => 從源節(jié)點刪除內(nèi)容。

5.redis的cluster集群是如何保證容錯性的?

Redis Cluster 可以為每個主節(jié)點設置若干個從節(jié)點,單主節(jié)點故障時,集群會自動將其中某個從節(jié)點提升為主節(jié)點。如果某個主節(jié)點沒有從節(jié)點,那么當它發(fā)生故障時,集群將完全處于不可用狀態(tài)。不過 Redis 也提供了一個參數(shù)cluster-require-full-coverage可以允許部分節(jié)點故障,其它節(jié)點還可以繼續(xù)提供對外訪問。

6.什么是網(wǎng)絡抖動?cluster集群如何防止網(wǎng)絡抖動帶來的數(shù)據(jù)不一致性?

所謂網(wǎng)絡抖動就是網(wǎng)絡異常情況,突然不可訪問,一會兒又好了。這種情況可能導致cluster的主從節(jié)點頻繁切換。

針對上述情況,cluster提供了一個選項cluster-node-timeout,他存在的意義在于防止網(wǎng)絡抖動而引起頻繁的節(jié)點切換。設置了該選項只有當節(jié)點長期失聯(lián)的時候才會進行主從切換。

7.cluster是如何判斷一個節(jié)點是否下線的?

只有當大多數(shù)節(jié)點都認定了某個節(jié)點失聯(lián)了,集群才認為該節(jié)點需要進行主從切換來容錯。

一個節(jié)點發(fā)現(xiàn)某個節(jié)點失聯(lián)了 (PFail),它會將這條信息向整個集群廣播,其它節(jié)點也就可以收到這點失聯(lián)信息。

如果一個節(jié)點收到了某個節(jié)點失聯(lián)的數(shù)量 (PFail Count) 已經(jīng)達到了集群的大多數(shù),就可以標記該節(jié)點為確定下線狀態(tài) (Fail),然后向整個集群廣播,強迫其它節(jié)點也接收該節(jié)點已經(jīng)下線的事實,并立即對該失聯(lián)節(jié)點進行主從切換。

8.如何使用cluster集群?(redis-py 客戶端不支持 Cluster 模式)

要使用 Cluster,必須安裝另外一個包,這個包是依賴 redis-py 包的。pip install redis-py-cluster

>>> from rediscluster import StrictRedisCluster
>>> # Requires at least one node for cluster discovery. Multiple nodes is recommended.
>>> startup_nodes = [{"host": "127.0.0.1", "port": "7000"}]
>>> rc = StrictRedisCluster(startup_nodes=startup_nodes, decode_responses=True)
>>> rc.set("foo", "bar")
True
>>> print(rc.get("foo"))
'bar'復制代碼

Cluster 是去中心化的,它有多個節(jié)點組成,構造 StrictRedisCluster 實例時,我們可以只用一個節(jié)點地址,其它地址可以自動通過這個節(jié)點來發(fā)現(xiàn)。不過如果提供多個節(jié)點地址,安全性會更好。如果只提供一個節(jié)點地址,那么當這個節(jié)點掛了,客戶端就必須更換地址才可以繼續(xù)訪問 Cluster。 第二個參數(shù) decode_responses 表示是否要將返回結果中的 byte 數(shù)組轉(zhuǎn)換成 unicode。

Cluster 使用起來非常方便,用起來和普通的 redis-py 差別不大,僅僅是構造方式不同。但是它們也有相當大的不一樣之處,比如 Cluster 不支持事務,Cluster 的 mget 方法相比 Redis 要慢很多,被拆分成了多個 get指令,Cluster 的 rename 方法不再是原子的,它需要將數(shù)據(jù)從原節(jié)點轉(zhuǎn)移到目標節(jié)點。

9.cluster集群是如何感知槽位遷移的?

客戶端保存了槽位和節(jié)點的映射關系表,它需要即時得到更新,才可以正常地將某條指令發(fā)到正確的節(jié)點中。

10.cluster集群發(fā)生變更客戶端是如何接受到通知的?

我們前面提到 Cluster 有兩個特殊的 error 指令,一個是 moved,一個是 asking。

第一個 moved 是用來糾正槽位的。

第二個 asking 指令和 moved 不一樣,它是用來臨時糾正槽位的。

moved 和 asking 指令都是重試指令,客戶端會因為這兩個指令多重試一次。

11.嘗試自己搭建一個cluster集群

11.1. 準備配置文件

創(chuàng)建cluster目錄,并創(chuàng)建6個配置文件

[圖片上傳中...(image-381a72-1566832438631-4)]

11.2. 修改配置文件

port 7000 //端口7000,7002,7003..

daemonize yes //redis后臺運行

pidfile ./redis_7000.pid //pidfile文件對應7000,7001,7002

cluster-enabled yes //開啟集群 把注釋#去掉

cluster-config-file nodes_7000.conf //集群的配置 配置文件首次啟動自動生成 7000,7001,7002

cluster-node-timeout 15000 //請求超時 默認15秒,可自行設置

appendonly yes //aof日志開啟 有需要就開啟,它會每次寫操作都記錄一條日志

//若設置密碼,master和slave需同時配置下面兩個參數(shù):

masterauth "12345678" //連接master的密碼

requirepass "12345678" //自己的密碼

[圖片上傳中...(image-6b450b-1566832438631-3)]

11.3. 啟動、測試所有redis實例

  • 創(chuàng)建啟動文件:vi start-all.sh
  • 賦予權限:chmod u+x start-all.sh
  • 啟動:./start-all.sh

[圖片上傳中...(image-2ded88-1566832438631-2)]

11.4. 安裝redis-trib所需的 ruby腳本

ruby redis-trib.rb //測試是否安裝成功,若已經(jīng)安裝過,可跳過此步

[圖片上傳中...(image-c2d177-1566832438631-1)]

安裝

cp /usr/andy/redis/redis-3.2.0/src/redis-trib.rb .

yum install ruby

yum install rubygems

gem install redis-3.2.2.gem //需下載redis-3.2.2.gem

11.5. 使用redis-trib.rb創(chuàng)建集群

執(zhí)行下面命令創(chuàng)建集群(需為真實ip,不然外網(wǎng)無法訪問):

./redis-trib.rb create --replicas 1 192.168.0.217:7000 192.168.0.217:7001 192.168.0.217:7002 192.168.0.217:7003 192.168.0.217:7004 192.168.0.217:7005

[圖片上傳中...(image-e7ff88-1566832438631-0)]

可以看到:

  • 7003是7000主節(jié)點的從節(jié)點,管理槽0-5460
  • 7004是7001主節(jié)點的從節(jié)點,管理槽5461-10992
  • 7005是7002主節(jié)點的從節(jié)點,管理槽10992-16383

12.使用客戶端操作對cluster集群進行一些常規(guī)指令的操作

集群

cluster info :打印集群的信息

cluster nodes :列出集群當前已知的所有節(jié)點( node),以及這些節(jié)點的相關信息。

節(jié)點

cluster meet ip port:將 ip 和 port 所指定的節(jié)點添加到集群當中,讓它成為集群的一份子。

cluster forget <node_id> :從集群中移除 node_id 指定的節(jié)點。

cluster replicate <node_id> :將當前節(jié)點設置為 node_id 指定的節(jié)點的從節(jié)點。

cluster saveconfig :將節(jié)點的配置文件保存到硬盤里面。

槽(slot)

cluster addslots <slot> [slot ...] :將一個或多個槽( slot)指派( assign)給當前節(jié)點。

cluster delslots <slot> [slot ...] :移除一個或多個槽對當前節(jié)點的指派。

cluster flushslots :移除指派給當前節(jié)點的所有槽,讓當前節(jié)點變成一個沒有指派任何槽的節(jié)點。

cluster setslot <slot> node <node_id> :將槽 slot 指派給 node_id 指定的節(jié)點,如果槽已經(jīng)指派給另一個節(jié)點,那么先讓另一個節(jié)點刪除該槽>,然后再進行指派。

cluster setslot <slot> migrating <node_id> :將本節(jié)點的槽 slot 遷移到 node_id 指定的節(jié)點中。

cluster setslot <slot> importing <node_id> :從 node_id 指定的節(jié)點中導入槽 slot 到本節(jié)點。

cluster setslot <slot> stable :取消對槽 slot 的導入( import)或者遷移( migrate)。

cluster keyslot <key> :計算鍵 key 應該被放置在哪個槽上。

cluster countkeysinslot <slot> :返回槽 slot 目前包含的鍵值對數(shù)量。

cluster getkeysinslot <slot> <count> :返回 count 個 slot 槽中的鍵

復盤

學完這一小節(jié)明白了cluster集群的基本原理,以及槽位等一些相關概念,了解了CRC16算法,學會如何搭建一個cluster集群。

掃描以下二維碼關注社區(qū)公眾號↓↓↓↓↓↓↓↓

更多資訊請在簡書、微博、今日頭條、掘金、CSDN都可以通過搜索“Share猿”加入Share猿社區(qū)!??!

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 1.1 Redis集群的設計原則和初衷 在官方文檔Cluster Spec中,作者詳細介紹了Redis集群為什么要...
    Flame_1109閱讀 2,267評論 1 5
  • NOSQL類型簡介鍵值對:會使用到一個哈希表,表中有一個特定的鍵和一個指針指向特定的數(shù)據(jù),如redis,volde...
    MicoCube閱讀 4,159評論 2 27
  • 前面我們介紹了國人自己開發(fā)的Redis集群方案——Codis,Codis友好的管理界面以及強大的自動平衡槽位的功能...
    Jackeyzhe閱讀 2,168評論 0 3
  • redis集群分為服務端集群和客戶端分片,redis3.0以上版本實現(xiàn)了集群機制,即服務端集群,3.0以下使用客戶...
    hadoop_null閱讀 1,677評論 0 6
  • 1 Redis介紹1.1 什么是NoSql為了解決高并發(fā)、高可擴展、高可用、大數(shù)據(jù)存儲問題而產(chǎn)生的數(shù)據(jù)庫解決方...
    克魯?shù)吕?/span>閱讀 5,717評論 0 36

友情鏈接更多精彩內(nèi)容