大数据量下Redis分片的5种策略

news2025/5/22 23:49:02

随着业务规模的增长,单一Redis实例面临着内存容量、网络带宽和计算能力的瓶颈。

分片(Sharding)成为扩展Redis的关键策略,它将数据分散到多个Redis节点上,每个节点负责整个数据集的一个子集。

本文将分享5种Redis分片策略。

1. 取模分片(Modulo Sharding)

取模分片是最直观的哈希分片方法,根据键的哈希值对节点数取模来确定分片位置。

工作原理

  • 计算键的哈希值
  • 对节点总数取模得到节点索引
  • 将操作路由到对应节点

实现示例

public class ModuloSharding {
    private final List<JedisPool> shards;
    
    public ModuloSharding(List<String> redisHosts, int port) {
        shards = new ArrayList<>();
        for (String host : redisHosts) {
            shards.add(new JedisPool(new JedisPoolConfig(), host, port));
        }
    }
    
    private int getShardIndex(String key) {
        return Math.abs(key.hashCode() % shards.size());
    }
    
    public String get(String key) {
        int index = getShardIndex(key);
        try (Jedis jedis = shards.get(index).getResource()) {
            return jedis.get(key);
        }
    }
    
    public void set(String key, String value) {
        int index = getShardIndex(key);
        try (Jedis jedis = shards.get(index).getResource()) {
            jedis.set(key, value);
        }
    }
    
    // 节点数变化时需要重新映射所有键
    public void reshardData(List<String> newHosts, int port) {
        List<JedisPool> newShards = new ArrayList<>();
        for (String host : newHosts) {
            newShards.add(new JedisPool(new JedisPoolConfig(), host, port));
        }
        
        // 这里需要迁移数据,遍历所有键并重新分配
        // 实际实现中需要更复杂的逻辑来处理大量数据的迁移
        // ...
        
        this.shards = newShards;
    }
}

优缺点

优点

  • 实现极其简单
  • 在节点数固定时数据分布相对均匀
  • 计算开销小

缺点

  • 节点数变化时需要大量数据迁移(几乎所有键都会重新映射)
  • 可能产生热点问题
  • 不适合需要频繁扩缩容的场景

适用场景

  • 节点数相对固定的场景
  • 简单实现且对扩容需求不高的小型应用
  • 数据量较小,可以接受全量迁移的系统

2. 代理分片(Proxy-based Sharding)

代理分片通过引入中间代理层来管理分片逻辑,常见的代理包括Twemproxy(nutcracker)和Codis。

工作原理

  • 代理作为应用与Redis节点之间的中间层
  • 客户端连接到代理而非直接连接Redis
  • 代理根据内部算法将请求路由到正确的Redis节点

Twemproxy配置示例

alpha:
  listen: 127.0.0.1:22121
  hash: fnv1a_64
  distribution: ketama
  auto_eject_hosts: true
  redis: true
  server_retry_timeout: 2000
  server_failure_limit: 3
  servers:
   - 127.0.0.1:6379:1
   - 127.0.0.1:6380:1
   - 127.0.0.1:6381:1

优缺点

优点

  • 对应用透明,客户端无需感知分片细节
  • 减少客户端与Redis的连接数
  • 便于管理和监控

缺点

  • 引入单点故障风险
  • 增加了额外的网络延迟
  • 扩容通常需要手动操作
  • 代理层可能成为性能瓶颈

适用场景

  • 需要对现有系统最小改动的场景
  • 多语言环境下统一分片策略
  • 连接数需要控制的高并发场景

3. Redis Cluster

Redis Cluster是Redis官方提供的集群解决方案,从Redis 3.0版本开始支持。

工作原理

  • 使用哈希槽(hash slots)概念,总共16384个槽
  • 每个键根据CRC16算法计算后对16384取模,映射到槽
  • 槽被分配到不同的节点上
  • 支持节点间数据自动迁移和复制

配置与搭建

节点配置示例:

port 7000
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes

创建集群命令:

redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 \
  127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 --cluster-replicas 1

客户端支持代码示例

// 使用Lettuce客户端连接Redis Cluster
RedisURI redisUri = RedisURI.Builder
    .redis("127.0.0.1", 7000)
    .withTimeout(Duration.ofSeconds(60))
    .build();

RedisClusterClient clusterClient = RedisClusterClient.create(redisUri);
StatefulRedisClusterConnection<String, String> connection = clusterClient.connect();
RedisAdvancedClusterCommands<String, String> commands = connection.sync();

// 正常操作,客户端会处理集群路由
commands.set("user:1000", "张三");
String value = commands.get("user:1000");

优缺点

