前言

  由于有一条业务线不理想,高层决定下架业务。对于我们技术团队而言,其对应的所有服务器资源和其他相关资源都要释放。释放了8台应用服务器;1台es服务器;删除分布式定时任务中心相关的业务任务;备份并删除MySQL数据库;删除Redis中相关的业务缓存数据。CTO指名点姓让我带头冲锋,才扣了我绩效……好吧,冲~
其他都还好,不多时就解决了。唯独这删除Redis中的数据,害得我又熬了一个通宵,真是折煞我也!

难点分析

共用Redis服务集群

  由于这条业务线的数据在Redis大概在3G左右,完全没必要单独建一个Redis服务集群,本着能节约就节约的态度,当初就决定和其他项目共享一个集群(这个集群配置:16个节点,128G内存,还算豪华吧~)集群配置如下:

  在这种共用集群的情况下,导致无法简单粗暴的释放。因此只能选择删除Key的方式。

Key命名不规范

  要删除Key,首先就要精准的定位出哪些Key需要删除,如果勿删Key,会影响到其他服务正常运转!如果Key本身设置了过期时间,但有些数据需是持久化的。然而那该死的项目经理一直催项目进度,导致开发人员在开发过程中很多地方都没有设计到位,比如Redis Key散落在项目代码的每个角落;比如命名不是很规范。真不知道是怎么review代码!哦,想必是没有时间review,那该死的项目经理……
我随便截个支付服务中的Key命名:

  怎么样?是不是觉得我们开发人员写的代码很low~别笑,在实际工作中,还有比这更low的!希望你别遇到,不然真的很痛苦~

解决思路

  经过以上的分析,我们简单归纳如下:

  • 我们真正关心的是那些未设置过期时间的Key

  • 不能误删除Key,否则下个月绩效也没了

  • 由于Key的命名及使用及其不规范,导致Key的定位难度很大

看来,通过scan命令扫描匹配Key的方式行不通了。只能通过人肉搜索了~
幸而Idea的搜索大法好,这个项目中使用的是spring-boot-starter-data-redis.因此我通过搜索RedisTemplate和StringRedisTemplate定位所有操作redis的代码,具体步骤如下:
1、通过这些代码统计出Key的前缀并录入到文本中;
2、通过python脚本把载入文中中的的Key并在后面加上“*”通配符;
3、通过python脚本通过scan命令扫描出这些key;
4、为了便于检查,我们并没有直接使用del命令删除key,在删除key之前,先通过debug object key的方式得到其序列化的长度,再执行删除并返回序列化长度。这样,我们就可以统计出所有key的序列化长度来得到我们释放的空间大小。关键代码如下:

def get_key(rdbConn,start):try:keys_list = rdbConn.scan(start,count=2000)return keys_listexceptException,e:print e
''' Redis DEBUG OBJECT command got key info '''
def get_key_info(rdbConn,keyName):try:rpiple = rdbConn.pipeline()rpiple.type(keyName)rpiple.debug_object(keyName)rpiple.ttl(keyName)key_info_list = rpiple.execute()return key_info_listexceptException,e:print"INFO : ",e
def redis_key_static(key_info_list):keyType = key_info_list[0]keySize = key_info_list[1]['serializedlength']keyTtl = key_info_list[2]key_size_static(keyType,keySize,keyTtl)

  通过以上方式,能够统计出究竟释放了多少内存了。
  由于这个集群是有这么接近7千万个key:

  因此,等到了第二天天亮,我睡眼朦胧的看了一下,终于删除完毕了,时间07:13...早高峰即将来临……

知耻而后勇

 从来没有经历过因业务下线而清除资源的经验。这次事情真心让我觉得细微之处见真功夫的道理。如果一开始我们就能够遵循开发规范来使用和设计redis key,也不至于浪费这么多时间。为了让key的命名和使用更加规范,以及今后避免再次遇到这种情况,下午睡醒之后,我就在redis公共组件库里面添加了一个配置和自定义了key序列化,代码如下:

