【JAVA架构师成长之路】【Redis】第17集:Redis热点Key问题分析与解决方案

30分钟自学教程:Redis热点Key问题分析与解决方案

目标

  1. 理解热点Key的定义、危害及成因。
  2. 掌握本地缓存、分片、读写分离等核心解决策略。
  3. 能够通过代码实现热点Key的读写优化。
  4. 学会熔断降级、自动探测等应急方案。

教程内容

0~2分钟:热点Key的定义与核心影响
  • 定义:某个或少数Key被极端高频访问(如百万QPS),导致Redis单节点负载过高。
  • 典型场景
    • 秒杀商品详情页的库存Key。
    • 热门微博、新闻的评论列表Key。
  • 危害
    • Redis单节点CPU/网络过载,引发性能抖动。
    • 集群模式下数据倾斜,部分节点压力过大。

2~5分钟:代码模拟热点Key场景(Java示例)
// 模拟高频访问热点Key(Java示例)  
@GetMapping("/product/{id}")  
public Product getProduct(@PathVariable String id) {  
    String key = "product:" + id;  
    Product product = redisTemplate.opsForValue().get(key);  
    if (product == null) {  
        product = productService.loadFromDB(id);  
        redisTemplate.opsForValue().set(key, product, 1, TimeUnit.HOURS);  
    }  
    return product;  
}  

// 使用JMeter模拟1000线程并发访问id=1001的接口  

问题复现

  • Redis监控显示product:1001的QPS飙升,单节点CPU占用超过90%。

5~12分钟:解决方案1——本地缓存(Caffeine)
  • 原理:在应用层缓存热点数据,减少对Redis的直接访问。
  • 代码实现(Spring Boot集成Caffeine)
// 配置Caffeine本地缓存  
@Bean  
public CacheManager cacheManager() {  
    CaffeineCacheManager cacheManager = new CaffeineCacheManager();  
    cacheManager.setCaffeine(Caffeine.newBuilder()  
        .expireAfterWrite(10, TimeUnit.SECONDS) // 短暂过期,防止数据不一致  
        .maximumSize(1000));  
    return cacheManager;  
}  

// 使用本地缓存  
@Cacheable(value = "productCache", key = "#id")  
public Product getProductWithLocalCache(String id) {  
    return redisTemplate.opsForValue().get("product:" + id);  
}  
  • 优势
    • 将99%的请求拦截在应用层,极大降低Redis压力。
    • 适合读多写少且容忍短暂不一致的场景。

12~20分钟:解决方案2——Key分片(Sharding)
  • 原理:将热点Key拆分为多个子Key,分散访问压力。
  • 代码实现(动态分片)
// 写入时随机分片  
public void setProductShard(Product product, int shardCount) {  
    String baseKey = "product:" + product.getId();  
    for (int i = 0; i < shardCount; i++) {  
        String shardKey = baseKey + ":shard_" + i;  
        redisTemplate.opsForValue().set(shardKey, product, 1, TimeUnit.HOURS);  
    }  
}  

// 读取时随机选择一个分片  
public Product getProductShard(String id, int shardCount) {  
    int shardIndex = new Random().nextInt(shardCount);  
    String shardKey = "product:" + id + ":shard_" + shardIndex;  
    return redisTemplate.opsForValue().get(shardKey);  
}  
  • 扩展
    • 分片数量可根据并发量动态调整(如QPS每增加1万,分片数+1)。

20~25分钟:解决方案3——读写分离与代理中间件
  • 原理:通过读写分离或代理层(如Twemproxy、Codis)分散请求。
  • 代码实现(读写分离)
// 配置读写分离数据源(Spring Boot示例)  
@Configuration  
public class RedisConfig {  
    @Bean  
    public RedisConnectionFactory writeConnectionFactory() {  
        // 主节点配置  
        RedisStandaloneConfiguration config = new RedisStandaloneConfiguration("master-host", 6379);  
        return new LettuceConnectionFactory(config);  
    }  

    @Bean  
    public RedisConnectionFactory readConnectionFactory() {  
        // 从节点配置  
        RedisStandaloneConfiguration config = new RedisStandaloneConfiguration("slave-host", 6379);  
        return new LettuceConnectionFactory(config);  
    }  

    @Bean  
    public RedisTemplate<String, Object> redisTemplate(  
        @Qualifier("writeConnectionFactory") RedisConnectionFactory writeFactory,  
        @Qualifier("readConnectionFactory") RedisConnectionFactory readFactory  
    ) {  
        RedisTemplate<String, Object> template = new RedisTemplate<>();  
        template.setConnectionFactory(writeFactory); // 默认写主  
        template.setDefaultSerializer(new StringRedisSerializer());  
        return template;  
    }  
}  

// 读操作手动切换至从节点  
public Product getProductFromSlave(String id) {  
    RedisTemplate slaveTemplate = createSlaveRedisTemplate(); // 从从节点获取连接  
    return slaveTemplate.opsForValue().get("product:" + id);  
}  

