Redis+Caffeine 多级缓存数据一致性解决方案
Redis+Caffeine 多级缓存数据一致性解决方案
背景
之前写过一篇文章Redis+Caffeine 实现两级缓存实战,文章提到了两级缓存Redis+Caffeine可以解决缓存雪等问题也可以提高接口的性能,但是可能会出现缓存一致性问题。如果数据频繁的变更,可能会导致Redis和Caffeine数据不一致的问题。
最近正好学习了一个项目,项目里也用到的Redis+Caffeine实现多级缓存,并且在项目中给出了解决多级缓存数据不一致问题的解决方案,今天正好给大家分享一下。
问题分析
通过Redis+Caffeine,似乎可以完成一级、二级缓存中数据的同步,如果在单节点项目中是没有问题的,但是,在分布式场景下是有问题的,看下图:

说明:
- 部署了2个transport-info微服务节点,每个微服务都有自己进程级的一级缓存,都共享同一个Redis作为二级缓存
- 假设,所有节点的一级和二级缓存都是空的,此时,用户通过节点1查询运单物流信息,在完成后,节点1的caffeine和Redis中都会有数据
- 接着,系统通过节点2更新了数据,此时节点2中的caffeine和Redis都是更新后的数据
- 用户还是进行查询动作,依然是通过节点1查询,此时查询到的将是旧的数据,也就是出现了一级缓存与二级缓存之间的数据不一致的问题
解决方案
如何解决该问题呢?可以通过消息的方式解决,就是任意一个节点数据更新了数据,发个消息出来,通知其他节点,其他节点接收到消息后,将自己caffeine中相应的数据删除即可。
关于消息的实现,可以采用RabbitMQ,也可以采用Redis的消息订阅发布来实现,在这里为了应用技术的多样化,所以采用Redis的订阅发布来实现。
方案概述

Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
当有新消息通过 publish 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端。
Redis的订阅发布功能与传统的消息中间件(如:RabbitMQ)相比,相对轻量一些,针对数据准确和安全性要求没有那么高的场景可以直接使用。
代码实现
- 在RedisConfig增加订阅的配置:
/*** 配置订阅,用于解决Caffeine一致性的问题** @param connectionFactory 链接工厂* @param listenerAdapter 消息监听器* @return 消息监听容器*/@Beanpublic RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,MessageListenerAdapter listenerAdapter) {RedisMessageListenerContainer container = new RedisMessageListenerContainer();container.setConnectionFactory(connectionFactory);container.addMessageListener(listenerAdapter, new ChannelTopic(CHANNEL_TOPIC));return container;}
- 编写
RedisMessageListener用于监听消息,删除caffeine中的数据。
/*** redis消息监听,解决Caffeine一致性的问题*/
@Slf4j
@Component
public class RedisMessageListener extends MessageListenerAdapter {@Resourceprivate Cache<String, TransportInfoDTO> transportInfoCache;@Overridepublic void onMessage(Message message, byte[] pattern) {// 获取到消息中的运单idString transportOrderId = Convert.toStr(message);log.info("redis消息监听缓存变更,运单id:{}", transportOrderId);// 将本jvm中的缓存删除掉this.transportInfoCache.invalidate(transportOrderId);}
}
- 更新数据后向redis发送消息:
@Resourceprivate StringRedisTemplate stringRedisTemplate;@Override@CachePut(value = "transport-info", key = "#p0")public TransportInfoEntity saveOrUpdate(String transportOrderId, TransportInfoDetail infoDetail) {// 省略代码// 清除缓存中的数据// this.transportInfoCache.invalidate(transportOrderId);// Caffeine本地缓存一致性,发布订阅消息到redis,通知订阅者更新缓存this.stringRedisTemplate.convertAndSend(RedisConfig.CHANNEL_TOPIC, transportOrderId);// 保存/更新到MongoDBreturn this.mongoTemplate.save(transportInfoEntity);}
总结
本文主要讲解了在使用Redis和Caffeine多级缓存时使用Redis的发布订阅模式来保证两级缓存的数据一致性。本地缓存是基于服务本地内存的,分布式系统中当缓存更新时,可能造成多个实例间的本地缓存不一致问题。可以使用RabbitMQ或者Redis的发布订阅来解决本地缓存不一致的问题。
相关文章:
Redis+Caffeine 多级缓存数据一致性解决方案
RedisCaffeine 多级缓存数据一致性解决方案 背景 之前写过一篇文章RedisCaffeine 实现两级缓存实战,文章提到了两级缓存RedisCaffeine可以解决缓存雪等问题也可以提高接口的性能,但是可能会出现缓存一致性问题。如果数据频繁的变更,可能会导…...
vscode ctrl+/注释不了css
方式一.全部禁用插件排查问题. 方式二.打开首选项的json文件,注释掉setting.json,排查是哪一行配置有问题. 我的最终问题:需要将 "*.vue": "vue",改成"*.vue": "html", "files.associations": { // "*.vue": &qu…...
《山海经》:北山
《山海经》:北山 北山一经单狐山求如山(水马:形状与马相似,滑鱼:背部红色)带山(䑏疏:似马,一只角,鵸鵌:状乌鸦五彩斑斓,儵鱼ÿ…...
oracle中删除指定前缀的表
近期接手做的项目,发觉数据库中有许多多余的表。究其原因,应该是同事贪图方便,将过去做过的项目复制粘贴,然后修修改改。包括数据库也是克隆过来的,然后又没有删除本项目多余的表,结果经过几个轮回…...
解决 Flutter Dio合并请求多个接口,如果一个接口500,那么导致其他请求不在执行
Flutter Dio如何自定义拦截异常 应用场景 我们一般会统一拦截DioExceptionType 如400,403,500 等错误 但有时候,有个地方合并请求多个接口,如果一个接口500,那么导致其他请求不在执行,因为统一拦截了500&…...
The selected directory is not a valid home for Go SDK
在idea里配置go语言的环境时,选择go语言的安装目录,一直提示这个 The selected directory is not a valid home for Go SDK后来查了一下,发现原来idea识别不出来 需要改一下配置文件,找到go环境的安装目录,我是默认安…...
基于云模型的车辆行驶速度估计算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于云模型的车辆行驶速度估计算法matlab仿真。在智能交通系统中,车辆行驶速度的准确估计对于交通流量监测、安全预警、自动驾驶辅助等方面具有极为重…...
MySQL有哪些日志?
MySQL主要有三种日志:undo log、redo log、binlog。前两种是InnoDB特有的,binlog是MySQL的Server层中的。 Buffer Pool buffer pool是MySQL的缓冲池,里面存储了数据页、索引页、undo页等(与数据库不一致的即为脏页)。…...
Axios:现代JavaScript HTTP客户端
在当今的Web开发中,与后端服务进行数据交换是必不可少的。Axios是一个基于Promise的HTTP客户端,用于浏览器和node.js,它提供了一个简单的API来执行HTTP请求。本文将介绍Axios的基本概念、优势、安装方法、基本用法以及如何使用Axios下载文件。…...
python学opencv|读取视频(一)灰度视频制作和保存
【1】引言 上一次课学习了用opencv读取图像,掌握了三个函数:cv.imread()、cv.imshow()、cv.imwrite() 相关链接如下: python学opencv|读取图像-CSDN博客 这次课我们继续,来学习用opencv读取视频。 【2】学习资源 首先是官网…...
【Rust WebAssembly 入门实操遇到的问题】
Rust WebAssembly 入门实操遇到的问题 什么是WebAssembly跟着教程走wasm-pack build error总结 什么是WebAssembly WebAssembly(简称Wasm)是一种基于堆栈的虚拟机的二进制指令 格式。Wasm 被设计为编程语言的可移植编译目标,支持在 Web 上部…...
掌握CMake中的变量:设置、使用及实际应用示例详解
掌握CMake中的变量:设置、使用及实际应用示例详解 在CMake中,变量的设置和使用是管理构建配置的核心部分,它使得项目配置更加灵活和动态。变量在CMake中用于保存各种数据,如路径、选项值或文件列表,可以在整个CMake配…...
React基础知识三 router路由全指南
现在最新版本是Router6和Router5有比较大的变化,Router5和Router4变化不大,本文以Router6的写法为主,也会对比和Router5的不同。比较全面。 安装路由 npm i react-router-dom基本使用 有两种Router,BrowserRouter和HashRouter&…...
[VUE]框架网页开发02-如何打包Vue.js框架网页并在服务器中通过Tomcat启动
在现代Web开发中,Vue.js已经成为前端开发的热门选择之一。然而,将Vue.js项目打包并部署到生产环境可能会让一些开发者感到困惑。本文将详细介绍如何将Vue.js项目打包,并通过Tomcat服务器启动运行。 1. 准备工作 确保你的项目能够正常运行,项…...
k8s Quality of Service
文章目录 QoS 分类规则QoS 类别影响创建 QoS 分类的案例1. Guaranteed QoS 示例示例 YAML 文件: 2. Burstable QoS 示例示例 YAML 文件: 3. BestEffort QoS 示例示例 YAML 文件: 4. 混合 QoS 示例(多个容器)示例 YAML …...
顶刊算法 | 鱼鹰算法OOA-BiTCN-BiGRU-Attention多输入单输出回归预测(Maltab)
顶刊算法 | 鱼鹰算法OOA-BiTCN-BiGRU-Attention多输入单输出回归预测(Maltab) 目录 顶刊算法 | 鱼鹰算法OOA-BiTCN-BiGRU-Attention多输入单输出回归预测(Maltab)效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实…...
什么语言适合做 Serverless 开发?
随着云计算的普及,**无服务器架构(Serverless Architecture)**成为一种流行的开发模式,它使得开发者无需管理服务器基础设施,专注于编写应用逻辑。无服务器架构通常按需提供计算资源,能够灵活地扩展&#x…...
使用OpenCV和卡尔曼滤波器进行实时活体检测
引言 在现代计算机视觉应用中,实时检测和跟踪物体是一项重要的任务。本文将详细介绍如何使用OpenCV库和卡尔曼滤波器来实现一个实时的活体检测系统。该系统能够通过摄像头捕捉视频流,并使用YOLOv3模型来检测目标对象(例如人)&…...
【25春招前端八股文】——JS数据类型检测方式
检测数据类型 # typeof 总结:数组、对象、null都会被判断为object,其他判断都正确的类型。 可以检测基本数据类型null会检测为Object,因为null也是一个空的引用对象复杂数据类型只能检测function和Object 情况说明: 数组&#x…...
Kafka的学习路径规划
目录标题 1. 记(记忆力)Kafka核心概念Kafka关键配置 2. 懂(理解力)Kafka工作原理Kafka核心功能Kafka架构设计 3. 网(知识网络)技术栈整合用例和场景 4. 拓(全面拓展)学习材料多样化内…...
华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...
通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...
基于Uniapp开发HarmonyOS 5.0旅游应用技术实践
一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架,支持"一次开发,多端部署",可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务,为旅游应用带来…...
【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...
SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...
Caliper 配置文件解析:config.yaml
Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...
C++:多态机制详解
目录 一. 多态的概念 1.静态多态(编译时多态) 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1).协变 2).析构函数的重写 5.override 和 final关键字 1&#…...
MFC 抛体运动模拟:常见问题解决与界面美化
在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...
快刀集(1): 一刀斩断视频片头广告
一刀流:用一个简单脚本,秒杀视频片头广告,还你清爽观影体验。 1. 引子 作为一个爱生活、爱学习、爱收藏高清资源的老码农,平时写代码之余看看电影、补补片,是再正常不过的事。 电影嘛,要沉浸,…...
