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

缓存问题解决方案

《服务器开发技术、方法与实用解决方案》

一、缓存预热

在系统刚启动或活动刚开始时,如果缓存中没有数据,那么大量请求将直接访问数据库。如果瞬时访问流量巨大,则可能导致数据库因过载而宕机,甚至引发系统雪崩。因此需要将缓存的数据加载到缓存系统中,以减轻数据库的压力

1. 应用启动预热策略

本地缓存,在应用启动时进行缓存预热。如在Spring中实现InitializingBean接口中的afterProperitesSet方法实现

但是该策略仅适合预热本地缓存,且与应用深度耦合

2.任务调度预热策略

如果预热场景涉及的数据规模非常大,可以采用任务调度预热

使用分布式任务调度中间件定时、周期触发缓存预热数据。常用的中间件有阿里的SchedulerX、蚂蚁的AntScheduler、XXL-JOB、ElasticJob

分布式任务调度中间件的基本架构:

  • Scheduler Console:控制台。可视化集中管理平台
  • Scheduler Server:服务端,负责客户端任务的调度触发、任务执行状态的监测、集群间任务分配等
  • Scheduler Client:客户端,多个,负责具体任务执行

预热步骤

  1. 数据分片:将需要处理的数据按照一定规则划分为若干份
  2. 数据加载:根据客户端业务服务器的数量、机房属性等将分片单元拆分为若干份,指派到多台客户端业务服务器中
  3. 数据处理:客户端根据任务调度中间件下发的业务参数(id)访问数据库,并将读取的商品数据写入分布式缓存

周期调度:数据规模巨大时,无法通过一次调度完成缓存预热,可以采用周期调度,指定每个调度周期预热的数据量。为了避免在数据加载环节重复服务数据,需要对已预热过的数据打标,如更新预热时间、预热版本号等。在加载数据时,通过标记来识别、加载数据

3. 模拟请求预热策略

任务调度预热和应用启动预热都需要定制开发,对业务应用有入侵。

可以采用模拟请求预热,通过模拟用户请求来实现数据预热,如模拟调用数据查询接口。该方式对业务应用的侵入非常小

4. 缓存预热思路

  1. 分析业务场景和用户行为来圈定需要预热的数据范围
  2. 根据待预热数据的特定设计合适的预热策略
  3. 根据业务需要为不同的预热策略编排执行时间

二、缓存淘汰

缓存大多是基于内存实现的,空间相对有限。为了高效利用存储空间,当缓存触及设定的空间上限时,通常需要借助淘汰算法将部分数据移除

1. LRU

LRU(最近最少使用)算法根据数据的历史访问记录优先淘汰最近未被使用的数据,核心思想为:如果数据最近被访问过,那么将来被访问的频率会更高。

实现一般采用Hash表+双向链表,将被访问的数据放到链表头部,淘汰链表尾部的数据

LRU算法简单、高效,但是一些偶发性、周期性的批量操作会导致LRU算法的缓存命中率急剧下降。如一次性读取大量数据块,这些数据块会占用大量空间,并淘汰最近最少使用的数据。但是这些数据并非是经常被访问的数据,从而导致缓存命中率低下

2. LFU

LFU(最近最不常用)算法根据数据的历史访问频次来淘汰数据,核心思想为:如果数据最近被使用的频率高,则将来大概率会被再次使用

LRU倾向于保留最近使用的数据,LFU倾向于保留使用频率较高的数据。LFU能避免偶发性情况对命中率的影响,但是一旦访问内容发生较大变化,LFU需要更长的时间来适应,因为历史的频次记录会使已无用的数据保留较长一段时间

3. ARC

ARC(自适应缓存替换)算法兼具LRU和LFU的优点,既可以根据时间进行优化,缓存最近使用的数据,又可以根据频率进行优化,同时还能根据负载来灵活调整缓存策略。ARC的命中率要显著优于LRU和LFU。

实现原理见P218

三、缓存更新

