博客 / 詳情

返回

redis 集羣常見問題 QA

數據分片

Q:redis 集羣是怎麼做數據分片的?

A:Redis集羣是通過數據分片(sharding)來實現數據在不同節點間的分配。Redis集羣中有16384個hash slot(槽位),每個節點可以處理其中的一部分槽位,不同節點之間可以共同處理這16384個槽位。當一個鍵值對需要被放到Redis集羣中時,Redis會先計算該鍵值對的key對應的hash值,然後將其放到對應的槽位中。Redis集羣的每個節點都知道自己負責處理哪些槽位,所以能夠快速定位數據在哪個節點上。

具體來説,Redis集羣使用哈希槽分片(hash slot sharding)來將所有數據分成16384個哈希槽。當客户端連接Redis集羣時,會得到集羣中任意一個節點的IP和端口信息,然後將客户端的請求路由到正確的節點上。每個節點都負責處理一部分哈希槽,這些哈希槽的範圍通過分佈式哈希算法(比如CRC16)來計算,然後分配到不同的節點上。當一個客户端請求需要操作某個key時,Redis會先根據key計算出該key對應的哈希槽,然後將請求路由到負責該哈希槽的節點上。這樣就實現了數據的分片存儲和訪問。

Q:一個槽位,可以被多個 redis 主節點共同持有嗎?

A:在 Redis 集羣中,一個槽位只能被一個 Redis 節點持有,即每個槽位只能被分配給 Redis 集羣中的一個主節點。在 Redis 集羣中,槽位會被均勻地分配給各個主節點,確保每個主節點都分配了一定數量的槽位,從而實現數據的分佈式存儲。如果一個槽位被多個主節點持有,那麼可能會導致數據衝突和數據一致性問題。因此,Redis 集羣的設計保證了一個槽位只被一個主節點持有。

Q:一個 redis 主節點,怎麼知道自己持有哪些槽位?持有的槽位是離散的,還是連續的?

A:在 Redis 集羣中,一個 Redis 主節點會持有一部分槽位,具體是哪些槽位是由集羣的節點管理器指定的。一個槽位只會被分配給一個 Redis 主節點,而不會被多個主節點共同持有。每個 Redis 主節點都會記錄自己持有的槽位信息,可以通過命令 CLUSTER SLOTS 來獲取當前節點所持有的槽位信息,例如:

127.0.0.1:6379> CLUSTER SLOTS
1) 1) (integer) 0
   2) (integer) 5460
   3) 1) "127.0.0.1"
      2) (integer) 6379
      3) "f2b5a96e2e79d08ce5d5a5b1d64b5a31f07a734f"
   4) 1) "127.0.0.1"
      2) (integer) 6380
      3) "92d24c0209384f4c4c9abef7adff0f129b73e7b6"
2) 1) (integer) 5461
   2) (integer) 10922
   3) 1) "127.0.0.1"
      2) (integer) 6380
      3) "92d24c0209384f4c4c9abef7adff0f129b73e7b6"
   4) 1) "127.0.0.1"
      2) (integer) 6379
      3) "f2b5a96e2e79d08ce5d5a5b1d64b5a31f07a734f"
...

上述命令返回了當前節點所持有的所有槽位信息。其中,每個槽位由一個起始槽號和一個結束槽號組成,例如 (integer) 0 到 (integer) 5460 表示第一個槽位的起始編號為 0,結束編號為 5460。對於連續的槽位,它們的起始和結束編號是連續的,而對於離散的槽位,它們的編號是不連續的。

Q:客户端怎麼知道應該把數據寫到 redis 集羣的哪個節點?

A:在 Redis 集羣中,客户端可以使用哈希槽位算法來確定應該將請求發送到哪個節點。哈希槽位算法將每個 key 映射到 16384 個槽位中的一個,並將每個槽位分配給集羣中的一個節點。當客户端需要與集羣通信時,它會將 key 映射到一個槽位,並向負責該槽位的節點發送請求。如果請求需要訪問多個 key,則使用所有 key 的槽位來確定應該將請求發送到哪個節點。

在 Redis 集羣中,每個節點都知道哪些槽位被分配給它。當一個節點收到一個請求,如果它不是負責該槽位的節點,則它會返回一個 MOVED 錯誤,告訴客户端應該將請求發送到負責該槽位的節點。

因此,客户端通過哈希槽位算法將 key 映射到節點,並使用 MOVED 錯誤來確定應該將請求發送到哪個節點。

Q:redis 集羣的客户端,怎麼知道哪個 redis server 節點負責哪個槽位?

A:Redis集羣的客户端通過集羣中的元數據(metadata)來獲取槽和節點之間的映射關係,這個元數據保存在所有的Redis節點上。當一個客户端需要知道某個槽位的信息時,它會向Redis集羣的其中一個節點發送CLUSTER SLOTS命令,該節點會返回一個包含當前集羣中節點和槽位信息的列表,客户端通過解析這個列表就可以瞭解槽位和節點之間的映射關係。客户端在獲取了這個映射關係後,就可以將請求發送到正確的節點上。

Q:redis 集羣的元數據一般會很大嗎?會佔用很多網絡通訊資源嗎?

