一、引言

本文将结合我的一次Redis大Key的治理经验,来浅谈一下缓存大Key的治理方案选择。文中主要包括缓存大Key基础知识大Key治理方案选择大Key治理案例等,适合有一定开发经验的开发者阅读,希望对大家有帮助。

二、缓存大Key基础知识

2.1 大Key的标准

集合类型元素数量>5000或者单个value大于1M。当然这个标准不是绝对的,而是需要根据具体的业务场景和Redis集群的实际情况来灵活调整

2.2 大Key带来的风险

  • 大key发生热点访问,响应积压在服务端后内存暴涨,最终导致服务端被杀造成数据丢失
  • 严重影响 QPS、TP99等指标,对大Key进行的慢操作会导致后续的命令被阻塞,从而导致一系列慢查询。
  • hgetall、smembers 等时间复杂度O(N)的命令使用不当,容易造成CPU使用率过高。
  • 集群各分片内存使用不均。某个分片占用内存较高或OOM,发送缓存区增大等,导致该分片其他Key被逐出,同时也会造成其他分片的资源浪费。
  • 集群各分片的带宽使用不均。某个分片被流控,其他分片则没有这种情况,且影响宿主机上的其它应用。
  • 数据迁移失败 过大的Key(如超过1G),在迁移、缩容、扩容,主从全量同步在序列化过程中,内存上涨,数据同步失败,且存在数据丢失风险。

三、缓存大Key治理方案

3.1事前预防

事前预防的基本思路是在缓存设计的时候,缓存中只存储必要的数据,且需要考虑将存储空间变小,具体的手段有:

  1. 对于JSON类型,可以删除不使用的Field;或者使用@JsonProperty 注解让 FiledName 字符集缩小;
  2. 采用Protobuf等压缩算法,利用时间换空间;
  3. 对于集合类型,设计上尽量避免整存整取;

3.2 事中监控

事中做好监控,对于缓存大Key,早发现,早治理;

3.3 事后

缓存大Key已经存在,那么应该怎么办?分2种情况进行考虑:

  1. 评估这些大Key是否还有存在的意义和价值,是否可以删除,对于可以删除的可以使用SCAN命令进行循序渐进式删除大Key;对于不可以直接删除的这种,是否可以将数据转移到其他的介质进行存储;
  2. 对于不能直接删除的大Key,进行“分而治之”,再通俗一点就是“拆”,将大Key进行拆分
  • String类型的大Key:可以尝试将对象分拆成几个Key-Value,使用MGET或者多个GET组成的pipeline获取值,分拆单次操作的压力,对于集群来说可以将操作压力平摊到多个分片上,降低对单个分片的影响。
  • 集合类型的大Key,每次只需操作部分元素:将集合类型中的元素分拆。以Hash类型为例,可以在客户端定义一个分拆Key的数量N,每次对HGET和HSET操作的field计算哈希值并取模N,确定该field落在哪个Key上。

四、缓存大Key治理案例

4.1 系统架构和业务场景说明

有这样一个电商活动管理系统,系统有2个应用:后台管理端、运营端;(后台管理端是管理人员进行操作;运营端可以创建营销活动)存储使用的是MySQL和Redis;

系统中有一个这样的场景,简单来说就是,后台管理端可以添加sku白名单,这个白名单是以“商家ID + skuId”为一条记录写入MySQL中的;运营端在创建营销活动,需要上传sku,上传的时候需要读取sku白名单进行校验。

系统现状是,在查询sku白名单的时候使用了Redis缓存。缓存模式采用的是旁路缓存,添加SKU白名单的流程是,写入数据库,并删除缓存;读取SKU白名单的流程是,先从缓存读取,缓存中没有则读取数据库,并将结果写入缓存。缓存的数据类型是String,value为数据库中的全量SKU白名单记录,是以JSON字符串存储的。

旁路缓存:读取缓存、读取数据、更新缓存和操作都是在应用程序中完成的。

但是随着业务的发展,添加的SKU白名单逐渐增多,发展成为了缓存大Key。截止治理之前,数据库的配置表中存在1w+条sku白名单记录,也就是说Redis的一个String结果存储了1w+条的白名单记录。

这里也许有人问,一张表中存储1w+条数据,也是没有压力的啊,其实这张配置表中不仅有商家SKU白名单配置,还包括系统中其他所有的配置信息存储,数据量还是可观的。

4.2 一种激进的治理方案

该业务场景中,缓存大Key是不可以直接进行删除处理的,处理思路是将其拆分为一些小的Key。

