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

随着业务规模的增长,单一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:22121hash: fnv1a_64distribution: ketamaauto_eject_hosts: trueredis: trueserver_retry_timeout: 2000server_failure_limit: 3servers:- 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-999999rangeMap.put(1000000L, new JedisPool("redis2.example.com", 6379)); // 1000000-1999999rangeMap.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.mzph.cn/diannao/84058.shtml

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

相关文章

CentOS 7上搭建高可用BIND9集群指南

在 CentOS 7 上搭建一个高可用的 BIND9 集群通常涉及以下几种关键技术和策略的组合&#xff1a;主从复制 (Master-Slave Replication)、负载均衡 (Load Balancing) 以及可能的浮动 IP (Floating IP) 或 Anycast。 我们将主要关注主从复制和负载均衡的实现&#xff0c;这是构成高…

LangChain4j入门AI(六)整合提示词(Prompt)

前言 提示词&#xff08;Prompt&#xff09;是用户输入给AI模型的一段文字或指令&#xff0c;用于引导模型生成特定类型的内容。通过提示词&#xff0c;用户可以告诉AI“做什么”、 “如何做”以及“输出格式”&#xff0c;从而在满足需求的同时最大程度减少无关信息的生成。有…

【MySQL】笔记

&#x1f4da; 博主的专栏 &#x1f427; Linux | &#x1f5a5;️ C | &#x1f4ca; 数据结构 | &#x1f4a1;C 算法 | &#x1f152; C 语言 | &#x1f310; 计算机网络 在ubuntu中&#xff0c;改配置文件&#xff1a; sudo nano /etc/mysql/mysql.conf.d/mysq…

TDengine 运维—容量规划

概述 若计划使用 TDengine 搭建一个时序数据平台&#xff0c;须提前对计算资源、存储资源和网络资源进行详细规划&#xff0c;以确保满足业务场景的需求。通常 TDengine 会运行多个进程&#xff0c;包括 taosd、taosadapter、taoskeeper、taos-explorer 和 taosx。 在这些进程…

OpenCV CUDA模块图像过滤------创建一个盒式滤波器(Box Filter)函数createBoxFilter()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::cuda::createBoxFilter 是 OpenCV CUDA 模块中的一个工厂函数&#xff0c;用于创建一个 盒式滤波器&#xff08;Box Filter&#xff09;&…

谷歌I/O 2025 完全指南:由Gemini开创的AI新时代及其对我们未来的影响

在这个朝着智能化一切狂奔的世界中,谷歌I/O 2025不仅展示了人工智能创新——它传递了一个明确的信息:未来已来临,而且由Gemini驱动。 从突破性的模型进步到沉浸式通信工具和个性化AI助手,谷歌正在重塑人机交互的本质。让我们一起了解最重大的公告及其对开发者、用户和AI生…

5000 字总结CSS 中的过渡、动画和变换详解

CSS 中的过渡、动画和变换详解 一、CSS 过渡(Transitions) 1. 基本概念 CSS 过渡是一种平滑改变 CSS 属性值的机制,允许属性值在一定时间内从一个值逐渐变化到另一个值,从而创建流畅的动画效果。过渡只能用于具有中间值的属性(如颜色、大小、位置等),不能用于 displa…

【图像生成大模型】CogVideoX-5b:开启文本到视频生成的新纪元

CogVideoX-5b&#xff1a;开启文本到视频生成的新纪元 项目背景与目标模型架构与技术亮点项目运行方式与执行步骤环境准备模型加载与推理量化推理 执行报错与问题解决内存不足模型加载失败生成质量不佳 相关论文信息总结 在人工智能领域&#xff0c;文本到视频生成技术一直是研…

辨析Spark 运行方式、运行模式(master)、部署方式(deploy-mode)

