重要的节日那么多,要及时「缓存」你们的珍贵时光

作者 | 后端学长

责编 | Carol

出品 | 程序员 cxuan

缓存概述

在很久很久以前人类和洪水作斗争的过程中,水库发挥了至关重要的作用 : 在发洪水时可以蓄水,缓解洪水对下游的冲击;在干旱时可以把库存的水释放出来以供人们使用。这里的水库就起着缓存的作用。在如今互联网的世界里随着互联网的普及,内容信息越来越复杂,用户数和访问量越来越大,我们的应用需要支撑更多的并发量,同时我们的应用服务器数据库服务器所做的计算也越来越多。

但是往往我们的应用服务器资源是有限的,且服务器技术变革是缓慢的,数据库每秒能接受的请求次数也是有限的,那么如何能够有效利用有限的资源来提供尽可能大的吞吐量呢?一个有效的办法就是引入缓存,打破标准流程,每个环节中请求可以从缓存中直接获取目标数据并返回,从而减少计算量,有效提升响应速度,让有限的资源服务更多的用户。

缓存的定义

缓存就是数据交换的缓冲区(称作Cache),这个概念最初是来自于内存和 CPU。当某一硬件要读取数据时,会首先从缓存中查找需要的数据,如果找到了则直接使用执行,缓存找不到的话则从内存中找。由于缓存的运行速度比内存快得多,故缓存的作用就是帮助硬件更快地运行。

缓存的分类

当用户从键入一个地址到页面的展示过程中通常包含了很多种缓存。有前端缓存、本地缓存(协商缓存,强缓存等)到我们的网关缓存(CDN 缓存)、最后到我们服务端缓存。服务端缓存又区分为进程缓存(本地缓存),还有比较火的分布式缓存,最后到了数据库层面的缓存。如下图所示:

缓存是一把双刃剑

在我们通常的软件设计中,有一些热点数据需要展示到页面,我们通常当这些数据缓存到内存或者其他读写速度优异的框架中。减少与数据库进行 I/O 操作。提升数据的响应速度。这一切看起来就是这么完美。

实际上,在缓存系统的设计架构中,还有很多坑。如果设计不当会导致很多严重的后果。设计不当,轻则请求变慢、性能降低,重则会数据不一致、系统可用性降低,甚至会导致缓存雪崩,整个系统无法对外提供服务。

接下来我们着重讲述一下在缓存设计过程中几大经典的问题。

缓存失效

先解释一下什么叫做缓存失效

我们在存放缓存的时候,可以指定缓存 Key 的失效时间,当失效时间到了,此缓存就会失效,由于在缓存中找不到该数据,所以这个时候如果用户有请求该数据就绕过缓存直接到数据库中请求数据。

看到这里小伙伴们肯定有很多问号?

这不是很正常的现象嘛?为什么要把这个问题拿出来说呢?莫急看下图图示

这里我们通过两个场景来说明一下

  • 场景一:这种情况下一般不会对数据库造成比较严重的影响,因为失效的 key 的数量比较少,即使同时请求到数据库层面也是可以接受的。

  • 场景二:在这种场景中,当缓存里面的大量 Key 同时失效,这个时候如果有请求过来,会穿过失效的 Key全部落到数据库层面。导致数据库的负荷瞬间添加。可能会出现数据库宕机等特大事故。

解决方案

看到这里很多聪明的小伙伴其实已经想到了。场景 2 的事故主要因为很多 key 一起失效的原因,跟我们日常写缓存的过期时间息息相关。如果我们在日常的开发过程中需要将一批 Key 设置到缓存中并制定失效时间。这个时候就要注意场景 2 发生的情况。我们可以在失效时间 + 随机时间。避免大量 Key 失效冲击我们的数据库。

缓存击穿

通常情况下,我们去查询数据都是存在的。那么如果请求去查询一条压根儿数据库中根本就不存在的数据,也就是缓存和数据库都查询不到的这条数据会怎么样呢?这样会导致每次访问都会直接打到数据库上面去。这种查询不存在数据的现象我们称为缓存穿透

下面是缓存失效的场景。

很多伙伴看到这里肯定又会觉得这是一件很正常的事情。试想一下,如果有黑客会对你的系统进行攻击,拿一个不存在的 key 不停的去查询数据,会产生大量的请求到数据库去查询。可能会导致你的数据库由于压力过大而宕掉。

