熬了一个通宵,终于把 7000 万个 Key 删完了

生产级机器学习系统:从模型部署到稳定运行的工程实践 机器学习模型上线不是终点,而是系统性工程挑战的起点。在真实业务场景中,模型需满足SLA契约、低延迟响应、高可用容错与全链路可追溯等硬性要求。其核心难点在于集成稳定性(如特征服务与模型服务的协议对齐)、确定性推理(避免GPU非确定性导致决策抖动)、数据与概念漂移的主动监控(PSI/KS检验、score-业务结果相关性),以及监管合规嵌入(血缘追踪、公平性审计、自动化解释)。本文聚焦金融风控等强约束场景,提供经P1事故验证的部署Checklist、熔断Fallback设计、分层特征缓存与审计就绪实践,将抽象的M 阅读详情

点击上方“芋道源码”,选择“设为星标”

管她前浪,还是后浪?

能浪的浪,才是好浪!

每天 8:55 更新文章,每天掉亿点点头发...

源码精品专栏

 

来源:juejin.im/post/5f18423fe51d453493113f5c

  • 前言

  • 难点分析

    • 共用Redis服务集群

    • Key命名不规范

  • 解决思路

  • 知耻而后勇

    • 使用效果

  • 总结


前言

由于有一条业务线不理想,高层决定下架业务。对于我们技术团队而言,其对应的所有服务器资源和其他相关资源都要释放。释放了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_list
    except Exception,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_list
    except Exception,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")
public class RedisKeyPrefixProperties {
 private Boolean enable = Boolean.TRUE;
 private String key;
 public Boolean getEnable() {
  return enable;
 }
 public void setEnable(Boolean enable) {
  this.enable = enable;
 }
 public String getKey() {
  return key;
 }
 public void setKey(String key) {
  this.key = key;
 }
}

/**
 * @desc 对字符串序列化新增前缀
 * @author create by liming sun on 2020-07-21 14:09:51
 */
public class PrefixStringKeySerializer extends StringRedisSerializer {
    private Charset charset = StandardCharsets.UTF_8;
    private RedisKeyPrefixProperties prefix;

    public PrefixStringKeySerializer(RedisKeyPrefixProperties prefix) {
     super();
     this.prefix = prefix;
    }

    @Override
    public String deserialize(@Nullable byte[] bytes) {
     String saveKey = new String(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);
    }

    @Override
    public byte[] serialize(@Nullable String key) {
     if (prefix.getEnable() != null && prefix.getEnable()) {
      key = spliceKey(prefix.getKey()) + key;
     }
     return (key == null ? null : key.getBytes(charset));
    }

    private String spliceKey(String prefixKey) {
     if (StringUtils.isNotBlank(prefixKey) && !prefixKey.endsWith(":")) {
      prefixKey = prefixKey + "::";
     }
     return prefixKey;
    }
}

使用效果

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

spring:
    redis:
        prefix:
            enable: true
            key: E00P01

@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
    RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
    redisTemplate.setConnectionFactory(redisConnectionFactory);
    // 支持key前缀设置的key Serializer
    redisTemplate.setKeySerializer(new PrefixStringKeySerializer());
    redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
    return redisTemplate;
}

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

总结

通过本次事情,我发现对于大多数开发者而言,差距其实不在于智力,而是在于态度。比如这次事件暴露出来的问题:大家都知道要遵循开发规范,然而到了真正“打仗”的时候,负责这个项目的开发者却没有几个人能始终如一的做好这些细微之事。另外,reviewer的工作其实是极其重要的,他就像那“纪检委”,如果“纪检委”都放水睁一只眼闭一只眼,那麻烦可就大了!千里之提,毁于日常的点滴松懈啊~~~

经过这次事件之后,如果上天再给一次这样的机会,我一定会对项目经理说:接着奏乐,接着舞~



欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢:

已在知识星球更新源码解析如下:

最近更新《芋道 SpringBoot 2.X 入门》系列,已经 20 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。

提供近 3W 行代码的 SpringBoot 示例,以及超 4W 行代码的电商微服务项目。

获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

兄弟,艿一口,点个赞!????