优点

  • 官方原生支持,持续更新和维护
  • 去中心化架构,无单点故障
  • 自动故障检测和故障转移
  • 自动处理节点间的数据分片和迁移

缺点

  • 客户端需要支持cluster协议
  • 多键操作受限于槽机制(必须在同一个槽)
  • 资源消耗较高,通信开销大
  • 配置管理相对复杂

适用场景

  • 大规模Redis部署
  • 需要高可用性和自动故障恢复
  • 数据量和负载随时间动态增长
  • Redis官方生态支持的环境

4. 一致性哈希分片(Consistent Hashing)

一致性哈希算法能够最小化节点变化时需要重新映射的键,适合节点经常变化的环境。

工作原理

  • 将哈希值空间映射到一个环上(0到2^32-1)
  • Redis节点被映射到环上的某些点
  • 每个键顺时针找到第一个遇到的节点
  • 新增或删除节点只影响相邻节点的数据

实现示例

public class ConsistentHashSharding {
    private final SortedMap<Integer, JedisPool> circle = new TreeMap<>();
    private final int numberOfReplicas;
    private final HashFunction hashFunction;
    
    public ConsistentHashSharding(List<String> nodes, int replicas) {
        this.numberOfReplicas = replicas;
        this.hashFunction = Hashing.murmur3_32();
        
        for (String node : nodes) {
            addNode(node);
        }
    }
    
    public void addNode(String node) {
        for (int i = 0; i < numberOfReplicas; i++) {
            String virtualNode = node + "-" + i;
            int hash = hashFunction.hashString(virtualNode, Charset.defaultCharset()).asInt();
            circle.put(hash, new JedisPool(new JedisPoolConfig(), node.split(":")[0], 
                       Integer.parseInt(node.split(":")[1])));
        }
    }
    
    public void removeNode(String node) {
        for (int i = 0; i < numberOfReplicas; i++) {
            String virtualNode = node + "-" + i;
            int hash = hashFunction.hashString(virtualNode, Charset.defaultCharset()).asInt();
            circle.remove(hash);
        }
    }
    
    public JedisPool getNode(String key) {
        if (circle.isEmpty()) {
            return null;
        }
        
        int hash = hashFunction.hashString(key, Charset.defaultCharset()).asInt();
        
        if (!circle.containsKey(hash)) {
            SortedMap<Integer, JedisPool> tailMap = circle.tailMap(hash);
            hash = tailMap.isEmpty() ? circle.firstKey() : tailMap.firstKey();
        }
        
        return circle.get(hash);
    }
    
    public String get(String key) {
        JedisPool pool = getNode(key);
        try (Jedis jedis = pool.getResource()) {
            return jedis.get(key);
        }
    }
    
    public void set(String key, String value) {
        JedisPool pool = getNode(key);
        try (Jedis jedis = pool.getResource()) {
            jedis.set(key, value);
        }
    }
}

优缺点

优点

  • 节点变化时最小化数据迁移
  • 相对均匀的数据分布
  • 适合动态伸缩的环境

缺点

  • 实现较为复杂
  • 虚拟节点引入额外的内存开销
  • 数据分布可能仍有不均衡现象

适用场景

  • 节点频繁增减的环境
  • 需要动态扩缩容的大型应用
  • 对数据迁移成本敏感的场景

5. 按范围分片(Range-based Sharding)

按范围分片基于键值的范围将数据分配到不同节点,特别适合有序数据集。

工作原理

  • 预先定义键的范围划分
  • 根据键所属范围决定存储节点
  • 通常结合有序键使用,如时间序列数据

实现示例

public class RangeSharding {
    private final TreeMap<Long, JedisPool> rangeMap = new TreeMap<>();
    
    public RangeSharding() {
        // 假设按用户ID范围分片
        rangeMap.put(0L, new JedisPool("redis1.example.com", 6379));      // 0-999999
        rangeMap.put(1000000L, new JedisPool("redis2.example.com", 6379)); // 1000000-1999999
        rangeMap.put(2000000L, new JedisPool("redis3.example.com", 6379)); // 2000000-2999999
        // 更多范围...
    }
    
    private JedisPool getShardForUserId(long userId) {
        Map.Entry<Long, JedisPool> entry = rangeMap.floorEntry(userId);
        if (entry == null) {
            throw new IllegalArgumentException("No shard available for userId: " + userId);
        }
        return entry.getValue();
    }
    
    public String getUserData(long userId) {
        JedisPool pool = getShardForUserId(userId);
        try (Jedis jedis = pool.getResource()) {
            return jedis.get("user:" + userId);
        }
    }
    
