網(wǎng)站全程設(shè)計(jì)技術(shù)百度一下打開網(wǎng)頁
Redis 集群是 Redis 提供的一種分布式實(shí)現(xiàn),用于水平擴(kuò)展數(shù)據(jù)存儲(chǔ)能力。通過 Redis 集群,可以將數(shù)據(jù)分片存儲(chǔ)在多個(gè) Redis 節(jié)點(diǎn)上,同時(shí)提供高可用性和故障轉(zhuǎn)移功能。
- 分片(Sharding):
- Redis 集群將數(shù)據(jù)劃分為 16384 個(gè)插槽(slots),每個(gè)插槽代表一部分?jǐn)?shù)據(jù)。
- 每個(gè) Redis 節(jié)點(diǎn)負(fù)責(zé)一部分插槽。數(shù)據(jù)鍵通過哈希函數(shù)映射到特定的插槽。
- 主從復(fù)制(Replication):
- 每個(gè)分片可以有一個(gè)主節(jié)點(diǎn)和多個(gè)從節(jié)點(diǎn)。
- 主節(jié)點(diǎn)負(fù)責(zé)處理寫請(qǐng)求,從節(jié)點(diǎn)作為備份,提供讀取和故障切換。
- 高可用性:
- 如果主節(jié)點(diǎn)故障,從節(jié)點(diǎn)會(huì)自動(dòng)提升為主節(jié)點(diǎn),確保服務(wù)可用性。
- 這只限于每個(gè)分片的主從節(jié)點(diǎn)范圍內(nèi),如果主從節(jié)點(diǎn)都掛了,那么這個(gè)分片上的數(shù)據(jù)是訪問不到的。
- 一致性模型:
- Redis 集群采用 最終一致性,在網(wǎng)絡(luò)分區(qū)的情況下使用部分可用性,但不會(huì)丟失數(shù)據(jù)。
在 Spring Boot 項(xiàng)目中集成 Redis 集群,可以使用 Spring Data Redis 來進(jìn)行配置。
在 Spring Boot 中,可以使用 RedisTemplate 來操作 Redis 數(shù)據(jù)。通過 Lettuce 客戶端來實(shí)現(xiàn) Redis 集群中的讀寫分離,可以利用 Lettuce 對(duì)讀策略(ReadFrom)的支持,將讀操作分配到從節(jié)點(diǎn),寫操作保持在主節(jié)點(diǎn)。這適用于 Redis 的主從復(fù)制架構(gòu)。
創(chuàng)建一個(gè)配置類,用于設(shè)置 RedisTemplate。
- 使用 LettuceConnectionFactory 配置 Redis 連接。
- 設(shè)置 ReadFrom 策略,選擇將讀請(qǐng)求發(fā)送到從節(jié)點(diǎn)。
- 使用 RedisTemplate 執(zhí)行讀寫操作,Lettuce 會(huì)根據(jù)配置的 ReadFrom 策略自動(dòng)選擇節(jié)點(diǎn)。
配置 LettuceConnectionFactory,通過自定義 LettuceConnectionFactory 配置 Redis 集群連接和讀策略。
可以將 Redis 集群的配置部分放在 application.yml 文件中,使配置更加靈活。
spring:redis:cluster:nodes:- 127.0.0.1:7000- 127.0.0.1:7001- 127.0.0.1:7002timeout: 5000lettuce:read-from: REPLICA_PREFERRED # 優(yōu)先從從節(jié)點(diǎn)讀取pool:max-active: 8max-idle: 8min-idle: 0
在配置類中讀取配置文件
@Configuration
public class RedisConfig {@Value("${spring.redis.cluster.nodes}")private List<String> clusterNodes;@Beanpublic LettuceConnectionFactory redisConnectionFactory() {// 使用配置文件中的 Redis 集群節(jié)點(diǎn)信息RedisClusterConfiguration clusterConfig = new RedisClusterConfiguration(clusterNodes);LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()// 使用配置文件中的讀取策略.readFrom(ReadFrom.REPLICA_PREFERRED).build();return new LettuceConnectionFactory(clusterConfig, clientConfig);}// 配置 RedisTemplate,用于與 Redis 交互@Beanpublic RedisTemplate<String, Object> redisTemplate() {RedisTemplate<String, Object> template = new RedisTemplate<>();template.setConnectionFactory(redisConnectionFactory());// 設(shè)置序列化器template.setKeySerializer(new StringRedisSerializer());template.setValueSerializer(new StringRedisSerializer());template.setHashKeySerializer(new StringRedisSerializer());template.setHashValueSerializer(new StringRedisSerializer());return template;}
}
- read-from 配置項(xiàng)說明:
- MASTER: 所有操作都在主節(jié)點(diǎn)執(zhí)行(默認(rèn))。
- MASTER_PREFERRED:優(yōu)先從主節(jié)點(diǎn)讀取數(shù)據(jù),如果主節(jié)點(diǎn)不可用則從從節(jié)點(diǎn)讀取。
- REPLICA: 所有讀取操作都從從節(jié)點(diǎn)執(zhí)行。
- REPLICA_PREFERRED: 優(yōu)先從從節(jié)點(diǎn)讀取,如果沒有可用從節(jié)點(diǎn)則讀取主節(jié)點(diǎn)。
- ANY: 讀取請(qǐng)求可以從任意節(jié)點(diǎn)執(zhí)行(包括主節(jié)點(diǎn)和從節(jié)點(diǎn))。
RedisTemplate 會(huì)根據(jù)配置的 LettuceConnectionFactory,自動(dòng)進(jìn)行讀寫分離。寫操作會(huì)默認(rèn)發(fā)往主節(jié)點(diǎn),而讀操作則根據(jù) ReadFrom 策略發(fā)往從節(jié)點(diǎn)。
在 Redis 集群中,為了在執(zhí)行 Lua 腳本時(shí)能夠確保操作的多個(gè)鍵位于同一哈希槽中,Redis 引入了 哈希標(biāo)簽(Hash Tag) 的概念。
- 哈希標(biāo)簽 是一種機(jī)制,用來告訴 Redis 集群哪些鍵應(yīng)該被視為一個(gè)整體,映射到同一個(gè)哈希槽(Hash Slot)中。
- 哈希標(biāo)簽是通過將鍵名的一部分用大括號(hào) {} 包圍來實(shí)現(xiàn)的。Redis 只會(huì)對(duì) {} 內(nèi)部的內(nèi)容進(jìn)行哈希計(jì)算,以決定該鍵的哈希槽位置。
- 如果你有兩個(gè)鍵 key1 和 key2,通常它們會(huì)映射到不同的哈希槽中。然而,如果使用哈希標(biāo)簽,例如 user:{123} 和 order:{123},那么 123 部分會(huì)被用于哈希計(jì)算,使這兩個(gè)鍵落在同一個(gè)哈希槽中。
- user:{123} 和 order:{123} 將會(huì)落在同一個(gè)哈希槽。
- user:123 和 order:123 將可能落在不同的哈希槽中。
- 在 Redis 集群環(huán)境中,當(dāng)執(zhí)行 Lua 腳本時(shí),所有涉及的鍵必須位于同一個(gè)哈希槽中,否則會(huì)報(bào)錯(cuò),因?yàn)?Redis 集群無法在不同的節(jié)點(diǎn)之間自動(dòng)協(xié)調(diào) Lua 腳本。使用哈希標(biāo)簽可以確保多個(gè)相關(guān)鍵位于同一哈希槽,這樣在執(zhí)行 Lua 腳本時(shí)可以正常運(yùn)行。
在 Redis 集群架構(gòu)中,如果發(fā)生數(shù)據(jù)傾斜(即某些節(jié)點(diǎn)存儲(chǔ)的數(shù)據(jù)明顯多于其他節(jié)點(diǎn)),這可能會(huì)導(dǎo)致部分節(jié)點(diǎn)的負(fù)載過高,影響性能和穩(wěn)定性。為了解決數(shù)據(jù)傾斜問題,可以采取以下措施:
調(diào)整哈希槽的分配
Redis 集群中使用哈希槽(hash slots)來分布數(shù)據(jù),每個(gè)節(jié)點(diǎn)管理一定數(shù)量的哈希槽。如果某些節(jié)點(diǎn)的哈希槽數(shù)量明顯多于其他節(jié)點(diǎn),可能會(huì)導(dǎo)致數(shù)據(jù)傾斜??梢酝ㄟ^ redis-cli --cluster rebalance 命令重新分配哈希槽,讓數(shù)據(jù)更均勻地分布在各個(gè)節(jié)點(diǎn)上。
# <node-address>:<port> 表示集群中任一主節(jié)點(diǎn)的地址和端口,用于連接到 Redis 集群。Redis 會(huì)通過這個(gè)節(jié)點(diǎn)獲取集群的狀態(tài)信息。
# 最終重新平衡哈希槽的分配是針對(duì)整個(gè)集群的。
redis-cli --cluster rebalance --cluster-use-empty-masters <node-address>:<port>
添加新的節(jié)點(diǎn):增加新的節(jié)點(diǎn)可以減輕現(xiàn)有節(jié)點(diǎn)的負(fù)擔(dān),并改善數(shù)據(jù)分布:
- 使用 redis-cli --cluster add-node 命令將新節(jié)點(diǎn)加入到集群中。
- 加入新節(jié)點(diǎn)后,使用 redis-cli --cluster rebalance 來重新平衡數(shù)據(jù)和哈希槽的分布,使得新節(jié)點(diǎn)參與數(shù)據(jù)存儲(chǔ)。
遷移數(shù)據(jù):可以手動(dòng)或自動(dòng)將數(shù)據(jù)從高負(fù)載節(jié)點(diǎn)遷移到其他節(jié)點(diǎn):
- 使用 redis-cli --cluster reshard 命令將部分哈希槽從高負(fù)載節(jié)點(diǎn)遷移到其他節(jié)點(diǎn)。
- 遷移數(shù)據(jù)時(shí),需要指定源節(jié)點(diǎn)、目標(biāo)節(jié)點(diǎn)以及要遷移的哈希槽數(shù)量。
redis-cli --cluster reshard <node-address>:<port>
- 輸入目標(biāo)哈希槽數(shù)量和目標(biāo)節(jié)點(diǎn),Redis 會(huì)自動(dòng)完成遷移。
選擇合適的分片鍵:如果數(shù)據(jù)傾斜是由于分片鍵選擇不合理造成的,可以考慮重新選擇分片鍵:
- 使用均勻分布的數(shù)據(jù)字段作為分片鍵,例如隨機(jī)數(shù)或 UUID,而不是用戶 ID 等容易造成數(shù)據(jù)集中化的字段。
- 使用哈希策略來確保分片鍵的散列值在集群中均勻分布。
監(jiān)控和優(yōu)化:通過監(jiān)控工具持續(xù)關(guān)注 Redis 集群的運(yùn)行狀態(tài),及早發(fā)現(xiàn)并解決數(shù)據(jù)傾斜問題:
- 使用 redis-cli --cluster info 或其他 Redis 監(jiān)控工具來查看每個(gè)節(jié)點(diǎn)的哈希槽和內(nèi)存使用情況。
- 借助 INFO 命令獲取每個(gè)節(jié)點(diǎn)的狀態(tài)信息,了解內(nèi)存和負(fù)載分布。
- 定期評(píng)估數(shù)據(jù)分布,必要時(shí)進(jìn)行數(shù)據(jù)遷移或重新分配哈希槽。
在創(chuàng)建 Redis 集群時(shí),哈希槽的分配通常是自動(dòng)進(jìn)行的,但也可以手動(dòng)分配哈希槽給每個(gè)主節(jié)點(diǎn)。
首先,使用以下命令創(chuàng)建一個(gè) Redis 集群,并為每個(gè)主節(jié)點(diǎn)分配哈希槽。
redis-cli --cluster create \
192.168.1.1:6379 \
192.168.1.2:6379 \
192.168.1.3:6379 \
192.168.1.4:6379 \
--cluster-replicas 1 \
--cluster-slots 16384
此命令將創(chuàng)建一個(gè)包含 4 個(gè)主節(jié)點(diǎn)的 Redis 集群,并為每個(gè)主節(jié)點(diǎn)指定 16384 個(gè)哈希槽。
手動(dòng)分配哈希槽
# 為主節(jié)點(diǎn) 1 分配哈希槽 0 - 4095
redis-cli --cluster addslots 192.168.1.1:6379 0 4095# 為主節(jié)點(diǎn) 2 分配哈希槽 4096 - 8191
redis-cli --cluster addslots 192.168.1.2:6379 4096 8191# 為主節(jié)點(diǎn) 3 分配哈希槽 8192 - 12287
redis-cli --cluster addslots 192.168.1.3:6379 8192 12287# 為主節(jié)點(diǎn) 4 分配哈希槽 12288 - 16383
redis-cli --cluster addslots 192.168.1.4:6379 12288 16383