Redis分片集群的實現(xiàn)方法
一、 為什么需要 Redis 分片集群? ??
想象一下,你開了一家生意爆火的小賣部 (單個 Redis 實例) ??。
- 問題一:地方不夠大 (內(nèi)存瓶頸) ??:顧客越來越多,貨架 (內(nèi)存) 都堆滿了,新商品放不下了。單個 Redis 服務(wù)器的內(nèi)存是有限的,當數(shù)據(jù)量超過這臺服務(wù)器的內(nèi)存容量時,就存不下了。
- 問題二:老板忙不過來 (CPU/網(wǎng)絡(luò)瓶頸) ??♂???:顧客排長隊結(jié)賬,老板一個人收錢、打包、找零,忙得團團轉(zhuǎn) (CPU 達到極限)。同時,店門口的路太窄 (網(wǎng)絡(luò)帶寬),進出的人太多,堵車了 ??????。單個 Redis 服務(wù)器的 CPU 處理能力和網(wǎng)絡(luò)帶寬也是有限的,當請求量非常大時,它會成為性能瓶頸,響應(yīng)變慢。
- 問題三:老板病了就關(guān)門 (可用性問題) ??:萬一老板生病了或者店里停電了 (服務(wù)器宕機),整個小賣部就得關(guān)門歇業(yè),顧客買不到東西。單個 Redis 實例存在單點故障風險,一旦它掛了,整個服務(wù)就不可用了。
分片集群就是為了解決這些問題! ??
它的思路是:既然一個小賣部不夠用,那就開連鎖超市!??????
- 解決內(nèi)存瓶頸 ??:開多家分店 (多個 Redis 節(jié)點),把商品 (數(shù)據(jù)) 分散到不同的店里。這樣總的存儲空間就大大增加了。
- 解決 CPU/網(wǎng)絡(luò)瓶頸 ??:顧客可以去不同的分店結(jié)賬,每個店的老板 (CPU) 壓力都小了,店門口的路 (網(wǎng)絡(luò)) 也不會那么擁擠了。請求被分散到多個節(jié)點處理,提高了整體的吞吐量。
- 解決可用性問題 ??:每個分店都配個副店長 (主從復(fù)制) ??。萬一某個店長病了 (主節(jié)點宕機),副店長立刻頂上 (從節(jié)點自動切換為主節(jié)點),超市還能繼續(xù)營業(yè)。提供了高可用性。
所以,Redis 分片集群的核心思想就是:
- 分片 (Sharding) ??:把數(shù)據(jù)“切”成很多片,分散存儲在多個 Redis 實例(主節(jié)點)上。
- 復(fù)制 (Replication) ??:給每個存儲數(shù)據(jù)的實例(主節(jié)點)配備一個或多個備份實例(從節(jié)點),保證高可用。
二、 Redis 分片集群是什么? ??
Redis Cluster 是 Redis 官方提供的分布式解決方案。它不是像哨兵(Sentinel)那樣只負責高可用切換,而是同時解決了數(shù)據(jù)分片和高可用兩個問題。?
它是一個去中心化的架構(gòu),這意味著沒有一個“中央調(diào)度員”或者“代理服務(wù)器”來指揮所有請求。集群中的每個節(jié)點都知道其他節(jié)點的存在,也知道哪些數(shù)據(jù)(通過后面會講的 Slot)應(yīng)該由哪個節(jié)點負責??蛻舳丝梢灾苯舆B接到集群中的任意一個節(jié)點發(fā)起請求,如果這個節(jié)點恰好負責處理這個請求的數(shù)據(jù),就直接處理;如果不是,它會告訴客戶端“喂,你應(yīng)該去找 XXX 節(jié)點 ??”,然后客戶端再去連接正確的節(jié)點。
三、 散列插槽 (Slot) 是什么? (數(shù)據(jù)怎么分?) ??
前面說到要把數(shù)據(jù)“切片”分散到不同的店(主節(jié)點)。那具體怎么切?怎么知道哪個數(shù)據(jù)該去哪個店呢? 這就是散列插槽 (Hash Slot) 的作用。
- 想象一個大郵局有 16384 個信箱 (Slot) ??:Redis Cluster 預(yù)設(shè)了 16384 個 Slot (編號 0 到 16383)。這個數(shù)字是固定的。
- 每封信 (Key) 都有個目標信箱 ??:當你存一個鍵值對 (比如
set mykey myvalue) 時,Redis Cluster 會對這個key(也就是 “mykey”) 做一個特殊的計算 (CRC16 算法),然后用計算結(jié)果對 16384 取模。HASH_SLOT = CRC16(key) % 16384。這個結(jié)果就是一個 0 到 16383 之間的數(shù)字,決定了這個key屬于哪個 Slot。 - 每個郵遞員 (Master Node) 負責一部分信箱 ????:在集群初始化的時候,這 16384 個 Slot 會被平均分配給所有的主節(jié)點。比如你有 3 個主節(jié)點,那么:
- 節(jié)點 A 可能負責 Slot 0 到 5460
- 節(jié)點 B 可能負責 Slot 5461 到 10922
- 節(jié)點 C 可能負責 Slot 10923 到 16383
- 找對郵遞員 ??:當客戶端要操作一個
key時,它會先計算這個key屬于哪個 Slot,然后根據(jù)自己緩存的“Slot 分配表”,找到負責這個 Slot 的主節(jié)點,再把請求發(fā)給那個主節(jié)點。
為什么是 16384? Redis 作者認為這個數(shù)字:
- 足夠分散數(shù)據(jù)到最多 1000 個主節(jié)點(實踐中很少有這么大規(guī)模的集群 ??)。
- 節(jié)點間傳輸 Slot 配置信息時,用 16384 個 Slot(即 16384 bit = 2KB)的位圖 (bitmap) 來表示,這個大小比較合適,不會太大導(dǎo)致網(wǎng)絡(luò)開銷過高。??
如何查看某個 Key 屬于哪個 Slot?
可以使用命令:CLUSTER KEYSLOT {key},例如 CLUSTER KEYSLOT mykey。
四、 如何搭建三主六從的 Redis 分片集群? ????
這里我們用 Docker Compose 來模擬 9 個 Redis 實例,組成一個 3 主 6 從(每個主節(jié)點帶 2 個從節(jié)點)的集群。
前提條件:
- 你的 Linux 系統(tǒng)安裝了 Docker。
- 你的 Linux 系統(tǒng)安裝了 Docker Compose。
步驟:
創(chuàng)建工作目錄: ??
mkdir redis-cluster-demo cd redis-cluster-demo
創(chuàng)建 docker-compose.yml 文件: ??
services:
# 定義 9 個 Redis 節(jié)點服務(wù) (這里只展示 node-1 和 node-4 作為例子, 其他類似)
redis-node-1: # Master 1 Candidate
image: redis:latest # 或者更新的版本
container_name: redis-node-1
# 注意:推薦將 nodes.conf 放在持久化數(shù)據(jù)目錄中
command: redis-server --port 6379 --cluster-enabled yes --cluster-config-file /data/nodes.conf --cluster-node-timeout 5000 --appendonly yes --bind 0.0.0.0
ports:
- "7001:6379" # 客戶端端口映射
- "17001:16379" # 集群總線端口映射
volumes:
- ./node-1/data:/data # 只映射數(shù)據(jù)目錄
networks:
- redis-cluster-net
redis-node-2: # Master 2 Candidate
image: redis:latest
container_name: redis-node-2
command: redis-server --port 6379 --cluster-enabled yes --cluster-config-file /data/nodes.conf --cluster-node-timeout 5000 --appendonly yes --bind 0.0.0.0
ports:
- "7002:6379"
- "17002:16379"
volumes:
- ./node-2/data:/data
networks:
- redis-cluster-net
redis-node-3: # Master 3 Candidate
image: redis:latest
container_name: redis-node-3
command: redis-server --port 6379 --cluster-enabled yes --cluster-config-file /data/nodes.conf --cluster-node-timeout 5000 --appendonly yes --bind 0.0.0.0
ports:
- "7003:6379"
- "17003:16379"
volumes:
- ./node-3/data:/data
networks:
- redis-cluster-net
redis-node-4: # Slave Candidate 1
image: redis:latest
container_name: redis-node-4
command: redis-server --port 6379 --cluster-enabled yes --cluster-config-file /data/nodes.conf --cluster-node-timeout 5000 --appendonly yes --bind 0.0.0.0
ports:
- "7004:6379"
- "17004:16379"
volumes:
- ./node-4/data:/data
networks:
- redis-cluster-net
# ... (省略 redis-node-5 到 redis-node-9 的定義,與 node-4 類似,只需修改名稱、端口映射和卷映射目錄即可) ...
# 例如 redis-node-5: ports: ["7005:6379", "17005:16379"], volumes: ["./node-5/data:/data"]
# 例如 redis-node-9: ports: ["7009:6379", "17009:16379"], volumes: ["./node-9/data:/data"]
redis-node-5:
image: redis:latest
container_name: redis-node-5
command: redis-server --port 6379 --cluster-enabled yes --cluster-config-file /data/nodes.conf --cluster-node-timeout 5000 --appendonly yes --bind 0.0.0.0
ports:
- "7005:6379"
- "17005:16379"
volumes:
- ./node-5/data:/data
networks:
- redis-cluster-net
redis-node-6:
image: redis:latest
container_name: redis-node-6
command: redis-server --port 6379 --cluster-enabled yes --cluster-config-file /data/nodes.conf --cluster-node-timeout 5000 --appendonly yes --bind 0.0.0.0
ports:
- "7006:6379"
- "17006:16379"
volumes:
- ./node-6/data:/data
networks:
- redis-cluster-net
redis-node-7:
image: redis:latest
container_name: redis-node-7
command: redis-server --port 6379 --cluster-enabled yes --cluster-config-file /data/nodes.conf --cluster-node-timeout 5000 --appendonly yes --bind 0.0.0.0
ports:
- "7007:6379"
- "17007:16379"
volumes:
- ./node-7/data:/data
networks:
- redis-cluster-net
redis-node-8:
image: redis:latest
container_name: redis-node-8
command: redis-server --port 6379 --cluster-enabled yes --cluster-config-file /data/nodes.conf --cluster-node-timeout 5000 --appendonly yes --bind 0.0.0.0
ports:
- "7008:6379"
- "17008:16379"
volumes:
- ./node-8/data:/data
networks:
- redis-cluster-net
redis-node-9:
image: redis:latest
container_name: redis-node-9
command: redis-server --port 6379 --cluster-enabled yes --cluster-config-file /data/nodes.conf --cluster-node-timeout 5000 --appendonly yes --bind 0.0.0.0
ports:
- "7009:6379"
- "17009:16379"
volumes:
- ./node-9/data:/data
networks:
- redis-cluster-net
networks:
redis-cluster-net:
driver: bridge # 或者其他網(wǎng)絡(luò)驅(qū)動
說明:
command: 啟動 Redis 并開啟集群模式,指定配置文件在/data目錄下。推薦這種方式,讓 Redis 自己管理nodes.conf。ports: 映射客戶端端口 (6379 -> 700x) 和集群總線端口 (16379 -> 1700x)。總線端口必須能互通! ??volumes: 將數(shù)據(jù)目錄掛載出來,保證持久化。networks: 所有節(jié)點在一個共享網(wǎng)絡(luò)里。
創(chuàng)建必要的目錄: ???
for i in {1..9}; do mkdir -p ./node-$i/data; done

