文章目录

  • Redis大Key
    • 一、什么是Redis大Key
    • 二、大Key的产生原因
    • 三、大Key的影响
    • 四、大Key的解决方案
      • 1. 检测大Key
      • 2. 解决方案
        • (1) 数据拆分
        • (2) 使用压缩算法
        • (3) 使用合适的数据结构
        • (4) 设置合理的过期时间
        • (5) 合理清理
        • (6) 配置优化
    • 五、预防措施
    • 总结
  • Redis热key
    • 一、热Key问题的本质
      • 1. 什么是热Key
      • 2. 热Key的危害
    • 二、热Key的识别方法
      • 1. 使用Redis内置命令
      • 2. 使用slowlog分析
      • 3. 客户端埋点统计
      • 4. 使用第三方工具
    • 三、热Key问题的解决方案
      • 1. 本地缓存方案
      • 2. Key拆分方案
      • 3. 多级缓存方案
      • 4. 读写分离方案
      • 5. 数据分片方案
      • 6. 缓存永不过期方案
      • 7. 请求合并方案
    • 四、预防热Key的最佳实践
    • 五、云服务商的热Key解决方案
      • 阿里云Redis
      • AWS ElastiCache
    • 六、总结

Redis大Key

在这里插入图片描述

Redis大Key问题是Redis使用过程中常见的性能瓶颈之一,它会对Redis的性能、稳定性和资源利用率产生显著影响。下面我将从大Key的定义、产生原因、影响以及解决方案几个方面进行全面分析。

一、什么是Redis大Key

Redis大Key并没有统一的固定标准,通常根据业务场景而定,主要分为以下几种情况:

  1. 字符串类型(String):单个Key的Value特别大,一般认为在普通业务场景下,如果单个String类型的value大于1MB,或者在高并发低延迟场景中大于10KB,就可能被视为大Key

  2. 集合数据类型:如Hash、Set、ZSet、List等,其中的元素数量过多或总体数据量过大。例如,一个Hash类型Key的成员数量虽只有1000个,但这些成员的Value总大小达到100MB,或者一个ZSet类型的Key成员数量达到10000个

  3. 内存占用过高:比如阿里云Redis定义中,一个String类型的Key其值达到5MB,或一个ZSet类型的Key成员数量达到10000个,都被视为大Key

二、大Key的产生原因

大Key的产生通常有以下几种原因:

  1. 业务设计不合理:最常见的原因是在没有合理拆分的情况下,直接将大量数据(如大的JSON对象或二进制文件数据)存储在一个键中

例如:

  • 缓存大数据(图片和视频元数据)

  • 明星或网红粉丝列表

  • 商品页所有信息

  1. 未能处理Value动态增长问题:随着时间推移,如果持续向某个键的Value中添加数据,而又没有相应的定期删除机制、合理的过期策略或大小限制,Value的大小最终会增长到难以管理的程度

    • 不断累积的微博粉丝列表、热门评论或直播弹幕

    • 缓存时间设置不合理,导致数据不断累积

      5

  2. 程序Bug:软件开发中的错误可能导致某些键的生命周期超出预期,或者其包含的元素数量异常增长

    • 负责消费LIST类型键的业务代码发生故障,导致该Key的成员只增不减

    • 数据结构使用不当,如List中重复添加数据

  3. 存储大量数据的容器:如list、set等,随着业务增长,数据量不断增加

三、大Key的影响

大Key会对Redis系统产生多方面的负面影响:

  1. 读取成本高:大Key由于体积大,读取时会消耗更多的时间,增加延迟,尤其是在网络传输中会占用更多带宽

  2. 写操作易阻塞:Redis采用单线程模型处理请求,操作大Key会阻塞其他命令的执行,导致整个Redis服务响应变慢

  3. 慢查询与主从同步异常:大Key的读写操作时间长,可能触发Redis的慢查询日志记录;在主从复制场景下,大Key的同步也会比小Key慢

  4. 内存问题:大Key占据大量内存空间,容易触发Redis的内存淘汰策略,造成重要数据被意外移除;在极端情况下可能导致Redis实例因内存耗尽而崩溃(OOM)

  5. 集群架构下的内存资源不均衡:在Redis集群中,若某个分片上有大Key,该分片的内存使用率将远高于其他分片,打破集群间内存使用的均衡状态

  6. 持久化效率降低:AOF与RDB持久化操作会因大Key耗费更多时间