解决方案一

  • 首先我们能想到的就是在网关参数进行过滤。校验请求的 key 是否是我们系统 key 的格式等

当然这网关层所能做到的只是一些简单过滤。每个后端的设计人员应该对服务的可用性和健壮性负责。接下来我们看看服务端应该如何处理

  • 服务端可以将不存在的 key 暂时保存到我们的缓存中,再次接收到同样的请求后如果直接命中缓存并且值为空那么就会直接返回,不会穿透到数据库层面,这样就避免了缓存击穿。

但是黑客/恶意攻击者是不会这么轻易被打发的。每次请求都会传不同的 key 来攻击我们的服务。这个时候这个方案起不到作用了。

解决方案二

构建一个 BloomFilter(布隆过滤器) 缓存过滤器,记录全量数据。这样访问数据时,可以直接通过 BloomFilter 判断这个 key 是否存在,如果不存在直接返回即可,根本无需查缓存和 DB。这样在缓存之前加了一层校验。如果key 值不存在,就不会请求到我们的缓存更加不会到我们的数据库中。

布隆过滤器可以理解为一个不怎么精确的 set结构,当你使用它的 contains 方法判断某个对象是否存在时,它可能会误判。但是布隆过滤器也不是特别不精确,只要参数设置的合理,它的精确度可以控制的相对足够精确,只会有小小的误判概率。当布隆过滤器说某个值存在时,这个值可能不存在;当它说不存在时,那就肯定不存在。即使误判不存在走到缓存和后端服务也是可以接受的。

缓存雪崩

缓存雪崩是指缓存的部分节点不可用导致整个缓存体系甚至整个服务系统不可用

那么你可能会有疑问,缓存雪崩和缓存击穿有什么关系呢?

从概念上来看,缓存击穿是因为查询不存在的 key 穿透缓存直接访问我们的数据库。而缓存雪崩是因为我们的缓存节点不可用,请求未经过缓存就直到了我们的数据库层面。然而两者都会影响我们的服务稳定性。

缓存节点的不可用会导致缓存雪崩,那么我们缓存组件集群部署是不是就解决了这个问题呢?

集群部署有两种情况:

  • 一种就是简单的主从例如 redis 的哨兵之殇

  • 采取一致性 hash 算法集群部署例如 redis 的分片集群

第一种情况:发送雪崩的时候一般是多个节点同时不可用,例如我们的节点服务器内容不足,虽然分主从节点都是存储的数据都是一样的。如果缓存中的数据过大导致节点不可用。那大部分节点也会存在这个问题。请求会大面积的落到数据库层面导致后端系统崩溃。

第二种情况:  首先看一下下图虽然数据根据会根据取模算法分配到不同的节点中,假设节点 A 不可用,数据 A 会按照逆时针找到节点 B,会因为本来应该存放到节点 A 的数据存放到节点 B,以此类推会导致整个缓存节点不可用。请求也会大面积落到我们后端的数据库层面导致系统崩溃。

解决方案

  • 对缓存体系进行实时监控,当请求访问的慢速比超过阀值时,及时报警,通过机器替换、服务替换进行及时恢复。

  • 对缓存增加多个副本,缓存异常或请求 miss 后,再读取其他缓存副本。

  • ehcache 本地缓存 + Hystrix 限流&降级,避免 MySQL被打死

  • 业务 DB 的访问增加读写开关,当发现 DB 请求变慢、阻塞,慢请求超过阀值时,就会关闭读开关,部分或所有读 DB 的请求进行 failfast 立即返回,待 DB 恢复后再打开读开关。

数据不一致

数据不一致的概念很简单:就是缓存中的数据和数据库中的数据不一致

那为什么会不一致呢?我们的数据被缓存之后,一旦数据被修改(修改时也是删除缓存中的数据)或删除,我们就需要同时操作缓存和数据库。这时就会存在一个数据不一致的问题。

如上图所示当我们先删除数据库再去操作缓存,缓存中未删除数据库其实已经不存在该数据了。这个时候就会出现缓存不一致的情况。

聪明的小伙伴肯定想到了我们还是需要先做缓存删除操作,再去完成数据库操作。则会去数据库中查询,如果缓存中没有该数据,则会去数据库中查询,之后再放入到缓存中。这样就完美了嘛?答案肯定不会这么简单。请看下图:

