使用CDN构建读取缓存设计

news2024/10/6 2:59:55

在构建需要高吞吐量和最小响应时间的系统的API时,缓存几乎是不可避免的。每个在分布式系统上工作的开发人员都曾在某个时候使用过某种缓存机制。在本文中,我们将探讨如何使用CDN构建读取缓存设计,不仅可以优化您的API,还可以降低基础架构成本。

了解一些关于缓存和CDN的知识将有助于理解本文。如果您对此一无所知,建议您先了解一些相关知识,然后再回到这里。

背景

作为后端开发人员,我们始终在努力构建高度优化的API,以为用户提供良好的体验。故事从这里开始,我们如何面对一个特定的问题,然后如何解决它。我希望您在阅读本文后能够从中学到一些关于大规模系统设计的东西。

问题

我们需要开发一些API,这些API具有以下特征:

1.数据不会经常更改。2.对所有用户来说,响应是相同的,没有意外的查询参数,只是简单的GET API。3.响应数据量最多为约600 KB。4.我们预计API的吞吐量非常高(最终约为每秒5-6万次查询)。

当您第一次看到这个问题时,你的第一反应是什么?对我来说,首先想到的是,只需在节点上添加内存缓存(例如Google Guava),使用Kafka发送失效消息(因为我喜欢Kafka,它很可靠),设置服务实例的自动缩放(因为流量在一天中不均匀)。类似于下面的示意图:

7ef48521c1cf96e22a67804b547b6a27.jpeg
1*F60S9SCN5JVmgutDCOwPKg.jpeg

嘭!问题解决了!很容易对吧?嗯,事实并非如此,像任何其他设计一样,这个设计也带来了一些缺陷。例如,对于一个简单的用例来说,这个设计略微复杂,基础架构成本将会增加,因为现在我们必须生成一个Kafka + Zookeeper集群,而且为了处理每秒5-6万次请求,我们需要水平扩展服务实例(对于我们来说是Kubernetes Pod),这意味着需要增加更多的物理节点或虚拟机。

因此,我们寻找了一种更简单和经济有效的方法,这就是我们最终开发了一种具有“使用CDN构建读取缓存”的解决方案。不久之后,我将讨论架构的细节以及权衡。

但在进一步探讨之前,让我们先了解设计的构建块。

读取缓存

标准的缓存更新策略有:

1.旁路缓存(Cache-Aside)2.读取通过缓存(Read-Through)3.写入通过缓存(Write-Through)4.写入后缓存(Write-Behind)5.提前刷新(Refresh-Ahead)

我将不详细讨论其他策略,而只关注读取缓存,因为本文只涉及此内容。让我们深入研究并了解它的工作原理。

67371ade46b80c5db0a69cb631452510.png
1*CZ3W153osigEQh1u09NFNQ.png

上图很容易理解,但简要总结一下:

1.应用程序永远不直接与数据库交互,而始终通过缓存进行。2.在缓存未命中时,缓存将从数据库中读取数据并丰富缓存存储。3.在缓存命中时,数据将从缓存中提供。

您可以看到,数据库很少被频繁访问,响应速度很快,因为缓存主要是内存中的(如Redis或Memcached)。已经解决了很多问题。

CDN

互联网上关于CDN的定义是:“内容传递网络(CDN)是一种全球分布的代理服务器网络,用于在离用户更近的位置提供内容,并用于提供静态文件,如图像、视频、HTML、CSS文件”。但我们将违反潮流,使用CDN提供动态内容(JSON响应,而不是JSON文件)。

此外,从概念上说,通常有两种CDN:

1.推送CDN(Push CDN):您负责将数据上传到CDN服务器。2.拉取CDN(Pull CDN):CDN将从您的服务器(源服务器)拉取数据。

我们将使用拉取CDN,因为使用推送方法,我必须处理重试、幂等性和其他内容,这对我来说是一个额外的麻烦,而且对于这个用例并没有真

正添加任何价值。

将CDN作为读取缓存

这个想法很简单,我们将CDN作为用户和实际后端服务之间的缓存层。如下图所示:

4e08e346123d63cb4e374521784ffc12.jpeg
1*fn-zmPouY7r3XoWS5c-mzQ.jpeg

