当前位置: 首页 > 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.如何使用自定义注解(包括:注解标记【没有任何东西】,元数据注解)? 三…...

Python|GIF 解析与构建(5):手搓截屏和帧率控制

目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...

day52 ResNet18 CBAM

在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析

这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...

FastAPI 教程:从入门到实践

FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...

Nuxt.js 中的路由配置详解

Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

Keil 中设置 STM32 Flash 和 RAM 地址详解

文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...

腾讯云V3签名

想要接入腾讯云的Api,必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口,但总是卡在签名这一步,最后放弃选择SDK,这次终于自己代码实现。 可能腾讯云翻新了接口文档,现在阅读起来,清晰了很多&…...

【Linux系统】Linux环境变量:系统配置的隐形指挥官

。# Linux系列 文章目录 前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变量的生命周期 四、环境变量的组织方式五、C语言对环境变量的操作5.1 设置环境变量:setenv5.2 删除环境变量:unsetenv5.3 遍历所有环境…...

永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器

一、原理介绍 传统滑模观测器采用如下结构: 传统SMO中LPF会带来相位延迟和幅值衰减,并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF),可以去除高次谐波,并且不用相位补偿就可以获得一个误差较小的转子位…...