CTF密码破解实战:Hashcat核心攻击模式与性能调优指南 哈希(Hash)是一种将任意长度数据映射为固定长度摘要的单向加密函数,广泛应用于密码存储与数据完整性校验。其核心原理是通过特定算法(如MD5、SHA系列)生成唯一指纹,理论上不可逆。在信息安全领域,高效破解哈希对于渗透测试、数字取证及CTF竞赛至关重要。Hashcat作为一款支持GPU加速的密码恢复工具,通过多种攻击模式(如字典、掩码、混合攻击)极大提升了破解效率。在CTF竞赛中,选手常面临**加盐哈希**与**掩码攻击**等场景,需结合题目提示精准构造字典与掩码,并利用Hashcat的会话管理、性能调优功 阅读详情

相关推荐

联想ThinkPad声卡驱动安装避坑指南:从E470到X1 Carbon的通用解法

本文详细介绍了ThinkPad声卡驱动安装的全流程,从硬件识别到驱动获取、安装技巧及深度排错。涵盖E470到X1 Carbon等不同机型的通用解法,帮助用户解决音频驱动问题,提升使用体验。重点讲解了声音驱动的精准识别和安装策略,确保系统稳定运行。

weixin_29207439的博客 711

spring使用Redis自定义前缀后缀名(去掉SimpleKey []+自定义)

spring使用Redis自定义前缀后缀名(去掉SimpleKey []+自定义) spring中自动加上SimpleKey [] 解决方案 一、自定义后缀名 1、定义类实现KeyGenerator接口 MyKeyGenerator package com.wbg.springRedis.service.impl; import org.sp...

weixin_42981419的博客 4995

从GEFCom到UCI:手把手教你构建电力负荷时空预测模型(Python版)

本文详细介绍了如何从GEFCom到UCI数据集构建电力负荷时空预测模型(Python版),涵盖数据集解析、时空特征工程、模型架构设计及工业部署优化。通过多任务图神经网络(MTGNN)实现高精度预测,并结合边缘计算和在线学习机制提升实际应用效果,为能源管理系统提供可靠解决方案。

lambda的博客 813

基于Spring Boot2.x使用Redis(Lettuce)详细教程---Redis的开发规范 (十)

10.1、键值设计 1、key名设计 可读性和可管理性 以业务名(或数据库名)为前缀(防止key冲突),用冒号分隔,比如业务名:表名:id ugc:video:1 简洁性 保证语义的前提下,控制key的长度,当key较多时,内存占用也不容忽视,例如: user:{uid}:friends:messages:{mid}简化为u:{uid}:fr:m:{mid}。 不要包含特殊字符 反例:包含空格...

jetty_welcome的博客 1306

手把手教你用Simulink+CANoe+Carsim搭建硬件在环仿真环境(避坑指南)

本文是一份详细的硬件在环仿真环境搭建指南,重点讲解如何将Simulink、CANoe和CarSim三大工具进行实战融合。内容涵盖软件版本兼容性、授权避坑、环境配置,并分步演示了从离线联合仿真到实现软实时同步的完整流程,旨在帮助汽车电子工程师高效构建稳定的HIL测试平台。

weixin_29092579的博客 406

Kisssoft软件在行星齿轮设计上的初试

行星齿轮传动与链传动相比较,具有质量小,体积小,承载能力强,传动比大,传动效率高等优点,但在行星齿轮传动种种优点下,不可避免的带来一些缺点,对其材料的要求过高,在追求传动比大而体积小的同时,其传动结构大大的复杂化,以及在制造和安装过程中较困难,对于行星齿轮传动设计来说,不仅应该了解其优点,而且应该在设计中,充分发挥其优点,且把其缺点降低到最低的限度。从而才能设计出性能优良的行星齿轮传动装置,为我们赛车提供更加强大的动力保证。 Kisssoft软件为我们行星齿轮传动设计提供了一体化方案,从设...

m0_69808569的博客 1万+

因 Redis Key 命令不规范,导致熬了一个通宵才把Key删完了!

点击蓝色“架构文摘”关注我哟加个“星标”,每天上午 09:25,干货推送!来源:http://dwz.date/cmSG前言由于有一条业务线不理想,高层决定下架业务。对于我们技术团队而言...

架构文摘 738

STM32的GPS数据提取程序设计说明——基于NMEA0183协议

