缓存的思考与总结

缓存的思考与总结

    • 什么是缓存
    • 缓存命中率
    • 数据一致性
      • 旁路模式 Cache aside
      • 双写模式
        • 直写模式 write through
        • 异步写 Write Behind
      • 旁路和双写
    • 案例

新技术或中间的引入,一定是解决了亟待解决的问题或是显著提升了系统性能,并且这种改变所带来的增幅,可以让我们忽略引入新技术所带来的系统复杂性等负面影响。好比是CAP理论中对C和A的权衡。

什么是缓存

从内存中读取数据,从文件系统通过IO读取磁盘数据,两者在时间上存在较大差异,毫无疑问,从内存中读取数据相较于磁盘会更快,于是便有了缓存,很典型的以空间换时间的运用。
如果数据都放在内存中自然是最好不过,也就没有缓存这么一说了。但目前来看,内存依旧属于紧张资源,需要有选择的将数据(读多写少)放入内存作为缓存来使用。
在缓存方面,大多数问题都可以归结到以下两个方面去讨论:

  • 缓存命中率
  • 数据一致性

缓存命中率

读取数据时,从缓存中是否读取到了数据。系统在设计添加缓存层时,一方面提升系统响应速度,另一方面也能拦截部分查询请求从而分担数据库压力。对于一些我们希望在缓存层被拦截的请求,如果缓存没有命中,那么缓存层将失去意义。比如常说的几个概念:

  • 缓存穿透:查询缓存中不存在的键(非法的key),请求到达DB层
  • 缓存击穿:查询缓存中不存在的键(尚未构建缓存),请求到达DB层
  • 缓存雪崩:缓存大面积失效,请求到达DB层

你会发现,上述都是在描述一个概念:缓存命中率。只不过是不同场景下缓存未命中的情况:
我们希望请求在缓存层被拦截,但由于未命中缓存导致请求到达DB层。所以上述场景的解决方案也都是围绕着:如何提高缓存命中率 来展开的。
缓存击穿还涉及并发场景下缓存重建问题,需要通过加锁来避免。

数据一致性

有了缓存,就意味着有了两份数据,DB层一份,内存一份,那就必然会涉及数据一致性的问题,并且由于是两份数据,数据同步期间必然会存在不一致情况,除非将数据的修改和缓存的修改作为一个原子操作(单体应用)。所以,不能仅仅要设计数据如何读取提高命中率,还要设计数据更新时的策略。也就是说,加入缓存层后,要从读写两方面进行约束,形成闭环,这样才能保证缓存和DB层的数据一致性。
常见的场景必然有成熟的解决方案,对于缓存的数据一致性问题,常见的设计有以下几种:

  • 旁路模式
  • 直写模式
  • 异步写模式

旁路模式 Cache aside

读取时先从缓存中读取数据。如果缓存中没有数据,则从数据库中读取,并将数据写入缓存。更新数据时,先更新数据库,然后再将缓存中的数据失效。

旁路模式中,并发场景下,先更新数据后再删除缓存先删除缓存再更新数据两者有所不同,即使双删策略保证第二次删除后读取到的都是新数据。
推荐使用先更新数据库再删除缓存的做法,优点是不存在使用旧数据重建缓存的情况,且数据不一致的窗口期不依赖于第二次删除,也就是说:更新数据后删除缓存前,并发读会读到旧缓存,但更新数据且删除缓存后,不一致窗口期便结束了。假如设定的第二次删除的延时是1小时,先更新数据库再删除缓存这种方式会在删除缓存后结束数据不一致;但先删除缓存再更新数据的方式则强依赖与第二次删除,会在1小时后才结束数据不一致。

双写模式

顾名思义,既写数据库,又写缓存。包括直写和异步写(严格的双写是指一份数据同时写入两种存储介质,这里的异步写归结到双写模式下便于记忆)

直写模式 write through

读取时先从缓存中读取数据,在写入数据时,数据同时写入缓存和数据库

异步写 Write Behind

写入数据时,数据只更新缓存,并异步批量刷新到数据库中

旁路和双写

为了方便理解和区分旁路和双写模式,最简单的区分就是:
旁路模式中,缓存更新(失效重建)是被动的,由后续的读操作进行缓存重建;而双写模式则是主动更新缓存