为了理清 Spark 运行方式、部署模式&#xff08;master&#xff09;、部署方式&#xff08;deploy-mode&#xff09; 之间的关系&#xff0c;我们先明确几个核心概念&#xff0c;再对比它们的联系与区别。 一、核心概念解析 1. Spark 运行方式&#xff08;代码执行方式&#…

从芯片互连到机器人革命:英伟达双线出击,NVLink开放生态+GR00T模型定义AI计算新时代

5月19日&#xff0c;在台湾举办的Computex 2025上&#xff0c;英伟达推出新技术“NVLink Fusion”&#xff0c;允许非英伟达CPU和GPU&#xff0c;同英伟达产品以及高速GPU互连技术NVLink结合使用&#xff0c;加速AI芯片连接。新技术的推出旨在保持英伟达在人工智能开发和计算领…

04算法学习_209.长度最小的子数组

04算法学习_209.长度最小的子数组题目描述&#xff1a;个人代码&#xff1a;学习思路&#xff1a;第一种写法&#xff1a;题解关键点&#xff1a; 第二种写法&#xff1a;题解关键点&#xff1a; 个人学习时疑惑点解答&#xff1a; 04算法学习_209.长度最小的子数组 力扣题目链…

【已解决】docker search --limit 1 centos Error response from daemon

在docker search的时候你是否遇到过这样的问题&#xff1f; Error response from daemon: Get "https://index.docker.io/v1/search?qcentos&n1": dial tcp 103.56.16.112:443: i/o timeout解决方案 可以尝试一下加一层docker镜像代理&#xff1a; 以mysql:5.…

vue好用插件

自动导入插件 cnpm i -D unplugin-auto-import配置 //在vite.config.js文件加入AutoImport({imports:["vue","vue-router","pinia"],dts:true,}),

算法--js--电话号码的字母组合

题&#xff1a;给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 function letterCombinations (digits){if (!digits.length)…

OSI 网络七层模型中的物理层、数据链路层、网络层

一、OSI 七层模型 物理层、数据链路层、网络层、传输层、会话层、表示层、应用层 1. 物理层&#xff08;Physical Layer&#xff09; 功能&#xff1a;传输原始的比特流&#xff08;0和1&#xff09;&#xff0c;通过物理介质&#xff08;如电缆、光纤、无线电波&#xff09;…

Linux 文件(3)

文章目录 1. Linux下一切皆文件2. 文件缓冲区2.1 缓冲区是什么2.2 缓冲区的刷新策略2.3 为什么要有缓冲区2.4 一个理解缓冲区刷新的例子 3. 标准错误 1. Linux下一切皆文件 在刚开始学习Linux的时候&#xff0c;我们就说Linux下一切皆文件——键盘是文件&#xff0c;显示器是文…

STM32之串口通信蓝牙(BLE)

一、串口通信的原理与应用 通信的方式 处理器与外部设备之间或者处理器与处理器之间通信的方式分两种&#xff1a;串行通信和并行通信。 串行通信 传输原理&#xff1a;数据按位依次顺序传输&#xff08;每一位占据固定的时间长度 MSB or LSB&#xff09; 优点&#xff1a…

基于python的机器学习(七)—— 数据特征选择

目录 一、特征选择概念 二、特征选择的方法 2.1 过滤式特征选择 2.1.1 方差分析 2.1.2 相关系数 2.1.3 卡方检验 2.2 包裹式特征选择 2.2.1 递归特征消除 2.3 嵌入式特征选择 2.3.1 决策树特征重要性 一、特征选择概念 特征选择是机器学习非常重要的一个步骤&#x…

《AI工程技术栈》:三层结构解析,AI工程如何区别于ML工程与全栈工程

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Redis数据库-消息队列

一、消息队列介绍 二、基于List结构模拟消息队列 总结&#xff1a; 三、基于PubSub实现消息队列 (1)PubSub介绍 PubSub是publish与subscribe两个单词的缩写&#xff0c;见明知意&#xff0c;PubSub就是发布与订阅的意思。 可以到Redis官网查看通配符的书写规则&#xff1a; …