缓存组件设计复盘:从硬编码到带模式参数的缓存进化
缓存组件设计复盘从硬编码到带模式参数的缓存进化电子面单对接实录 · 技术深潜 前情《Token刷新与缓存失效一对被忽视的上下游》新架构里有一个缓存组件专门缓存各平台的Token配置避免每次取号都查数据库。最初的设计很简单平台编码加组织ID做Key查不到就查库查到就缓存。跑了一段时间后发现一个隐患同一个平台的不同业务模式缓存会互相覆盖。这篇文章完整复盘这个缓存组件的设计演进过程——从最初的两层缓存结构到新增六个方法、提取公共查询逻辑、处理JDK版本兼容以及最重要的给缓存Key加一个模式后缀。01 初始设计两层缓存按平台加组织路由缓存组件的最初版本结构清晰两层缓存平台应用配置缓存Key 平台编码存平台基础配置平台Token配置缓存Key 平台编码 分隔符 组织ID存Token的数据库记录查询逻辑先从缓存取缓存未命中就查数据库查到后放入缓存。支持手动清除指定缓存支持定时全量刷新。平台差异处理大部分平台通过通用Token配置表查Token但有一个社交电商平台的Token存在专门的授权表里需要特殊处理——直接跳过通用查询走白名单通道。这个设计跑了一段时间没问题。直到有一天我在梳理Token刷新逻辑时发现了一个隐患。02 问题发现两种业务模式在抢同一个缓存Key系统里有一个短视频电商平台它有两种业务模式普通商家模式和代发模式。两种模式用同一个平台编码但Token存在不同的字段——普通Token和代发Token是两套独立的凭证。问题来了缓存Key是平台编码_组织ID两种模式的Key完全一样。普通取号缓存Key PLAT_A_123 → 查到的是普通Token 代发取号缓存Key PLAT_A_123 → 缓存命中返回的还是普通Token应该是代发Token先刷新普通Token再刷代发Token或者反过来缓存会被互相覆盖。当前没出问题是因为两种模式的刷新在同一个定时任务里几乎同时更新缓存清空后重新加载的值恰好是正确的。但未来如果把普通和代发的刷新任务分离比如普通每小时刷一次代发每两小时刷一次就会出现缓存加载到过期Token的情况。03 解决方案给缓存Key加一个模式后缀最简单的方案在缓存Key中增加业务模式维度。// 原Key平台编码 _ 组织IDStringkeyplatCode_orgId;// 新Key平台编码 _ 组织ID _ 业务模式StringkeyplatCode_orgId;if(bizMode!null!bizMode.isEmpty()){keykey_bizMode;}不同模式存在不同的Key下互不干扰普通取号缓存Key PLAT_A_123_normal → 缓存未命中 → 查库 → 拿到普通Token 代发取号缓存Key PLAT_A_123_daifa → 缓存未命中 → 查库 → 拿到代发Token设计约束bizMode为null或空字符串时退化为原有Key格式。完全向后兼容——现有调用方不需要任何修改只有需要区分模式的场景才传入bizMode。04 方法扩展新增六个方法覆盖所有场景加了一个参数就需要配套的查询和清除方法。最终新增了六个方法方法用途getTokenConfig(platCode, org, bizMode)带模式参数的查询evictToken(platCode, org, bizMode)带模式参数的单个清除evictTokenById(platCode, orgId, bizMode)带模式参数的按ID清除evictByPlatform(platCode, bizMode)带模式参数的按平台批量清除evictTokenById(platCode, orgId)按组织ID清除不需要完整对象evictByPlatform(platCode)按平台批量清除无模式参数按组织ID清除原本的清除方法需要传入完整的组织对象。但有些调用场景比如外部监控系统检测到Token过期只知道组织ID没有完整对象。新增一个重载方法只传ID即可。按平台批量清除原本只能单个清除或全部清除。如果某个平台的AppKey全局变更需要失效该平台下所有组织的缓存只能遍历组织逐个清除。新增按平台批量清除一次操作搞定。带模式参数的批量清除更进一步——如果只是代发模式的AppKey变更只清除代发模式的缓存不影响普通模式。批量清除时按模式后缀匹配。05 JDK兼容removeIf不能用批量清除的核心逻辑是遍历缓存Map删除匹配前缀和后缀的Key。Java 8 有现成的方法// Java 8简洁优雅cache.keySet().removeIf(key-key.startsWith(prefix));但项目的运行环境是旧版本JDK不支持removeIf。只能改为迭代器模式// 旧版本JDK兼容迭代器遍历IteratorStringitcache.keySet().iterator();while(it.hasNext()){Stringkeyit.next();if(key.startsWith(prefix)){it.remove();}}带模式参数的批量清除需要在匹配前缀的基础上再加后缀判断// 匹配以 PLAT_A_ 开头、以 _daifa 结尾的KeyIteratorStringitcache.keySet().iterator();while(it.hasNext()){Stringkeyit.next();if(key.startsWith(prefix)key.endsWith(suffix)){it.remove();}}代码量多了几行但逻辑完全一致。遗留系统的技术栈约束就是这样——新版本JDK的流式API、Lambda表达式都用不了设计方案时必须考虑向下兼容。06 代码重构提取公共查询方法加带模式参数的查询方法时发现整个数据库查询逻辑在两个重载方法中完全重复——包括白名单判断、通用表查询、各平台分支的判断。提取一个公共方法loadTokenFromDBprivateOrgTokenConfigloadTokenFromDB(StringplatCode,OrgInfoorg){// 白名单社交电商平台直接查授权表if(isWhiteListPlatform(platCode)){returnqueryFromAuthTable();}// 其他平台查通用Token表TokenRecordrecordqueryFromTokenTable(org.getId());if(recordnull){returnnull;}// 根据平台编码获取对应的配置对象if(isPlatformA(platCode)){returnrecord.getConfigA();}elseif(isPlatformB(platCode)){returnrecord.getConfigB();}// ... 其他平台分支}关键细节每个分支保留了原有的日志输出包括平台中文名。这确保了回归测试时日志一字不差不会因为日志格式变化触发监控告警。重构后两个查询方法只剩缓存Key构建方式的差异——一个带模式后缀一个不带。数据库查询完全委托给公共方法。07 向后兼容旧代码一行不动所有新增方法都是可选的扩展原有方法的行为完全不变原有查询方法两个参数行为不变原有清除方法按对象清除行为不变原有全部清除方法行为不变新方法是额外的工具旧代码不需要任何修改。当需要区分模式时调用方传入bizMode参数即可。回归测试验证通过所有平台分支的日志输出与原有代码完全一致。08 核心收获1. 缓存Key的粒度设计在系统演进中会被重新审视。最初设计时只有普通模式代发是后来加的。一个后缀解决两个模式抢Key的问题改动量很小——但前提是Key的构建逻辑是收敛在一处的而不是散落在各调用方。2. 公共方法提取的价值不在当下在未来。提取数据库查询公共方法后后续新增平台只需要在判断分支中加一个条件两个查询方法自动生效。如果没提取新增平台要改两个地方忘了一个就是Bug。3. 向后兼容是遗留系统改造的底线。bizMode为 null 时退化为原有行为——这行判断保证了新老代码可以并存。新增方法、提取公共逻辑都不影响已有调用方。4. 技术栈约束影响设计决策。removeIf一行代码能解决的问题在旧版本JDK上要多写四行。这不是设计缺陷是工程现实。讨论话题你做缓存设计时遇到过Key粒度不够导致数据互相覆盖的情况吗是加后缀还是重新设计了Key结构评论区聊聊。