A:Redis 集羣的元數據一般不會很大,因為它只包含了關於槽位與節點的映射信息。在默認的情況下,Redis 集羣有 16384 個槽位,因此元數據的大小與節點數目和槽位的數量成正比。當集羣中有成百上千個節點時,元數據會變得比較大,但是它通常不會成為瓶頸。

關於網絡通訊資源的佔用,元數據的大小相對較小,因此它對網絡通訊資源的佔用也較小。在 Redis 集羣中,每個節點都需要與其他節點交換元數據信息以保持整個集羣的狀態一致性,這可能會佔用一定的網絡帶寬。但是,Redis 採用了一些優化措施,如增量同步和只同步變化的信息等,以降低網絡通訊資源的佔用。

Q:redis 集羣的客户端,怎麼知道哪個 redis server 節點上線了或者下線了?怎麼更新元信息?

A:Redis集羣的客户端可以通過監聽cluster:slots、cluster:meet、cluster:forget等事件來感知Redis節點的上線、下線、添加、刪除等操作,並相應地更新集羣元數據。

具體來説,客户端可以使用Redis提供的SUBSCRIBE命令來訂閲cluster:slots、cluster:meet、cluster:forget等事件的通知,當Redis節點的狀態發生變化時,Redis會發布相應的事件通知給所有客户端。客户端接收到通知後,可以更新自己本地的集羣元數據,以確保後續的操作可以正確地路由到相應的節點。

例如,Python客户端redis-py-cluster提供了RedisCluster類來操作Redis集羣,可以使用該類的pubsub屬性來訂閲相應的事件通知,如下所示:

from rediscluster import RedisCluster

startup_nodes = [{"host": "127.0.0.1", "port": "7000"}]
rc = RedisCluster(startup_nodes=startup_nodes, decode_responses=True)

# 訂閲cluster:slots事件
pubsub = rc.pubsub(ignore_subscribe_messages=True)
pubsub.subscribe("__keyspace@0__:*")

# 監聽事件通知
for item in pubsub.listen():
    print(item)

上面的代碼訂閲了__keyspace@0__:*頻道,即監聽所有key空間的事件通知。當有節點上線、下線、添加、刪除等操作時,Redis會發布相應的事件通知到該頻道,客户端通過監聽該頻道,就可以更新自己本地的集羣元數據。

Q:對於一個 redis 集羣,如果有一個 redis 主節點宕機下線了,這個時候,客户端往這個節點寫入數據怎麼辦?

A:如果一個 Redis 主節點宕機下線了,客户端往這個節點寫入數據的請求會失敗。為了避免這種情況,Redis 集羣提供了自動故障遷移(automatic failover)機制,使得當主節點宕機下線後,集羣能夠自動將從節點升級為新的主節點,以保證集羣的高可用性。

當主節點宕機下線後,集羣會檢測到該節點下線,然後從其它從節點中選出一個新的主節點。選舉新主節點的過程是通過集羣內的投票機制來實現的。首先,集羣會在所有從節點中選舉一個新主節點,然後將新主節點的信息廣播給集羣中的所有節點。當客户端向集羣發送寫入請求時,集羣會自動將請求路由到新的主節點上,從而保證集羣的正常運行。

Q:Redis 集羣提供的"自動故障遷移"需要幾秒鐘?

A:Redis 集羣提供的自動故障轉移(Automatic Failover)可以在幾秒鐘內完成,具體時間取決於集羣的配置和網絡延遲情況。在默認情況下,Redis 集羣會在 15 秒內嘗試執行故障轉移。這個時間可以通過 cluster-node-timeout 參數進行配置。如果某個主節點超過了設定的 cluster-node-timeout 時間沒有響應,那麼這個節點將被認為是宕機了,Redis 集羣就會開始自動故障轉移過程。

在自動故障轉移過程中,Redis 集羣會選舉一個新的主節點來接管原來宕機的節點的槽位,並將數據重新分佈到集羣中的其他節點。這個過程通常只需要幾秒鐘的時間。但是需要注意的是,在自動故障轉移期間,集羣中的某些操作可能會出現短暫的不可用性,直到轉移過程完成。

Q:那這 15 秒內,客户端都無法往這些槽寫入數據了,對嗎?

A:是的,如果發生故障遷移,需要在遷移完成之前暫停向失效節點所持有的槽寫入數據,否則可能會造成數據的不一致性。在 Redis 集羣的故障遷移過程中,通常需要在數秒內完成。

數據副本

Q:redis 集羣的副本是怎麼分配的?

A:在 Redis 集羣中,每個主節點會被分配若干個從節點,每個從節點都會在運行時通過複製主節點的數據來保持與主節點的數據一致。在默認情況下,每個主節點會被分配一個從節點,可以通過增加主節點的數量來增加集羣的可用性和容錯性。Redis 集羣使用的是無中心架構,所以每個節點都會分配一個固定的槽位,對於任何給定的槽位,只會有一個主節點和一個或多個從節點負責處理。

當一個主節點下線時,其對應的從節點會被提升為新的主節點,從而確保集羣的高可用性和可靠性。Redis 集羣還支持對數據進行分片,從而將數據分佈在多個主節點之間,提高併發處理能力和可擴展性。

user avatar ticktank 頭像 pudongping 頭像 jiegeng_23 頭像 hufeng 頭像
4 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.