缓存、分布式缓存、缓存的风险

为系统引入缓存的理由

在软件的开发中,引入缓存的负面作用明显大于硬件的缓存。主要由以下几个方面
从开发者角度来说引入缓存会提高系统的复杂度,因为你需要考虑缓存的失效、更新、一致性等问题(硬件缓存也存在这些问题,只是不需要你考虑了)
从运维角度来说 缓存会掩盖掉一些缺陷,让问题在更久的时间以后,出现在距离发生现场更远的位置上;缓存还可能存在泄漏某些保密数据,这也是容易攻击的薄弱点
存在这么多问题,为什么系统还会引入缓存呢
第一种为了缓解CPU压力而做的缓存
比如说,把方法运行的结果存储起来、把原本要实时计算的内容提前算好、把一些公用的数据进行复用等等,这些引入缓存的做法,都可以节省CPU算力,顺带提升响应性能
第二种,为了缓解I/O压力而做缓存
比如说,通过引入缓存,把原本对网络、磁盘等较慢介质的访问;把原本对单点部件(如数据库)的读写访问,变为可扩缩部件(如缓存中间件)的访问,等等,也顺带提升了响应性能
最后能通过花钱,(比如扩服务器的数量)来满足需要的话,那升级硬件往往是更好的解决方案

缓存属性

通常我们在设计或选择缓存时,至少需要考虑以下四个维度的属性
吞吐量:缓存的吞吐量使用QPS来衡量,它反映了对缓存进行并发读、写操作的效率,即缓存本身工作效率的高低
命中率 缓存的命中率即成功从缓存中返回结果次数与总请求次数的比值,它反映了引入缓存的价值高低、命中率越低,引入缓存的收益越小,价值越低
**扩展功能:**缓存处理基本读写功能外,还提供了一些额外的管理功能,比如最大容量,失效时间、失效事件、命中率统计等
分布式支持缓存可以分为进程内缓存和分布式缓存两大类,前者只为节点本身提供服务,无网络访问操作,速度快,但缓存的数据不能在各个服务节点中共享。后者则相反

缓存最主要的数据竞争来源于读取数据的同时,也会伴随着对数据状态的写入操作,而写入数据的同时,也会伴随着数据状态的读取操作。
一种是以Guava Cache 为代表的同步处理机制,即在访问数据时一并完成缓存、淘汰、失效等状态变更操作,通过分段加锁等手段来尽量减少数据竞争。
另外一种是以Caffeine为代表的异步日志提交机制。这种机制参考了经典的数据库设计理论,它把对数据的读、写过程看作是日志(即对数据的操作指令)的提交过程

命中率与淘汰策略

第一种:FIFO(First In First Out)
即优先淘汰最早进入被缓存的数据。这个淘汰策略并不优秀,因为越是访问频繁的数据,往往越会早早地被存入缓存中。所以这种淘汰策略,很可能会大幅度降低缓存的命中率
第二种:LRF(Least Recent Used)
即优先淘汰最久未被使用访问过的数据。LRU通常会采用HashMap加LinkedList的双重结构(如LinkedHashMap)来实现。也就是,它以HashMap来提供访问接口,保证常量时间的读取性能,以LinkedList的链表元素顺序来表示数据的时间顺序,在每次命中缓存时,把返回对象调整到LinkedList开头,每次缓存淘汰时从链表末端开始清理

第三种 :LFU (Least Frequently Used)
即优先淘汰掉最不经常使用的数据。LFU会给每个数据添加一个访问计数器,每访问一次就加1,当要淘汰数据的时候,就清理计数器数值最小的那批数据**。第一个问题**这个的缺点就是需要针对每个缓存数据都专门去维护一个计数器,每次访问都要更新,吞吐量会降低。第二个问题不便于处理随时间变化的热度变化,比如某个曾经频繁访问的数据现在不需要了,它也很难被自动清理出缓存。
TinyLFU
TinyLFU时LFU的改进版。为了缓解LFU每次访问都需要修改计数器所带来的性能负担。TinyLFU 首先采用Sketch结构来分析访问数据,所谓的Sketch,它实际上是统计学中的概念。即采用少量样本数据来估计全部样本数据的特征。
借助Count-Min-Sketch 算法(类似布隆过滤器的一种等价变种结构)可以用相对小得多的记录频率和空间,来近似地找出缓存中的低价值数据
另外为了解决LFU不便于处理时间变化的热度变化问题,TinyLFU采用基于“滑动时间窗口“的热度衰减算法。简单理解就是每隔一段时间,会把计数器的数值减半,以此解决”旧热点“数据难以清除的问题