25~28分钟:应急处理方案
  1. 熔断降级(Sentinel熔断示例)
@SentinelResource(value = "getProduct", blockHandler = "handleBlock")  
public Product getProduct(String id) {  
    // 正常业务逻辑...  
}  

public Product handleBlock(String id, BlockException ex) {  
    return new Product("默认商品", 0.0); // 返回兜底数据  
}  
  1. 动态热点探测与自动扩容
// 热点Key监控器(伪代码)  
public class HotKeyDetector {  
    private ConcurrentHashMap<String, AtomicLong> counter = new ConcurrentHashMap<>();  

    @Scheduled(fixedRate = 1000)  
    public void detectHotKeys() {  
        counter.entrySet().removeIf(entry -> {  
            if (entry.getValue().get() > 10000) { // QPS超过1万判定为热点  
                expandSharding(entry.getKey()); // 触发分片扩容  
                return true;  
            }  
            return false;  
        });  
    }  

    private void expandSharding(String key) {  
        // 动态增加分片数量并迁移数据  
    }  
}  

28~30分钟:总结与优化方向
  • 核心原则:分散请求、就近缓存、动态调整。
  • 高级优化
    • 使用Redis Cluster自动分片。
    • 结合一致性哈希算法优化分片策略。
    • 通过监控系统(如Prometheus)实时预警热点Key。

练习与拓展

练习

  1. 使用Caffeine实现一个本地缓存,拦截高频访问的product:1001请求。
  2. 修改分片代码,支持根据Key的QPS动态调整分片数量。

推荐拓展

  1. 研究阿里开源的Tair对热点Key的优化方案。
  2. 学习Redis Cluster的Gossip协议与数据迁移机制。
  3. 探索代理中间件(如Twemproxy)的源码实现。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

项目实战--网页五子棋(对战功能)(9)

上期我们完成了websocket建立连接后的数据初始化&#xff0c;今天我们完成落子交互的具体代码&#xff1a; 这里我们先复习一下&#xff0c;之前约定好的落子请求与响应包含的字段&#xff1a; 1. 发送落子请求 我们在script.js文件中找到落子的相关方法&#xff0c;增加发送请…

elementplus的cascader级联选择器在懒加载且多选时的一些问题分析

1. 背景 在之前做的一个项目中使用到了element的级联选择器&#xff0c;并且是需要懒加载、多选、父子不关联等等&#xff0c;在选的时候当然没问题&#xff0c;但是回显的时候就会回显不出来&#xff0c;相信大部分伙伴都遇到过这个问题。我在以前出过一篇文章写过关于级联选…

基于PySide6的CATIA零件自动化着色工具开发实践

引言 在汽车及航空制造领域&#xff0c;CATIA作为核心的CAD设计软件&#xff0c;其二次开发能力对提升设计效率具有重要意义。本文介绍一种基于Python的CATIA零件着色工具开发方案&#xff0c;通过PySide6实现GUI交互&#xff0c;结合COM接口操作实现零件着色自动化。该方案成…

Uniapp项目运行到微信小程序、H5、APP等多个平台教程

摘要&#xff1a;Uniapp作为一款基于Vue.js的跨平台开发框架&#xff0c;支持“一次开发&#xff0c;多端部署”。本文将手把手教你如何将Uniapp项目运行到微信小程序、H5、APP等多个平台&#xff0c;并解析常见问题。 一、环境准备 在开始前&#xff0c;请确保已安装以下工具…

ROS分布式部署通信

目录 一、概念 二、设置 ROS 分布式网络 1. 环境要求 2. 主机&#xff08;Master&#xff09;设置 3. 从机&#xff08;节点设备&#xff09;设置 4. 测试是否正常通信 三、进阶启动多从机节点&#xff08;launch&#xff09;。 一、概念 ROS 分布式通信用于在多台计算机…

qt open3dAlpha重建

qt open3dAlpha重建 效果展示二、流程三、代码效果展示 二、流程 创建动作,链接到槽函数,并把动作放置菜单栏 参照前文 三、代码 1、槽函数实现 void on_actionAlpha_triggered();//alpha重建 void MainWindow::

我的三维引擎独立开发之路:坚持与迷茫

今天终于解决了&#xff0c;之前开发的基于threeceisum开发的融合引擎Merge3D,引用threejs版本过低的问题&#xff0c;也算又前进了一步&#xff01; 有人说&#xff0c;直接用最新版本不就行了&#xff0c;哎关键之前版本怎么办哪&#xff0c;很多不兼容性&#xff0c;需要一个…

【ArcGIS】地理坐标系

文章目录 一、坐标系理论体系深度解析1.1 地球形态的数学表达演进史1.1.1 地球曲率的认知变化1.1.2 参考椭球体参数对比表 1.2 地理坐标系的三维密码1.2.1 经纬度的本质1.2.2 大地基准面&#xff08;Datum&#xff09;的奥秘 1.3 投影坐标系&#xff1a;平面世界的诞生1.3.1 投…