正如您所看到的,CDN位于客户端和我们的后端服务之间,并成为缓存。数据流顺序如下:

2294f3260aad5737ee6daaa46093d6d6.png
1*4oGxf26V7E7MYAGKl4MtnA.png

让我们深入探讨一下,因为这是设计的精髓。

用于缩写的缩写

T1 -> 时间实例1 + 毫秒数•T2 -> 时间实例1 + 1分钟+某些毫秒数•TTL -> 存活时间•源服务器 -> 您实际的后端服务

1.T1:客户端请求获取user1。2.T1:请求着陆在CDN上。3.T1:CDN发现在其缓存存储中没有user1相关的键。4.T1:CDN到上游,即实际的后端服务,以获取user1。5.T1:后端服务返回user1作为标准的JSON响应。6.T1:CDN接收到JSON,现在它需要存储它。7.所以现在需要决定这个数据的TTL,它是如何做到的?8.通常有两种设置TTL的方式,要么源服务器指定数据应该被缓存多长时间,要么在CDN配置中设置了一个恒定值,它使用该时间来设置TTL。9.最好让源服务器控制TTL,这样我们有能力根据需要控制TTL或具有条件的TTL。10.那么问题就产生了,源服务器如何指定TTL。缓存控制头(Cache-Control headers)来拯救。来自源服务器的响应可以包含像 cache-control: public, max-age: 180 这样的缓存控制头。这将转化为该数据可以被公开缓存,有效期为180秒。11.T1:现在CDN看到这一点并使用180秒的TTL缓存了数据。12.T1:CDN向调用者响应user1 JSON。13.T2:另一个客户端请求user1。14.T2:请求着陆在CDN上。15.T2:CDN看到它的缓存中有user1键,因此不会到源服务器,而是返回缓存的JSON响应。16.T3:CDN在180秒后缓存失效。17.T4:某个客户端请求user1,但由于缓存为空,流程再次从第3步开始。这种情况一直重复。

不一定要将TTL设置为180秒。选择TTL是根据您能够提供过期数据多长时间以及是否接受它而选择的。如果这引发了一个问题,为什么不能在数据更改时使缓存失效,那么请稍等,我马上在缺点部分回答。

实施

cc73f35c860e26e62fe3c7658aedeea4.jpeg
1*vrlRYFpBKKy5IqDSbrUidA.jpeg

请求合并

但还有一个问题,CDN承担了所有负载,我们不必进行扩展。但我们的吞吐量达到了每秒60,000次查询,这意味着在缓存未命中的情况下,会有60,000个请求同时命中我们的源服务(假设需要1秒来填充CDN缓存),这可能会使服务不堪重负。

这就是请求合并的工作方式:

7e8e469803bcb95a523fd890395e2dda.jpeg
1*ze0WtYQVhFRtClZq0GEoVQ.jpeg

顾名思义,它基本上将具有相同查询参数的多个请求合并在一起,并将很少的请求发送到源服务器。

我们设计的美妙之处在于,我们不必自己执行请求合并,CDN将帮助我们执行。正如我已经提到的,我们使用的是Google Cloud CDN,它有请求合并的概念,这只是请求合并的另一种名称。因此,当在同一时间进行大量的缓存填充请求时,CDN会识别出这一点,每个CDN节点只发送一个请求到源服务器,然后从该响应中响应所有这些请求。这就是如何保护我们的源服务器免受高流量的影响。

好的,我们现在接近结束了,任何设计在没有经过利弊分析之前都是不完整的。因此,让我们稍微分析一下这个设计,看看它如何有所帮助,以及它的不足之处。

设计的优点

1.简单性: 这个设计非常简单,易于实现和维护。2.响应时间: 您已经知道CDN服务器的地理位置优化了数据传输,因此我们的响应时间也变得非常快。例如,忽略TCP连接建立时间,60毫秒听起来如何?3.减少负载: 由于实际的后端服务器现在只收到约每180秒1个请求,负载非常低。

设计的缺点