分布式缓存如何与本地缓存配合,提高系统性能

复制式缓存与集中式缓存
复制式缓存,你可以看作是能够支持分布式的进程内缓存。它的工作原理与Session复制类似,缓存中的所有数据,在分布式集群的每个节点里面都存一份副本,当读取数据时,无需网络访问,直接从当前节点的进程内存中返回。读取效率很高,但是当数据变更时,就必须遵从复制协议,将变更的数据同步到集群的每一个节点,代价很高,在小规模集群中还算可以,但是在大规模集群下,网络同步速度跟不上写的速度,进而导致内存中有大量的待重发对象,最终导致OOM
集中式缓存,集中式缓存是目前分布式缓存中的主流形式。集中式缓存的读写都需要网络访问,它的好处就是不会随着集群的节点数量增加而增加额外的负担
透明多级缓存 分布式缓存和进程内缓存,各有所长,也各有局限,它们是互补的,而不是竞争关系,而多级缓存就是,使用进程内缓存做一级缓存,分布式做二级缓存,如果能在一级缓存中查询到结果接直接返回,否则就到二级缓存中去查询,再将二级缓存的结果回填到一级缓存,以后的访问就没有网络请求了。但是我们需要透明的解决这些问题,多级缓存才有意义。一种常见的设计原则,就是变更以分布式缓存中的数据为准,访问以进程内缓存的数据优先
大致做法就是当数据发生变动时,在集群内发送推送通知(简单点可以使用Redis的发布订阅模式,求严谨也可以引入Zookeeper或Etcd来处理),让各个节点的一级缓存自动失效掉响应的数据。
然后,当访问缓存时,缓存框架封装好一二级缓存联合查询接口,接口外部只查询一次,接口内部实现优先查询一级缓存。如果没获取到数据,就再自动查询二级缓存

缓存的风险

缓存穿透
如果查询的数据数据库中根本就不存在的话,缓存里面自然也不会有。这样请求的流量每次都不会命中,每次都会打到末端数据库,缓存自然就起不到缓存压力的作用了。这种现象就是缓存穿透
对于业务逻辑本身就不能避免的缓存穿透
我们可以约定在一定时间内,对返回为空的Key值依然进行缓存(注意正常返回,但是结果为空,不要把抛异常的当作空值缓存了)这样在一段时间内只会被穿透一次。如果后续业务在数据库中对该Key值插入新的记录,那我们就应当在插入之后主动清理掉缓存的Key值,如果业务实效性允许的话,也可以设置一个较短的超时时间来自动处理缓存
对于恶意攻击导致的缓存穿透
针对这种原因,我们通常会在缓存之前设置一个布隆过滤器来解决。所谓的恶意攻击是指,请求者刻意构造数据库中肯定不存在的Key值,然后发送大量请求进行查询,而布隆过滤器是最小的代价,来判断某个元素是否存在某个集合的办法。
如果布隆过滤器给出的判断结果是请求数据不存在,那直接返回即可,连缓存都不必去查。虽然维护布隆过滤器需要一定的成本,但是比起攻击造成的损失损耗,还是比较值得

缓存击穿
缓存中的某些热点数据忽然因为某种原因失效了,比如典型的超期而失效,而此时又有了多个针对该数据的请求同时发送过来,那么这些请求就会全部未能命中缓存,都打到真实的数据库了,导致压力剧增,甚至宕机。这种现象,就被称为缓存击穿。
如果要避免我们通常可以采用这样两种方法
1、加锁同步。以请求该数据Key值为锁,这样只有第一个请求可以流入真实的数据源中,其他线程采用阻塞或者重试策略。如果是进程内缓存出现了问题,施加普通互斥锁就可以了,如果是分布式缓存问题,就实施分布式锁
2、热点数据由代码来手动管理。缓存击穿是指针对热点数据被自动失效才引发的问题,所以针对这类数据,我们可以通过代码来有计划的实现更新、失效、避免缓存的策略自动管理