1. Cache Aside

  • 读场景:先读缓存、若缓存命中则从缓存取数据,直接返回;若缓存未命中,则从数据库读取数据,成功后将数据放到缓存中
  • 写场景:先更新数据库,再失效缓存
  1. 是否可以先更新缓存,再更新数据库
    一旦出现缓存成功而更新数据库失败的情况,会导致缓存错误值,导致业务上无法接受的一致性问题
  2. 是否可以先失效缓存,再更新数据库
    通常数据库的写操作耗时大于读操作,一旦更新数据库期间有读请求并未命中缓存,会导致写回的数据为脏数据
  3. 为什么是失效缓存,而不是更新缓存
    如A、B两个线程都执行写操作,A线程早于B执行(B数据是最新的),但A线程晚于B线程更新缓存,这样就会导致缓存中的数据是A线程更新的旧值,而不是B线程更新的最新值
  4. 先更新数据库,再失效缓存是否存在问题?
    可能存在更新数据成功,失效缓存失败,导致缓存脏数据的问题。这种场景最常用的解决方案是为缓存设置失效时间,到期自动失效

事实上,保证缓存和数据库的强一致性是非常困难的,一般须通过Paxos或2PC来保证一致性,但这些协议耗时或实现复杂,实用性不高。在大多数使用缓存场景中,通常有一个重要前提,可接受弱一致性

2. Read/Write Through 模式

Read/Write Through 模式将更新数据库的操作交由缓存代理,从应用的角度看,缓存是主存储,应用层的读写操作均面向缓存,缓存服务代理对数据库的读写

  • Read Through:若缓存未命中,则由缓存服务负责加载数据写入缓存
  • Write Through:数据更新时,若没有命中缓存,则直接更新数据库;如命中缓存,则更新缓存,由缓存服务更新数据库(同步更新)

3. Write Behind Caching

Read/Write Through 模式同步更新数据库和缓存,而Write Behind Caching只更新缓存,缓存会异步批量更新数据库(类似Linux的Writeback机制)

但是该机制无法保证数据强一致性,且可能会丢失数据(没有完美的机制)

四、缓存雪崩

缓存雪崩是指缓存因为某些原因(如大量key集中过期、服务器宕机等)导致大量查询请求到达服务端数据库,造成数据库压力骤增、甚至宕机、进而引起整个系统崩溃的现象

1. 缓存常驻策略

为缓存设置较长的有效期,保证缓存在业务高峰期一定不会过期

2. 多级缓存策略

本地缓存作为一级缓存,分布式缓存作为二级缓存。多级缓存相结合,可以有效分担查询请求压力,防止雪崩

3. 过期时间优化策略

  • 为缓存有效期增加随机值,防止集中失效
  • 将热点Key有效期设置为永久有效(内存到达限定值时依旧会淘汰)
  • 逻辑过期与异步更新:为每个Key维护一个逻辑过期时间,当逻辑过期时间小于当前时间时,说明当前缓存逻辑已经失效,需要进行更新。如Redis中设置Key的过期时间为60min,Value中设置逻辑过期时间为30min。若命中缓存时发现已到达30min逻辑过期时间,则在返回数据的同时,异步更新这个Key的缓存

4. 加锁重建策略

如果以上策略均失效,在高并发场景下大量Key依旧集中过期或热点Key过期,则需要控制通过查询数据库重建缓存的请求量,常用策略是加锁和限流

若缓存为命中,则对Key加锁,只有获得锁的线程才能访问数据库并加载数据重建缓存,最后释放锁。未获得锁的线程直接返回空结果或休眠一段时间后重试

缺点是不能保证系统的吞吐量,有损用户体验

五、缓存穿透

缓存穿透是指查询一条缓存和数据库都不存在的数据,会导致查询这条数据的请求会穿透缓存,直接查询数据库,最后返回空。如果用户发起大量请求去查询这条根本不存在的数据,则会对数据库造成极大压力

1. 缓存空值策略

未不存在的Key缓存一个空值,对于之后的请求会命中缓存中的空值,直接返回空数据,减少对数据库的访问。

