高性能系统架构设计之:多级缓存

前言

        为了提高系统的性能,一般会引入“缓存机制”,将部分热点数据存入缓存中,用空间换取时间,以达到快速响应的目的。

        其实,缓存的应用远远不止存在于服务层(传统的Redis缓存),从客户端发起请求开始,经过域名服务器(DNS) → 内容分发服务器(CDN) → 反向代理服务器(Nginx),然后到达我们的分布式系统(ES),再经过分布式缓存服务(Redis、memcache) → 线程内缓存(Spring-cache、guava-cache),最后到达数据库(RDS),整个链路中每个节点都可以使用缓存,这就是所谓的“多级缓存”。其中缓存策略,算法也是层出不穷,今天就带大家走进缓存。

相关文章:

  • 关于:Ngnix的搭建,参数,复杂均衡,反向代理和调优讲解【篇】(专题汇总)
  • Guava Cache 原理分析与最佳实践
  •  Redis 3.0 的六种缓存淘汰策略

参考文章:

  • 性能为王:微服务架构中的多级缓存设计

正文

一、两种方式

1.1 传统缓存方式

        考虑到 mysql 的性能瓶颈,传统方案中,只在服务层做一级缓存。

  • 当请求到达 tomcat 后,先去 Redis 中获取缓存,不命中再去 mysql 中获取。
  • 当 mysql 成功获取数据以后,返回给前端的同时,将数据缓存进 Redis 一份,以便下次请求命中。

1.2 多级缓存方式

        多级缓存方案利用请求处理的每个环节,分别添加缓存,使最终到达 tomcat 的请求并发数远小于传统方案,达到减轻服务器压力,提升服务性能的目的。


二、多级缓存介绍

        请收好下面的图 - “多级缓存架构总览”,下面将围绕这个架构展开,分别介绍一下每层缓存的使用:

2.1 客户端(HTTP)缓存

        当用户通过浏览器请求服务器的时候,会发起 HTTP 请求,如果对每次 HTTP 请求进行缓存,那么可以减少应用服务器的压力。

        当第一次请求的时候,浏览器本地缓存库没有缓存数据,会从服务器取数据,并且放到浏览器的缓存库中,下次再进行请求的时候会根据缓存的策略来读取本地或者服务的信息。

         一般信息的传递通过 HTTP 请求头 Header 来传递。目前比较常见的缓存方式有两种,分别是:

  • 强制缓存

        当浏览器本地缓存库保存了缓存信息,在缓存数据未失效的情况下,可以直接使用缓存数据。否则就需要重新获取数据。

        在 HTTP 1.1 会使用 Cache-Control 来完成这样的功能,Cache-Control 中有个 max-age 属性,单位是秒,用来表示缓存内容在客户端的过期时间。客户端第一次请求完后,将数据放入本地缓存。那么在 max-age 以内客户端再发送请求,都不会请求应用服务器,而是从本地缓存中直接返回数据。如果两次请求相隔时间超过了 max-age,那么就需要通过服务器获取数据。

  • 对比缓存

        需要对比前后两次的缓存标志来判断是否使用缓存。

        浏览器第一次请求时,服务器会将缓存标识与数据一起返回,浏览器将二者备份至本地缓存库中。浏览器再次请求时,将备份的缓存标识发送给服务器。服务器根据缓存标识进行判断,如果判断数据没有发生变化,把判断成功的 304 状态码发给浏览器这时浏览器就可以使用缓存的数据来。服务器返回的就只是 Header,不包含 Body,这样会很大程度上节约了带宽。     

2.2 CDN缓存

        CDN(Content Delivery Network),即内容分发网络,依靠部署在各地的边缘服务器,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。

        CDN 主要缓存对象是静态数据。如果在客户端和服务器之间再加上一层 CDN,可以让 CDN 为应用服务器提供缓存,当命中CDN缓存时,就不用再请求应用服务器了。

       注: HTTP 缓存提到的两种策略同样可以在 CDN 服务器执行。

        在互联网应用中,因为 CDN 设计多地域多节点组网前期投入成本较高,所以更多的中小型企业会可以选择阿里云、腾讯云等提供的CDN服务。