缓存雪崩
大量的数据同时失效,那么之所以会出现这样的情况,往往是因为系统有专门的缓存预热功能,也可能是因为,大量的公共数据都是由某一次冷操作加载的,这样可能会出现又一次载入的缓存的大批数据具有相同的过期时间,在同一时刻一起失效。
还有一种情况就是因为缓存服务因为某些原因崩溃重启后,此时会造成大量数据同时失效。
而避免缓存雪崩问题,我们通常可以采取这三种方法
1、提升系统的可用性,建设分布式缓存的集群
2、启用透明多级缓存,各个服务器节点的一级缓存中的数据,通常会具有不一样的加载时间,这样做也就分散了它们的过期时间
3、将缓存的生存期从固定时间改为一个时间段内的随机时间

缓存污染
所谓的缓存污染,就是指,缓存中的数据与真实数据源中的数据不一致的现。
为了提高使用缓存时的一致性,人们总结了不少遵循的设计模式,介绍一种Cache Aside模式,因为这种设计模式最简单,成本也最低。它的主要内容就两条
读数据时,先读缓存,缓存没有的话,再读数据源,然后将数据放入缓存,再响应请求
写数据时,先写数据库,然后失效(而不是更新)掉缓存
一个是先数据源后缓存
二个是应当先失效缓存,而不是尝试更新缓存

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

串口和 蓝牙模块HC08

串口基本认知 串行接口简称串口,也称 串行通信 接口或 串行通讯接口 (通常指 COM 接口 ),是采用串行通信方 式的 扩展接口 。串行 接口(Serial Interface )是指数据一位一位地顺序传送。其特点是 通信线路…

【LangChain学习之旅】—(16)检索增强生成:通过RAG助力大模型

【LangChain学习之旅】—(16)检索增强生成:通过RAG助力大模型 RAG 的工作原理文档加载文本转换文本分割器文本嵌入存储嵌入缓存存储向量数据库(向量存储)数据检索向量存储检索器各种类型的检索器索引总结什么是 RAG?其全称为 Retrieval-Augmented Generation,即检索增强…

Java 同步机制方法及其部分源码解读

1. synchronized 关键字 互斥锁 使用关键字synchronized修饰的方法或代码块,可以保证其修饰内容在任何时刻,最多只有一个线程可以访问,可用于控制多个线程在访问共享资源时的并发问题。 每个对象都有一把锁,每个synchronized修饰…

优秀企业都在用的企微知识库,再不搭建就晚了!

每个团队都在寻找让工作效率提升的方法。如果你想知道哪些团队能够高效地完成任务,而另一些却步履维艰,那么答案可能就是“企业微信知识库”。见过很多团队都在使用它,而且效果非常显著。如果你还没有搭建属于自己的企微知识库,可…

你真的会写接口自动化测试断言吗?

你真的会写自动化测试断言吗? 在接口测试中,断言是一项非常重要的操作,它是用来校验接口返回结果是否符合预期的一种手段。一般来说,接口测试断言大致可以分为以下几类: 状态码断言:这是最基本也是最常用的…

【C语言】汉诺塔问题

目录 一、何为汉诺塔问题? 二、汉诺塔计算规律 三、打印汉诺塔的移动路径 总结 一、何为汉诺塔问题? 汉诺塔问题是一个经典的问题。汉诺塔(Hanoi Tower),又称河内塔,源于印度一个古老传说。大梵天创造世…

16_I2C库函数