一、硬软件平台 本次程序实现效果为对GPS信号穿送来的数据进行筛选,并将筛选后的信息通过上位机显示出来,所以此次设计所需硬件包括STM32F407、RS232转TTL、CH340USB转串口模块,注意该模块在使用前,对应的系统需要安装驱动,否则串口调试助手无法识别,另外还包括JLink下载器。 本次代码设计软件为KEIL5并结合F4固件包,上位机系统为WIN7,主机系统为WIN10。 二、算法总体思路设计 由于GPS通过RS232将数据传送给板子,因此使用两个串口资源(串口1和串口2),其中一个用来

小景的博客 6181

redis中使用key的规则

在设置key时,我们使用了命名空间的方式,将所有用户相关的缓存数据都放在"user:"命名空间下。在获取缓存数据时,如果缓存未命中,则从数据库中加载,并将数据放入缓存中,并设置过期时间为5分钟。例如,可以将一个用户对象拆分成多个字段,每个字段对应一个key,这样当只需要获取部分信息时,就可以减少读取数据的量。需要注意的是,在使用Redis缓存时,要避免将大量占用内存的对象放入缓存中,否则会影响缓存的性能和稳定性。3. 设置过期时间:根据数据的生命周期来设置过期时间,避免缓存数据过期而占用内存。

2301_77162163的博客 605

[Python]:热血传奇-Wzl,Wzx的解析

