当前位置: 首页 > news >正文

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 实现两级缓存实战&#xff0c;文章提到了两级缓存RedisCaffeine可以解决缓存雪等问题也可以提高接口的性能&#xff0c;但是可能会出现缓存一致性问题。如果数据频繁的变更&#xff0c;可能会导…...

vscode ctrl+/注释不了css

方式一.全部禁用插件排查问题. 方式二.打开首选项的json文件,注释掉setting.json,排查是哪一行配置有问题. 我的最终问题:需要将 "*.vue": "vue",改成"*.vue": "html", "files.associations": { // "*.vue": &qu…...

《山海经》:北山

《山海经》&#xff1a;北山 北山一经单狐山求如山&#xff08;水马&#xff1a;形状与马相似&#xff0c;滑鱼&#xff1a;背部红色&#xff09;带山&#xff08;䑏疏&#xff1a;似马&#xff0c;一只角&#xff0c;鵸鵌&#xff1a;状乌鸦五彩斑斓&#xff0c;儵鱼&#xff…...

oracle中删除指定前缀的表

近期接手做的项目&#xff0c;发觉数据库中有许多多余的表。究其原因&#xff0c;应该是同事贪图方便&#xff0c;将过去做过的项目复制粘贴&#xff0c;然后修修改改。包括数据库也是克隆过来的&#xff0c;然后又没有删除本项目多余的表&#xff0c;结果经过几个轮回&#xf…...

解决 Flutter Dio合并请求多个接口,如果一个接口500,那么导致其他请求不在执行

Flutter Dio如何自定义拦截异常 应用场景 我们一般会统一拦截DioExceptionType 如400&#xff0c;403&#xff0c;500 等错误 但有时候&#xff0c;有个地方合并请求多个接口&#xff0c;如果一个接口500&#xff0c;那么导致其他请求不在执行&#xff0c;因为统一拦截了500&…...

The selected directory is not a valid home for Go SDK

在idea里配置go语言的环境时&#xff0c;选择go语言的安装目录&#xff0c;一直提示这个 The selected directory is not a valid home for Go SDK后来查了一下&#xff0c;发现原来idea识别不出来 需要改一下配置文件&#xff0c;找到go环境的安装目录&#xff0c;我是默认安…...

基于云模型的车辆行驶速度估计算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于云模型的车辆行驶速度估计算法matlab仿真。在智能交通系统中&#xff0c;车辆行驶速度的准确估计对于交通流量监测、安全预警、自动驾驶辅助等方面具有极为重…...

MySQL有哪些日志?

MySQL主要有三种日志&#xff1a;undo log、redo log、binlog。前两种是InnoDB特有的&#xff0c;binlog是MySQL的Server层中的。 Buffer Pool buffer pool是MySQL的缓冲池&#xff0c;里面存储了数据页、索引页、undo页等&#xff08;与数据库不一致的即为脏页&#xff09;。…...

Axios:现代JavaScript HTTP客户端

在当今的Web开发中&#xff0c;与后端服务进行数据交换是必不可少的。Axios是一个基于Promise的HTTP客户端&#xff0c;用于浏览器和node.js&#xff0c;它提供了一个简单的API来执行HTTP请求。本文将介绍Axios的基本概念、优势、安装方法、基本用法以及如何使用Axios下载文件。…...

python学opencv|读取视频(一)灰度视频制作和保存

【1】引言 上一次课学习了用opencv读取图像&#xff0c;掌握了三个函数&#xff1a;cv.imread()、cv.imshow()、cv.imwrite() 相关链接如下&#xff1a; python学opencv|读取图像-CSDN博客 这次课我们继续&#xff0c;来学习用opencv读取视频。 【2】学习资源 首先是官网…...

【Rust WebAssembly 入门实操遇到的问题】

Rust WebAssembly 入门实操遇到的问题 什么是WebAssembly跟着教程走wasm-pack build error总结 什么是WebAssembly WebAssembly&#xff08;简称Wasm&#xff09;是一种基于堆栈的虚拟机的二进制指令 格式。Wasm 被设计为编程语言的可移植编译目标&#xff0c;支持在 Web 上部…...

掌握CMake中的变量:设置、使用及实际应用示例详解

掌握CMake中的变量&#xff1a;设置、使用及实际应用示例详解 在CMake中&#xff0c;变量的设置和使用是管理构建配置的核心部分&#xff0c;它使得项目配置更加灵活和动态。变量在CMake中用于保存各种数据&#xff0c;如路径、选项值或文件列表&#xff0c;可以在整个CMake配…...

React基础知识三 router路由全指南

现在最新版本是Router6和Router5有比较大的变化&#xff0c;Router5和Router4变化不大&#xff0c;本文以Router6的写法为主&#xff0c;也会对比和Router5的不同。比较全面。 安装路由 npm i react-router-dom基本使用 有两种Router&#xff0c;BrowserRouter和HashRouter&…...

[VUE]框架网页开发02-如何打包Vue.js框架网页并在服务器中通过Tomcat启动

在现代Web开发中&#xff0c;Vue.js已经成为前端开发的热门选择之一。然而&#xff0c;将Vue.js项目打包并部署到生产环境可能会让一些开发者感到困惑。本文将详细介绍如何将Vue.js项目打包&#xff0c;并通过Tomcat服务器启动运行。 1. 准备工作 确保你的项目能够正常运行,项…...

k8s Quality of Service

文章目录 QoS 分类规则QoS 类别影响创建 QoS 分类的案例1. Guaranteed QoS 示例示例 YAML 文件&#xff1a; 2. Burstable QoS 示例示例 YAML 文件&#xff1a; 3. BestEffort QoS 示例示例 YAML 文件&#xff1a; 4. 混合 QoS 示例&#xff08;多个容器&#xff09;示例 YAML …...

顶刊算法 | 鱼鹰算法OOA-BiTCN-BiGRU-Attention多输入单输出回归预测(Maltab)

顶刊算法 | 鱼鹰算法OOA-BiTCN-BiGRU-Attention多输入单输出回归预测&#xff08;Maltab&#xff09; 目录 顶刊算法 | 鱼鹰算法OOA-BiTCN-BiGRU-Attention多输入单输出回归预测&#xff08;Maltab&#xff09;效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实…...

什么语言适合做 Serverless 开发?

随着云计算的普及&#xff0c;**无服务器架构&#xff08;Serverless Architecture&#xff09;**成为一种流行的开发模式&#xff0c;它使得开发者无需管理服务器基础设施&#xff0c;专注于编写应用逻辑。无服务器架构通常按需提供计算资源&#xff0c;能够灵活地扩展&#x…...

使用OpenCV和卡尔曼滤波器进行实时活体检测

引言 在现代计算机视觉应用中&#xff0c;实时检测和跟踪物体是一项重要的任务。本文将详细介绍如何使用OpenCV库和卡尔曼滤波器来实现一个实时的活体检测系统。该系统能够通过摄像头捕捉视频流&#xff0c;并使用YOLOv3模型来检测目标对象&#xff08;例如人&#xff09;&…...

【25春招前端八股文】——JS数据类型检测方式

检测数据类型 # typeof 总结&#xff1a;数组、对象、null都会被判断为object&#xff0c;其他判断都正确的类型。 可以检测基本数据类型null会检测为Object&#xff0c;因为null也是一个空的引用对象复杂数据类型只能检测function和Object 情况说明&#xff1a; 数组&#x…...

Kafka的学习路径规划

目录标题 1. 记&#xff08;记忆力&#xff09;Kafka核心概念Kafka关键配置 2. 懂&#xff08;理解力&#xff09;Kafka工作原理Kafka核心功能Kafka架构设计 3. 网&#xff08;知识网络&#xff09;技术栈整合用例和场景 4. 拓&#xff08;全面拓展&#xff09;学习材料多样化内…...

Oracle查询表空间大小

1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...

Cinnamon修改面板小工具图标

Cinnamon开始菜单-CSDN博客 设置模块都是做好的&#xff0c;比GNOME简单得多&#xff01; 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面

代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口&#xff08;适配服务端返回 Token&#xff09; export const login async (code, avatar) > {const res await http…...

反射获取方法和属性

Java反射获取方法 在Java中&#xff0c;反射&#xff08;Reflection&#xff09;是一种强大的机制&#xff0c;允许程序在运行时访问和操作类的内部属性和方法。通过反射&#xff0c;可以动态地创建对象、调用方法、改变属性值&#xff0c;这在很多Java框架中如Spring和Hiberna…...

CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云

目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

SpringTask-03.入门案例

一.入门案例 启动类&#xff1a; package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...

【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具

第2章 虚拟机性能监控&#xff0c;故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令&#xff1a;jps [options] [hostid] 功能&#xff1a;本地虚拟机进程显示进程ID&#xff08;与ps相同&#xff09;&#xff0c;可同时显示主类&#x…...

【JavaWeb】Docker项目部署

引言 之前学习了Linux操作系统的常见命令&#xff0c;在Linux上安装软件&#xff0c;以及如何在Linux上部署一个单体项目&#xff0c;大多数同学都会有相同的感受&#xff0c;那就是麻烦。 核心体现在三点&#xff1a; 命令太多了&#xff0c;记不住 软件安装包名字复杂&…...

基于matlab策略迭代和值迭代法的动态规划

经典的基于策略迭代和值迭代法的动态规划matlab代码&#xff0c;实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...

C++使用 new 来创建动态数组

问题&#xff1a; 不能使用变量定义数组大小 原因&#xff1a; 这是因为数组在内存中是连续存储的&#xff0c;编译器需要在编译阶段就确定数组的大小&#xff0c;以便正确地分配内存空间。如果允许使用变量来定义数组的大小&#xff0c;那么编译器就无法在编译时确定数组的大…...