    public void setUserData(long userId, String data) {
        JedisPool pool = getShardForUserId(userId);
        try (Jedis jedis = pool.getResource()) {
            jedis.set("user:" + userId, data);
        }
    }
}

优缺点

优点

  • 特定范围的数据位于同一节点,便于范围查询
  • 分片策略简单明确
  • 键与节点的映射关系易于理解

缺点

  • 可能造成数据分布不均
  • 热点数据可能集中在某个分片
  • 重新分片操作复杂

适用场景

  • 时间序列数据存储
  • 地理位置数据分区
  • 需要支持高效范围查询的场景

结论

Redis分片是应对大数据量挑战的有效策略,每种分片方法都有其独特的优势和适用场景。选择合适的分片策略需要综合考虑数据规模、访问模式、扩展需求以及运维能力等因素。

无论选择哪种分片策略,都应当遵循最佳实践,包括合理的数据模型设计、良好的监控和预见性的容量规划,以确保Redis集群的稳定性和高性能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2383475.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java 代码生成工具:如何快速构建项目骨架?

Java 代码生成工具&#xff1a;如何快速构建项目骨架&#xff1f; 在 Java 项目开发过程中&#xff0c;构建项目骨架是一项繁琐但又基础重要的工作。幸运的是&#xff0c;Java 领域有许多代码生成工具可以帮助我们快速完成这一任务&#xff0c;大大提高开发效率。 一、代码生…

Nginx核心服务

一&#xff0e;正向代理 正向代理&#xff08;Forward Proxy&#xff09;‌是一种位于客户端和原始服务器之间的代理服务器&#xff0c;其主要作用是将客户端的请求转发给目标服务器&#xff0c;并将响应返回给客户端 Nginx 的 正向代理 充当客户端的“中间人”&#xff0c;代…

第22天-Python ttkbootstrap 界面美化指南

环境安装 pip install ttkbootstrap 示例1:基础主题切换器 import ttkbootstrap as ttk from ttkbootstrap.constants import *def create_theme_switcher():root = ttk.Window(title="主题切换器", themename="cosmo")def change_theme():selected = t…

Kubernetes控制平面组件:Kubelet详解(七):容器网络接口 CNI

云原生学习路线导航页&#xff08;持续更新中&#xff09; kubernetes学习系列快捷链接 Kubernetes架构原则和对象设计&#xff08;一&#xff09;Kubernetes架构原则和对象设计&#xff08;二&#xff09;Kubernetes架构原则和对象设计&#xff08;三&#xff09;Kubernetes控…

web应用技术第6次课---Apifox的使用

Apifox - API 文档、调试、Mock、测试一体化协作平台。拥有接口文档管理、接口调试、Mock、自动化测试等功能&#xff0c;接口开发、测试、联调效率&#xff0c;提升 10 倍。最好用的接口文档管理工具&#xff0c;接口自动化测试工具。 第一个问题&#xff1a;为什么需要用Apif…

Redis队列与Pub/Sub方案全解析:原理、对比与实战性能测试

一、为什么选择Redis实现消息队列&#xff1f; Redis凭借其内存级操作&#xff08;微秒级响应&#xff09;、丰富的数据结构以及持久化能力&#xff0c;成为构建高性能消息队列的热门选择。相比传统消息队列&#xff08;如Kafka/RabbitMQ&#xff09;&#xff0c;Redis在以下场…

OBOO鸥柏丨AI数字人触摸屏查询触控人脸识别语音交互一体机上市

OBOO鸥柏丨AI数字人触摸屏查询触控人脸识别语音交互一体机上市分析 OBOO鸥柏品牌推出的AI数字人触摸屏查询触控人脸识别语音交互一体机&#xff0c;是其在智能交互设备领域的又一创新产品。该一体机整合了触摸屏查询、AI人脸识别、AI声源定位语音麦克风&#xff0c;触控交互以…

第5天-python饼图绘制

一、基础饼图绘制(Matplotlib) 1. 环境准备 python 复制 下载 pip install matplotlib numpy 2. 基础饼图代码 python 复制 下载 import matplotlib.pyplot as plt# 数据准备 labels = [1, 2, 3, 4] sizes = [30, 25, 15, 30] # 各部分占比(总和建议100) colors…

2023 睿抗机器人开发者大赛CAIP-编程技能赛-本科组(国赛) 解题报告 | 珂学家

前言 题解 2023 睿抗机器人开发者大赛CAIP-编程技能赛-本科组(国赛)。 vp了下&#xff0c;题目挺好的&#xff0c;难度也适中&#xff0c;但是彻底红温了。 第二题&#xff0c;题意不是那么清晰&#xff0c; M i n ( K 1 , K 2 ) Min(K_1, K_2) Min(K1​,K2​)容易求&#x…