I2C库函数 1.void I2C_DeInit(I2C_TypeDef* I2Cx);2.void I2C_Init(I2C_TypeDef* I2Cx, I2C_InitTypeDef* I2C_InitStruct);3.void I2C_StructInit(I2C_InitTypeDef* I2C_InitStruct);4.void I2C_Cmd(I2C_TypeDef* I2Cx, FunctionalState NewState);5.void I2C_DMACmd(I2C_Type…

BM57 岛屿数量(回溯)

对数组index的判断要放前面,要不然报数组越界异常。 import java.util.*;public class Solution {/*** 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可** 判断岛屿数量* param grid char字符型二维数组 * return …

Unity开发者3D模型基础

术语“3D 建模”是指使用特殊软件创建对象或表面的 3D 数字表示的过程。 3D 模型可用于各种不同的目的,包括电影、视频游戏、建筑和工程。 3D 建模也是创建虚拟现实 (VR) 和增强现实 (AR) 体验工作的重要组成部分。 我们通常通过构建或获取 3D 模型并将其导入 Unit…

ssm028蜀都天香酒楼的网站设计与实现+jsp

基于JSP的蜀都天香酒楼管理系统的设计与实现 摘要 近年来,信息化管理行业的不断兴起,使得人们的日常生活越来越离不开计算机和互联网技术。首先,根据收集到的用户需求分析,对设计系统有一个初步的认识与了解,确定蜀都…

加速 Redis 操作:掌握管道技术提升性能与效率

Redis 管道技术是一种用于优化 Redis 命令执行效率的机制。在传统的 Redis 操作中,每次向 Redis 服务器发送一个命令,都需要等待命令执行完成并返回结果,这样会导致频繁的网络通信和服务器端的命令执行开销,降低系统的性能和吞吐量…

ssm026校园美食交流系统+vue

校园美食交流系统 摘 要 1 前 言 3 第1章 概述 4 1.1 研究背景 4 1.2 研究目的 4 1.3 研究内容 4 第二章 开发技术介绍 5 2.1Java技术 6 2.2 Mysql数据库 6 2.3 B/S结构 7 2.4 SSM框架 8 第三章 系统分析 9 3.1 可行性分析 9 3.1.1 技术可行性 9 3.1.2 经济可行…

极客时间: 用 Word2Vec, LangChain, Gemma 模拟全本地检索增强生成(RAG)

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…

第7章 数据安全

思维导图 7.1 引言 数据安全包括安全策略和过程的规划、建立与执行,为数据和信息资产提供正确的身份验证、授权、访问和审计。虽然数据安全的详细情况(如哪些数据需要保护)因行业和国家有所不同,但是数据安全实践的目标是相同的,即根据隐私和…

在Qt中使用Python时报错, expected unqualified-id before ‘;‘ token

在Qt中使用Python时报错&#xff0c;主要原因是include了一个 <pybind11/embed.h>文件 //object.h PyType_Slot *slots; ----------------------报错信息---------------------- /usr/include/python3.8/object.h:190: error: expected unqualified-id before ; token19…

jQuery笔记 01

目录 01 jquery概述 02 jq的特点和基本操作 03 jq的过滤选择器 04 jq的筛选选择器 05 jq对象和js对象的相互转化 06 jq的css方法 07 jq的class方法 01 jquery概述 jq是一个第三方的库文件 是其他团队 把js一些繁琐的操作封装成了一个个的方法 放到一个单独的js文件里…

隐私计算实训营第七讲-隐语SCQL的开发实践

隐私计算实训营第七讲-隐语SCQL的开发实践 文章目录 隐私计算实训营第七讲-隐语SCQL的开发实践1.如何使用SCQL&#xff1f;2.使用流程3.SCQL部署4.SCQL使用示例4.1创建用户4.2创建项目&用户授权4.3创建表4.4设置CCL4.5发起联合分析查询 1.如何使用SCQL&#xff1f; 2.使用流…

Echarts实现高亮某一个点

背景 接口会返回所有点的数据&#xff0c;以及最优点的数据。产品要求在绘制图形后&#xff0c;高亮最优点&#xff0c;添加一个红色的样式&#xff0c;如图。点击select选择器时&#xff0c;可选择不同指标和花费对应的关系。 以下介绍实现思路 1、自定义配置选择器的数据源…

关于Fragment这一篇就够了

Fragment是什么&#xff1f; Fragment是Android中的一个组件&#xff0c;它被引入在Android 3.0&#xff08;API 11&#xff09;中。Fragment是依赖于Activity的&#xff0c;不能独立存在。一个Activity可以有多个Fragment&#xff0c;一个Fragment也可以被多个Activity重用。…

C#基础:类,对象,类成员简介(第四节课)

本节内容&#xff1a; 类与对象的关系 什么时候叫“对象”&#xff0c;什么时候叫实例引用变量与实例的关系 类的三大成员 属性方法事件 类的静态成员与实例成员 关于“绑定” 1.什么是类&#xff1a;&#xff08;再详细一点&#xff09; 类是对现实世界事物进行抽象所…