1.缓存失效: 缓存失效是计算机科学中最难正确执行的事情之一,而且由于CDN成为缓存,它变得更加困难。在CDN上的任意即兴的缓存失效是一个昂贵的过程,通常不会实时发生。如果数据发生更改,由于我们无法使CDN上的缓存失效,您的客户端可能会在一段时间内获得旧数据。但这又取决于您设置的TTL,如果TTL为几小时,那么您也可以在CDN上调用缓存失效。但如果TTL以秒/分钟为单位,这可能会有问题。此外,请记住,并非所有CDN提供商都提供API以使CDN缓存失效。2.控制较少: 由于请求现在不会着陆在我们的服务器上,因此会有这样一种感觉,即作为开发人员,您对系统没有足够的控制。可观察性可能会受到轻微影响,您可以在CDN上设置日志记录和监控,但这通常会带来一定的成本。

最后

在分布式世界中的任何设计都具有一定程度的主观性,并且总会有一些权衡。作为开发人员/架构师,我们的职责是权衡各种权衡,并选择适合我们的设计。说到这里,没有哪种设计足够具体以继续下去,因此鉴于约束条件,我们选择了一种设计,根据它的运作方式,我们可能会进一步演化它。

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

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

相关文章

JVM第十六讲:调试排错 - Java 线程分析之线程Dump分析

调试排错 - Java 线程分析之线程Dump分析 本文是JVM第十六讲,Java 线程分析之线程Dump分析。Thread Dump是非常有用的诊断Java应用问题的工具。 文章目录 调试排错 - Java 线程分析之线程Dump分析1、Thread Dump介绍1.1、什么是Thread Dump1.2、Thread Dump特点1.3、…

maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories

前言 略 说明 新设备上安装了mvn 3.8.5,编译新项目出错: [ERROR] Non-resolvable parent POM for com.admin.project:1.0: Could not transfer artifact com.extend.parent:pom:1.6.9 from/to maven-default-http-blocker (http://0.0.0.0/): Bl…

【LeetCode】 387. 字符串中的第一个唯一字符

题目链接 文章目录 所有方法 复杂度 ( O ( n ) O(n) O(n)、 O ( ∣ Σ ∣ ) O(|\Sigma|) O(∣Σ∣)) Python3方法一:collections.Counter() 统计频次方法二:哈希映射 { key字符:value【首次出现的索引 or -1 出现多次】}方法三: c…

账号合租平台源码Thinkphp6.1|内置详细搭建教程

小白账号合租平台说明 系统采用的是常见的租号平台模式,现在网络上流出的这种类型的源码还很少 平台介绍 1.租号模式,用户可自行选择单独租号或采用合租的模式。 2.支付,采用易支付通用接口 3.邀请返利,为了站长能更好推广推荐了邀请返利功能 4.用户提现功能 5.工单…

社会网络分析软件

UCINET UCINET 6 for Windows

vue3中弹框中的el-select下拉组件显示value而不显示label

1.场景 使用element-ui中的el-select&#xff0c;给选择框赋值时显示的值是value不是label 2.原因分析 3.解决方法 在点击编辑按钮后将获取到的对象中的os属性值改为string类型 <el-select v-model"form.os" clearable placeholder"请选择" style&qu…

【Java】正则表达式,校验数据格式的合法性。

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ 正则表达式 正则表达式&#xff1a; ①可以校…

互联网Java工程师面试题·Java 面试篇·第一弹

目录 1、Java 中能创建 volatile 数组吗&#xff1f; 2、volatile 能使得一个非原子操作变成原子操作吗&#xff1f; 3、volatile 修饰符的有过什么实践&#xff1f; 4、volatile 类型变量提供什么保证&#xff1f; 5、10 个线程和 2 个线程的同步代码&#xff0c;哪个更容…

MPI并行编程技术

MPI并行编程技术 MPI含义及环境搭建安装点对点通信阻塞型接口MPI_SendMPI_Recv 阻塞式示例tag雅可比迭代示例死锁 MPI含义及环境搭建安装 MPICH官网 Github地址 MPI历史版本下载地址 安装教程 MPI介绍 MPI课程 点对点通信 阻塞型接口 MPI_Send MPI_Recv 阻塞式示例 tag 雅…

贪心算法(1)--经典贪心算法

目录 一、活动安排问题 二、最优装载问题 三、分数背包问题 四、多机调度问题 一、活动安排问题 1、策略 活动安排问题&#xff1a;设有n个活动的集合E{1,2,...,n}&#xff0c;每个活动i都有一个使用该资源的起始时间和一个结束时间&#xff0c;且。如果选择了活动i则它在…

新年学新语言Go之五

一、前言 Go虽然不算是面向对象语言&#xff0c;但它支持面向对象一些特性&#xff0c;面向接口编程是Go一个很重要的特性&#xff0c;而Go的接口与Java的接口区别很大&#xff0c;Go的接口比较复杂&#xff0c;这里仅用一个最简单例子做介绍&#xff0c;复杂的我也还没学。 …

VMware中安装centos无网络,配置教程

VMware虚拟机中装了centos7,装完之后一直无法联网&#xff0c;网上的教程都试了也没用&#xff0c;这里记录一下最后的解决方案。 VMware配置 1. 点击 虚拟机-》设置 windows配置 打开电脑网络连接 共享选项选中我们虚拟机网络中包含的VMnet8的 VMnet8网络就自动变成这样了&a…

软件研发流程、架构规范、技术标准、需求过程等全文档

前言&#xff1a; 软件项目管理全文档包括以下几个方面&#xff1a;需求分析、项目规划、过程管理、测试和部署。 全文档获取&#xff1a;Q:262086839 例图在文末。 正文&#xff1a; 一、需求分析是软件项目管理的第一步&#xff0c;也是非常关键的一步。在需求分析阶段&…

SpringCloud 微服务全栈体系(二)

第三章 Eureka 注册中心 假如我们的服务提供者 user-service 部署了多个实例&#xff0c;如图&#xff1a; 思考几个问题&#xff1a; order-service 在发起远程调用的时候&#xff0c;该如何得知 user-service 实例的 ip 地址和端口&#xff1f;有多个 user-service 实例地址…

Xline 源码解读(四)—— CURP 状态机引擎

在上一篇源码解读的文章&#xff08;Xline 源码解读&#xff08;三&#xff09; —— CURP Server 的实现&#xff09;中&#xff0c;我们简单阐述了Xline 的 Curp Server 是如何实现的。接下来&#xff0c;就让我们话接上回&#xff0c;继续深入地来了解 Curp Server 中的一些…

网络安全中的人工智能:优点、缺点、机遇和危险

2022 年秋天&#xff0c;人工智能在商业领域爆发&#xff0c;引起了轰动&#xff0c;不久之后&#xff0c;似乎每个人都发现了 ChatGPT 和 DALL-E 等生成式 AI 系统的新的创新用途。世界各地的企业开始呼吁将其集成到他们的产品中&#xff0c;并寻找使用它来提高组织效率的方法…

Spring Cloud Gateway 路由构建器的源码分析

Spring Cloud Gateway 路由构建器的源码分析 文章目录 1. 路由构建器的入口2. 创建路由规则3. 设置路由规则和属性4. 路由过滤器的设置5. 构建和获取路由规则&#xff1a;6. 实例化路由构建器&#xff1a;8. 路由构建器的源码分析8.1 RouteLocator接口8.2 RouteLocatorBuilder…

漏刻有时地理信息系统LOCKGIS小程序配置说明(web-view组件、服务器域名配置、复制链接和转发功能)

漏刻有时地理信息系统说明文档(LOCKGIS、php后台管理、三端一体PC-H5-微信小程序、百度地图jsAPI二次开发、标注弹窗导航)漏刻有时地理信息系统LOCKGIS小程序配置说明(web-view组件、服务器域名配置、复制链接和转发功能)漏刻有时地理信息系统LOCKGIS主程序配置说明(地图调起弹…

【面试经典150 | 栈】有效的括号

文章目录 Tag题目来源题目解读解题思路方法一&#xff1a;栈哈希表 其他语言cpython3 写在最后 Tag 【栈】 题目来源 20. 有效的括号 题目解读 括号有三种类型&#xff0c;分别是小括号、中括号和大括号&#xff0c;每种括号的左右两半括号必须一一对应才是有效的括号&#…

react 中获取多个input输入框中的值的 俩种写法

目录 1. 使用受控组件 2. 使用非受控组件 1. 使用受控组件 这是React中最常见的方法&#xff0c;每个输入框都与React组件的state相关联&#xff0c;并通过onChange事件来更新state。 代码示例&#xff1a; import React, { Component } from react;class MultipleInputExam…