四、大Key的解决方案

1. 检测大Key

在解决问题前,首先需要检测和识别大Key:

  1. redis-cli --bigkeys:Redis自带的命令,可以查询当前Redis中所有key的信息,对整个数据库中的键值对大小情况进行统计分析

    redis-cli --bigkeys
    
  2. MEMORY USAGE命令:Redis 4.0后推出的命令,可以返回指定key的内存使用情况

    MEMORY USAGE keyname
    
  3. RDB Tools:使用Redis RDB Tools等第三方工具分析RDB文件,找出大Key

    rdb -c memory dump.rdb --bytes 10240 -f bigkeys.csv
    
  4. Lua脚本遍历:编写Lua脚本遍历所有Key并统计大Key

2. 解决方案

(1) 数据拆分

将大Key拆分成多个小Key是最常见的解决方案:

  • 按业务逻辑拆分:例如,对于一个包含全品类商品销售数据的大Key,可以按照品类拆分为多个小的键

  • 按时间范围拆分:对于时间序列数据,可以按照时间范围进行拆分

  • 分片存储:如将用户订单按用户ID分桶存储

示例代码:

// 原始大Key存储
RedisTemplate.opsForValue().set("bigKey", largeValue);// 拆分后的存储
for (int i = 0; i < largeValue.size(); i++) {RedisTemplate.opsForValue().set("smallKey_" + i, largeValue.get(i));
}
(2) 使用压缩算法

对于可以压缩的数据类型(如字符串),可以使用压缩算法来减少内存占用

Python示例:

import zlib
# 压缩Value
compressed_value = zlib.compress(large_value)
# 存储压缩后的Value
redis.set("compressedKey", compressed_value)
# 解压缩Value
original_value = zlib.decompress(redis.get("compressedKey"))
(3) 使用合适的数据结构
  • 选择合适的Redis数据结构:例如,用Bitmap代替String记录URL访问情况 ,用HyperLogLog统计UV

  • 考虑使用其他存储系统:对于不适合Redis存储的大数据,可考虑转移到分布式文件系统,只在Redis中保留元数据

(4) 设置合理的过期时间

如果大Key中的数据不是一直需要的,可以设置过期时间,让Redis在一定时间后自动删除该Key

(5) 合理清理
  • 异步删除:使用UNLINK命令代替DEL命令异步删除大Key

    UNLINK big_hash_key
    
  • 分批定时定量删除:在低峰期分批删除大Key,防止阻塞

(6) 配置优化

调整Redis配置参数优化内存使用

CONFIG SET hash-max-ziplist-entries 512
CONFIG SET hash-max-ziplist-value 64

五、预防措施

  1. 合理设计数据结构:在业务设计初期就应该避免生成大Key,仅缓存必要的数据字段

  2. 监控预警:建立对Redis的监控系统,实时监测大Key的出现和内存使用情况

  3. 版本控制:为每个Value加入版本号,以进行一致性检查

  4. 定期维护:定期检查并清理潜在的大Key

总结

Redis大Key问题会对系统性能产生多方面的影响,需要通过合理的检测方法识别问题Key,并根据业务场景选择合适的解决方案。最佳实践是在系统设计阶段就考虑数据规模的增长,避免大Key的产生,同时建立完善的监控机制,及时发现和处理潜在的大Key问题


Redis热key

热Key(Hot Key)是Redis使用过程中常见的一个性能问题,指在短时间内被大量访问的单个Key或多个Key,可能导致Redis服务器负载不均、性能下降甚至服务不可用。

一、热Key问题的本质

1. 什么是热Key