解决方案

这里其实没有什么很完美的解决方法。可以将变更的 key 添加到安全队列中。当另一个查询请求 B 进来时,如果发现缓存中没有该值,则会先去队列中查看该数据是否正在被更新或删除,如果队列中有该数据,则阻塞等待,直到 A 操作数据库成功之后,唤醒该阻塞线程,再去数据库中查询该数据。这里其实也是有很多缺陷的。线程需要阻塞等待。

最好的解决方案就是如果数据更新比较频繁且对数据有一定的一致性要求,我通常不建议使用缓存。看到这里是不是发出了一句切!!!!

总结

缓存虽然能大幅度的提高服务器的性能以及用户的体验感。但是随着而来的就是各种由于缓存导致的一系列问题。所以当我们使用缓存的过程中需要注意以上的经典问题。

 

推荐阅读

  • 在 520 这天,竟然有人把 Docker讲清楚了? | 原力计划

  • 如何使用 SQL Server FILESTREAM 存储非结构化数据?这篇文章告诉你!

  • 对不起,我把APP也给爬了

  • 平安科技王健宗:所有 AI 前沿技术,都可以在联邦学习中大展身手!

  • 踢翻这碗狗粮:程序员花 7 个月敲出 eBay,只因女票喜欢糖果盒!

  • 又一年5.20,用Python助力程序员脱单大攻略(视频版)

  • 斗地主吗?能学区块链那种! | 原力计划

真香,朕在看了!

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

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

相关文章

我和面试官之间关于操作系统的一场对弈 | 原力计划

作者 | Guide哥责编 | 伍杏玲出品 | CSDN博客大家好,我是 Guide 哥!很多读者抱怨计算操作系统的知识点比较繁杂,自己也没有多少耐心去看,但是面试的时候又经常会遇到。所以,我带着我整理好的操作系统的常见问题来啦&am…

LaTex中参考文献引用

