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

缓存及其不一致

        在实际开发过程中,一般都会遇到缓存,像本地缓存(直接在程序里搞个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的外卖超时判断 问题描述 测试样例 解题思路&#xff1a; 问题理解 数据结构选择 算法步骤 最终代码&#xff1a; 运行结果&#xff1a; 二、小C的排列询问 问题描述 测试样例 最终代码&#xff1a; 运行结果&#xff1a; ​编辑 一、小C的外卖超时判断…...

PHP 伪静态详解及实现方法

概述 在现代 Web 开发中&#xff0c;URL 的设计对用户体验和搜索引擎优化&#xff08;SEO&#xff09;至关重要。动态 URL 虽然功能强大&#xff0c;但往往显得冗长且不友好。伪静态&#xff08;URL 重写&#xff09;技术通过将动态 URL 转换为静态样式&#xff0c;不仅提高了…...

Spring Boot 简单预览PDF例子

目录 前言 一、引入依赖 二、使用步骤 1.创建 Controller 处理 PDF 生成和预览 2.创建预览页面 总结 前言 使用 Spring Boot 创建一个生成 PDF 并进行预览的项目&#xff0c;你可以按以下步骤进行。我们将使用 Spring Boot、Thymeleaf、iText 等技术来完成这个任务。 一、引入…...

【魔珐有言-注册/登录安全分析报告-无验证方式导致安全隐患】

前言 由于网站注册入口容易被机器执行自动化程序攻击&#xff0c;存在如下风险&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露&#xff0c;不符合国家等级保护的要求。短信盗刷带来的拒绝服务风险 &#xff0c;造成用户无法登陆、注册&#xff0c;大量收到垃圾短信的…...

LabVIEW 使用 Snippet

在 LabVIEW 中&#xff0c;Snippet&#xff08;代码片段&#xff09; 是一个非常有用的功能&#xff0c;它允许你将 一小段可重用的代码 保存为一个 图形化的代码片段&#xff0c;并能够在不同的 VI 中通过拖放来使用。 什么是 Snippet&#xff1f; 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——小恐龙躲避游戏

首先&#xff0c;你需要安装Pygame库。如果你还没有安装&#xff0c;可以通过以下命令安装&#xff1a; 【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,是不是这个类的对象&#xff0c;或者判断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 零基础可视化 数组 一些知识&#xff1a; 关于给数组赋值&#xff0c;一个函数为memset&#xff0c;其在cplusplus.com中的描述如下&#xff1a; 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()中的一个缓冲区溢出漏洞&#xff0c;实现将文件读取提升为任意命令执行漏洞 在php读取文件的时候可以使用 php://filter伪协议利用 iconv 函数, 从而可以利用该漏洞进行 RCE 漏洞的利用场景 PHP的所有标准文件读取操作都受到了影响&#xff1…...

应用升级/灾备测试时使用guarantee 闪回点迅速回退

1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间&#xff0c; 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点&#xff0c;不需要开启数据库闪回。…...

PHP和Node.js哪个更爽?

先说结论&#xff0c;rust完胜。 php&#xff1a;laravel&#xff0c;swoole&#xff0c;webman&#xff0c;最开始在苏宁的时候写了几年php&#xff0c;当时觉得php真的是世界上最好的语言&#xff0c;因为当初活在舒适圈里&#xff0c;不愿意跳出来&#xff0c;就好比当初活在…...

在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:

在 HarmonyOS 应用开发中&#xff0c;手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力&#xff0c;既支持点击、长按、拖拽等基础单一手势的精细控制&#xff0c;也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档&#xff0c…...

Go 语言接口详解

Go 语言接口详解 核心概念 接口定义 在 Go 语言中&#xff0c;接口是一种抽象类型&#xff0c;它定义了一组方法的集合&#xff1a; // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的&#xff1a; // 矩形结构体…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

JVM垃圾回收机制全解析

Java虚拟机&#xff08;JVM&#xff09;中的垃圾收集器&#xff08;Garbage Collector&#xff0c;简称GC&#xff09;是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象&#xff0c;从而释放内存空间&#xff0c;避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

css的定位(position)详解:相对定位 绝对定位 固定定位

在 CSS 中&#xff0c;元素的定位通过 position 属性控制&#xff0c;共有 5 种定位模式&#xff1a;static&#xff08;静态定位&#xff09;、relative&#xff08;相对定位&#xff09;、absolute&#xff08;绝对定位&#xff09;、fixed&#xff08;固定定位&#xff09;和…...

Android15默认授权浮窗权限

我们经常有那种需求&#xff0c;客户需要定制的apk集成在ROM中&#xff0c;并且默认授予其【显示在其他应用的上层】权限&#xff0c;也就是我们常说的浮窗权限&#xff0c;那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...

Java编程之桥接模式

定义 桥接模式&#xff08;Bridge Pattern&#xff09;属于结构型设计模式&#xff0c;它的核心意图是将抽象部分与实现部分分离&#xff0c;使它们可以独立地变化。这种模式通过组合关系来替代继承关系&#xff0c;从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...

人工智能 - 在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型

在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型。这些平台各有侧重&#xff0c;适用场景差异显著。下面我将从核心功能定位、典型应用场景、真实体验痛点、选型决策关键点进行拆解&#xff0c;并提供具体场景下的推荐方案。 一、核心功能定位速览 平台核心定位技术栈亮…...