進階的Redis之哈希分片原理與集羣實戰

前面介紹了《進階的Redis之數據持久化RDB與AOF》《進階的Redis之Sentinel原理及實戰》,這次來了解下Redis的集羣功能,以及其中哈希分片原理。

集羣分片模式

如果Redis只用複製功能做主從,那麼當數據量巨大的情況下,單機情況下可能已經承受不下一份數據,更不用說是主從都要各自保存一份完整的數據。在這種情況下,數據分片是一個非常好的解決辦法。

Redis的Cluster正是用於解決該問題。它主要提供兩個功能:

  1. 自動對數據分片,落到各個節點上
  2. 即使集羣部分節點失效或者連接不上,依然可以繼續處理命令

對於第二點,它的功能有點類似於Sentienl的故障轉移(可以瞭解下之前Sentinel的文章),在這裏不細說。下面詳細瞭解下Redis的槽位分片原理,在此之前,先了解下分佈式簡單哈希算法和一致性哈希算法,以幫助理解槽位的作用。

簡單哈希算法

假設有三臺機,數據落在哪臺機的算法爲

  c = Hash(key) % 3

例如key A的哈希值爲4,4%3=1,則落在第二臺機。Key ABC哈希值爲11,11%3=2,則落在第三臺機上。

利用這樣的算法,假設現在數據量太大了,需要增加一臺機器。A原本落在第二臺上,現在根據算法4%4=0,落到了第一臺機器上了,但是第一臺機器上根本沒有A的值。這樣的算法會導致增加機器或減少機器的時候,引起大量的緩存穿透,造成雪崩。

一致性哈希算法

在1997年,麻省理工學院的Karger等人提出了一致性哈希算法,爲的就是解決分佈式緩存的問題。

一致性哈希算法中,整個哈希空間是一個虛擬圓環

9059622-eb1128f4f8ba6437

 

假設有四個節點Node A、B、C、D,經過ip地址的哈希計算,它們的位置如下

 

9059622-5ba5e71276abe0d2

有4個存儲對象Object A、B、C、D,經過對Key的哈希計算後,它們的位置如下

 

9059622-71b1d77c55e24e0d

 

對於各個Object,它所真正的存儲位置是按順時針找到的第一個存儲節點。例如Object A順時針找到的第一個節點是Node A,所以Node A負責存儲Object A,Object B存儲在Node B。

一致性哈希算法大概如此,那麼它的容錯性擴展性如何呢?

假設Node C節點掛掉了,Object C的存儲丟失,那麼它順時針找到的最新節點是Node D。也就是說Node C掛掉了,受影響僅僅包括Node B到Node C區間的數據,並且這些數據會轉移到Node D進行存儲。

 

9059622-94cff91cbb75e408

同理,假設現在數據量大了,需要增加一臺節點Node X。Node X的位置在Node B到Node C直接,那麼受到影響的僅僅是Node B到Node X間的數據,它們要重新落到Node X上。

所以一致性哈希算法對於容錯性和擴展性有非常好的支持。但一致性哈希算法也有一個嚴重的問題,就是數據傾斜

如果在分片的集羣中,節點太少,並且分佈不均,一致性哈希算法就會出現部分節點數據太多,部分節點數據太少。也就是說無法控制節點存儲數據的分配。如下圖,大部分數據都在A上了,B的數據比較少。

 

9059622-29a59cf03b025384

哈希槽

Redis集羣(Cluster)並沒有選用上面一致性哈希,而是採用了哈希槽(SLOT)的這種概念。主要的原因就是上面所說的,一致性哈希算法對於數據分佈、節點位置的控制並不是很友好。

首先哈希槽其實是兩個概念,第一個是哈希算法。Redis Cluster的hash算法不是簡單的hash(),而是crc16算法,一種校驗算法。

另外一個就是槽位的概念,空間分配的規則。其實哈希槽的本質和一致性哈希算法非常相似,不同點就是對於哈希空間的定義。一致性哈希的空間是一個圓環,節點分佈是基於圓環的,無法很好的控制數據分佈。而Redis Cluster的槽位空間是自定義分配的,類似於Windows盤分區的概念。這種分區是可以自定義大小,自定義位置的。

Redis Cluster包含了16384個哈希槽,每個Key通過計算後都會落在具體一個槽位上,而這個槽位是屬於哪個存儲節點的,則由用戶自己定義分配。例如機器硬盤小的,可以分配少一點槽位,硬盤大的可以分配多一點。如果節點硬盤都差不多則可以平均分配。所以哈希槽這種概念很好地解決了一致性哈希的弊端。