@ConfigurationProperties(prefix = "spring.redis.prefix")
publicclassRedisKeyPrefixProperties{privateBoolean enable = Boolean.TRUE;privateString key;publicBoolean getEnable() {return enable;}publicvoid setEnable(Boolean enable) {this.enable = enable;}publicString getKey() {return key;}publicvoid setKey(String key) {this.key = key;}
}
/*** @desc 对字符串序列化新增前缀* @author create by liming sun on 2020-07-21 14:09:51*/
publicclassPrefixStringKeySerializerextendsStringRedisSerializer{privateCharset charset = StandardCharsets.UTF_8;privateRedisKeyPrefixProperties prefix;publicPrefixStringKeySerializer(RedisKeyPrefixProperties prefix) {super();this.prefix = prefix;}@OverridepublicString deserialize(@Nullablebyte[] bytes) {String saveKey = newString(bytes, charset);if(prefix.getEnable() != null&& prefix.getEnable()) {String prefixKey = spliceKey(prefix.getKey());int indexOf = saveKey.indexOf(prefixKey);if(indexOf > 0) {saveKey = saveKey.substring(indexOf);}}return(saveKey.getBytes() == null? null: saveKey);}@Overridepublicbyte[] serialize(@NullableString key) {if(prefix.getEnable() != null&& prefix.getEnable()) {key = spliceKey(prefix.getKey()) + key;}return(key == null? null: key.getBytes(charset));}privateString spliceKey(String prefixKey) {if(StringUtils.isNotBlank(prefixKey) && !prefixKey.endsWith(":")) {prefixKey = prefixKey + "::";}return prefixKey;}
}

使用效果

  为了避免再次发生这种工作低效而又不得不做的事情,我们在开发规范中规定,新项目中redis的使用必须设置此配置,前缀就设置为:项目编号。另外,一个模块中的key必须统一定义在二方库的RedisKeyConstant类中。配置如下:

spring:redis:prefix:enable: truekey: E00P01
@Bean
publicRedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {RedisTemplate<String, Object> redisTemplate = newRedisTemplate<>();redisTemplate.setConnectionFactory(redisConnectionFactory);// 支持key前缀设置的key SerializerredisTemplate.setKeySerializer(newPrefixStringKeySerializer());redisTemplate.setValueSerializer(newGenericJackson2JsonRedisSerializer());return redisTemplate;
}

  通过以上方式,我们至少可以从项目维度来区分出key,避免了多个项目之间共用同一个集群时而导致重复key的问题。从项目维度对key进行了划分。更方便管理和运维。如果对于key的管理粒度要求更细,我们甚至可以细化到具体业务维度。我们在测试环境进行了压测,增加key前缀对redis性能几乎没有影响。性能方面能接受。

往期推荐

ElasticSearch搜索引擎原理,都给你整理好了

一键生成Springboot & Vue项目! 【私活神器】

MyBatis批量插入数据时,一定要考虑慎用foreach

4000字讲明白InnoDB 数据recovery过程解析

面试官:这份Spring Boot 核心知识点总结收好了!

抖音项目Semi Design涉嫌抄袭?技术团队发文致歉!

除了Swagger-ui,你还可以信任knife4j

Java实现短信验证码最佳实践

深入浅出Linux的 I/O 原理

java中这些判断空的用法,太优雅了

MySQL判断是否"存在",除了用count,这个办法更快捷!

回复干货】获取精选干货视频教程

回复加群】加入疑难问题攻坚交流群

回复mat】获取内存溢出问题分析详细文档教程

回复赚钱】获取用java写一个能赚钱的微信机器人

回复副业】获取程序员副业攻略一份

好文请点赞+分享