首先我们要了解,wzl与wzx的对应关系,wzx里面存的是每张二进制图片数据在wzl中的偏移量,所以取到wzx中的偏移数据就可以取到wzl每张图片数据,其实就这么简单。结构体为 [Byte][Byte][Byte][Byte][short][short][short][short][int]-读取44至48字节代表为,[wzx中偏移值总数量] [int类型] [4字节]-根据在wzx中取得的偏移值总数量,每张图片偏移值在wzl中取图片数据。2.[取wzl中图片偏据]:根据wzx中取得数据对[

qq_36138506的博客 3456

ValueError: numpy.dtype size changed, may indicate binary incompatibility. Expected 96 from C 解决方案

本文主要介绍了ValueError: numpy.dtype size changed, may indicate binary incompatibility. Expected 96 from C header, got 88 from PyObject解决方案,希望能对使用Numpy的同学们有所帮助。 文章目录 1. 问题描述 2. 解决方案

weixin_43178406的博客 1万+

SpringBoot中,redis的key和value为基本类型时需要注意的

在SpringBoot中的redisTemplate, 无论操作那种类型, 如果key或者value的值为基本类型,貌似都需要转为string, 取出来的时候需要把String转为对应的基本类型

qq_42682745的博客 1058

支付宝h5参数如何实现跳转?(包含相关Demo代码)

🏆本文收录于专栏,主要记录项目实战过程中所遇到的Bug或因后果及提供真实有效的解决方案,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家!持续更新中,up!up!up!!

**My Coding Family** 3254

从“单机崩盘”到“集群稳如狗”:Redis 高可用避坑指南(保姆级实战)

本文通过电商秒杀场景下的真实案例,剖析了单机Redis在高并发下的瓶颈问题,系统讲解了Redis集群的三种解决方案:主从复制、哨兵模式和Cluster分片集群。文章从实战角度分析了每种方案的原理、配置方法和适用场景,并提供了关键避坑指南。特别针对生产环境中常见的fork阻塞、主从延迟、故障转移等痛点问题给出了具体解决方案,最后通过对比表格帮助读者根据业务场景选择合适的集群方案。对于Java开发者来说,这是一份兼具理论深度和实践价值的Redis高可用指南。

baidu_25106585的博客 339

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

Springboot集成redis和解决redis key乱码问题

springboot集成redis 1、 导包 <!--springboot中的redis依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- lettuce pool 缓存连接池--

白鸽 2756

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

Redis——key命名规范及redis容量预估

Redis——命名规范及容量预估

娜娜米的博客 1万+

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Redis的使用规范

1、Redis的使用规范 1.1、 key的规范要点 我们设计Redis的key的时候,要注意以下这几个点: 以业务名为key前缀,用冒号隔开,以防止key冲突覆盖。如,live:rank:1 确保key的语义清晰的情况下,key的长度尽量小于30个字符。 key禁止包含特殊字符,如空格、换行、单双引号以及其他转义字符。 Redis的key尽量设置ttl,以保证不使用的Key能被及时清理或淘汰。 1.2、value的规范要点 Redis的value值不可以随意设置的哦。 第一点,如果.

Meiko记录 1049

redis key命名规范

1.建议全部大写 2.key不能太长也不能太短,键名越长越占资源,太短可读性太差 3.key 单词与单词之间以 : 分开 user id userName age 1 zhangsan 18 2 lisi 16 4.redis使用的时候注意命名空间,一个项目一个命名空间,项目内业务不同命...

weixin_34191734的博客 2266

redis规范

建议根据业务只将高频热数据存储到Redis中【QPS大于5000】,对于低频冷数据可以使用MySQL/ElasticSearch/MongoDB等基于磁盘的存储方式,不仅节省内存成本,而且数据量小在操作时速度更快、效率更高。Redis主要用于缓存处理,加快读取效率,但在使用过程中需要注意合理的使用,一般存储全局配置数据和一些访问非常频繁的较为静态的数据,另外注意过期时间控制,减少资源的不必要消耗。并发量:如果你的应用程序具有高并发的特点,可以增加连接数的值,以确保有足够的连接可供同时使用。

kkkkm1的博客 1552

Redis Key 命名规范详解

在Redis中,合理的key命名是非常重要的,它不仅影响代码的可读性,还关系到数据的组织结构和维护效率。

鸟人的博客 1169

使用Redis,你必须知道的21个注意要点

前言 最近在学习Redis相关知识,看了阿里的redis开发规范,以及Redis开发与运维这本书。分使用规范、有坑的命令、项目实战操作、运维配置四个方向。整理了使用Redis的21个注意点,希望对大家有帮助,一起学习哈 公众号:捡田螺的小男孩 1、Redis的使用规范 1.1、 key的规范要点 我们设计Redis的key的时候,要注意以下这几个点: 以业务名为key前缀,用冒号隔开,以防止key冲突覆盖。如,live:rank:1 确保key的语义清晰的情况下,key的长度尽量小于30个

m0_50180963的博客 1182

Redis 的标准使用规范之基础规范

【必须】key 禁止使用特殊字符:如空格、换行符、单双引号及其他转义字符等。【建议】key 的命名需遵循小写原则,且不允许重复 key,否则会产生覆盖情况,合理控制 key 的长度,避免使用过长的 key 或者过简单的 key,减少内存消耗并增加易读性,一般 key 长度不建议超过 30 字符。【建议】建议使用“项目名”+“分隔符”+“业务含义” 的英文作为 key 的前缀,防止 key 冲突,“:” 或 “.” 作为间隔,字符包。

风信子的博客 1733

Redis使用规范

在实际开发过程中,从性能或者规范的角度考虑,都需要给团队的成员制定使用redis的使用规范。防止出现例如,key的定义五花八门,危险命令代码中随便使用等情况。

他叫阿来 765

Redis key命名规范

Redis key命名规范 一、实现目标 简洁,高效,可维护 二、键值设计规约 1 Redis key 命名风格 **【推荐】**Redis key 命名需具有可读性以及可管理性,不该使用含义不清的 key 以及特别长的 key 名; 【强制】以英文字母开头,命名中只能出现小写字母、数字、英文点号 (.) 和英文半角冒号(????; 【强制】不要包含特殊字符,如下划线、空格、换行、单双引号以及其他转义字符; 2 命名规范 【强制】命名规范:业务模块名: 业务逻辑含义: 其他: value 类型 1

大张伟 1589

redis key命名规范_Redis设计思路总结

前言 目前大部分程序员,在使用redis的过程中,基本都存在或多或少的滥用。其中包括key的命名,失效时间,key的存储结构都非常随意。项目上线后,短短时间内 内存水涨船高。我决定将我个人设计redis的习惯分享给各位(有不对,不合理的地方希望可以谅解)我将会在以下几个方面进行说明 key 命名设计key 常见业务场景php 命令使用场景key 过期时间设置redis连接池 一、key命...

m0_37695902的博客 701

redis key命名规范_redis简介

key里面存储filed-value的map类型redis数据结构字符串类型散列类型(Hash)列表类型集合类型有序集合类型key不要太长,最好不要超过1024个字节,但也别太短,要有一个统一的命名规范。value存储最长的字长是512M。int 普通字符串不能用incr,incrby没有的key则会帮忙创建int类型,还可自定义加减。decr , decrbystring 还可以进行拼接,app...

weixin_39807954的博客 606
上一篇: 谈谈微服务设计中的 API 网关模式
下一篇: 你的登录接口真的安全吗?
公众号-芋道源码
博客等级 码龄10年 1634粉丝 377原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值