缓存集群槽分片的使用示例
1 简介
本文基于redis cluster 集群深入分析Redis Cluster 分片(槽分片机制),并且使用go 和go-redisv8 实现一个在2个cluster节点的商品零售排行榜服务,说明Cluster集群相对单节点的优势。
2 槽分片机制的分析
Redis Cluster 分片(槽分片机制)分析,Redis Cluster 分片机制通过将数据分布在逻辑槽(hash slot)中实现:
- 槽分片机制:
Redis Cluster 将整个键空间划分为 16384 个逻辑槽。
每个键根据 CRC16 哈希计算结果取模 16384 决定其槽位。
每个节点负责一定范围的槽位。
- 数据分布:
数据均匀分布在多个节点上,减少单节点负载。
客户端通过槽位直接访问目标节点,避免额外代理层。
- 扩展性:
动态扩容/缩容时,以槽为单位迁移数据,降低迁移成本。
- 高可用:
支持主从模式,主节点故障时从节点自动提升为主节点,保证服务可用性。
3 Cluster 集群的优势
-
性能扩展:
数据分布在多个节点,支持高并发和大数据存储。 -
高可用性:
支持主从复制和自动故障转移,增强系统可靠性。 -
动态扩展:
集群节点可动态添加或删除,灵活应对容量变化。 -
无代理层:
客户端通过槽位直连目标节点,减少中间层开销。 -
实现商品零售排行榜服务
目标:构建一个商品销售排行榜服务,使用 Redis Cluster 分片存储销售数据,并根据销售额动态生成排行榜。
4 Redis 数据设计
键结构:
sales:{product_id}:存储单个商品的销售额。
有序集合:
使用 Redis 的 Sorted Set 维护全局排行榜,键名为 sales:ranking。
技术栈
5 编程语言实现应用
go-redis/v8:支持 Redis Cluster 的 Go 客户端。代码实现如下
package main
import (
"context"
"fmt"
"log"
"strconv"
"github.com/go-redis/redis/v8"
)
// Redis Cluster configuration
var redisClusterAddrs = []string{"127.0.0.1:6379", "127.0.0.1:6380"}
var ctx = context.Background()
// Redis Client initialization
func initRedisCluster() *redis.ClusterClient {
rdb := redis.NewClusterClient(&redis.ClusterOptions{
Addrs: redisClusterAddrs,
})
// Ping to check the connection
if err := rdb.Ping(ctx).Err(); err != nil {
log.Fatalf("Failed to connect to Redis Cluster: %v", err)
}
return rdb
}
// RecordSale: Add sales for a product
func recordSale(rdb *redis.ClusterClient, productID string, amount float64) error {
// Increment the sales for the product
productKey := fmt.Sprintf("sales:%s", productID)
if err := rdb.IncrByFloat(ctx, productKey, amount).Err(); err != nil {
return fmt.Errorf("failed to record sale: %w", err)
}
// Update the global ranking
if err := rdb.ZIncrBy(ctx, "sales:ranking", amount, productID).Err(); err != nil {
return fmt.Errorf("failed to update ranking: %w", err)
}
return nil
}
// GetTopProducts: Retrieve top N products from the ranking
func getTopProducts(rdb *redis.ClusterClient, topN int) ([]string, error) {
rankings, err := rdb.ZRevRangeWithScores(ctx, "sales:ranking", 0, int64(topN-1)).Result()
if err != nil {
return nil, fmt.Errorf("failed to retrieve top products: %w", err)
}
var results []string
for _, ranking := range rankings {
results = append(results, fmt.Sprintf("ProductID: %s, Sales: %.2f", ranking.Member, ranking.Score))
}
return results, nil
}
func main() {
// Initialize Redis Cluster client
rdb := initRedisCluster()
defer rdb.Close()
// Example: Record sales
products := []string{"prod1", "prod2", "prod3", "prod4"}
sales := []float64{150.0, 200.0, 50.0, 300.0}
fmt.Println("Recording sales...")
for i, product := range products {
if err := recordSale(rdb, product, sales[i]); err != nil {
log.Printf("Error recording sale for %s: %v", product, err)
}
}
// Retrieve and display the top 3 products
fmt.Println("Top products:")
topProducts, err := getTopProducts(rdb, 3)
if err != nil {
log.Fatalf("Error retrieving top products: %v", err)
}
for _, product := range topProducts {
fmt.Println(product)
}
}
6 程序说明
功能细节,记录销售额(recordSale):
使用 IncrByFloat 更新单个商品的销售总额。
使用 ZIncrBy 更新排行榜(Sorted Set)。
查询排行榜(getTopProducts):
使用 ZRevRangeWithScores 按销售额降序获取前 N 个商品。
- 运行环境
Redis Cluster 配置:
至少 2 个节点(127.0.0.1:6379 和 127.0.0.1:6380)。
可通过 Docker 或手动搭建 Redis Cluster。
Cluster 相对单节点的优势
- 数据分布:
Cluster 自动分片,销售数据(如 sales:prod1 和 sales:prod2)存储在不同节点,避免单节点瓶颈。
单节点模式无法水平扩展,当数据或流量增加时容易超出处理能力。
- 高可用性:
Cluster 提供主从备份和故障转移能力,确保服务可用性。
单节点模式没有容错能力,节点故障会导致服务中断。
- 动态扩展:
Cluster 支持动态扩容,节点增加后自动迁移部分槽位。
单节点模式需要手动分片并迁移数据,增加运维复杂度。
7 小结
Cluster 将请求分散到多个节点,提升并发处理能力。
单节点模式的资源有限,性能瓶颈明显。
通过以上实现,我们展示了 Redis Cluster 的分片机制和高可用特性,适合大规模、高并发的商品零售场景,而单节点模式仅适用于小规模场景。
- 点赞
- 收藏
- 关注作者
评论(0)