LabVIEW风机状态实时监测

在当今电子设备高度集成化的时代&#xff0c;设备散热成为关键问题。许多大型设备机箱常采用多个风机协同散热&#xff0c;确保系统稳定运行。一旦风机出现故障&#xff0c;若不能及时察觉&#xff0c;可能导致设备损坏&#xff0c;造成巨大损失。为满足对机箱内风机状态实时监…

十一、面向对象底层逻辑-Dubbo过滤器Filter接口

一、引言&#xff1a;分布式系统中的可观测性与治理基石 在分布式服务调用链路中&#xff0c;如何在服务调用前后植入通用逻辑&#xff08;如日志记录、权限校验、性能监控等&#xff09;&#xff0c;是构建可观测、可治理系统的关键需求。Dubbo通过Filter接口实现了面向切面编…

linux安装nginx和前端部署vue项目

1、打包前端项目 npm run build 执行完后会在根目录下生成一个dist文件夹&#xff0c;这个dist文件夹就是我们后面要部署到nginx的东西。 2、将dist文件夹上传到服务器中 自己建一个目录&#xff0c;上传即可&#xff08;尽量不要在root目录下&#xff0c;可能涉及权限问题…

软件设计师“数据流图”真题考点分析——求三连

数据流图考点分析 1. 考点分值占比与趋势分析 综合知识题分值统计表 年份考题数量分值分值占比考察重点2018111.33%数据流图基本元素2019222.67%数据流图绘制原则2020111.33%数据流图与控制流图的区别2021334.00%数据字典与数据流图的关系2022222.67%分层数据流图的分解原则…

基于R语言的贝叶斯网络模型实践技术应用:开启科研新视角

在现代科研领域&#xff0c;变量间的因果关系推断是生态学、环境科学、医学等多学科研究的核心问题。然而&#xff0c;传统的统计学方法往往只能揭示变量间的相关关系&#xff0c;而非因果关系。贝叶斯网络作为一种结合图论与统计学理论的新型模型&#xff0c;不仅能够统合多种…

【Git】远程操作

Git 是一个分布式版本控制系统 可以简单理解为&#xff0c;每个人的电脑上都是一个完整的版本库&#xff0c;这样在工作时&#xff0c;就不需要联网 了&#xff0c;因为版本库就在自己的电脑上。 因此&#xff0c; 多个人协作的方式&#xff0c;譬如说甲在自己的电脑上改了文件…

DeepSpeed简介及加速模型训练

DeepSpeed是由微软开发的开源深度学习优化框架&#xff0c;专注于大规模模型的高效训练与推理。其核心目标是通过系统级优化技术降低显存占用、提升计算效率&#xff0c;并支持千亿级参数的模型训练。 官网链接&#xff1a;deepspeed 训练代码下载&#xff1a;git代码 一、De…

openlayer:10点击地图上某些省份利用Overlay实现提示省份名称

实现点击地图上的省份&#xff0c;在点击经纬度坐标位置附近利用Overlay实现提示框提示相关省份名称。本文介绍了如何通过OpenLayers库实现点击地图上的省份&#xff0c;并在点击的经纬度坐标位置附近显示提示框&#xff0c;提示相关省份名称。首先&#xff0c;定义了两个全局变…

upload-labs通关笔记-第13关 文件上传之白名单POST法

目录 一、白名单过滤 二、%00截断 1.截断原理 2、截断条件 &#xff08;1&#xff09;PHP版本 < 5.3.4 &#xff08;2&#xff09;magic_quotes_gpc配置为Off &#xff08;3&#xff09;代码逻辑存在缺陷 三、源码分析 1、代码审计 &#xff08;1&#xff09;文件…

数据库健康监测器(BHM)实战:如何通过 HTML 报告识别潜在问题

在数据库运维中,健康监测是保障系统稳定性与性能的关键环节。通过 HTML 报告,开发者可以直观查看数据库的运行状态、资源使用情况与潜在风险。 本文将围绕 数据库健康监测器(Database Health Monitor, BHM) 的核心功能展开分析,结合 Prometheus + Grafana + MySQL Export…

Oracle 11g 单实例使用+asm修改主机名导致ORA-29701 故障分析

解决 把服务器名修改为原来的&#xff0c;重启服务器。 故障 建表空间失败。 分析 查看告警日志 ORA-1119 signalled during: create tablespace splex datafile ‘DATA’ size 2000M… Tue May 20 18:04:28 2025 create tablespace splex datafile ‘DATA/option/dataf…