分析场景,商家可以登录运营端进行创建营销活动,在创建营销活动和上传SKU的过程中,只需要查询该商家的SKU白名单,那么存储和查询全部都是不必要的,那么可以将全量白名单数据按照商家维度进行拆分存储和查询。

关于缓存结构的选择,我使用的是Hash结构(新缓存),key与原缓存String结构 key 相同,field为商家ID,value为sku白名单列表。大概流程图如下:

新缓存Hash结构key与原缓存String结构 key 完全相同,意味着新的Hash结构缓存和旧的String缓存是无法共存的,只能选择其一,意味着不存在百分比切量的过程,一步到位切量,你就说是否激进?

这样激进的方案是基于什么的考量呢?

  1. 夜间流量几乎为0,且缓存切换操作秒级完成,风险可控。运营端系统,商家创建促销活动基本都是工作时间,晚上和凌晨几乎没有流量;而且,新旧缓存切换可以秒级完成:①运营端添加测试SKU白名单,删除缓存;②将开关切到新缓存;风险可控。
  2. 方案支持秒级回滚.①运营端添加测试SKU白名单,删除缓存;②将开关切到旧缓存。
  3. 代码改动和上线部署工作量小。这个方案可以保持管理后端删除缓存的逻辑不变,也就是在添加SKU白名单的时候还是删除所有的白名单缓存;只需要改动运营后端代码,且上线部署只需要部署运营端。
  4. 虽然管理后端删除缓存为全量删除,存在管理端添加商家A的SKU白名单,导致缓存中的商家B、商家C等的白名单数据也被删除(其实是无需删除的),综合评估可以暂时保持现状,后续优化

4.3 更加通用的治理方案

4.3.1 三个阶段

更加通用的缓存大key治理方案,包括双写、双读对比和读写新key等阶段:

  1. 双写阶段

在不影响现有业务的情况下,将新数据同时写入旧key和新key;

  1. 双读对比阶段

验证新key的数据与旧key的数据是否一致,并准备切换读操作到新key;

  1. 读写新key阶段

将所有读写操作都切换到新key,并废弃旧key;需要注意删除大key时要避免阻塞Redis服务。

4.3.2 注意事项

  • 数据一致性:在整个治理过程中,需要确保数据的一致性。特别是在双写和双读对比阶段,要仔细验证数据是否一致。
  • 性能影响:在双写和双读对比阶段,由于需要同时操作旧key和新key,可能会对性能产生一定影响。因此,需要在业务低峰期进行这些操作,并监控系统的性能指标。
  • 错误处理:在治理过程中,可能会遇到各种错误情况(如数据不一致、网络问题等)。需要制定完善的错误处理机制来确保系统的稳定性和可用性。
  • 备份和恢复:在执行治理操作之前,建议对Redis数据进行备份。以便在出现问题时可以快速恢复数据。

五、小结

本文是一个真实的线上缓存大Key治理案例,区别于通用的治理方案,我选择了一种激进和简单的治理策略。对于缓存大Key进行简单总结一下,对于使用缓存,需要考虑缓存大Key问题,设计和开发过程中尽量避免;如果已经出现,考虑删除,如果不可以删除,考虑拆分。可以在权衡之下,选择最适合自己的方案。

一起学习

欢迎各位在评论区或者私信我一起交流讨论,或者加我主页weixin,备注技术渠道(如博客园),进入技术交流群,我们一起讨论和交流,共同进步!

也欢迎大家关注我的博客园、公众号(码上暴富),点赞、留言、转发。你的支持,是我更文的最大动力!