2.3 Nginx缓存

        说完客户端(HTTP)缓存和 CDN 缓存,我们离应用服务越来越近了,在到达应用服务之前,请求还要经过负载均衡器 。

        虽说它的主要工作是对应用服务器进行负载均衡,但是它也可以作缓存。可以把一些修改频率不高的数据缓存在这里,例如:用户信息,配置信息。通过服务定期刷新这个缓存就行了。

        以 Nginx 为例,Nginx 是一款跨平台的,高性能的 Web 服务器,支持反向代理,负载均衡以及缓存功能。下面,来看看它是如何工作的:

  • 用户请求在达到应用服务器之前,会先访问 Nginx 负载均衡器;
  • 如果发现有缓存信息,直接返回给用户;
  • 如果没有发现缓存信息,Nginx 回源到应用服务器获取信息;
  • 另外,可以设置一个缓存更新服务,定期把应用服务器中相对稳定的信息更新到 Nginx 本地缓存中。

        相关配置可参考下面:

 2.4 进程内缓存

        进程内缓存,是在应用中开辟一块内存空间,数据在运行时被存入这块内存,通过本地内存低延迟、高吞吐的特性提高程序的访问速度。由于其运行在内存中,对数据的响应速度很快,通常我们会把热点数据放在这里。

        目前比较流行的实现:

  • 框架的:Mybatis 框架的一二级缓存,SpringMVC 的页面缓存等;
  • 进程内的:Ehcache、GuavaCache、Caffeine。

        本地缓存的特点:

  • 优点:读取本地内存,没有网络开销,速度更快;
  • 缺点:存储容量有限,可靠性低(如重启后丢失),无法在集群中共享;
  • 场景:性能要求高,缓存数据量少的地方。

        由于目前的系统架构都是分布式的,即:一个服务被部署在多台机器上以实现高性能,而进程内缓存只能存在于当前服务器,所以就会存在进程内缓存数据一致性的问题,如何保障?可以采用 RocketMQ 实现消息的最终一致性方案:        

 2.5 分布式缓存(进程外缓存)

        与进程内缓存不同,进程外缓存在应用运行的进程之外,它可以部署到不同的物理节点,并且拥有更大的缓存容量,通常会用分布式缓存的方式实现,如:Redis集群。

        分布式缓存是与应用分离的缓存服务,最大的特点是:自身是一个独立的应用/服务,与本地应用隔离,多个应用可直接共享一个或者多个缓存应用/服务。

        为了提高缓存的可用性,使部分节点失败或者大部分节点无法通信的情况下集群仍然可用,Redis集群使用了主从复制模型,每个节点都会有 N-1 个复制品(假设:一共有 N 个节点,则每个节点有一个 Master 和 N-1 个 Slave)。当缓存数据写入 Master 节点的时候,会同时同步一份到 Slave 节点。一旦 Master 节点失效,可以通过代理直接切换到 Slave 节点,这时 Slave 节点就变成了 Master 节点,保证缓存的正常工作。

        在 Redis 集群中,因为缓存也是分布式部署的,这样就会产生一个问题:数据根据怎样的规律分配到每个缓存应用/服务上?这里介绍三种缓存数据分片的算法:

  • 哈希算法

        这个算法很好理解,就是对数据记录的关键值进行 Hash 运算,然后再对需要分片的缓存节点个数进行取模,利用得到的余数进行数据分配。Hash 算法是某种程度上的平均放置,策略比较简单。但是它有一个很大的不足:如果要增加缓存节点,对已经存在的数据会有较大的变动,因为节点个数变了,取模后的结果也就不同了。

  • Range Based 算法

        和哈希算法类似,这种方式是按照关键值(例如 ID)将数据划分成不同的区间,每个缓存节点负责一个或者多个区间,相当于预设好了区间。

        例如:存在三个缓存节点分别是 N1,N2,N3。他们用来存放数据的区间分别是,N1(0, 100], N2(100, 200], N3(300, 400]。那么,数据根据自己 ID 作为关键字做 Hash 以后的结果就会分别对应放到这几个区域里面了。

  • 一致性哈希算法

        上面的2种方式似乎都不能解决缓存节点增减带来的问题,所以 Redis 集群引入了一致性 Hash算法(哈希槽)的概念 。一致性hash算法就是为了节点数目发生改变时,尽可能少的数据迁移而出现的。

        Redis 集群有16384(2的32次方)个哈希槽,将数据按照特征值映射到一个首尾相接的 Hash 环上,同时也将缓存节点映射到这个环上。

        每个key通过CRC16校验后对16384取模来决定放置哪个槽,这些值按照顺序在环上排列,集群的每个节点负责一部分hash槽。当需要增减缓存节点的时候,只会变动节点前后的部分数据,其他的数据不受影响,以此来将影响降到最低。