热Key是指那些访问频率显著高于其他Key的特定Key,通常表现为:

  • 单个Key的QPS(每秒查询量)远高于平均水平
  • 对某个Key的访问量占整体访问量的很大比例
  • 由于访问集中导致Redis单线程处理瓶颈

2. 热Key的危害

  1. 性能瓶颈:Redis单线程模型下,热Key可能导致其他请求排队
  2. CPU负载高:处理大量相同Key请求消耗CPU资源
  3. 网络带宽压力:大量相同数据的重复传输
  4. 数据倾斜:在集群模式下导致某些节点负载过高
  5. 缓存击穿:热Key突然失效可能导致大量请求直达数据库

二、热Key的识别方法

1. 使用Redis内置命令

# 使用redis-cli的hotkeys功能(Redis 4.0+)
redis-cli --hotkeys# 使用monitor命令临时监控(谨慎使用,影响性能)
redis-cli monitor | grep "GET\|HGET\|SMEMBERS"

2. 使用slowlog分析

# 配置slowlog
redis-cli config set slowlog-log-slower-than 1000  # 记录执行超过1ms的命令
redis-cli config set slowlog-max-len 1000         # 保留1000条记录# 查看slowlog
redis-cli slowlog get

3. 客户端埋点统计

// 示例:使用AOP统计Key访问频率
@Aspect
@Component
public class RedisKeyMonitorAspect {private ConcurrentHashMap<String, AtomicLong> keyAccessCount = new ConcurrentHashMap<>();@Around("execution(* com.xxx.RedisService.*(..))")public Object monitorKeyAccess(ProceedingJoinPoint pjp) throws Throwable {String key = parseRedisKey(pjp.getArgs());keyAccessCount.computeIfAbsent(key, k -> new AtomicLong(0)).incrementAndGet();return pjp.proceed();}// 定期输出热Key统计@Scheduled(fixedRate = 60000)public void reportHotKeys() {keyAccessCount.entrySet().stream().sorted((e1, e2) -> Long.compare(e2.getValue().get(), e1.getValue().get())).limit(10).forEach(e -> System.out.println("HotKey: " + e.getKey() + " - " + e.getValue()));}
}

4. 使用第三方工具

  • RedisInsight:Redis官方可视化工具
  • CacheCloud:搜狐开源的Redis监控平台
  • Prometheus + Grafana:配合Redis exporter监控

三、热Key问题的解决方案

1. 本地缓存方案

适用场景:读多写少、数据一致性要求不严格的场景