旁路模式和双写模式是保证缓存和DB数据一致性的常用做法。分布式系统中也存在一些在旁路和双写基础上进行改进增强的设计,比如旁路模式+TTL过期时间,双写+补偿机制等,用来处理缓存操作失败时的场景,感兴趣的可以继续研究。

案例

写这篇偏总结性的文章,起因是之前写的一个IDEA插件 ,在第一版设计的时候,考虑到之后插件记录的数据增多,于是通过代理模式预留了扩展。
在这里插入图片描述
这里通过代理模式添加缓存层,在代理对象中统一进行缓存的处理。
在这里插入图片描述
由于插件开发是单体应用且不考虑多线程场景(多编辑器同时操作一个源文件时,会提示并拒绝),所以这里我们使用旁路模式实现最简单的LRU缓存。具体怎么做呢?

  1. 读操作优先读缓存,缓存没有再读DB(这里是持久化文件)
  2. 数据一旦发生修改,例如修改了高亮记录中的笔记内容,则失效缓存,等待下一次读取时重新构建缓存即可。
    但是有个问题:这里使用的缓存key和value,key是源码文件名称,value是该文件所有的高亮笔记。这里缓存的粒度很大,如果每次修改一条高亮笔记就重建整个源码文件的数据,不是很合理。所以还是双写模式更适合,避免牵一发动全身。每次更新笔记,只更新缓存中笔记列表里面相同ID的缓存记录即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/147945.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【开源服务框架】Dubbo

🎄欢迎来到边境矢梦的csdn博文🎄 🎄本文主要梳理Java面试中开源服务框架Dubbo会涉及到的知识点 🎄 🌈我是边境矢梦,一个正在为秋招和算法竞赛做准备的学生🌈 🎆喜欢的朋友可以关注一…

GAMES101(15节)

Irradiance辐射度量学 辐射度量学在渲染领域,可以帮助理解基于物理的光照模型 radiant energy辐射能量Q,累计总能量(单位J joule焦耳),就像太阳能板,光照时间越长接收能量越多,收到的能量总和…

jetlinks物联网平台学习2(加盐算法登陆)

加盐算法 加盐算法加密验证密码是否正确 对于传统的MD5加密,比更传统的直接保存账号密码稍微安全一点。 md5加密是一种hash算法 比如对于123456来说,md5算法结果一定是e10adc3949ba59abbe56e057f20f883e 这个结果是固定的。于是有的人准备一张彩虹表 预先…

ECharts基础使用方法 ---vue

1.安装依赖文件 仔细看项目" README.md " 描述,确定用什么安装 npm npm install echarts --save //官网推荐使用 pnpm pnpm install echarts --save 其他也是 在项目根目录,打开当前目录命令控制栏,输入以上命令并运行 安装成功后…

第十三章:使用html和css做一个静态登录网页练习

我们在使用浏览器 浏览某些网站的时候 有可能会遇到登录这种网页,这种网页是怎么制作出来的呢? 下面 我就来分享一个简单的 登录页 实现方案! 登录页面的作用: 身份验证:登录页面的核心作用就是验证用户身份。用户输入用户名(或邮箱、手机号)和密码,系统通过验证来判断…

[数据结构]无头单向非循环链表的实现与应用

文章目录 一、引言二、线性表的基本概念1、线性表是什么2、链表与顺序表的区别3、无头单向非循环链表 三、无头单向非循环链表的实现1、结构体定义2、初始化3、销毁4、显示5、增删查改 四、分析无头单向非循环链表1、存储方式2、优点3、缺点 五、总结1、练习题2、源代码 一、引…

尚品汇-秒杀商品定时任务存入缓存、Redis发布订阅实现状态位(五十一)

目录: (1)秒杀业务分析 (2)搭建秒杀模块 (3)秒杀商品导入缓存 (4)redis发布与订阅实现 (1)秒杀业务分析 需求分析 所谓“秒杀”&#xff0…

百度智能云API调用

植物识别API import base64 import urllib import requestsAPI_KEY = "你的图像识别API_KEY" SECRET_KEY = "你的图像识别SECRET_KEY"def main():url = "https://aip.baidubce.com/rest/2.0/image-classify/v1/plant?access_token=" + get_acc…

12、等保安全通用要求

