大数据量下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集群的稳定性和高性能。
相关文章:
大数据量下Redis分片的5种策略
随着业务规模的增长,单一Redis实例面临着内存容量、网络带宽和计算能力的瓶颈。 分片(Sharding)成为扩展Redis的关键策略,它将数据分散到多个Redis节点上,每个节点负责整个数据集的一个子集。 本文将分享5种Redis分片策略。 1. 取模分片(M…...
muduo库TcpServer模块详解
Muduo库核心模块——TcpServer Muduo库的TcpServer模块是一个基于Reactor模式的高性能TCP服务端实现,负责管理监听端口、接受新连接、分发IO事件及处理连接生命周期。 一、核心组件与职责 Acceptor 监听指定端口,接受新连接,通过epoll监听l…...

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

Nginx核心服务
一.正向代理 正向代理(Forward Proxy)是一种位于客户端和原始服务器之间的代理服务器,其主要作用是将客户端的请求转发给目标服务器,并将响应返回给客户端 Nginx 的 正向代理 充当客户端的“中间人”,代…...

第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
云原生学习路线导航页(持续更新中) kubernetes学习系列快捷链接 Kubernetes架构原则和对象设计(一)Kubernetes架构原则和对象设计(二)Kubernetes架构原则和对象设计(三)Kubernetes控…...

web应用技术第6次课---Apifox的使用
Apifox - API 文档、调试、Mock、测试一体化协作平台。拥有接口文档管理、接口调试、Mock、自动化测试等功能,接口开发、测试、联调效率,提升 10 倍。最好用的接口文档管理工具,接口自动化测试工具。 第一个问题:为什么需要用Apif…...
Flutter与Kotlin Multiplatform(KMP)深度对比及鸿蒙生态适配解析
Flutter 与 Kotlin Multiplatform(KMP)深度对比及鸿蒙生态适配解析 在跨平台开发领域,Flutter 与 Kotlin Multiplatform(KMP)代表了两种不同的技术路线:前者以 “统一 UI 体验” 为核心,后者以…...
Predict Podcast Listening Time-(回归+特征工程+xgb)
Predict Podcast Listening Time 题意: 给你每个播客的信息,让你预测观众的聆听时间。 数据处理: 1.构造新特征收听效率进行分组 2.对数据异常处理 3.对时间情绪等进行数值编码 4.求某特征值求多项式特征 5.生成特征组合 6.交叉验证并enc…...

Redis队列与Pub/Sub方案全解析:原理、对比与实战性能测试
一、为什么选择Redis实现消息队列? Redis凭借其内存级操作(微秒级响应)、丰富的数据结构以及持久化能力,成为构建高性能消息队列的热门选择。相比传统消息队列(如Kafka/RabbitMQ),Redis在以下场…...
深度估计中为什么需要已知相机基线(known camera baseline)?
在计算机视觉和立体视觉的上下文中,“已知相机基线”(known camera baseline)的解释 1. 相机基线的定义 相机基线是指两个相机中心之间的距离。在立体视觉系统中,通常有两个相机(或一个相机在不同位置拍摄两张图像&a…...
显卡、Cuda和pytorch兼容问题
这里写目录标题 驱动与CUDA版本兼容性问题1. **驱动与CUDA版本兼容性问题**2. **任务特性与硬件适配差异**3. **优化策略与框架配置差异**4. **散热与功耗限制**5. **数据传输与CPU瓶颈**排查建议总结 查询PyTorch中实际使用的CUDA版本**1. 查询PyTorch中实际使用的CUDA版本***…...
SseEmitter是什么
SseEmitter 是 Spring Framework 中用于实现 Server-Sent Events (SSE) 的一个类。SSE 是一种允许服务器向客户端推送实时更新的技术,特别适合需要从服务器到客户端的单向消息传递场景,如股票价格更新、社交媒体的新消息通知等。 Server-Sent Events (S…...

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

第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了下,题目挺好的,难度也适中,但是彻底红温了。 第二题,题意不是那么清晰, M i n ( K 1 , K 2 ) Min(K_1, K_2) Min(K1,K2)容易求&#x…...

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

十一、面向对象底层逻辑-Dubbo过滤器Filter接口
一、引言:分布式系统中的可观测性与治理基石 在分布式服务调用链路中,如何在服务调用前后植入通用逻辑(如日志记录、权限校验、性能监控等),是构建可观测、可治理系统的关键需求。Dubbo通过Filter接口实现了面向切面编…...
双检锁(Double-Checked Locking)单例模式
在项目中使用双检锁(Double-Checked Locking)单例模式来管理 JSON 格式化处理对象(如 ObjectMapper 在 Jackson 库中,或 JsonParser 在 Gson 库中)是一种常见的做法。这种模式确保了对象只被创建一次,同时在…...

linux安装nginx和前端部署vue项目
1、打包前端项目 npm run build 执行完后会在根目录下生成一个dist文件夹,这个dist文件夹就是我们后面要部署到nginx的东西。 2、将dist文件夹上传到服务器中 自己建一个目录,上传即可(尽量不要在root目录下,可能涉及权限问题…...
打破次元壁,VR 气象站开启气象学习新姿势
在教育领域,VR 气象站同样发挥着巨大的作用,为气象教学带来了全新的模式,打破了传统教学的次元壁,让学生们以全新的姿势学习气象知识。 在传统的气象教学中,学生们主要通过课本、图片和老师的讲解来学习气象知识。这…...

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

基于R语言的贝叶斯网络模型实践技术应用:开启科研新视角
在现代科研领域,变量间的因果关系推断是生态学、环境科学、医学等多学科研究的核心问题。然而,传统的统计学方法往往只能揭示变量间的相关关系,而非因果关系。贝叶斯网络作为一种结合图论与统计学理论的新型模型,不仅能够统合多种…...
用 VS Code / PyCharm 编写你的第一个 Python 程序
用ChatGPT做软件测试 编写你的第一个 Python 程序——不只是“Hello, World”,而是构建认知、习惯与未来的起点 “第一行代码,是一个开发者认知世界的方式。” 编程的入门,不只是运行一个字符串输出,更是开始用计算机思维来理解、…...

【Git】远程操作
Git 是一个分布式版本控制系统 可以简单理解为,每个人的电脑上都是一个完整的版本库,这样在工作时,就不需要联网 了,因为版本库就在自己的电脑上。 因此, 多个人协作的方式,譬如说甲在自己的电脑上改了文件…...
低代码AI开发新趋势:Dify平台化开发实战
在人工智能快速发展的今天,AI应用的开发方式也在不断演变。从传统的手写代码到如今的低代码甚至零代码开发,技术的进步让更多的非专业开发者也能轻松上手。本文将带你走进Dify平台化开发的世界,探索如何通过这一强大的低代码AI开发平台&#…...

DeepSpeed简介及加速模型训练
DeepSpeed是由微软开发的开源深度学习优化框架,专注于大规模模型的高效训练与推理。其核心目标是通过系统级优化技术降低显存占用、提升计算效率,并支持千亿级参数的模型训练。 官网链接:deepspeed 训练代码下载:git代码 一、De…...
网络安全面试题(一)
文章目录 一、基础概念与模型1. 什么是通信协议?列举三种常见的网络通信模型?2. 解释OSI七层模型及各层功能3. TCP/IP四层模型与OSI模型的对应关系是什么?4. 五层协议体系结构与TCP/IP模型的区别?5. 什么是面向连接与非面向连接的服务&…...
Linux 内核探秘:从零构建 GPIO 设备驱动程序实战指南
在嵌入式系统开发领域,GPIO(通用输入 / 输出)作为硬件与软件交互的桥梁,是实现设备控制与数据采集的基础。编写高效、稳定的 GPIO 设备驱动程序,对于发挥硬件性能至关重要。本文将深入剖析 Linux 内核中 GPIO 驱动开发…...

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