数据分析人员需要掌握sql到什么程度?

学习SQL三个层次 熟悉基本的增删改查语句及函数&#xff0c;包括select、where、group by、having、order by、delete、insert、join、update等&#xff0c;可以做日常的取数或简单的分析&#xff08;该水平已经超过90%非IT同事&#xff09;;掌握并熟练使用高阶语法&#xff0…

简洁实用的3个免费wordpress主题

高端大气动态炫酷的免费企业官网wordpress主题 非常简洁的免费wordpress主题&#xff0c;安装简单、设置简单&#xff0c;几分钟就可以搭建好一个wordpress网站。 经典风格的免费wordpress主题 免费下载 https://www.fuyefa.com/wordpress

golang从入门到做牛马:第一篇-我与golang的缘分,go语言简介

还记得2018年的夏天,刚毕业的我不知道该做些什么,于是自学了一周的go语言,想要找一份go语言工作的代码,当时的go还没有go mod来管理依赖包,在北京找了一个月的工作,找到了一个小公司做了后端开发,当然使用go语言开发,带着兴奋劲,年轻身体也好,边努力学习,边工作。 时…

【Python编程】高性能Python Web服务部署架构解析

一、FastAPI 与 Uvicorn/Gunicorn 的协同 1. 开发环境&#xff1a;Uvicorn 直接驱动 作用&#xff1a;Uvicorn 作为 ASGI 服务器&#xff0c;原生支持 FastAPI 的异步特性&#xff0c;提供热重载&#xff08;--reload&#xff09;和高效异步请求处理。 启动命令&#xff1a; u…

Sentinel 笔记

Sentinel 笔记 1 介绍 Sentinel 是阿里开源的分布式系统流量防卫组件&#xff0c;专注于 流量控制、熔断降级、系统保护。 官网&#xff1a;https://sentinelguard.io/zh-cn/index.html wiki&#xff1a;https://github.com/alibaba/Sentinel/wiki 对比同类产品&#xff1…

JQuery 语法 $

jQuery 语法是通过选取 HTML 元素, 并对选取的元素执⾏某些操作 JQuery 选择器 jQuery 中所有选择器都以 $ 开头&#xff1a;$(). JQuery事件 事件由三部分组成: 1. 事件源: 哪个元素触发的 2. 事件类型: 是点击, 选中, 还是修改? 3. 事件处理程序: 进⼀步如何处理. …

算法每日一练 (9)

&#x1f4a2;欢迎来到张胤尘的技术站 &#x1f4a5;技术如江河&#xff0c;汇聚众志成。代码似星辰&#xff0c;照亮行征程。开源精神长&#xff0c;传承永不忘。携手共前行&#xff0c;未来更辉煌&#x1f4a5; 文章目录 算法每日一练 (9)最小路径和题目描述解题思路解题代码…

2025/3/8 第 27 场 蓝桥入门赛 题解

1. 38红包【算法赛】 签到题&#xff1a; 算倍数就行了 #include <bits/stdc.h> using namespace std; int main() {int ans0;for(int i1;i<2025;i){if(i % 3 0)ans;else if(i % 8 0)ans;else if(i % 38 0)ans;}cout<<ans<<endl;return 0; } 2. 祝福…

《白帽子讲 Web 安全》之深入同源策略(万字详解)

目录 引言 一、同源策略基础认知 &#xff08;一&#xff09;定义 &#xff08;二&#xff09;作用 &#xff08;三&#xff09;作用机制详解 二、同源策略的分类 &#xff08;一&#xff09;域名同源策略 &#xff08;二&#xff09;协议同源策略 &#xff08;三&…

基于SpringBoot的商城管理系统(源码+部署教程)

运行环境 数据库&#xff1a;MySql 编译器&#xff1a;Intellij IDEA 前端运行环境&#xff1a;node.js v12.13.0 JAVA版本&#xff1a;JDK 1.8 主要功能 基于Springboot的商城管理系统包含管理端和用户端两个部分&#xff0c;主要功能有&#xff1a; 管理端 首页商品列…

FFmpeg-chapter7和chapter8-使用 FFmpeg 解码视频(原理篇和实站篇)

解码流程如下图 流程&#xff1a;首先&#xff0c;通过 avcodec_alloc_context3(nullptr) 分配一个 AVCodecContext 结构体&#xff0c;然后使用 avcodec_parameters_to_context 将参数复制到上下文中&#xff0c;接着通过 avcodec_find_decoder 查找指定的解码器&#xff0c;并…

【银河麒麟高级服务器操作系统实例】虚拟机桥接网络问题分析及处理

更多银河麒麟操作系统产品及技术讨论&#xff0c;欢迎加入银河麒麟操作系统官方论坛 https://forum.kylinos.cn 了解更多银河麒麟操作系统全新产品&#xff0c;请点击访问 麒麟软件产品专区&#xff1a;https://product.kylinos.cn 开发者专区&#xff1a;https://developer…