手动删除7千万个Reids的Key是什么体验响!相关推荐

  1. 计算机c盘那个是系统文件夹,C盘有哪些文件可以删除?可以手动删除的几个C盘中的文件夹...

    C盘是现在Windows系统下的默认系统盘,C盘不仅作为系统盘占用了许多系统关键文件,同时也是多数软件默认安装的位置.作为系统的存放之处,C盘需要保持较为充足的空间以保证系统的稳定运行,但是各种软件缓 ...

  2. windows10卸载程序_如何从Windows卸载程序列表中手动删除程序

    windows10卸载程序 If there's a program lingering on your Windows "Add or Remove Programs" list ...

  3. oracle服务怎么删除数据库,Oracle中手动删除数据库教程

    在很多情况下,或无法使用dbca工具的时候,我们需要手动来删除数据库.对此,可以借助drop database命令来实现,下面的描述中给出手动删除数据库. 的具体步骤,包含文件系统数据库以及ASM数据 ...

  4. linux下手动删除数据库实例

    linux下手动删除数据库实例,直接删除相应的目录就可以了,不多说了.... 1. $ORACLE_HOME/dbs/ [oracle9@frogger dbs]$ pwd /u01/app/orac ...

  5. oracle手动删除数据库

    有时候,无法使用图形界面时,我们需要手动删除数据库,具体操作步骤如下: 一.手动删除文件系统数据库    1.停止监听,防止有新的连接产生,同时,在数据库配置了em的,也需要停止 $ lsnrctl ...

  6. mysql利用binlog删除数据库_MySQL数据库之mysql手动删除BINLOG的方法

    本文主要向大家介绍了MySQL数据库之mysql手动删除BINLOG的方法 ,通过具体的内容向大家展现,希望对大家学习MySQL数据库有所帮助. 在MySQL中执行以下命令: 复制代码 代码如下: P ...

  7. 如何手动删除并重新安装 .NET Framework 2.0

    如何手动删除并重新安装 .NET Framework 2.0 本文可能包含一个指向 Windows 安装程序清理实用程序 (MSICUU2.exe) 的链接.如果被定向到本文使用 Windows 安装 ...

  8. 设置自动清理mysql binlog日志和手动删除的方法

    MYSQL主从复制(replication)采用 RBR 模式后,binlog的格式为"ROW",能解决很多原先出现的主键重复问题. 在一个繁忙的master db server上 ...

  9. Adobe系列软件彻底清理方法(手动删除)

    最近安装DW遇见不少问题,百度找到一篇关于手动删除Adobe全家桶博客 记录一下 这里我把win系统的Adobe软件彻底卸载方法梳理一遍,主要是系统盘(C盘)里面的注册信息 .软件使用残留信息.激活信 ...

最新文章

  1. java底层语言_JAVA语言思维的底层基础
  2. 数据结构:最大子序列和
  3. 在PPT中插入flash动画和影片
  4. linux shell if 或和且的表示方法
  5. 3分钟入门python_3分钟带你了解世界第一语言Python 入门上手也这么简单!
  6. 深入理解 Git 的实现原理
  7. 《软件项目管理(第二版)》第 10 章——项目收尾 重点部分总结
  8. linux+tomcat+jdk环境验证码无法显示
  9. 英特尔CEO称他们相信到2030年,芯片将占到汽车成本20%
  10. C++设计模式详解之命令模式解析
  11. (十七)Java springcloud B2B2C o2o多用户商城 springcloud架构-消息驱动 Spring Cloud Stream...
  12. 最简洁的PHP把PHP生成HTML代码
  13. bt磁力种子与php文件,使用Python实现BT种子和磁力链接的相互转换
  14. ibus五笔快捷键 繁简 单字 词组切换
  15. hdoj1814 Peaceful Commission【2-set】
  16. 金蝶K/3 Cloud 实施笔记
  17. 前端初学者的痛,没学历没工作经验如何找工作?
  18. PHP解决中文乱码问题
  19. MAC下安装ElasticSearch(官网下载安装包)
  20. web前端常用长度单位(px,em,rem,pt)

热门文章

  1. 东师18秋学期计算机基础3,东师18秋学期(1709、1803、1809)《概率论与统计原理》在线作业答案...
  2. SQL Server 修改数据库名、修改逻辑文件名、修改数据库物理文件名
  3. c语言tab什么意思_收藏 | C语言最全入门笔记
  4. 实验吧-密码学-疑惑的汉字(当铺密码)
  5. 微型计算机的字符信息编码方案,微型计算机中普遍采用的字符信息编码方案是(.doc...
  6. 移植0.96四针脚OLED程序到msos系统
  7. 【动网论坛7.1 sp1 修改】-论坛短信无刷新弹出
  8. 安全狗漏洞通告|Linux kernel越界写入漏洞解决方案
  9. Revit二次开发-根据名称获取标高
  10. 中国电信物联网发展研究中心与华为战略合作协议