缺点:

  • 浪费空间:需要缓存空值
  • 防御能力若:若攻击者构建不重复的请求,该策略就会被攻破,失去防御能力

2. 布隆过滤器

布隆过滤器可以在不查询数据库的情况下准确地判断数据是否一定不存在,从而过滤请求

布隆过滤器由一个固定大小的二进制向量(或位图)和一系列映射函数组成。元素被加入到布隆过滤器中时,该元素经k个哈希函数生成k个哈希值,然后将位图对应的k个点置为1。
如果需要判断某个元素是否在布隆过滤器中,只需对给定元素进行相同的哈希计算得到k个哈希值,如果有任何一个点为0,则说明这个元素一定不在布隆过滤器中

提前将真实存在的数据的Key(如商品Id)添加到布隆过滤器中,用户查询时,若不存在,则直接返回;若存在,继续查询缓存,缓存未命中则进一步查询数据库

实现方案:

  • Guava:适用于单机环境
  • Redis:Redis中的Bitmaps数据结构可以实现布隆过滤器
  • RedisBloom:开源的Redis插件,可提供布隆过滤器、布谷鸟过滤器、TopK等功能

缺陷:

  • 由于哈希碰撞存在误判,无法判断是否一定存在
  • 不支持删除元素,因为布隆过滤器每一个Bit位不是独占的,若直接删除可能会影响其他元素

3. 布谷鸟过滤器

布谷鸟过滤器支持删除元素,但是存在误删的概率,且插入操作的复杂度高,且会随着插入元素的增加而增加

六、缓存热点

当大量用户集中访问热点数据时,压力将汇聚于单一缓存服务器实例,可能导致热点数据所在的服务器过载,缓存服务不可用

1. 前置缓存策略

将热点数据提前缓存在应用服务器的本地内存中,对于数据查询请求,首先查询本地缓存,命中则直接返回

缺陷:

  • 无法防御未知热点,对于难以预见的突发热点无效
  • 数据更新存在延迟。本地缓存可能会存在短时数据不一致

2. 热点散列策略

多副本策略,将热点数据复制多份,分别缓存在多台缓存服务器上,减轻缓存热点导致的单台缓存服务器压力

实践中,散列数量一般与分布式缓存集群的服务器数量相等。

实现方案,如Redis Cluster

相关文章:

缓存问题解决方案

《服务器开发技术、方法与实用解决方案》 一、缓存预热 在系统刚启动或活动刚开始时,如果缓存中没有数据,那么大量请求将直接访问数据库。如果瞬时访问流量巨大,则可能导致数据库因过载而宕机,甚至引发系统雪崩。因此需要将缓存…...

数据结构————寻路算法

(一)基础补充 二维数组 定义:基本概念与方法和一维数组相似,一般形式为:类型符 数组名[常量表达式][常量表达式]; 其中,数组长度只能是常量;通常把二维数组第一个下标理解成行,第二个下标为列,常量表达式: 表达式里面只有常量的式子(如数字类常量); 二维数组常…...

蓝桥杯 题库 简单 每日十题 day7

01 啤酒和饮料 题目描述 本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。啤酒每罐2.3元,饮料每罐1.9元。小明买了若干啤酒和饮料,一共花了82.3元。我们还知道他买的啤酒比饮料的数量少,请你…...

go -- 获取当前24点的时间戳 --chatGpt

gpt: 要获取当前24点的时间戳,你可以使用 Go 标准库中的 time 包来实现。以下是一个示例函数,它可以获取当前日期的24点的时间戳: go package main import ( "fmt" "time" ) func getMidnightTimestamp() in…...

docker 容器内手动设置服务自启动

需求描述:不使用DockerFile实现容器内的服务自动启动 1、创建执行程序,以crond为例 //进入容器xxx docker exec -it xxx /bin/sh //切换root账户 bash //创建自动执行文件 vim /root/cron.sh2、自动执行文件内容 crond start3、修改执行文件权限 chmod x /root/…...

腾讯云微服务平台 TSF 异地多活单元化能力重磅升级