相关新闻

AutoJs6应用打包:从脚本到独立应用的完整转型指南

AutoJs6应用打包:从脚本到独立应用的完整转型指南

AutoJs6应用打包:从脚本到独立应用的完整转型指南 【免费下载链接】AutoJs6 安卓平台 JavaScript 自动化工具 (Auto.js 二次开发项目) 项目地址: https://gitcode.com/gh_mirrors/au/AutoJs6 你是否曾想过将精心编写的JavaScript自动化脚本变成独立的安卓应用…

2026/8/5 13:24:58 阅读更多 →
三菱PLC工具包升级:从兼容性审计到工程化部署的完整指南

三菱PLC工具包升级:从兼容性审计到工程化部署的完整指南

最近在整理工控项目资料时,发现一个挺有意思的现象:很多工程师朋友,无论是刚入行的新手还是有一定经验的熟手,在拿到一个新版本的PLC编程软件或工具包时,第一反应往往是“赶紧装上试试”。结果呢?要么是安装…

2026/8/5 13:24:58 阅读更多 →
如何在Linux上实现毫秒级文件搜索:FSearch深度指南与实战技巧

如何在Linux上实现毫秒级文件搜索:FSearch深度指南与实战技巧

如何在Linux上实现毫秒级文件搜索:FSearch深度指南与实战技巧 【免费下载链接】fsearch A fast file search utility for Unix-like systems based on GTK3 项目地址: https://gitcode.com/gh_mirrors/fs/fsearch 在Linux系统中查找文件时,你是否…

2026/8/5 13:24:58 阅读更多 →

最新新闻

Unity-MCP:用自然语言操控Unity编辑器,AI大模型与MCP协议实战

Unity-MCP:用自然语言操控Unity编辑器,AI大模型与MCP协议实战

1. 项目概述:当AI助手成为你的Unity开发伙伴最近在和一些独立游戏开发者朋友聊天,发现大家普遍有个痛点:Unity编辑器功能强大,但操作界面复杂,菜单层级深。有时候想实现一个简单的功能,比如“给所有选中的物…