// 使用Guava Cache实现本地缓存
LoadingCache<String, Object> localCache = CacheBuilder.newBuilder().maximumSize(10000).expireAfterWrite(10, TimeUnit.SECONDS)  // 10秒过期.build(new CacheLoader<String, Object>() {@Overridepublic Object load(String key) throws Exception {// 从Redis获取数据return redisTemplate.opsForValue().get(key);}});// 使用示例
public Object getData(String key) {try {return localCache.get(key);} catch (ExecutionException e) {// 异常处理return null;}
}

注意事项

  • 设置合理的过期时间,避免本地缓存与Redis数据不一致
  • 考虑使用消息队列通知本地缓存失效
  • 监控本地缓存命中率

2. Key拆分方案

适用场景:大Value的热Key

// 将一个大Key拆分为多个子Key
public void setBigData(String bigKey, BigData data) {// 拆分为多个子KeyMap<String, String> parts = splitBigData(data);// 使用pipeline批量写入redisTemplate.executePipelined((RedisCallback<Object>) connection -> {parts.forEach((subKey, value) -> {connection.set(("bigkey:"+bigKey+":"+subKey).getBytes(), value.getBytes());});return null;});
}public BigData getBigData(String bigKey) {// 获取所有子KeySet<String> subKeys = redisTemplate.keys("bigkey:"+bigKey+":*");// 批量获取List<Object> values = redisTemplate.executePipelined((RedisCallback<Object>) connection -> {subKeys.forEach(key -> connection.get(key.getBytes()));return null;});// 合并结果return mergeValues(values);
}

3. 多级缓存方案

架构示例

客户端 → 本地缓存 → Redis集群 → 数据库

实现要点

  1. 第一级:客户端内存缓存(短时间,如1秒)
  2. 第二级:Redis集群
  3. 第三级:持久化存储

4. 读写分离方案

配置Redis主从复制

# 在从节点配置
replica-read-only yes

客户端实现

public class RedisReadWriteClient {private Jedis master;private List<Jedis> replicas;private AtomicInteger counter = new AtomicInteger(0);// 读操作路由到从节点public String get(String key) {Jedis replica = getNextReplica();return replica.get(key);}// 写操作使用主节点public void set(String key, String value) {master.set(key, value);}private Jedis getNextReplica() {int index = counter.incrementAndGet() % replicas.size();return replicas.get(index);}
}

5. 数据分片方案

Redis Cluster自动分片

# 创建集群(3主3从)
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

客户端分片示例

public class ShardedRedisClient {private List<Jedis> nodes;public void set(String key, String value) {getNode(key).set(key, value);}public String get(String key) {return getNode(key).get(key);}private Jedis getNode(String key) {// 使用一致性哈希选择节点int hash = Math.abs(key.hashCode());return nodes.get(hash % nodes.size());}
}

6. 缓存永不过期方案

适用场景:配置类数据,极少变更

// 设置Key永不过期
redisTemplate.opsForValue().set("config:key", "value");// 后台更新逻辑
public void updateConfig(String key, Object value) {// 1. 更新数据库db.updateConfig(key, value);// 2. 更新RedisredisTemplate.opsForValue().set("config:"+key, value);// 3. 发送消息通知其他服务更新messageQueue.publish("config.update", key);
}

7. 请求合并方案

使用Google Guava的RateLimiter

private RateLimiter limiter = RateLimiter.create(1000); // 每秒1000个请求public Object getData(String key) {if (limiter.tryAcquire()) {return redisTemplate.opsForValue().get(key);} else {// 返回缓存中的旧数据或默认值return getCachedValue(key);}
}

四、预防热Key的最佳实践

  1. 设计阶段预防

    • 避免使用全局计数器等容易成为热点的设计
    • 对可能的热点数据提前规划拆分方案
  2. 监控报警

    # 监控单个Key的QPS
    while true; doredis-cli info stats | grep total_commands_processedsleep 1
    done
    
  3. 压力测试

    • 使用redis-benchmark模拟高并发
    redis-benchmark -t get,set -n 100000 -r 100000 -d 100
    
  4. Key命名规范

    • 业务前缀:数据类型:唯一标识 如 user:info:1001
    • 避免使用过长的Key名
  5. 数据过期策略

    • 对热Key设置合理的过期时间
    • 采用随机过期时间避免集中失效

五、云服务商的热Key解决方案

阿里云Redis

  1. 性能洞察功能:自动识别热Key
  2. 代理查询缓存:在Proxy层缓存热Key结果
  3. 读写分离版:自动将读请求路由到从节点

AWS ElastiCache

  1. Auto Scaling:根据负载自动扩展
  2. Enhanced Monitoring:提供详细的Key统计
  3. Read Replicas:配置多个只读副本

六、总结

解决Redis热Key问题需要综合考虑业务场景、数据特性和系统架构,主要解决方案包括:

  1. 本地缓存:减少对Redis的直接访问
  2. Key拆分:将大Key/热Key拆分为多个子Key
  3. 多级缓存:构建分层缓存体系
  4. 读写分离:利用从节点分担读压力
  5. 数据分片:将负载分散到不同节点
  6. 请求合并:减少重复请求

实际应用中,通常需要组合使用多种方案。例如,对商品详情页的热点数据可以同时采用:

  • 本地缓存(短时间)
  • Redis多级缓存
  • 读写分离
  • 监控报警

最后,热Key问题的解决不是一劳永逸的,需要持续监控并根据业务变化调整策略。建立完善的监控体系和应急预案,才能在热Key出现时快速响应,保障系统稳定运行。

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

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

相关文章

恒温晶振与温补晶振的区别

在电子设备领域&#xff0c;晶振如同精准的“心脏起搏器”&#xff0c;为电路提供稳定的时钟信号。恒温晶振&#xff08;OCXO&#xff09;和温补晶振&#xff08;TCXO&#xff09;作为两类重要的晶体振荡器&#xff0c;在不同的应用场景中发挥着关键作用&#xff0c;它们的区别…

基于SpringBoot的在线考试智能监控系统设计与实现

目录 一.&#x1f981;前言二.&#x1f981;开源代码与组件使用情况说明三.&#x1f981;核心功能1. ✅算法设计2. ✅Java开发语言3. ✅Vue.js框架4. ✅部署项目 四.&#x1f981;演示效果1. 管理员模块1.1 用户管理 2. 教师模块2.1 考试管理2.2 浏览试题列表2.3 添加试题2.4 成…

0基础学Python系列【16】自动化邮件发送的终极教程:Python库smtplib与email详解

大家好,欢迎来到Python学习的第二站!🎉 Python自带了一些超好用的模块,可以让你不必从头写代码就能实现很多功能。比如数学计算、文件操作、网络通信等。花姐会挑选常用的一些模块来讲解,确保你能在实际项目中用到。🎉 本章要学什么? 接下来花姐会深入浅出的讲解下面…

环卫车辆定位与监管:安心联车辆监控管理平台--科技赋能城市环境卫生管理

一、 引言 城市环境卫生是城市文明的重要标志&#xff0c;也是城市管理的重要内容。随着城市化进程的加快&#xff0c;环卫作业范围不断扩大&#xff0c;环卫车辆数量不断增加&#xff0c;传统的管理模式已难以满足现代化城市管理的需求。为提高环卫作业效率&#xff0c;加强环…

GIS 数据质检:验证 Geometry 有效性

前言 在GIS开发中&#xff0c;数据的几何有效性直接影响分析结果的准确性。无效的几何&#xff08;如自相交、空洞或坐标错误&#xff09;可能导致空间计算失败或输出偏差。无论是Shapefile、GeoJSON还是数据库中的空间数据&#xff0c;几何质检都是数据处理中不可忽视的关键步…

AI大模型学习之基础数学:高斯分布-AI大模型概率统计的基石

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家、CSDN平台优质创作者&#xff0c;高级开发工程师&#xff0c;数学专业&#xff0c;10年以上C/C, C#, Java等多种编程语言开发经验&#xff0c;拥有高级工程师证书&#xff1b;擅长C/C、C#等开发语言&#xff0c;熟悉Java常用开…

HarmonyOS性能优化——耗时操作减少

耗时操作减少 在应用开发中&#xff0c;避免主线程执行冗余和耗时操作至关重要。这可以降低主线程负载&#xff0c;提升UI响应速度。 避免主线程冗余操作 冗余操作是不必要的、重复执行且对程序功能无实质性贡献的操作。这些操作浪费计算资源&#xff0c;降低程序运行效率&a…

emscripten 编译 wasm 版本的 openssl

搭建emscripten环境【参考&#xff1a;https://emscripten.org/docs/getting_started/downloads.html】 下载openssl解压复制到emsdk目录 依次执行下列命令&#xff1a; cd emsdk #激活emsdk source ./emsdk_env.shcd opensslemconfigure ./Configure linux-x32 -no-asm -sta…

uniapp 实战新闻页面(一)

新闻系统 一、 创建项目 创建个人中心 page.json 配置 tabar "tabBar": {"color":"#666","selectedColor": "#31C27C","list": [{"text": "首页","pagePath": "pages/inde…

JAVA锁机制:对象锁与类锁

JAVA锁机制&#xff1a;对象锁与类锁 在多线程编程中&#xff0c;合理使用锁机制是保证数据一致性和线程安全的关键。本文将通过示例详细讲解 Java 中的对象锁和类锁的原理、用法及区别。 一、未加锁的并发问题 先看一段未加锁的代码&#xff1a; public class Synchronize…

maxcomputer 和 hologres中的EXTERNAL TABLE 和 FOREIGN TABLE

在阿里云的大数据和实时数仓产品中&#xff0c;MaxCompute 和 Hologres 都支持类似于 EXTERNAL TABLE 和 FOREIGN TABLE 的机制&#xff0c;但它们的实现和语义有所不同。 下面分别说明&#xff1a; ☁️ 一、MaxCompute 中的 EXTERNAL TABLE 和 FOREIGN TABLE 1. EXTERNAL T…

稳定币:从支付工具到金融基础设施的技术演进与全球竞争新格局

引言&#xff1a;稳定币的崛起与金融体系重构 2025年6月&#xff0c;全球稳定币市值突破2500亿美元历史大关&#xff0c;单年链上交易额高达35万亿美元——这一数字已超越Visa和万事达卡交易总和。这一里程碑事件标志着稳定币已从加密货币市场的边缘实验&#xff0c;蜕变为重构…

用 HTML、CSS 和 jQuery 打造多页输入框验证功能

多页输入框验证功能总结:使用 HTML、CSS 和 jQuery 实现 一、多页表单验证的核心概念与应用场景 多页输入框验证是指将复杂表单拆分为多个页面或步骤,逐步引导用户完成输入,并在每一步对用户输入进行验证的功能。这种设计具有以下优势: 提升用户体验:避免长表单带来的心…

DeepSpeed 深度学习学习笔记:高效训练大型模型

主要参考官网文档&#xff0c;对于具体内容还需参考官方文档 1. 引言&#xff1a;为什么需要 DeepSpeed&#xff1f; 大型模型训练的挑战 随着深度学习模型规模的爆炸式增长&#xff08;从 BERT 的几亿参数到 GPT-3 的千亿参数&#xff0c;再到现在的万亿参数模型&#xff09…

编程基础:耦合

能帮到你的话&#xff0c;就给个赞吧 &#x1f618; 文章目录 耦合&#xff1a;功能的单一性&#xff0c;功能越拆分则单一功能越好维护 耦合&#xff1a;功能的单一性&#xff0c;功能越拆分则单一功能越好维护

基于Qt的UDP主从服务器设计与实现

概述 一个基于Qt框架实现的UDP主从服务器系统&#xff0c;该系统具备自动主机选举、故障转移和状态同步等关键功能&#xff0c;适用于分布式能源管理系统中的设备通信与协调。 系统核心功能 1. 自动主机选举与故障转移 系统通过优先级机制实现自动主机选举&#xff0c;当主机…

【51单片机2位数码管100毫秒的9.9秒表】2022-5-16

缘由 这一题刚设计好要去回复就看到结帖了&#xff0c;好似看到我设计完成就盗窃去了&#xff0c;如此下面类似题目很容易也懒得回复了。 #include "reg52.h" sbit k0P3^0; sbit k1P3^1; unsigned char code SmZiFu[]{63,6,91,79,102,109,125,7,127,111};//0-9 uns…

安装ClickHouse

安装ClickHouse ClickHouse是一个用于联机分析的列式数据库管理系统&#xff0c;主要用于在线分析处理查询&#xff08;OLAP&#xff09;&#xff0c;能够使用SQL查询实时生成分析数据报告。 ClickHouse是一个完全的列式数据库管理系统&#xff0c;允许在运行时创建表和数据库&…

PX4无人机集成自带的深度相机进行gazebo仿真

修改mavros_posix_sitl.launch文件 修改以下两行代码 <arg name"my_model" default"iris_depth_camera"/><arg name"sdf" default"$(find mavlink_sitl_gazebo)/models/$(arg my_model)/$(arg my_model).sdf"/>iris_dept…

正点原子STM32cubeide学习——TFTLCD(MCU 屏)实验

使用的是正点原子的精英版&#xff0c;单片机是STM32F103ZET6&#xff0c;使用开发板的 MCU 屏接口连接正点原子 TFTLCD 模块(仅限 MCU 屏模块)&#xff0c;实现 TFTLCD 模块的显示。通过把 LCD 模块插入底板上的 TFTLCD 模块接口&#xff0c;按下复位之后&#xff0c; 就可以看…