另外在容錯性擴展性上,表象與一致性哈希一樣,都是對受影響的數據進行轉移。而哈希槽本質上是對槽位的轉移,把故障節點負責的槽位轉移到其他正常的節點上。擴展節點也是一樣,把其他節點上的槽位轉移到新的節點上。

但一定要注意的是,對於槽位的轉移和分派,Redis集羣是不會自動進行的,而是需要人工配置的。所以Redis集羣的高可用是依賴於節點的主從複製與主從間的自動故障轉移。

集羣搭建

下面以最簡單的例子,拋開高可用主從複製級轉移的內容,來重點介紹下Redis集羣是如何搭建,槽位是如何分配的,以加深對Redis集羣原理及概念的理解。

redis.conf配置

先找到redis.conf,啓用cluster功能。

 

9059622-0167d53568dd6770

cluster-enabled yes默認是關閉的,要啓用cluster,讓redis成爲集羣的一部分,需要手動打開才行。

然後配置cluster的配置文件

 

9059622-dde63bb3e132946d

 

每一個cluster節點都有一個cluster的配置文件,這個文件主要用於記錄節點信息,用程序自動生成和管理,不需要人工干預。唯一要注意的是,如果在同一臺機器上運行多個節點,需要修改這個配置爲不同的名字。

本次爲了方便搭建,所有Redis實例都在同一臺機器上,所以修改不同的cluster config名字後,複製三份redis.conf配置,以用於啓動三個集羣實例(cluster至少要三個主節點才能進行)。

集羣關聯

  > redis-server /usr/local/etc/redis/redis-6379.conf --port 6379 &
  > redis-server /usr/local/etc/redis/redis-6380.conf --port 6380 &
  > redis-server /usr/local/etc/redis/redis-6381.conf --port 6381 &

&符號的作用是讓命令在後臺執行,但程序執行的log依然會打印在console中。也可以通過配置redis.conf中deamonize yes,讓Redis在後臺運行。

連上6379的Redis實例,然後通過cluster nodes查看集羣範圍。

9059622-94f8376aa58e159e


連上其他實例也是一樣,目前6379、6380、6381在各自的集羣中,且集羣只有它們自己一個。

 

在6379上,通過cluster meet命令,與6380、6381建立鏈接。

  127.0.0.1:6379> cluster meet 127.0.0.1 6380
  127.0.0.1:6379> cluster meet 127.0.0.1 6381

9059622-1b58083e28684f07

 

可以看到集羣中已經包含了6379、6380、6381三個節點了。登錄其他節點查看也是一樣的結果。即使6380與6381之間沒有直接手動關聯,但在集羣中,節點一旦發現有未關聯的節點,會自動與之握手關聯。

槽位分配

通過cluster info命令查看集羣的狀態

9059622-4ca2dccc76bba260


state的狀態是fail的,還沒啓用。看下官方的說明

9059622-349bad2dfc2dc324


只有state爲ok,節點才能接受請求。如果只要有一個槽位(slot)沒有分配,那麼這個狀態就是fail。而一共需要分配16384槽位才能讓集羣正常工作。

 

接下來給6379分配05000的槽位,給6380分配500110000的槽位,給6381分配10001~16383的槽位。

  > redis-cli -c -p 6379 cluster addslots {0..5000}
  > redis-cli -c -p 6380 cluster addslots {5001..10000}
  > redis-cli -c -p 6381 cluster addslots {10001..16383}

再看看cluster info

9059622-ff2e83af634a659f


state已經爲ok,16384個槽位都已經分配好了。現在集羣已經可以正常工作了。

 

效果測試

隨便登上一個實例,記得加上參數-c,啓用集羣模式的客戶端,否則無法正常運行。

  redis-cli -c -p 6380

嘗試下set、get操作

 

9059622-0366c261da5e3536

 

可以看到,Redis集羣會計算key落在哪個卡槽,然後會把命令轉發到負責該卡槽的節點上執行。

利用cluster keyslot命令計算出key是在哪個槽位上,從而得出會跳轉到哪個節點上執行。


更多技術文章、精彩乾貨,請關注
博客:zackku.com
微信公衆號:Zack說碼

發佈了18 篇原創文章 · 獲贊 0 · 訪問量 1564
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章