缓存及其不一致
在实际开发过程中,一般都会遇到缓存,像本地缓存(直接在程序里搞个map也可以,但是可能会随着数据的增长出现OOM,建议使用正经的本地缓存框架,因为自己实现淘汰策略啥的挺费劲的)、分布式缓存,简单记录以下自己对这两方面的理解。
本地缓存就是将数据缓存在当前应用程序本地,它速度快,易于管理,但是它无法跨多节点共享,在集群环境中会出现不一致的问题。多个本地缓存之间的数据可能不一致。
分布式缓存就是将数据存储到多个节点的内存中,这些节点可以再不同服务器甚至不同的地理位置上。分布式缓存可以支持多个程序共享数据,提高系统的可伸缩性和可用性,但是成本比较高,考虑的地方也比较多,如数据一致性和故障恢复等问题。
从上面不难看出来缓存有个共性,那就是缓存的一致性问题,在分布式的系统中,只能在CA中进行平衡,根据具体得到业务甚至数据特性进行平衡。
本地缓存
首先在选择上,现在的缓存框架多的很,Caffeine、Guava等,但是spring cache默认是支持Caffeine的

启用本地缓存呢,就是为了减少网络连接(数据库、redis这都要的),有些数据频繁访问,而且这些数据在其他应用模块中不会使用或很少使用且这些数据很少会有所变动,如行政区划、行业信息、纳税人识别号以及一些系统内的数据。这种就适合放到本地内存里。
但是本地内存有个问题,就是在集群环境里,多份数据的存储会造成内存的浪费,这点需要考虑到,但是世上安有两全法,只能是在,两者之间做权衡,选性能还是选成本。
一旦要涉及到本地内存的一致性问题,那这问题就麻烦了,解决办法也不是没有,但一到实际中就等于是脱裤子放屁了,比如:数据库或者redis里弄个版本号,用本地缓存之前先看看版本号是否一致,这就和使用本地缓存的初衷不一致了啊,我就是想减少数据库访问或者redis连接的,结果现在还要再去访问,我为了什么呢?干嘛不直接用redis啊?
所以本人认为一旦要考虑本地缓存的一致性问题了,那就说明你这个缓存没必要要了。
分布式缓存
分布式缓存解决了各个应用之间的一致性的问题,但它还是会存在与数据库的一致性问题。
而这个一致性问题的解决方式有很多,具体要根据业务以及数据的特性来确定。
先说说数据不一致产生的原因,拿redis举例,在逻辑中有两个操作,更新数据库与刷新缓存(有时候缓存信息很多,比如我存了一件商品的信息,里面有商品价格,有商品的库存,如果是更新的话,两个线程并发,首先都先后获取到了缓存的信息,都进行了修改,然后保存的时候一次提交,那这时候肯定有一个是没更新进去的),这两个操作都有可能失败,但是数据库可以开启事务,失败了就回滚,但是redis可没有回滚这一说,所以要想保证数据和缓存的一致性,大家就要想尽办法来解决这个问题。
①开启事务
如果要求强一致性,缓存更新失败可以让数据库事务回滚。先执行逻辑更新数据库,然后刷新缓存。这样会有三种情况:1、都成功,皆大欢喜;2、数据库刷新成功,缓存刷新失败,数据库回滚,缓存未变,数据库也未变;3、数据库失败,直接回滚;
②刷新数据,操作缓存
系统并发没那么高或者对一致性要求不高的可以采用更新缓存,删除的缓存可以消除并发操作缓存导致的数据不一致的问题。这种情况下如果更新缓存失败,可以根据业务的需求来确定是否采取重试机制或者采用MQ消息进行异步修改策略。
③延迟双删
具体步骤是:删除缓存,刷新数据库,延迟1-2秒,删除数据库。
刷新缓存失败的可能性比删除的可能性大很多,所以采用删除缓存的方式。并发高的情况下还要考虑到刷新缓存也可能会导致数据不一致的问题,所以采用删除的方式。第二次的删除是防止在第一次删除缓存,数据还未落到数据库的时候有线程查缓存没查到直接拿的数据库,之后又将数据缓存;虽然这第二次删除可能会导致删除掉正确数据,但是顶多会发生一次cache miss。
总的来说,针对分布式缓存与数据库的一致性问题,要根据具体情况来进行分析,并发量大且要求一致性高的数据就延迟双删,至于之后可能产生的缓存击穿问题,那就是另外的问题了,缓存击穿有缓存击穿的解决方案。如果并发量不大的情况下,直接刷数据库然后再刷缓存(删或者刷看具体情况),如果失败了可以采用重试机制或者异步MQ消息重试的方式进行解决。
没有啥完美方案,只能找最适合业务的方案
相关文章:
缓存及其不一致
在实际开发过程中,一般都会遇到缓存,像本地缓存(直接在程序里搞个map也可以,但是可能会随着数据的增长出现OOM,建议使用正经的本地缓存框架,因为自己实现淘汰策略啥的挺费劲的)、分布式缓存&…...
Leetcode 有效的数独
这段代码解决的是 验证一个数独是否有效 的问题,其算法思想是基于 规则校验和状态记录。具体思想如下: 算法思想 核心目标: 检查每个数字在 同一行、同一列 和 同一个 3x3 子格 中是否重复。 状态记录: 使用 3 个布尔二维数组分别…...
《Java核心技术 卷I》用户界面中首选项API
首选项API 在桌面程序中,通常都会存储用户首选项,如用户最后处理的文件、窗口的最后位置等。 利用Properties类可以很容易的加载和保存程序的配置信息,但有以下缺点: 有些操作系统没有主目录概念,很难为匹配文件找到…...
Android 中的 Zygote 和 Copy-on-Write 机制详解
在 Android 系统中,Zygote 是一个关键的进程,几乎所有的应用进程都是通过它 fork(派生)出来的。通过 Zygote 启动新进程的方式带来了显著的性能优势,这得益于 fork 操作和 Linux 中的 Copy-on-Write(COW&am…...
【人工智能】从零开始用Python实现逻辑回归模型:深入理解逻辑回归的原理与应用
解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 逻辑回归是一种经典的统计学习方法,用于分类问题尤其是二分类问题。它通过学习数据的特征和目标标签之间的…...
推荐一款功能强大的光学识别OCR软件:Readiris Dyslexic
Readiris Dyslexic是一款功能强大的光学识别OCR软件,可以扫描任何纸质文档并将其转换为完全可编辑的数字文件(Word,Excel,PDF),然后用你喜欢的编辑器进行编辑。该软件提供了一种轻松创建,修改和签名PDF的完整解决方法&…...
Python爬虫----python爬虫基础
一、python爬虫基础-爬虫简介 1、现实生活中实际爬虫有哪些? 2、什么是网络爬虫? 3、什么是通用爬虫和聚焦爬虫? 4、为什么要用python写爬虫程序 5、环境和工具 二、python爬虫基础-http协议和chrome抓包工具 1、什么是http和https协议…...
css-50 Projects in 50 Days(3)
html <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>旋转页面</title><link rel"sty…...
另外一种缓冲式图片组件的用法
文章目录 1. 概念介绍2. 使用方法2.1 基本用法2.2 缓冲原理3. 示例代码4. 内容总结我们在上一章回中介绍了"FadeInImage组件"相关的内容,本章回中将介绍CachedNetworkImage组件.闲话休提,让我们一起Talk Flutter吧。 1. 概念介绍 我们在本章回中介绍的CachedNetwo…...
字节青训-小C的外卖超时判断、小C的排列询问
目录 一、小C的外卖超时判断 问题描述 测试样例 解题思路: 问题理解 数据结构选择 算法步骤 最终代码: 运行结果: 二、小C的排列询问 问题描述 测试样例 最终代码: 运行结果: 编辑 一、小C的外卖超时判断…...
PHP 伪静态详解及实现方法
概述 在现代 Web 开发中,URL 的设计对用户体验和搜索引擎优化(SEO)至关重要。动态 URL 虽然功能强大,但往往显得冗长且不友好。伪静态(URL 重写)技术通过将动态 URL 转换为静态样式,不仅提高了…...
Spring Boot 简单预览PDF例子
目录 前言 一、引入依赖 二、使用步骤 1.创建 Controller 处理 PDF 生成和预览 2.创建预览页面 总结 前言 使用 Spring Boot 创建一个生成 PDF 并进行预览的项目,你可以按以下步骤进行。我们将使用 Spring Boot、Thymeleaf、iText 等技术来完成这个任务。 一、引入…...
【魔珐有言-注册/登录安全分析报告-无验证方式导致安全隐患】
前言 由于网站注册入口容易被机器执行自动化程序攻击,存在如下风险: 暴力破解密码,造成用户信息泄露,不符合国家等级保护的要求。短信盗刷带来的拒绝服务风险 ,造成用户无法登陆、注册,大量收到垃圾短信的…...
LabVIEW 使用 Snippet
在 LabVIEW 中,Snippet(代码片段) 是一个非常有用的功能,它允许你将 一小段可重用的代码 保存为一个 图形化的代码片段,并能够在不同的 VI 中通过拖放来使用。 什么是 Snippet? Snippet 就是 LabVIEW 中的…...
单片机_day3_GPIO
目录 1. 灯如何才能亮 1.1原理图 1.2 二极管 1.3 换了一个灯和原理图 编辑 1.4 三极管 1.4.1 NPN型三极管 1.4.2 PNP型三极管 2. 基本概念 3. 输入 3.1 浮空输入 3.2 上拉输入 3.3 下拉输入 3.4 模拟输入 4. 输出 4.1 推挽输出 4.2 开漏输出 如何让开漏输出…...
Python小游戏24——小恐龙躲避游戏
首先,你需要安装Pygame库。如果你还没有安装,可以通过以下命令安装: 【bash】 pip install pygame 【python】代码 import pygame import random # 初始化Pygame pygame.init() # 设置屏幕尺寸 screen_width 800 screen_height 600 screen …...
Python 的多态笔记
Python的多态实际是通过instance 实现的 class Person:def __init__(self, name,age):self.name nameself.age agedef feed_pet(self,pet):#isinastance(obj,类)-->判断obj,是不是这个类的对象,或者判断obj是不是该类的子类的对象if isinstance(pet, Pet):sel…...
go module使用
go module介绍 go module是go官⽅⾃带的go依赖管理库,在1.13版本正式推荐使⽤ go module可以将某个项⽬(⽂件夹)下的所有依赖整理成⼀个 go.mod ⽂件,⾥⾯写⼊了依赖的版本等 使⽤ go module之后我们可不⽤将代码放置在src下了 使⽤ go module 管理依赖后会在项⽬根⽬录下⽣成…...
c ++零基础可视化——数组
c 零基础可视化 数组 一些知识: 关于给数组赋值,一个函数为memset,其在cplusplus.com中的描述如下: void * memset ( void * ptr, int value, size_t num );Sets the first num bytes of the block of memory pointed by ptr to…...
CVE-2024-2961漏洞的简单学习
简单介绍 PHP利用glibc iconv()中的一个缓冲区溢出漏洞,实现将文件读取提升为任意命令执行漏洞 在php读取文件的时候可以使用 php://filter伪协议利用 iconv 函数, 从而可以利用该漏洞进行 RCE 漏洞的利用场景 PHP的所有标准文件读取操作都受到了影响࿱…...
iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...
《C++ 模板》
目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板,就像一个模具,里面可以将不同类型的材料做成一个形状,其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式:templa…...
TSN交换机正在重构工业网络,PROFINET和EtherCAT会被取代吗?
在工业自动化持续演进的今天,通信网络的角色正变得愈发关键。 2025年6月6日,为期三天的华南国际工业博览会在深圳国际会展中心(宝安)圆满落幕。作为国内工业通信领域的技术型企业,光路科技(Fiberroad&…...
redis和redission的区别
Redis 和 Redisson 是两个密切相关但又本质不同的技术,它们扮演着完全不同的角色: Redis: 内存数据库/数据结构存储 本质: 它是一个开源的、高性能的、基于内存的 键值存储数据库。它也可以将数据持久化到磁盘。 核心功能: 提供丰…...
32单片机——基本定时器
STM32F103有众多的定时器,其中包括2个基本定时器(TIM6和TIM7)、4个通用定时器(TIM2~TIM5)、2个高级控制定时器(TIM1和TIM8),这些定时器彼此完全独立,不共享任何资源 1、定…...