2026/8/5 14:08:17 阅读更多 →
全栈JavaScript性能调优实战与优化策略

全栈JavaScript性能调优实战与优化策略

1. 为什么全栈JavaScript性能调优如此重要?在当今的Web开发领域,JavaScript已经成为了无可争议的王者语言。根据2023年Stack Overflow开发者调查,JavaScript连续11年成为最常用的编程语言,而Node.js则是最受欢迎的Web框架之一。这…

2026/8/5 14:08:17 阅读更多 →
SMT钢网设计:外露焊盘防空洞与焊接可靠性优化方案

SMT钢网设计:外露焊盘防空洞与焊接可靠性优化方案

1. 项目概述:揭开“外露焊盘”钢网设计的神秘面纱 在SMT(表面贴装技术)产线上,回流焊炉前最关键的一步就是锡膏印刷。而决定锡膏印刷质量的灵魂,就是那张薄薄的钢网。今天,我们不聊常规的QFN或者BGA&#x…

2026/8/5 14:08:17 阅读更多 →
UCX v1.19.0 CUDA 依赖与 CUDA Hook 机制分析

UCX v1.19.0 CUDA 依赖与 CUDA Hook 机制分析

分析对象:OpenUCX tag v1.19.0 分析日期:2026-08-041. UCX v1.19.0 CUDA 依赖 1.1. CUDA 编译/运行依赖 1.1.1 启用开关配置选项说明--with-cuda[DIR]启用 CUDA 支持并指定 CUDA Toolkit 路径(默认 guess,自动探测)--w…

2026/8/5 14:08:17 阅读更多 →
UE5 Niagara特效系统入门与实战技巧

UE5 Niagara特效系统入门与实战技巧

1. 项目概述:UE5 Niagara特效系统入门指南第一次打开Unreal Engine 5的Niagara特效编辑器时,我被那些密密麻麻的节点和参数吓到了。作为一个从传统粒子系统转型过来的特效师,这套新工具既令人兴奋又充满挑战。经过半年多的实战摸索&#xff0…

2026/8/5 14:08:17 阅读更多 →
Blackbox Protobuf CLI教程:3分钟上手Protobuf编解码

Blackbox Protobuf CLI教程:3分钟上手Protobuf编解码

Blackbox Protobuf CLI教程:3分钟上手Protobuf编解码 【免费下载链接】blackboxprotobuf Blackbox Protobuf is a set of tools for working with encoded Protocol Buffers (protobuf) without the matching protobuf definition. 项目地址: https://gitcode.com…

2026/8/5 14:07:16 阅读更多 →

日新闻

Java缓存框架:JetCache

Java缓存框架:JetCache

TOC 一、简介 JetCache 是一个 Java 缓存抽象框架,为不同的缓存解决方案提供了统一的使用方式。 它提供的注解比 Spring Cache 更加强大。 JetCache 的注解支持原生 TTL、两级缓存以及在分布式环境中的自动刷新功能,同时你也可以通过代码直接操作 Cach…

2026/8/5 0:00:43 阅读更多 →
AD 铺铜设置十字连接,过孔全连接,新版AD的简单设置

AD 铺铜设置十字连接,过孔全连接,新版AD的简单设置

需求:通孔焊盘 十字花;过孔 Via 实心直连;贴片焊盘按需设置 AD 测试版本AD24 很多工程师踩坑:全部统一十字,导致接地过孔阻抗高、大电流发热! 一、快捷键打开规则 PCB 界面按下:D R 展开…

2026/8/5 0:00:43 阅读更多 →
AI素描转换技术深度拆解(2024最新论文+工业级落地代码):从Stable Diffusion ControlNet到LoRA微调全链路解析

AI素描转换技术深度拆解(2024最新论文+工业级落地代码):从Stable Diffusion ControlNet到LoRA微调全链路解析

更多请点击: https://kaifayun.com 第一章:AI生成素描效果 AI生成素描效果是计算机视觉与风格迁移技术融合的典型应用,其核心在于将彩色照片或RGB图像转换为具有手绘质感、明暗对比强烈、边缘清晰的单色素描图像。该过程通常依赖于深度学习模…

2026/8/5 0:00:43 阅读更多 →

周新闻

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

1. 从水管网络到最大流:一个核心问题的诞生想象一下,你是一个城市供水系统的总工程师。你的城市有多个水源(水库),需要通过一个复杂的地下管道网络,将水输送到各个居民区。每条管道都有其最大通水能力&…

2026/8/4 13:24:41 阅读更多 →
基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/5 13:13:56 阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/5 10:20:36 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/4 13:38:24 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/4 11:09:16 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/4 13:38:40 阅读更多 →