在这里插入图片描述


三、缓存的优缺点

        一句话概况:更快读写的存储介质+减少IO+减少CPU计算=性能优化

3.1 缓存带来的好处

        显而易见,缓存给我们带来最直接的体验就是“快”,我们来总结一下:

  • 通过减少IO(包括磁盘和网络)来提高吞吐量,减少计算量(CPU计算)释放CPU;

  • 通过缩短访问链路,减小访问时间,降低服务器和DB的压力,以达到高性能、高可用的目的;

  • 通过切面的处理方式,可以在各层进行插拔,是所有性能优化最简单有效的解决方案。

        对于不熟悉业务代码或算法的优化者,显然加一层缓存的复杂度和风险更低,而这一层看似简单的缓存,它给系统带来的性能优化有可能大大超过前者。

3.2 缓存带来的困扰

        我们不能否认缓存给我们带来诸多便利,同时,我们不能忽略缓存确实也给我们带来了不少困扰:

  • 数据的一致性、实时性受影响:需要对数据的一致性,时效性进行评估,进而确定是否要缓存或设定缓存的过期时间,比如个性化的数据是否值得缓存?

  • 缓存介质带来的不可靠性:一般使用内存做缓存的话,若机器故障,如何保证缓存的高可用?可考虑对缓存进行分布式做成高可用,同时,需要接受这种不可靠不安全会给数据带来的问题,在异常情况下进行补偿处理,定期持久化等方式。

  • 缓存的数据使得更难排查问题:因为缓存命中是随着访问随时变化的,缓存的行为难以重现,使得出现BUG很难排查。

  • 进程内缓存可能会增加GC压力:在具有垃圾收集功能的语言中(如Java),大量长寿命的缓存对象会增加垃圾收集的时间和次数。

        所以,在使用缓存之前我们需要对数据进行分类,对访问行为进行预估,思考哪些数据需要缓存,缓存时需要采用什么策略?这样,我们才不被缓存所困扰,才能规避这些问题。


四、缓存的适用场景

        在实际应用中,我们需要对数据进行分类,才能更好的使用缓存以及一些策略来辅助。比如:哪些为冷热数据?哪些数据量很大,读取会严重影响IO?哪些数据查多改少(日志数据,爬虫数据)?哪些数据又是经过很复杂的计算得到的结果(这些珍贵的数据需要好好保存利用)?等等。

  • 情况一:缓存数据比较稳定

        如:邮政编码,省市区编码,地域区块,归档的历史数据,这类信息适合通过多级缓存Redis来减少数据库的压力。

  • 情况二:瞬间产生高并发的场景

        如:春晚抢红包,双十一活动,整点秒杀等,存在瞬间的流量洪峰,可以通过多级缓存防止Redis击穿和穿透。

  • 情况三:一定程度上允许数据不一致

        如:库存,余额这种需要强一致性的数据,在分布式系统中需要分布式事务控制,但是如果允许数据段时间的有差别,可以使用先使用缓存,最后利用RocketMQ或定时任务实现最终一致。