啟動所有 Redis 容器: ??
docker compose up -d

等待所有容器啟動完成。可以用 docker ps 查看狀態(tài)。
創(chuàng)建集群: ? 關(guān)鍵一步 ?
這一步需要使用 redis-cli 工具來告訴這些獨立的 Redis 節(jié)點:“嘿,你們現(xiàn)在組成一個大家庭了!”
找到你的宿主機 IP 地址: 不能用 127.0.0.1 或 localhost。用 ip addr 或 ifconfig 查找。假設(shè)你的 IP 是 172.29.0.10 (請?zhí)鎿Q成你自己的!)??梢允褂?docker inspect redis-node-1 | grep '"IPAddress":' 命令查看:

執(zhí)行集群創(chuàng)建命令:
# 獲取任一節(jié)點的 redis-cli (用 node-1 舉例) docker exec -it redis-node-1 redis-cli --cluster create \ 172.28.120.43:7001 172.28.120.43:7002 172.28.120.43:7003 \ 172.28.120.43:7004 172.28.120.43:7005 172.28.120.43:7006 \ 172.28.120.43:7007 172.28.120.43:7008 172.28.120.43:7009 \ --cluster-replicas 2
解釋:
docker exec -it redis-node-1 redis-cli: 進入redis-node-1容器執(zhí)行命令。--cluster create: 創(chuàng)建集群。- 后面是一長串
IP:PORT列表 (用宿主機 IP 和映射的客戶端端口)。 --cluster-replicas 2: 核心參數(shù)!告訴工具,給每個主節(jié)點配 2 個從節(jié)點。它會自動算:9 個節(jié)點 / (1主 + 2從) = 3 個主節(jié)點。所以,它會把前 3 個 (7001, 7002, 7003) 當作主,后 6 個 (7004-7009) 當作從,并自動分配。 magically! ?確認創(chuàng)建:
redis-cli會打印出計劃的配置方案,問你Can I set the cluster configuration? (type 'yes' to accept):。輸入yes并回車。
驗證集群狀態(tài): ?
連接到任意一個節(jié)點(使用映射的端口),查看集群信息。
# 連接到 7001 節(jié)點 (在容器內(nèi)) docker exec -it redis-node-1 redis-cli -p 6379 cluster info # 或者從宿主機連接 (需要安裝 redis-cli, -c 表示啟用集群模式) # redis-cli -c -h 172.29.0.10 -p 7001 cluster info
你應(yīng)該看到 cluster_state:ok。
查看節(jié)點信息:
docker exec -it redis-node-1 redis-cli -p 6379 cluster nodes # 或者從宿主機連接 # redis-cli -c -h 172.29.0.10 -p 7001 cluster nodes
你會看到 9 個節(jié)點的信息,包括角色 (master/slave)、負責的 Slot 等。你會發(fā)現(xiàn) 3 個 master 和 6 個 slave,關(guān)系明確。
?? 恭喜!你的 3 主 6 從 Redis 集群現(xiàn)在跑起來了!
五、 分片集群的集群伸縮是什么? ??
集群搭好了,但業(yè)務(wù)發(fā)展太快 ??,3 家分店又不夠用了,或者某個區(qū)域顧客少了 ??,想關(guān)掉一家店。這就是集群伸縮。
伸:擴容 (Scale Out) - 增加新的 Redis 節(jié)點。
- 開新店 (添加節(jié)點) ??:先按照上面的方法啟動一個新的 Redis 實例(比如
redis-node-10,映射端口7010和17010),讓它也運行在集群模式下,但它剛開始是“孤單”的。 - 把它拉進連鎖體系 (加入集群) ??:使用
redis-cli --cluster add-node命令,告訴集群里的某個老節(jié)點,把這個新家伙拉進來。默認加進來是作為 主節(jié)點,但它還沒分到活兒 (Slot)。如果要加從節(jié)點,用# 新節(jié)點 172.29.0.10:7010, 加入到現(xiàn)有集群 (通過 7001 節(jié)點操作) docker exec -it redis-node-1 redis-cli --cluster add-node 172.29.0.10:7010 172.29.0.10:7001
--cluster-slave和--cluster-master-id <主節(jié)點ID>。 - 分配工作 (遷移 Slot) ??:新來的主節(jié)點不能閑著,需要從老主節(jié)點那里“勻”一些 Slot (和對應(yīng)的數(shù)據(jù)) 過來。這叫 Resharding (重新分片)。使用
redis-cli --cluster reshard命令,它會像個向?qū)б粯訂柲悖?ul> - 要搬多少個 Slot 呀?
- 搬給誰呢 (輸入新節(jié)點的 Node ID)?
- 從哪里搬 (可以輸入
all讓大家分攤,或者指定某些節(jié)點)?
- 開新店 (添加節(jié)點) ??:先按照上面的方法啟動一個新的 Redis 實例(比如
# 連接到任一節(jié)點發(fā)起 reshard (例如 7001) docker exec -it redis-node-1 redis-cli --cluster reshard 172.29.0.10:7001 # ... 根據(jù)提示一步步操作 ...
縮:縮容 (Scale In) - 移除 Redis 節(jié)點。
- 交接工作 (遷移 Slot) ??:如果要移除的是一個 主節(jié)點,必須先把它的 Slot 全部遷走,交給其他主節(jié)點。還是用
redis-cli --cluster reshard,這次把要移除節(jié)點的所有 Slot 作為“源”,分配給別人。確保它手里的 Slot 清零! 如果移除的是 從節(jié)點,就不用操心 Slot 了,直接下一步。 - 辦理離職手續(xù) (移除節(jié)點) ??:使用
redis-cli --cluster del-node命令,告訴集群,把這個節(jié)點“開除”掉。# 假設(shè)要移除 7003 節(jié)點,其 Node ID 是 <node-3-id> (用 cluster nodes 查) # 通過 7001 節(jié)點操作 docker exec -it redis-node-1 redis-cli --cluster del-node 172.29.0.10:7001 <node-3-id>
- 關(guān)店 (關(guān)閉實例) :最后,把被移除節(jié)點的 Redis 進程或 Docker 容器停掉。
docker-compose stop redis-node-3 # 如果用 docker-compose 管理 # 或者 docker stop redis-node-3
伸縮操作都需要時間讓集群狀態(tài)同步和數(shù)據(jù)遷移。耐心點哦!?
六、 如何使用 RedisTemplate 訪問分片集群???
在 Java 應(yīng)用中(特別是 Spring Boot / Spring Data Redis),訪問 Redis Cluster 很方便。配置好后,用 RedisTemplate 就行,跟用單實例差不多。
添加依賴: (pom.xml / build.gradle)
確保有spring-boot-starter-data-redis。它通常默認使用 Lettuce 客戶端,Lettuce 對 Cluster 支持很好。<!-- Maven 示例 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- 一般不需要額外添加 Lettuce 或 Jedis,除非你想強制用 Jedis -->配置
application.properties或application.yml:
告訴 Spring Data Redis 你的集群在哪兒。不需要寫全所有節(jié)點,寫幾個就行,客戶端會自動發(fā)現(xiàn)其他的。??application.properties示例:# Redis Cluster 節(jié)點列表 (逗號分隔 host:port) spring.redis.cluster.nodes=172.29.0.10:7001,172.29.0.10:7002,172.29.0.10:7003 # 如果有密碼 # spring.redis.password=yourpassword # 連接池配置 (可選, Lettuce) spring.redis.lettuce.pool.max-active=8 spring.redis.lettuce.pool.max-idle=8
application.yml示例:spring: redis: cluster: nodes: - 172.29.0.10:7001 - 172.29.0.10:7002 - 172.29.0.10:7003 # password: yourpassword # 可選 lettuce: # 可選連接池 pool: max-active: 8 max-idle: 8在代碼中使用
RedisTemplate:
注入RedisTemplate或StringRedisTemplate,然后就像操作普通 Redis 一樣用。import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; @Service public class MyRedisService { @Autowired private StringRedisTemplate stringRedisTemplate; // 或者 RedisTemplate<String, Object> public void setValue(String key, String value) { // 直接用!它會自動找到正確的節(jié)點去執(zhí)行 set 命令 stringRedisTemplate.opsForValue().set(key, value); System.out.println("設(shè)置 Key: " + key + " 到集群! ??"); } public String getValue(String key) { // 同樣,自動路由到持有這個 key 的節(jié)點去 get String value = stringRedisTemplate.opsForValue().get(key); System.out.println("從集群獲取 Key: " + key + ", Value: " + value + " ??"); return value; } // 其他操作 hash, list, set, zset 都類似! }
關(guān)鍵點:
- 無感操作: 大部分單 Key 操作,你感覺不到集群的存在。??
- 自動尋址: 客戶端庫內(nèi)部維護 Slot -> 節(jié)點映射,自動把命令發(fā)給對的節(jié)點。
- 聰明糾錯: 如果映射過時 (比如剛發(fā)生了故障轉(zhuǎn)移),節(jié)點會返回
MOVED或ASK錯誤。客戶端庫收到后會自動更新映射,然后重試命令,對你的程序來說幾乎是透明的。?? - 多 Key 操作要注意! ??:像
MSET,MGET, 事務(wù) (MULTI/EXEC) 這類涉及多個 Key 的,默認必須保證所有 Key 都在同一個 Slot 里。怎么保證?用 Hash Tags! Key 里用{}包起來的部分才參與 Slot 計算。例如user:{1000}:name和user:{1000}:profile就會落到同一個 Slot,因為都看{1000}。 如果 Key 不在同個 Slot,執(zhí)行這些命令會報錯哦!??
七、 分片集群的原理是什么? ????
Redis Cluster 的魔法主要靠這幾招:
節(jié)點間八卦 (Gossip 協(xié)議):
深入了解Gossip協(xié)議請看:Gossip協(xié)議:分布式系統(tǒng)中的“八卦”傳播藝術(shù)
- 每個節(jié)點心里都有本賬(集群狀態(tài):誰活著,誰管哪些 Slot,主從關(guān)系等)。
- 節(jié)點之間通過 集群總線端口 (客戶端端口+10000那個) 定期互相 PING/PONG,順便交換自己知道的“八卦消息”(集群狀態(tài)信息)。?????
- 這種方式沒有中心老大,大家互相通氣,最終信息會傳遍整個集群,達成一致(雖然可能有點延遲,叫最終一致性)。
Slot 地盤劃分與同步:
- 每個主節(jié)點“認領(lǐng)”自己負責的 Slot。
- 認領(lǐng)信息通過 Gossip 協(xié)議告訴所有人。
- 客戶端連上任何一個節(jié)點,都能拿到最新的“地盤劃分圖”(Slot -> 節(jié)點映射)。???
心跳檢測與“懷疑人生”(PFAIL & FAIL):
- 節(jié)點間互相 PING,如果 A 在
cluster-node-timeout內(nèi)沒收到 B 的 PONG 回復(fù),A 就開始“懷疑” B 是不是掛了,標記為 PFAIL (Possible Fail - 可能掛了)。這只是 A 的個人看法。?? - A 會把這個“懷疑”通過 Gossip 告訴其他主節(jié)點。
- 如果超過一半的主節(jié)點都覺得“嗯,我也聯(lián)系不上 B 了”,大家就達成共識:B 確實掛了!狀態(tài)升級為 FAIL。這個“噩耗”會廣播給所有人。??
- 節(jié)點間互相 PING,如果 A 在
小弟上位記 (自動故障轉(zhuǎn)移 Failover):
- 一旦某個主節(jié)點被確認 FAIL 了,它的從節(jié)點們就開始騷動了:“大哥倒了,機會來了!” ??
- 誰能上位?得看:確認大哥真掛了,并且自己數(shù)據(jù)跟大哥差別不大(同步延遲?。?。
- 選舉流程:
- 想上位的從節(jié)點,先給自己“資歷”加一分 (
currentEpoch++), 然后廣發(fā)英雄帖給所有主節(jié)點:“選我!選我!” ??? - 還活著的主節(jié)點收到帖子,如果在這個“任期”(
epoch) 內(nèi)還沒投過票,就給第一個發(fā)帖的從節(jié)點投一票。 - 哪個從節(jié)點最先拿到超過半數(shù)主節(jié)點的投票,就成功當選新大哥!??
- 想上位的從節(jié)點,先給自己“資歷”加一分 (
- 走馬上任:新大哥(原從節(jié)點)立馬:
- 宣布自己是主節(jié)點了。
- 接管原來大哥的所有 Slot 地盤。
- 通過 Gossip 昭告天下:“從今天起,這些 Slot 歸我管了!”??
- 服務(wù)恢復(fù):整個過程是自動的,客戶端在短暫的切換后就能找到新大哥繼續(xù)工作。注意??:如果某個主節(jié)點和它的所有從節(jié)點同時掛掉,那它負責的 Slot 就真的服務(wù)不了了,需要人工介入。另外,如果超過半數(shù)的主節(jié)點都掛了,為了防止數(shù)據(jù)錯亂,整個集群會停止服務(wù)!??
客戶端導(dǎo)航 (MOVED & ASK):
- MOVED (搬家了,去那邊!) ??:客戶端可能拿著舊地圖(過時的 Slot 映射)找錯了節(jié)點。這個節(jié)點會說:“兄弟,這個 Slot 不歸我管了,已經(jīng)搬到
ip:port那家去了,你去那邊吧!” 并返回MOVED <slot> <correct_ip>:<correct_port>??蛻舳耸盏胶?,會更新地圖,然后乖乖去新地址重新請求。 - ASK (稍等,問問那邊) ??:在 Slot 遷移過程中,比如 Slot X 正從 A 往 B 搬。客戶端還是找舊主 A 問 Slot X 里的某個 key:
- 如果 key 還在 A 這,A 就處理了。
- 如果 key 已經(jīng)搬到 B 那了,A 會說:“這個 key 可能在 B 那了,你去問問 B 試試?” 并返回
ASK <slot> <destination_ip>:<destination_port>。 - 客戶端收到
ASK,不會更新地圖(因為搬家還沒徹底完成)。它會先去 B 那邊敲門說ASKING(表明我是被 A 指過來的),然后再發(fā)真正的命令。B 收到ASKING就知道怎么回事了,即使 Slot X 還沒完全歸它管,也會臨時處理這條命令。ASK只管用一次。
- MOVED (搬家了,去那邊!) ??:客戶端可能拿著舊地圖(過時的 Slot 映射)找錯了節(jié)點。這個節(jié)點會說:“兄弟,這個 Slot 不歸我管了,已經(jīng)搬到
八、 分片集群的優(yōu)缺點是什么?
優(yōu)點:
- 能屈能伸 (Scalability) ?:加機器就能加容量、加性能,理論上可以搞很大規(guī)模。就像開連鎖店,想開多少開多少。
- 打不死的小強 (High Availability) ?:主從熱備 + 自動切換,掛掉一兩個節(jié)點服務(wù)基本不受影響(只要不是主從一起掛,或掛掉太多主)。
- 跑得快 (Performance) ?:請求分散到多個節(jié)點,大家分擔壓力,整體響應(yīng)快。
- 親兒子待遇 (Official Solution) ?:Redis 官方出品,穩(wěn)定性和兼容性有保障,社區(qū)活躍。
- 群龍無首也行 (Decentralized) ?:沒有中央控制節(jié)點,避免了單點瓶頸和故障。
缺點:
- 多 Key 操作有點瘸 (Multi-key Operations Limitation) ??:像
MSET、事務(wù)等,默認要求 Key 在同一個 Slot,否則報錯。需要開發(fā)者注意,或者用 Hash Tags 繞一下???Slot 的復(fù)雜操作比較麻煩。 - 有點復(fù)雜 (Complexity) ??:配置、管理、排錯比單機或哨兵模式復(fù)雜,需要懂 Slot、Gossip 這些概念。運維成本高點。
- 話癆費網(wǎng) (Network Overhead) ??:節(jié)點間需要不停地 Gossip 來同步狀態(tài),會消耗一些網(wǎng)絡(luò)帶寬和 CPU。
- 客戶端要配套 (Client Compatibility) ??:必須用支持 Redis Cluster 的客戶端庫(新版的 Lettuce、Jedis 都支持)。
- 可能偏心 (Data Skew) ??:如果 Key 設(shè)計不好(比如 Hash Tag 用得太集中,或有超級熱點 Key),可能導(dǎo)致數(shù)據(jù)和流量集中在少數(shù)節(jié)點,失去均衡效果。??♀?
- 批量活兒效率可能不高 (Batch Efficiency) ??:如果要操作一大堆分布在不同 Slot 的 Key,客戶端得跟多個節(jié)點打交道,可能不如單實例高效。
- 團結(jié)就是力量(但散了就…) (Cluster Integrity Requirement) ??:集群的正常運行和故障轉(zhuǎn)移依賴于“少數(shù)服從多數(shù)”原則。如果掛掉的主節(jié)點太多(超過半數(shù)),整個集群就“癱瘓”了,拒絕服務(wù)以保護數(shù)據(jù)。
到此這篇關(guān)于Redis分片集群的實現(xiàn)方法的文章就介紹到這了,更多相關(guān)Redis分片集群內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Redis數(shù)據(jù)類型之散列類型hash命令學習
這篇文章主要為大家介紹了Redis數(shù)據(jù)類型之散列類型hash命令學習,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-07-07
Redis源碼解析:集群手動故障轉(zhuǎn)移、從節(jié)點遷移詳解
這篇文章主要介紹了Redis源碼解析:集群手動故障轉(zhuǎn)移、從節(jié)點遷移的相關(guān)內(nèi)容,涉及通過集群定時器函數(shù)clusterCron實現(xiàn)從節(jié)點遷移等知識,具有一定參考價值,需要的朋友可以了解。2017-10-10
Redis 實現(xiàn)好友關(guān)注和關(guān)注推送的示例代碼
本文介紹了使用Redis實現(xiàn)好友關(guān)注和關(guān)注推送功能,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2025-03-03
基于?Spring?Aop?環(huán)繞通知實現(xiàn)?Redis?緩存雙刪功能(示例代碼)
基于 spring aop 常規(guī)應(yīng)用場景多是用于日志記錄以及實現(xiàn) redis 分布式鎖,在 github 中也有項目是把它拿來當作緩存的異常捕捉,這篇文章主要介紹了基于?Spring?Aop?環(huán)繞通知實現(xiàn)?Redis?緩存雙刪,需要的朋友可以參考下2022-08-08