数据来源:12.等保安全通用要求_哔哩哔哩_bilibili 基本要求

docker启动mysql未读取my.cnf配置文件问题

描述 在做mysql主从复制配置两台mysql时,从节点的my.cnf配置为: [mysqld] datadir /usr/local/mysql/slave1/data character-set-server utf8 lower-case-table-names 1 # 主从复制-从机配置# 从服务器唯一 ID server-id 2 # 启用中继日志 relay-l…

thop计算模型复杂度(params,flops)

thop安装 -pip install thop在线安装失败 -离线安装 github网址: pytorch-OpCounter:Count the MACs / FLOPs of your PyTorch model. - GitCode python setup.py install 测试: from options import config as c import os os.environ["CUD…

【高分系列卫星简介——高分三号卫星(GF-3)】

高分三号卫星(GF-3) 高分三号(GF-3)是我国首颗高分辨率、C频段、多极化合成孔径雷达(SAR)卫星,由中国空间技术研究院北京空间飞行器总部设计部研制,并于2016年8月10日成功发射。该卫…

vue实现扫雷代码复制即可用,vue2和vue3都可适用

效果预览 代码实现 <template><div id"app"><div class"mine-sweeper"><div class"board" v-for"row in board" :key"row-${row.index}"><divclass"cell":class"{ no-clickable…

Vue3:mitt实现组件通信

目录 一.性质 1.轻量级 2.单例 3.异步 4.事件绑定与解绑 二.作用 1.组件间通信 2.解耦 3.状态管理 4.事件的集中处理 三.使用 1.安装mitt 2.引入mitt&#xff1b;调用mitt&#xff1b;暴露mitt 3.组件1 4.组件2 四.代码 1.组件1 2.组件2 五.效果 一.性质 1…

qt-C++笔记之Q_DECLARE_METATYPE和qRegisterMetaType

qt-C笔记之Q_DECLARE_METATYPE和qRegisterMetaType code review! 文章目录 qt-C笔记之Q_DECLARE_METATYPE和qRegisterMetaType一.Q_DECLARE_METATYPE使用方法应用场景 二.为什么需要注册类型&#xff1f;三.使用 Q_DECLARE_METATYPE 处理自定义类型的简短示例3.1.自定义类型定…

ElasticSearch-2-核心语法集群高可用实战-Week2-3

ES批量操作 1.批量获取文档数据 这里多个文档是指&#xff0c;批量操作多个文档&#xff0c;搜索查询文档将在之后的章节讲解 批量获取文档数据是通过_mget的API来实现的 (1)在URL中不指定index和type 请求方式&#xff1a;GET 请求地址&#xff1a;_mget 功能说明 &#…

(C++23) expected 基础使用

文章目录 ⭐前言⭐expected&#x1f39b;️基础使用&#x1f39b;️单子操作 (Monadic operations)&#x1f39a;️and_then & or_else&#x1f39a;️transform & transform_error ⭐END&#x1f31f;跋&#x1f31f;交流方式 ⭐前言 在 C17 中&#xff0c;提出了 op…

嵌入式系统stm32cube本地安装出现的问题

stm32cube在线安装很慢&#xff0c;本地安装中出现的一个bug stm32cube_fw_f4_v1281安装成功之后&#xff0c;如果想安装stm32cube_fw_f4_v1281会提示stm32cube_fw_f4_v1280未安装。 如果先安装stm32cube_fw_f4_v1280之后&#xff0c;再安装stm32cube_fw_f4_v1281还会提示这个…

算法练习题24——leetcode3296移山所需的最小秒数(二分模拟)

【题目描述】 【代码示例&#xff08;java&#xff09;】 class Solution {// 计算让工人们将山的高度降到0所需的最少时间public long minNumberOfSeconds(int mountainHeight, int[] workerTimes) {long left 0; // 最少时间初始为0long right 0; // 最大时间初始化为0// …

java--面向对象编程(中级部分)

IDE&#xff08;集成开发环境&#xff09; java-----IDE&#xff08;集成开发环境&#xff09;-CSDN博客 包 包的三大作用 区分相同名字的类 当类很多时,可以很好的管理类[看Java API 文档] 控制访问范围 包基本语 package com.hsppedu; 说明: 1. package 关键字,表示打…