总结

        大流量下的多级缓存设计,大致有五大策略,从用户请求开始到数据库依次是:HTTP 缓存,CDN 缓存,Ngginx负载均衡缓存,Cache进程内缓存,Redis分布式缓存,其中:

  • CDN 缓存和 HTTP 缓存是好搭档,他们主要缓存静态数据,将静态资源放在距离用户最近的地方;
  • Nginx 负载均衡器缓存相对稳定的资源,需要服务协助工作(如:设置一个缓存更新服务,定期把应用服务器中相对稳定的信息更新到 Nginx 本地缓存中),毕竟负载均衡才是Nginx的本职工作;
  • Cache 进程内缓存,效率高,但容量有限制,只有性能要求极高,又不需要数据强一致性的场景才适合使用。进程内缓存需要注意数据一致性的问题,利用 RocketMQ 可以实现数据最终一致。
  • 分布式缓存容量大,能力强,牢记三个性能算法并且防范三个缓存风险(缓存穿透,缓存击穿,缓存雪崩)。

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

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

相关文章

虚拟试衣人像合成新SOTA!IMAGDressing-v1:ControlNet和IP-Adapter的最佳拍档

文章链接:https://arxiv.org/pdf/2407.12705 github链接:https://imagdressing.github.io/ Demo试用:https://sf.dictdoc.site/ 亮点直击 为商家引入了一项新的虚拟试衣(VD)任务,并设计了一个综合亲和力测量…

最新缺失msvcp140.dll的多种解决方法,有效解决电脑dll问题

msvcp140.dll 是一个关键的动态链接库(DLL)文件,属于 Microsoft Visual C 2015 Redistributable 的一部分。它为使用 Microsoft Visual C 编译的应用程序提供了运行时支持,确保这些应用程序能够正常运行。以下是对 msvcp140.dll 的…

《0基础》学习Python——第十九讲__爬虫\<2>

一、用get请求爬取一般网页 首先由上节课我们可以找到URL、请求方式、User-Agent以及content-type 即:在所在浏览器页面按下F12键,之后点击网路-刷新,找到第一条双击打开标头即可查看上述所有内容,将上述URL、User-Agent所对应的…

ABAP打印WORD的解决方案

客户要求按照固定格式输出到WORD模板中,目前OLE和DOI研究了均不太适合用于这种需求。 cl_docx_document类可以将WORD转化为XML文件,利用替换字符串方法将文档内容进行填充同 时不破坏WORD现有格式。 首先需要将WORD的单元格用各种预定义的字符进行填充…

四个节点即可实现的ComfyUI批量抠图工作流

原文链接:ComfyUI面部修复完全指南 (chinaz.com) 下图就是批量抠图的工作流 虽然工作流很简单,但是我们前提还是需要安装好我们的节点 首先安装我们的抠图节点 安装 BiRefNet 所需依赖:timm,如已安装无需运行 requirements.txt…

苹果电脑crossover怎么下载 苹果电脑下载crossover对电脑有影响吗 MacBook下载crossover软件

CodeWeavers 发布了 CrossOver 24 版本更新,不仅兼容更多应用和游戏,得益于 Wine 9.0 带来的 7000 多项改进,CrossOver 还可以在 64 位系统上运行Windows应用的软件,使得用户可以在Mac系统中轻松安装使用仅支持Windows系统运营环境…

搜维尔科技:【研究】动作捕捉加速游戏开发行业的发展

动作捕捉加速游戏开发行业的发展 Sunjata 的故事始于 2004 年,它将席卷乌干达视频游戏行业,然后席卷全世界。但首先,Klan Of The Kings 的小团队需要工具来实现他们的愿景。 漫画家兼非洲民间传说爱好者罗纳德卡伊马 (Ronald Kayima) 在将…

idea navigate mysql生成实体类

参考:https://blog.51cto.com/u_16175427/7251120 使用idea导航MySQL生成实体类 1、在IDEA的顶部菜单中选择View -> Tool Windows -> Database 2、找到表,右键表Scripted Extensions -> Generate POJO...

6. dolphinscheduler-3.0.0伪集群部署

环境说明: 主机名:cmc01为例 操作系统:centos7 安装部署软件版本部署方式centos7zookeeperzookeeper-3.4.10伪分布式hadoophadoop-3.1.3伪分布式hivehive-3.1.3-bin伪分布式clickhouse21.11.10.1-2单节点多实例dolphinscheduler3.0.0单节…