经验之谈:我为什么选择了这样一个激进的缓存大Key治理方案的更多相关文章

  1. 哪种缓存效果高?开源一个简单的缓存组件j2cache

    背景 现在的web系统已经越来越多的应用缓存技术,而且缓存技术确实是能实足的增强系统性能的.我在项目中也开始接触一些缓存的需求. 开始简单的就用jvm(java托管内存)来做缓存,这样对于单个应用服务 ...

  2. 闲来无事,用Java的软引用写了一个山寨的缓存

    闲来无事,用Java的软引用写了一个山寨的缓存 博客分类: java基础 众所周知java中的引用分为 StrongReference.SoftReference.WeakReference.Phan ...

  3. Hbase 学习笔记(一) Hbase的物理模型 Hbase为每个值维护了一个多级索引,即<key, column family, column name, timestamp>

      比如第一个region 代表 0-100 第二个region 代表 101 -200的 分的越多越不好管理,但同时方便了并行化处理,并发度越高,处理的越快.mapreduce就是按照rowkey的 ...

  4. 10.我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。 请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

    我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形. 请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法? 是不是发现看不懂,哈哈:编程题就是这样,一定要归纳,手写过程: n ...

  5. W-TinyLFU——设计一个现代的缓存

    缓存设计是个基础架构领域里的重要话题,本号之前也有谈论过相关话题,点击原文可以看之前的介绍. 近日,HighScalability网站刊登了一篇文章,由前Google工程师发明的W-TinyLFU—— ...

  6. Java实现一个简单的缓存方法

    缓存是在web开发中经常用到的,将程序经常使用到或调用到的对象存在内存中,或者是耗时较长但又不具有实时性的查询数据放入内存中,在一定程度上可以提高性能和效率.下面我实现了一个简单的缓存,步骤如下. 创 ...

  7. java梳理-一个汉字占多大空间

    面试题:一个汉字占多大空间. 事实上这个问题我了解不深的,知道结论不知道为什么.借此梳理下认识. 先回想下java基本类型 一基本类型 :简称四类八种,声明变量的同一时候分配了空间.举比例如以下:   ...

  8. NSIS编译报错:您可能有有一个或两个(大)的旧临时文件

    一.有时在编译NSIS时会出现如下错误: 注意: 您可能有有一个或两个(大)的旧临时文件 残留在临时目录文件夹中 (通常这种情况只会发生在 Windows 9x 系统中). 二.本人遇到的问题原因: ...

  9. 在Hibernate中使用Memcached作为一个二级分布式缓存

    转自:http://www.blogjava.net/xmatthew/archive/2008/08/20/223293.html   hibernate-memcached--在Hibernate ...

  10. SpringBoot,用200行代码完成一个一二级分布式缓存

    缓存系统的用来代替直接访问数据库,用来提升系统性能,减小数据库复杂.早期缓存跟系统在一个虚拟机里,这样内存访问,速度最快. 后来应用系统水平扩展,缓存作为一个独立系统存在,如redis,但是每次从缓存 ...

随机推荐

  1. 聊聊微信小程序的隐私协议开发

    为什么需要隐私协议? 小程序隐私授权弹窗FAQ官方:https://developers.weixin.qq.com/community/develop/doc/00000ebac5c3e042384 ...

  2. Android为按钮Button添加事件

    匿名内部类 1 <!--匿名内部类方式--> 2 <Button 3 android:id="@+id/btn2" 4 android:layout_width= ...

  3. IPv4地址的结构体与网络字节序

    IPv4地址的结构体 /* Fixed-size types, underlying types depend on word size and compiler. */ typedef signed ...

  4. IT的贵与慢

    本文于2019年7月24日完成,发布在个人博客网站上. 考虑个人博客因某种原因无法修复,于是在博客园安家,之前发布的文章逐步搬迁过来. 笔记而已,没有逻辑. 贵与慢,一方面是事实,另一方面是偏见. 流 ...

  5. OpenHarmony父子组件单项同步使用:@Prop装饰器

      @Prop装饰的变量可以和父组件建立单向的同步关系.@Prop装饰的变量是可变的,但是变化不会同步回其父组件. 说明: 从API version 9开始,该装饰器支持在ArkTS卡片中使用. 概述 ...

  6. C++ 异常和错误处理机制:如何使您的程序更加稳定和可靠

    在C++编程中,异常处理和错误处理机制是非常重要的.它们可以帮助程序员有效地处理运行时错误和异常情况.本文将介绍C++中的异常处理和错误处理机制. 什么是异常处理? 异常处理是指在程序执行过程中发生异 ...

  7. 详讲openGauss 5.0 单点企业版如何部署_Centos7_x86

    本文分享自华为云社区<openGauss 5.0 单点企业版部署_Centos7_x86>,本文作者:董小姐 本文档环境:CentOS7.9 x86_64 4G1C40G python2. ...

  8. 鸿蒙手表定位功能Demo体验,适用儿童、老年和外出旅游安全市场

    针对儿童和老人,可穿戴的智能手表用处很大.市场也有许多类似的产品,支持接打电话.支付扫码.定位等功能,属于新兴的商业机会.依托华为品牌,鸿蒙手表也致力为用户打造精品的.产品质量佳.可穿戴的智能体验.对 ...

  9. cmd中怎么清屏--cls

    平时我们在 Linux 系统中清除屏幕 用的命令是:  clear 现在在Windows上用的清屏命令是 : cls

  10. HDC2021技术分论坛:跨端分布式计算技术初探

    作者:zhengkai,分布式通信首席技术专家 当今的移动应用都向着智能化和多样化方向发展,例如AI辅助,VR/AR应用,沉浸式游戏等.然而现实中的移动设备,因为便携性要求受限于尺寸.电池容量以及温控 ...