导语 2023腾讯全球数字生态大会已于9月7-8日完美落幕,40专场活动展示了腾讯最新的前沿技术、核心产品、解决方案。 微服务与消息队列专场,腾讯云微服务平台 TSF 产品经理张桢带来了《腾讯云微服务平台 TSF 异地多活单元化能力重磅升级》的精彩演讲。本…...

01贪心:算法理论知识

贪心:01算法理论知识 什么是贪心 贪心的本质是选择每一阶段的局部最优,从而达到全局最优。 这么说有点抽象,来举一个例子: 例如,有一堆钞票,你可以拿走十张,如果想达到最大的金额&#xff0…...

目标分类笔记(二): 利用PaddleClas的框架来完成多标签分类任务(从数据准备到训练测试部署的完整流程)

文章目录 一、演示多分类效果二、PaddleClas介绍三、代码获取四、数据集获取五、环境搭建六、数据格式分析七、模型训练7.1 模型恢复训练7.2 多卡训练7.3 其他训练指标 八、模型预测九、模型评估十、PaddleClas相关博客 一、演示多分类效果 二、PaddleClas介绍 PaddleClas主要…...

PageHelp插件在复杂sql下引起的Having无法识别错误及其解决方案

1: 问题出现的场景 系统中有一个复杂SQL内嵌套了多个子查询.在改动时需要将SQL的最后一行加上having来做额外的过滤处理. 添加完having语句后发现SQL能够正常执行就直接将代码提交到了测试环境.结果在测试环境报错Unknown column ‘xxx‘ in ‘having clause. 2: 分析问题 1…...

linux中的开发工具

在刚开始使用linux的时候,我们需要在系统上写一些简单的代码,来熟悉环境以及各种指令 并且熟悉属于linux的一套开发的环境,而这对于c来说需要三个软件就可以进行简单的编码 和使用,让我们来认识一下下列工具,以及工具的…...

2023 第十二届中国智能产业高峰论坛 - 文档大模型的未来展望

目录 前言文档图像分析识别与理解中的技术挑战 文档图像分析识别与理解的研究主题文档图像分析与预处理文档解析与识别版面分析与还原文档信息抽取与理解AI安全知识化&存储检索和管理 多模态大模型在文档图像处理中的应用多模态的GPT-4在文档图像上的表现多模态的Google Ba…...

【小沐学NLP】关联规则分析Apriori算法(Mlxtend库,Python)

文章目录 1、简介2、Mlxtend库2.1 安装2.2 功能2.2.1 User Guide2.2.2 User Guide - data2.2.3 User Guide - frequent_patterns 2.3 入门示例 3、Apriori算法3.1 基本概念3.2 apriori3.2.1 示例 1 -- 生成频繁项集3.2.2 示例 2 -- 选择和筛选结果3.2.3 示例 3 -- 使用稀疏表示…...

对话ChatGPT:AIGC时代下,分布式存储的应用与前景

随着科技的飞速发展,我们正步入一个被称为AIGC时代的全新阶段,人工智能、物联网、大数据、云计算成为这个信息爆炸时代的主要特征。自2022年11月以来,ChatGPT的知名度迅速攀升,引发了全球科技爱好者的极大关注,其高超的…...

java多线程学习笔记一

一、线程的概述 1.1 线程的相关概念 1.1.1 进程(Process) 进程(Process)是计算机的程序关于某数据集合上的一次运行活动,是操作系统进行资源分配与调度的基本单位。 可以把进程简单的理解为操作系统中正在有运行的一…...

BOM与DOM--记录