ELK kibana查询与过滤

ELK kibana查询与过滤 1、通过布尔操作符 AND 、 OR 和 NOT 来指定更多的搜索条件(注意:这AND、OR、NOT必须大写)。例如,搜索message包含服务层关键词并且日志级别为INFO的条目,您可以输入 message:“服务层” AND level:“INFO”。 2、要搜…

KU FPGA FLASH boot失败debug

原因 新板子回来后,测试flash 烧录正常,但是无法BOOT,此时SPI设置为X4模式,使用内部时钟,速度90M。烧录过程不报错,校验也正常。 FLASH理论支持最大速度108M,90M应该还好。另外板卡预留了EMCCLK外部时钟模…

Python+Flask+MySQL/Sqlite的个人博客系统(前台+后端管理)【附源码,运行简单】

PythonFlaskMySQL/Sqlite的个人博客系统(前台后端管理)【附源码,运行简单】 总览 1、《个人博客系统》1.1 方案设计说明书设计目标工具列表 2、详细设计2.1 管理员登录2.2 程序主页面2.3 笔记新增界面2.4 文章新增界面2.5 文章/笔记管理界面2…

分享一个 .NET EF 6 扩展 Where 的方法

前言 Entity Framework 6(EF 6)中的 Where 方法用于筛选数据库中的数据并返回符合条件的结果,但 Where 方法只能进行简单的筛选条件,例如相等、大于、小于等简单条件,如果需要处理更复杂的逻辑条件,则需要…

iMazing 3 换手机后苹果游戏数据还有吗 换iPhone怎么转移游戏数据

当你想要更换手机,无论是选择升级到最新款iPhone,或者换到“经典”旧款iPhone,单机游戏数据的转移总是让人发愁。本文将详细介绍换手机后苹果游戏数据还有吗,以及换iPhone怎么转移游戏数据,确保你能无缝继续你的游戏体…

力扣第十七题——电话号码的字母组合

内容介绍 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。 示例 1: 输入:digits "23" 输出…

CTFshow--web--xss

目录 web316 web317~319 web320~326 web327 web328 web329 web330 web331 web332 web333 先在自己的服务器写上代码 <?php$content $_GET[1]; if(isset($content)){file_put_contents(flag.txt,$content); }else{echo no data input; }要拿到管理员的cookie , 而…

FairGuard游戏加固入选《嘶吼2024网络安全产业图谱》

2024年7月16日&#xff0c;国内网络安全专业媒体——嘶吼安全产业研究院正式发布《嘶吼2024网络安全产业图谱》(以下简称“产业图谱”)。 本次发布的产业图谱&#xff0c;共涉及七大类别&#xff0c;127个细分领域。全面展现了网络安全产业的构成和重要组成部分&#xff0c;探…

通义千问AI模型对接飞书机器人-集成飞书机器人(2-2)

接上一篇 通义千问AI模型对接飞书机器人-模型配置&#xff08;2-1&#xff09; 1、通过飞书机器人对接ai的在线接口 参考文档&#xff1a;发送 HTTP 请求 1.1 创建飞书应用 创建流程 配置http请求 http请求地址上一篇百炼平台配置的应用地址 1.2 企业自建应用对接AI 添加应用…

HumanitZ人道主义z用服务器开服教程

1、登录服务器&#xff08;百度莱卡云&#xff09; 进入控制面板后会出现正在安装的界面&#xff0c;安装大约5分钟&#xff08;如长时间处于安装中请联系我们的客服人员&#xff09; 2、修改查询端口 点击网络&#xff0c;两个端口已经创建完成 复制不是首选的端口&#xff…

无需标注即可训练,自监督学习框架实现大量未标注毫米波雷达数据预训练自动驾驶感知任务

Abstract 由于雷达&#xff08;radar&#xff09;在雾天和恶劣天气下的操作能力&#xff0c;自动驾驶车辆使用雷达进行感知引起了越来越多的研究兴趣。然而&#xff0c;训练雷达模型受到大规模雷达数据注释的成本和难度的阻碍。为了克服这一瓶颈&#xff0c;我们提出了一种自监…