一、引用参考文献 这里我们使用的是BibTeX的引用格式,因此文件中应包括两个文件(.bib-参考文献 和 .bst-文献格式)。 有了这两个文件后,我们在bib文件中创建参考文献:(注意,作者的名字是逗号前…

如何在Flutter上实现高性能的动态模板渲染

背景 最近小组在尝试使用一套阿里dinamicX的DSL,通过动态模板下发,实现Flutter端的动态化模板渲染;本来以为只是DSL到Widget的简单映射和数据绑定,但实际跑起来的效果出乎意料的差,列表卡顿严重,帧率丢失严…

稀疏数组(数据结构)

稀疏数组(数据结构) 需求:编写五子棋游戏中,有存盘和续上盘的功能 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 …

揭秘 Flink 1.9 新架构,Blink Planner 你会用了吗?

本文为 Apache Flink 新版本重大功能特性解读之 Flink SQL 系列文章的开篇,Flink SQL 系列文章由其核心贡献者们分享,涵盖基础知识、实践、调优、内部实现等各个方面,带你由浅入深地全面了解 Flink SQL。 1. 发展历程 今年的8月22日 Apache…

阿里面试官整理的JVM面试要点,99%的你都不知道!

最近网上出现一个面试题:“一个线程OOM后,其他线程还能运行吗?”网上出现了很多答案。这道题其实很有难度,涉及的知识点有jvm内存分配、作用域、gc等,不是简单的是与否的问题。在面试时被问到这个问题你是会哑口无言还…

6 个 K8s 日志系统建设中的典型问题,你遇到过几个?

作者 | 元乙 阿里云日志服务数据采集客户端负责人,目前采集客户端 logtail 在集团百万规模部署,每天采集上万应用数 PB 数据,经历多次双 11、双 12 考验。 导读:随着 K8s 不断更新迭代,使用 K8s 日志系统建设的开发者…

如何加快 Node.js 应用的启动速度

我们平时在开发部署 Node.js 应用的过程中,对于应用进程启动的耗时很少有人会关注,大多数的应用 5 分钟左右就可以启动完成,这个过程中会涉及到和集团很多系统的交互,这个耗时看起来也没有什么问题。 目前,集团 Serve…

技术人看《长安十二时辰》的正确姿势是?

阿里妹导读:从“叉手礼”、“水盆羊汤”、“酒晕妆”这些唐朝人的生活细节,到精美的坊间造型、充满意境的诗词歌赋,《长安十二时辰》不仅以缜密剧情赢得赞誉,更还原了一个真实的大唐长安。在精良制作之上,技术人如何让…

我们已经不用AOP做操作日志了! | 原力计划

来源 | JAVA葵花宝典责编 | 王晓曼、Carol 头图 | CSDN下载自东方IC前言用户在操作我们系统的过程中,针对一些重要的业务数据进行增删改查的时候,我们希望记录一下用户的操作行为,以便发生问题时能及时的找到依据,这种日志就是业务…

会向业务“砍需求”的技术同学,该具备哪6点能力?

阿里妹导读:“会”砍需求,并不是件容易的事情,这涉及到工程师的商业头脑,要会判断技术和业务的关系。技术与业务好比“两条腿”,相互配合才能走得更远。如何具备business sense就是我们今天的课题。 论工程师的商业头…

(进阶篇)Redis6.2.0 集群 主从复制_原理剖析_02

文章目录一、主从复制流程1. 主从复制流程图2. 主从复制日志二、主从复制信息剖析2.1. 主节点信息剖析2.2. 从节点信息剖析三、关键术语3.1. 复制功能开启3.2. 全量复制场景3.3. 主从复制异步性3.4. 过期key的处理3.5. 加速复制一、主从复制流程 1. 主从复制流程图 第一条线&a…

如何抢占云栖大会C位?史上最强强强攻略来了

如何抢占云栖大会C位?史上最强强强攻略来了 原文链接 本文为云栖社区原创内容,未经允许不得转载。

寻找榜样的力量!CSDN【百万人学 AI】评选活动重磅启动

AI 业界历经算法更迭、技术方案升级,有企业攻城略池,占据更多行业山头,有企业中途折戟沉沙。AI 发展浮浮沉沉,但每一年我们都希望审视当下,一窥未来。2020 无疑是特殊的一年,而 AI 在开年的这场”战疫“中表…

重构:改善饿了么交易系统的设计思路

我在2017年5月加入饿了么的交易部门,先后负责搜索、订单、超时、赔付、条约、交付、金额计算以及评价等系统,后期开始做些整体系统升级的工作。 这篇文章成型于交易系统重构一期之后,主要是反思其过程中做决策的思路,我没有使用「…

(进阶篇)Redis6.2.0 集群 主从复制_故障解决_03

文章目录一、 主从数据一致性1. 主多从少2. 主少从多3. 知识点补充二、 数据延迟2.1. 数据延迟因素2.2. 解决方案三、 脏数据3.1. 脏数据产生的场景3.2. 解决方案四、 数据安全性4.1. 场景4.2. 解决方案五、 规避全量复制5.1. 低峰时段5.2. 主节点变更5.3. 增大复制缓冲区六、 …

以“基”取胜:青立方超融合易捷版,助力企业“极简”上云

2020年春天,以云计算、5G、人工智能为代表的“新基建”蔚然成风,不仅助力中国产业智能化、信息化进入加速推进的快车道,促使全产业链迈开高质量发展的新步伐。更是面向长远,构筑数字经济创新发展之基。可以说,没有任何…

从零开始入门 K8s| K8s 的应用编排与管理

一、资源元信息 1. Kubernetes 资源对象 我们知道,Kubernetes 的资源对象组成:主要包括了 Spec、Status 两部分。其中 Spec 部分用来描述期望的状态,Status 部分用来描述观测到的状态。 今天我们将为大家介绍 K8s 的另外一个部分&#xff0c…

创建对象内存分析

创建对象内存分析 package com.oop.demo03;public class Pet {public String name;public int age;public void shout(){System.out.println("叫了一声");}}/* //一个项目应该这存在一个main方法 public class Application {public static void main(String[] args) …

AliOS Things 维测典型案例分析 —— 内存泄漏

维测典型案例分析1 —— 内存泄漏 在系统运行的过程中,内存泄漏是较为常见但是很难复现的现象,一般的内存泄漏点都是比较隐蔽的,每次几十个字节的泄漏,往往需要压测很久才能复现问题。本节案例分析,我们从一个已经压测…