BOM基础(BOM简介、常见事件、定时器、this指向) BOM和DOM的区别和联系 JavaScript的DOM与BOM的区别与用法详解 DOM和BOM是什么?有什么作用? 图解BOM与DOM的区别与联系 BOM和DOM详解 JavaScript 中的 BOM(浏览器对…...

Docker安装MongoDB

一、docker安装mongodb MongoDB 是一个免费的开源跨平台面向文档的 NoSQL 数据库程序。 二、安装步骤 1.docker 拉取mysql镜像 docker pull mongo:latest 2.运行容器 docker run -itd --name mongo -p 27017:27017 mongo --auth参数说明: -p 27017:27017 &#…...

不要对正则表达式进行频繁重复预编译

背景 在频繁调用场景,如方法体内或者循环语句中,新定义Pattern会导致重复预编译正则表达式,降低程序执行效率。另外,在 JDK 中部分 入参为正则表达式格式的 API,如 String.replaceAll, String.split 等,也…...

vue入门及小项目小便签条

vue 框架:是一个半成品软件,是一套可重用的,通用的,软件基础代码模型。基于框架进行开发,更加快捷 ,更加高效 v-bind为HTML标签绑定属性值,如设置href,css样式等 v-model在表单元素上创建双向数…...

详解TCP/IP协议第四篇:数据在网络中传输方式的分类概述

文章目录 前言 一:面向有连接型与面向无连接型 1:大致概念 2:面向有连接型 3:面向无连接型 二:电路交换与分组交换 1:分组交换概念 2:分组交交换过程 三:根据接收端数量分…...

SpringMvc决战-【SpringMVC之自定义注解】

目录 一、前言 1.1.什么是注解 1.2.注解的用处 1.3.注解的原理 二.注解父类 1.注解包括那些 2.JDK基本注解 3. JDK元注解 4.自定义注解 5.如何使用自定义注解(包括:注解标记【没有任何东西】,元数据注解)? 三…...

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...

C++_核心编程_多态案例二-制作饮品

#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为&#xff1a;煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例&#xff0c;提供抽象制作饮品基类&#xff0c;提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现

摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序&#xff0c;以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务&#xff0c;提供稳定高效的数据处理与业务逻辑支持&#xff1b;利用 uniapp 实现跨平台前…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。

1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj&#xff0c;再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

PH热榜 | 2025-06-08

1. Thiings 标语&#xff1a;一套超过1900个免费AI生成的3D图标集合 介绍&#xff1a;Thiings是一个不断扩展的免费AI生成3D图标库&#xff0c;目前已有超过1900个图标。你可以按照主题浏览&#xff0c;生成自己的图标&#xff0c;或者下载整个图标集。所有图标都可以在个人或…...

Android屏幕刷新率与FPS(Frames Per Second) 120hz

Android屏幕刷新率与FPS(Frames Per Second) 120hz 屏幕刷新率是屏幕每秒钟刷新显示内容的次数&#xff0c;单位是赫兹&#xff08;Hz&#xff09;。 60Hz 屏幕&#xff1a;每秒刷新 60 次&#xff0c;每次刷新间隔约 16.67ms 90Hz 屏幕&#xff1a;每秒刷新 90 次&#xff0c;…...

五、jmeter脚本参数化

目录 1、脚本参数化 1.1 用户定义的变量 1.1.1 添加及引用方式 1.1.2 测试得出用户定义变量的特点 1.2 用户参数 1.2.1 概念 1.2.2 位置不同效果不同 1.2.3、用户参数的勾选框 - 每次迭代更新一次 总结用户定义的变量、用户参数 1.3 csv数据文件参数化 1、脚本参数化 …...

MySQL基本操作(续)

第3章&#xff1a;MySQL基本操作&#xff08;续&#xff09; 3.3 表操作 表是关系型数据库中存储数据的基本结构&#xff0c;由行和列组成。在MySQL中&#xff0c;表操作包括创建表、查看表结构、修改表和删除表等。本节将详细介绍这些操作。 3.3.1 创建表 在MySQL中&#…...

深入理解 C++ 左值右值、std::move 与函数重载中的参数传递

在 C 编程中&#xff0c;左值和右值的概念以及std::move的使用&#xff0c;常常让开发者感到困惑。特别是在函数重载场景下&#xff0c;如何合理利用这些特性来优化代码性能、确保语义正确&#xff0c;更是一个值得深入探讨的话题。 在开始之前&#xff0c;先提出几个问题&…...