我不会起名字322· 后端 / 算法 / 数据库 技术栈 力扣 Hot100 Go 项目 Redis MySQL文章目录Redis 从 0 到 1二十三一个热 key 打到 10 万 QPS——hotkey 与本地缓存的 Go 实现一、现象单 key 的 QPS 超过了整个实例的容量二、hotkey 的 3 种发现方式收藏点 1三、二级缓存本地缓存 短 TTL 版本号收藏点 2四、效果对比收藏点 3五、排查步骤节点 QPS 打满但 key 分布均匀六、总结Redis 从 0 到 1二十三一个热 key 打到 10 万 QPS——hotkey 与本地缓存的 Go 实现上一篇《Redis 从 0 到 1二十二一个 500MB 的 Hash 拖垮实例——bigkey 的 Go 渐进删除》我们解决了大的问题链接https://blog.csdn.net/2501_92769340/article/details/167399887 。本篇解决热的问题bigkey 撑大的延迟hotkey 打爆的是 QPS。一、现象单 key 的 QPS 超过了整个实例的容量明星官宣微博系统里那条动态的缓存 key 瞬间被打到 10 万 QPS。上了 Cluster 也没用——CRC16 决定这个 key 永远落在一个槽、一个节点上那个节点的单线程第 5 篇就这么被钉死了。hotkey 的本质负载均衡是按key 数量分的不是按访问热度分的。一万个冷门 key 摊在 10 个节点不如一个 10 万 QPS 的热 key 对一个节点的冲击大。解法是把读请求从 Redis 上卸掉一层本地缓存。二、hotkey 的 3 种发现方式收藏点 1方式原理优缺点monitor 采样MONITOR抓命令流统计 key 频率看到真实分布但 MONITOR 本身吃 30% CPU只能采样 30 秒OBJECT FREQLFU 策略下记录每个 key 的访问计数零成本但要求淘汰策略含 lfu 且计数是采样值代理/客户端埋点在 Redis 前面proxy或客户端统计最准确但要改链路# 方式 2 示例切到 allkeys-lfu 后看访问频率CONFIG SET maxmemory-policy allkeys-lfu OBJECT FREQ hot:key:weibo:12345# 输出访问计数# 方式 1 示例采样 10 秒生产低峰期做redis-cli --latency-history 不适用用timeout10redis-cli monitor|grep-oE[^]|sort|uniq-c|sort-rn|head发现之后做确认redis-cli -c --stat看节点 QPS 分布配合 hot key 名单锁定。三、二级缓存本地缓存 短 TTL 版本号收藏点 2架构请求 → [本地缓存 L1] 命中──是──→ 返回不经 Redis │否 ▼ [Redis L2] 命中──是──→ 回填 L1短 TTL→ 返回 │否 ▼ 回源数据库 → 回填 L2 L1关键设计三点L1 TTL 要短5~30 秒牺牲一点一致性换 Redis 90% 的读流量消失版本号防穿透L1 缓存 value versionL2 更新时 version1L1 发现 version 落后就回 L2 拉新L1 要有容量上限本地内存不是无限的LRU 淘汰第 6 章策略同款思路。Go 实现简化版本地缓存生产可换 freecache/bigcachepackagehotkeyimport(contextsynctimegithub.com/redis/go-redis/v9)typeitemstruct{valuestringversionint64expire time.Time}typeLocalCachestruct{mu sync.Mutex datamap[string]*item sizeintrdb*redis.Client ttl time.Duration}funcNewLocalCache(rdb*redis.Client,sizeint,l1TTL time.Duration)*LocalCache{c:LocalCache{data:make(map[string]*item,size),size:size,rdb:rdb,ttl:l1TTL}goc.gc()// 定期清理过期项returnc}// Get 两级读取L1 命中且未过期直接返回否则打 L2func(c*LocalCache)Get(ctx context.Context,keystring)(string,error){c.mu.Lock()ifit,ok:c.data[key];oktime.Now().Before(it.expire){v:it.value c.mu.Unlock()returnv,nil}c.mu.Unlock()// L1 未命中 → L2Redis顺便带版本号val,err:c.rdb.Get(ctx,key).Result()iferr!nil{return,err}c.mu.Lock()iflen(c.data)c.size{// 简单淘汰随机踢一个生产换 LRUfork:rangec.data{delete(c.data,k)break}}c.data[key]item{value:val,version:time.Now().Unix(),expire:time.Now().Add(c.ttl)}c.mu.Unlock()returnval,nil}// Invalidate 写路径调用L2 更新后主动作废 L1多实例时配合 Redis 订阅广播func(c*LocalCache)Invalidate(keystring){c.mu.Lock()delete(c.data,key)c.mu.Unlock()}func(c*LocalCache)gc(){t:time.NewTicker(time.Minute)forranget.C{c.mu.Lock()now:time.Now()fork,it:rangec.data{ifnow.After(it.expire){delete(c.data,k)}}c.mu.Unlock()}}写路径更新数据库 → 更新 Redis → 作废所有实例的 L1。多实例作废用 Redis Pub/Sub 广播第 18 篇这是 Pub/Sub 为数不多的正确用法——消息丢了也有 TTL 兜底rdb.Publish(ctx,cache:invalidate,key)// 各实例订阅后调用 Invalidate四、效果对比收藏点 3假设热 key 10 万 QPS、L1 TTL 15 秒、命中率 90%层级QPS应用收到的请求100,000打到 Redis≈10,00010% 未命中 失效瞬间打到数据库≈0L2 兜底Redis 节点压力降一个数量级且 L1 命中率可监控加计数器上报。五、排查步骤节点 QPS 打满但 key 分布均匀redis-cli -c --stat或监控看单节点QPS 是否远超其他节点是该节点的所有 key 都热还是某几个MONITOR 采样 10 秒按 key 聚合确认 hotkey 后评估改造为本地缓存 短 TTL无法本地缓存的场景强一致考虑 key 拆分key:1~key:10 带副本读牺牲一致性换分散。六、总结hotkey 打的是单节点Cluster 治不了单槽热点发现三板斧MONITOR 采样、OBJECT FREQ、客户端埋点解法核心L1 本地缓存短 TTL 容量上限 L2 Redis Pub/Sub 广播失效目标是把 Redis 热 key 的 QPS 卸掉 90%。下一篇预告单 key 的问题解决了下一篇优化次数——下一篇《1 万次 GET 从 800ms 降到 9ms——Pipeline 的 Go 压测》RTT 是隐藏的性能税。
企业数字化 ERP 产品动态
相关推荐
34970A:接 LabVIEW 常踩的 5 个坑 34970A 是插卡式数据采集与开关主机,一台机箱里既做多路切换也做测量,接口有 GPIB 和 RS-232,接 LabVIEW 常用原厂的插件式或 IVI 驱动。这台设备最容易卡住的地方是串口连不上、扫描列表不对,以及和 Switch Executive 配合时的驱… · 2026/11/5 3:40:16
FreeRTOS 第三课:C 语言扩展 学习笔记 FreeRTOS 第三课:C 语言扩展 学习笔记 嵌入式学习笔记 FreeRTOS 第 3 课 今天学习了 C 语言扩展:变量的作用域和生命周期、变量在 SRAM 里的分布、堆和栈的概念、FreeRTOS 的任务栈,以及 FreeRTOS 的代码规范,整理成文方便复习。… · 2026/11/5 3:40:16
JX3Toy 剑网3宏脚本使用指南:PVE循环与日常操作的减负工具 JX3Toy 剑网3宏脚本使用指南:PVE循环与日常操作的减负工具 【免费下载链接】JX3Toy 全功能减负工具 项目地址: https://gitcode.com/GitHub_Trending/jx/JX3Toy
团队副本打BOSS时,技能循环要不断开,机制、减伤还得兼顾;日常… · 2026/11/5 3:40:16
TED精读如何训练高阶英语思维与认知能力 1. 项目概述:这不是一节普通英语课,而是一次认知升级的实操训练“跟TED演讲学英文:How AI can save our humanity by Kai-Fu Lee”——这个标题乍看是语言学习类内容,但真正懂行的人一眼就能看出,它根本不是在教“how … · 2026/11/5 4:39:54
PostgreSQL INSERT操作全面指南与性能优化 1. PostgreSQL INSERT 操作深度解析PostgreSQL 作为一款功能强大的开源关系型数据库,其 INSERT 语句提供了远超基础数据插入的丰富功能。在实际开发中,合理运用这些特性可以显著提升数据操作效率和可靠性。1.1 基础语法与核心组件INSERT 语句的基础结构包… · 2026/11/5 4:39:54
Python在线考试系统开发:微服务架构与大数据分析实践 1. 项目概述与设计背景在线考试系统作为教育信息化的重要载体,正在经历从传统纸质考试向智能化评估的转型。我们团队基于Python技术栈开发的这套系统,核心目标是解决三个行业痛点:一是人工阅卷效率低下,二是考试过程监管困难&… · 2026/11/5 4:39:54
MySQL执行机制解析与性能优化实战 1. 项目概述MySQL作为最流行的开源关系型数据库之一,其内部执行机制一直是开发者们关注的焦点。在实际工作中,我们经常遇到这样的困惑:为什么这条SQL执行这么慢?索引为什么没生效?连接池配置多少合适?要真正… · 2026/11/5 4:39:54
小波阈值去噪五种改进变体:原理、MATLAB实现与避坑指南 简介:面向信号处理初学者与工程实践者的MATLAB小波阈值去噪工具包,聚焦软阈值、硬阈值及五种改进阈值方法的快速实现。作者在wden、thselect与wthresh三个函数基础上进行改造,并进一步封装为filterWaveletTh函数,延续专栏一贯的代… · 2026/11/5 4:39:54
从NRZ到PAM4:SerDes高速链路调制选型、均衡与眼图调试 高速串行链路这个圈子,做得久了你会发现一个很有意思的现象:真正决定一个系统能不能跑通的,往往不是那几百页的协议栈,而是最底层那一对差分线上的信号到底长什么样。SerDes 系统里 NRZ 和 PAM4 这两种调制方式的取舍,… · 2026/11/5 4:38:47
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38
多智能体协作系统架构设计与实践优化 1. 多智能体协作系统的时代背景2017年Transformer架构的诞生彻底改变了人工智能的发展轨迹。当行业还沉浸在单一大模型带来的性能突破时,Anthropic的研究团队已经将目光投向了更前沿的领域——如何让多个智能体通过协作产生超越单体能力的系统智能。这就像交响乐团中… · 2026/11/5 0:00:39
大模型系统性入门实战指南:从原理到部署微调的全链路路线 提到大模型的系统性入门,我先说个结论:这事真不难,难的是资料太散、路线太多,今天这个框架明天那个工具,新人很容易在“收藏夹吃灰”和“教程看到一半放弃”之间反复横跳。市面上关于大模型的内容少说有几十万篇&#… · 2026/11/5 0:00:39
鸿蒙文件系统沙箱机制解析与开发实践 1. 鸿蒙文件系统沙箱机制深度解析作为一名从Android转向鸿蒙开发的工程师,我深刻体会到文件系统访问是迁移过程中最先遇到的"拦路虎"。在Android上运行良好的文件读写代码,在鸿蒙真机环境却频频出现文件写入后神秘消失或直接抛出权限拒绝错误的… · 2026/11/5 0:00:39
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38