【架构】客户端优化

这篇文章总结一下服务器网关及之前部分的优化,如客户端的优化,CDN/DNS等。

这里我们先谈一谈客户端缓存优化的手段。一般我们后端在说到缓存,第一时间想到的往往是redis,其实缓存在架构层次还有很多其他可以实现的地方,如客户端缓存。对不同的场景,我们可以尝试不同的客户端优化手段。

1,资源下载

压缩资源:对资源进行压缩,如某些业务场景,不需要展示全像素的图片,可以图片压缩成缩略图,存储在文件系统中,前端需要时,将缩略图传输给前端进行展示,只有在必要时,才会将全像素的原图传输给前端。或者如我们在下载某些资源时,常常是zip格式,这也是对资源进行压缩的表现。

删除不必要的cookie:浏览器第一次访问服务器时,会生成一个session对象保存在服务器中,浏览器中保存sessionId作为查询用户信息的凭证[1,2],而浏览器在访问服务器时,将sessionid放在了cookie中。对于开发来说,有时候经常会随手携带上cookie。但其实对于接口不需要的session和cookie的,我们可以不用带上cookie,避免带宽的占用。

js删除无效字符和注释:这个的作用有两个,1是降低体积。2是为了代码安全,防止代码被轻易理解,进而对于服务器的恶意攻击。

css压缩:类似js压缩。1是删除注释,无效的字符、空格、回车。可以借助压缩网站进行压缩[3]。2是样式的语义合并

http请求压缩:head中加参数:Accept-Encoding:gzip,deflate,表示 客户端 可以接受的压缩内容的格式,客户端接收到数据后可以以这种格式进行解压;服务端响应时,在head中加参数: Content-Encoding:gzip,并在服务端手动做一些压缩的操作。

此外由于这种方式浏览器需要等待服务器将数据压缩完再发送给浏览器,等待时间长。因此往往配合transfer-encoding:chunked来使用,服务器将会把数据分块压缩并直接传输给浏览器,浏览器不用等待所有数据都压缩完再解压[4]。

将多个小图标合并为雪碧图(CSS Sprite, CSS精灵):如官网边缘常常显示多个小图标,这种小图标如果每个都单独请求接口,对于网络的压力会更大。可以使用这种叫做雪碧图[5,6]的技术,将多个小图标合并为雪碧图,可以减轻后端网络的压力。前端通过指定background-position来指定小图标坐标。

前端 < svg >生成矢量图代替后端直接传输矢量图图片:< svg >可以用于生成矢量图[7],这种生成的矢量图可以无限放大而不失真,同时后端也只用传输矢量图的数据而不是图片本身,减小了网络压力。

js文件合并打包:将多个js文件合并为一个文件,便于下载。

使用base64编码对图片进行转换后再压缩:如果图片不适用前面直接对图片压缩为缩略图的方式,可以使用这种方式,先使用base64将图片转换为字符串,再使用压缩算法对字符串进行压缩。客户端那里反向解压再转换回图片。如一篇文章[8]中举例,使用base64编码后,字符串大小和图片本身差不多大。再使用gzip压缩,压缩率可达50%以上。

转移第三方:将文件系统的压力转移给第三方,如阿里云OSS服务。

2,资源缓存优化

资源缓存是对资源下载的优化之一,但是客户端缓存的优化比较复杂,这里单独拆出来讲。通俗的说,资源缓存有客户端缓存/页面缓存,代理服务器缓存/CDN缓存,这些缓存并不是孤立存在,经常是同时存在的。此时需要前端与后端一起对缓存进行控制,如下所述。

客户端/页面缓存 & CDN/代理缓存[13]:控制 客户端、各级代理(中间的各个节点),对页面资源的缓存。请求头中添加Cache-Control,有些参数是客户端请求时添加的缓存请求指令,有些参数是服务端响应时添加的缓存响应指令,列举参数如下[13]:

缓存策略

//public和private是服务器做响应时添加的参数才能生效。
pubic(服务器 响应): 各级都能缓存。private(服务器 响应): 只能 客户端 缓存,中间各级不缓存,默认就是private。no-cache: (请求,响应):可以缓存,但是不能直接使用缓存,要去服务端验证一下(即缓存协商)。no-store: (请求,响应):哪都不要存。

缓存有效期

max-age=秒(服务器 响应),缓存可以存活的相对时间。s-maxage=秒(服务器 响应),在各级cache服务器(CDN,代理服务器[14])存活的时间,仅在为public缓存生效,如果是客户端缓存忽略。max-stale=秒(客户端 请求),可以忍受从代理服务器拿缓存资源过期的时间。min-fresh=秒(客户端 请求),需要的代理服务器缓存资源的新鲜度,即要求代理服务器的缓存资源至少要在过期时间之前min-fresh秒才可以使用和获取

重新验证和加载的设置

must-revalidate(服务器 响应)[15]: 资源过期后,服务器重新验证之前,不可以使用该资源。proxy-revalidate(服务器 响应): 作用与must-revalidate类似,但是仅对各级缓存节点有效,对客户端私有缓存无效。no-transform(服务器 响应): 不允许代理对资源格式如Content-EncodingContent-RangeContent-Type进行改变,因为如非透明代理或者如Google's Light Mode可能对图像格式进行转换,以便节省缓存空间或者减少缓慢链路上的流量。only-if-cached(客户端 请求): 只要各级代理服务器与CDN的资源,不要服务器的资源,也不需要检查服务器资源的更新。

使用缓存,就可能存在缓存导致的一致性问题。源站更新了缓存,CDN或者代理服务器如何保证一致性呢?

对于CDN,比如阿里云提供的CDN[16],提供了刷新功能。在调用CDN服务提供商的刷新API接口后,CDN会刷新缓存节点中的数据,大约五分钟左右生效,这段期间,会将请求路由给源站。

在这里插入图片描述
在这里插入图片描述
对于代理服务器,如nginx,ATS,则没有这么智能了。那它们如何解决一致性问题呢?

(1),更新文件名
更新的文件名可以根据版本号或url时间戳的变化而变化,如my.js,my-1.js。这种方案要求客户端和服务器要达成一致,那么客户端请求代理服务器时,查不到新名字的资源,就会被路由到源站进行资源的查询与资源刷新,旧名字的资源超时后被代理服务器删掉。

(2),协商缓存验证缓存有效性
前面讲过一个叫做缓存协商的策略(Cache-Control:no-cache),即查询到CDN/代理缓存后,不会直接返回客户端,而是去服务器验证有效性再返回客户端。

协商缓存主要有四个头字段,它们两两组合配合使用,Last-ModifiedIf-Modified-Since 一组验证修改时间,EtagIf-None-Match 一组验证版本号,当同时存在的时候会以 EtagIf-None-Match 为主。当命中协商缓存的时候,服务器会返回HTTP状态码304,让客户端直接从本地缓存里面读取文件[13],未命中协商缓存,会从服务器返回具体资源,状态码200。

修改时间:

If-Modified-Since:请求头,当前缓存资源最近修改时间,由浏览器告诉服务器。其实就是第一次访问服务端返回的Last-Modified的值。Last-Modified:响应头,服务器中资源最近修改时间,由服务器告诉浏览器。

版本号:

If-None-Match:请求头,缓存资源标识,由浏览器告诉服务器。其实就是第一次访问服务端返回的Etag的值。Etag:响应头,资源标识,由服务器告诉浏览器。

3,客户端连接优化

http长短连接:http1.0仅支持短链接,不支持长连接,而现在的http协议大多至少为http1.1协议是支持长连接的。需要注意的是,http协议是基于请求/响应模式的协议,不管是长连接还是短连接都是响应结束就关闭。http协议中的长短连接,是指的是否复用OSI七层模型中传输层的tcp协议[9],即http长连接中,请求响应结束后,一段时间内,tcp协议不会关闭,等待http协议复用tcp协议。而短连接则是每次都会三次握手建立新的tcp连接,并且再结束时四次挥手。

http1.1建立长连接,在请求头中加入Connection:keep-alive即可,Keep-Alive: timeout=60表示超时时间为60秒[10]。

长轮询与短轮询:准确得说,长轮询是服务端的一种模式。我们平时的服务端,收到客户端的请求,去查询数据,不管查到与否,会直接将响应返回。这个是短轮询,也就是轮询[11](客户端轮询查询服务器),这种方式实现简单,但是对于需要多次频繁请求的业务场景,往往会对服务器造成很大的压力。这时服务端可以使用长轮询[11],即服务端阻塞一段时间,在数据有变化了以后,再将数据返回给客户端,或者直到请求超时返回。在阻塞的这段期间,可以使用redis的pubsub订阅发布或者MQ来接收数据变化的通知。或者使用循环,阻塞指定时间后查询数据库,直到超时或有数据更新。

双工通信:对于客户端轮询服务端造成的网络开销问题,也可以使用Netty来实现一个websocket服务,websocket是一个基于tcp协议的双工通信协议[12],即可以客户端给服务端发信息,也可以服务端给客户端发信息。这里可以客户端每隔一段时间给客户端发请求,也可以服务端数据变化发给客户端。具体的要看业务。

双工通信与长轮询的区别在于,长轮询由服务器控制,而双工通信,客户端和服务端是平等的。相同点是都可以减小网络连接与销毁的开销。

4,优化加载顺序

懒加载:仅仅加载 最基础的元素,以后再根据用户的操作,进行局部加载。将原来一次性要加载的内容拆分成了多次加载,目的在于将数据进行分流,常见于h5/app界面、树形组件、折叠面板、标签页等。
使用时尽量灵活一些,支持多种情况。到了不得不看具体数据的时候,才调用后端。但是上述场景是否使用懒加载是不一定的,对于一些经常不变的数据,就没必要了,一切要以适合业务为准。

预加载

1.同一个域名下,

预加载拉取资源[17],

#告诉浏览器立即加载资源
<link rel="preload" href="xxxx.js" />
#告诉浏览器空闲时再加载资源
<link rel="prefetch" href="xxxx.js" />

如在一些小说网站的下一页会使用预加载,刚进入页面时下一页的页码是灰色的,过几秒变成了绿色的,代表此时预加载完成,可以提高用户的体验。

2,不同域名下,

打开浏览器的dns预解析[18],

<meta http-equiv="x-dns-prefetch-control" content="on">

设置dns解析目标

#使用不完整的url域名解析,这些域名前要加//[18]。
<link rel="dns-prefetch" href="//www.baidu.com">

预加载拉取资源[17],

#告诉浏览器立即加载资源
<link rel="preload" href="xxxx.js" />
#告诉浏览器空闲时再加载资源
<link rel="prefetch" href="xxxx.js" />

5,客户端数据库

pc客户端可以使用h5支持的html web sql数据库[19],安卓上可以使用sqlite数据库[20],pc浏览器上的web sql如下:

在这里插入图片描述
如在访问百度时,本地存储中存了一些永不过期的数据,会话存储存了一些生命周期为会话级的数据。借助web sql数据库,可以实现更多缓存和存储的操作,减小对于后端的访问量。

6,动静分离

前面讲了客户端缓存,CDN/代理服务器缓存,可能有人会讲,静态数据的缓存不少讲了么,为什么还要讲动静分离呢?这部分需要重申的就是,什么是静态数据,静态数据应该放在哪里?

什么是静态数据?
静态数据不仅包括 传统意义上的页面/图片等,也包括和访问者无关的非个性化数据。

如一篇新闻,假设其和用户推荐无关,那么这篇新闻就可以放入CDN中作为静态数据。

再比如,有时电商网站访问高峰期,猜你喜欢会关闭动态推荐,改为所有用户推荐一样的数据,那么这些数据也可以作为静态数据,放入CDN或代理服务器缓存中。

静态数据应该放在哪里?
放在离客户端最近的地方,包括不限于浏览器缓存、CDN、代理服务器缓存等。

要怎么做?
链接和数据做唯一kv映射,根据url可以直接从CDN获得一个静态数据。如果缓存到了客户端,甚至都不用发http请求了(如下面京东商城的图片)。特殊展示的元素做分离:尽可能的多做静态化。将页面中的cookie,与用户个性化相关的东西去掉。

举个例子,京东商城的产品详情页,如果url定义为www.xxx.com/getItem?itemId=1类似于这种,如此是把产品定义为动态数据,商品数据从后端数据库返回,图片数据要从文件系统服务器查询后返回,如此,商品数据+样式文件,渲染出最终的h5页面。

在业务允许的范围内,我们把如果我们把页面视为静态数据,那么用户可以直接访问h5的url。下面举例京东商城,就是直接把商品详情页链接和数据做映射,直接访问h5资源。
在这里插入图片描述

在这里插入图片描述

而图片是由代理服务器nginx处理返回的,X-Cache-Lookup通常为CDN添加,cache hit表示缓存命中[21]。

在这里插入图片描述
这种方式,最终的目的就是流量的分流,借助CDN和代理服务器,缓解了后端的压力。

先写这么多,后面有再补充。

参考文章:
[1],Session(会话)的三种创建方式
[2],一文讲透Token与Cookie、Session的区别
[3],性能优化: 资源合并与压缩 – 压缩(前端开发过程中 JavaScript、HTML、CSS 文件的压缩)
[4],HTTP 传输内容的压缩
[5],浅谈 CSS Sprites 雪碧图应用
[6],CSS Sprite(雪碧图)简单使用
[7],SVG 教程
[8],Base64详解:玩转图片Base64编码
[9],http的长连接和短连接(史上最通俗!)以及应用场景
[10],HTTP长连接、短连接使用及测试
[11],实现Web端即时通讯的方法:轮询(短轮询)、长轮询(comet)、长连接(SSE)、WebSocket
[12],什么是WebSocket (经常听别人讲感觉很高大上其实不然)
[13],彻底弄懂前端缓存
[14],缓存代理服务器的实现机制和技术选型
[15],Cache-Control
[16],刷新和预热资源
[17],预加载属性 preload 与 prefetch 区别
[18],meta标签属性x-dns-prefetch-control的含义
[19],HTML5 Web SQL 数据库
[20],SQLite 教程
[21],腾讯云 CDN 的 X-Cache-Lookup

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

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

相关文章

度言软件介绍

度言软件管理员操作后台 https://www.duyansoft.com企业后台为公司管理员操作后台&#xff0c;共计有七个功能版块 控制台 成员管理——员工管理 成员管理——员工管理&#xff08;添加员工&#xff09; 成员管理——团队管理 公司管理员可以新建/编辑/删除团队&#xff0c…

SSM整合快速学习

目录 步骤&#xff1a; 一、环境搭建 1.创建JdbcConfig配置类 2.创建JdbcConfig配置类 3.创建MybatisConfig配置类 4.创建jdbc.properties 5.创建SpringMVC配置类 6.创建Web项目入口配置类 二、功能模块开发 步骤1:创建数据库及表 步骤2:编写模型类 步骤3:编写Dao接…

Java面试题--JVM大厂篇之Java中Parallel GC的调优技巧与最佳实践

目录 引言&#xff1a; 正文&#xff1a; 1. 理解Parallel GC的工作原理 2. 常见痛点与解决方案 痛点一&#xff1a;长时间暂停 痛点二&#xff1a;频繁的Minor GC 痛点三&#xff1a;内存溢出 3. 调优参数推荐 4. 实战经验分享 结束语&#xff1a; 引言&#xff1a;…

定时任务-xxl-job

一. 为什么定时任务可以定时执行 定时任务可以定时执行的原理是通过操作系统提供的定时器实现的。 以下是定时任务能够准时执行的基本原理和相关技术&#xff1a; 操作系统的调度器&#xff1a; 操作系统&#xff08;如Linux、Windows等&#xff09;内部都有一个调度器&#x…

electron 配置、打包 -报错解决

目录 一、配置途中遇到的问题&#xff1a; 二、 make 配置好后开始打包 三、Electron-builder 打包报错 一、配置途中遇到的问题&#xff1a; 1. 安装 yarn add electron -D 一直卡在这里失败 一直卡可以使用下面这个&#xff0c;然后再重新装依赖 1. 采用新的镜像地址 npm …

机械学习—零基础学习日志(高数22——泰勒公式理解深化)

核心思想&#xff1a;函数逼近 在泰勒的年代&#xff0c;如果想算出e的0.001次方&#xff0c;这是很难计算的。那为了能计算这样的数字&#xff0c;可以尝试逼近的思想。 但是函数又不能所有地方都相等&#xff0c;那退而求其次&#xff0c;只要在一个极小的范围&#xff0c;…

Modbus-RTU详解

目录 Modbus-RTU协议 帧结构示例 CRC16校验算法 CRC16算法的过程 modbus-rtu的使用 发送数据 接收数据 tcp网口完整实现modbus-rtu协议 使用NModbus4实现modbus-rtu协议 安装NModbus4库。 串口实现NModbus4 Modbus-RTU协议 Modbus RTU 协议是一种开放的串行协议&#xff0c;广…

GroupMamba实战:使用GroupMamba实现图像分类任务(二)

文章目录 训练部分导入项目使用的库设置随机因子设置全局参数图像预处理与增强读取数据设置Loss设置模型设置优化器和学习率调整策略设置混合精度&#xff0c;DP多卡&#xff0c;EMA定义训练和验证函数训练函数验证函数调用训练和验证方法 运行以及结果查看测试完整的代码 在上…

26集 ESP32 AIchat启动代码分析-《MCU嵌入式AI开发笔记》

26集 ESP32 AIchat启动代码分析-《MCU嵌入式AI开发笔记》 这集我们分析代码如何组织起来&#xff0c;如何编译 先用sourceinsight把代码加进工程。 新建一个sourceinsight工程&#xff0c;把AI-CHAT代码加进来&#xff0c;之后把ESP IDF代码加进来&#xff0c;之后把ESP-ADF加…

大语言模型(LLM)文本预处理实战

大语言模型&#xff08;LLM&#xff09;文本预处理实战 文章目录 大语言模型&#xff08;LLM&#xff09;文本预处理实战2.1 理解词嵌入2.2 文本分词2.3 将 token 转换为 token ID2.4 添加特殊上下文 token2.5 字节对编码 (BytePair Encoding, BPE)2.6 使用滑动窗口进行数据采样…

sql注入部分总结和复现

一个端口对应一个服务 联合查询注入 所有的程序中&#xff0c;单双引号必须成对出现 需要从这个引号里面逃出来 在后面查询内容 ?id1 要查库名&#xff0c;表名&#xff0c;列名。但是联合查询要知道有多少列&#xff0c;所以通过order by 去查询 order by # 通过二分法…

Cartopy简介和安装

Cartopy 是一个开源免费的第三方 Python 扩展包&#xff0c;由英国气象办公室的科学家们开发&#xff0c;支持 Python 2.7 和 Python 3&#xff0c;致力于使用最简单直观的方式生成地图&#xff0c;并提供对 matplotlib 友好的协作接口。初学Cartopy&#xff0c;欢迎指正&#…

算法回忆录(3)

11. 假设有7个物品&#xff0c;它们的重量和价值如下表所示。若这些物品均不能被分割&#xff0c;且背包容量M&#xff1d;150&#xff0c;设计算法求解怎么装才能使得获取的价值最大&#xff1f;请写出伪代码。 #include <stdio.h>#define MAX_ITEMS 100 #define …

新手小白嵌入式单片机教程,ESP32

1.什么是ESP32。 ESP32是一款由乐鑫信息科技&#xff08;Espressif Systems&#xff09;推出的高度集成的低功耗系统级芯片&#xff08;SoC&#xff09;&#xff0c;它结合了双核处理器、无线通信、低功耗特性和丰富的外设&#xff0c;特别适用于各种物联网&#xff08;IoT&am…

Robot Operating System——深度解析单线程执行器(SingleThreadedExecutor)执行逻辑

大纲 创建SingleThreadedExecutor新增Nodeadd_nodetrigger_entity_recollectcollect_entities 自旋等待get_next_executablewait_for_workget_next_ready_executableTimerSubscriptionServiceClientWaitableAnyExecutable execute_any_executable 参考资料 在ROS2中&#xff0c…

python 爬虫入门实战——爬取维基百科“百科全书”词条页面内链

1. 简述 本次爬取维基百科“百科全书”词条页面内链&#xff0c;仅发送一次请求&#xff0c;获取一个 html 页面&#xff0c;同时不包含应对反爬虫的知识&#xff0c;仅包含最基础的网页爬取、数据清洗、存储为 csv 文件。 爬取网址 url 为 “https://zh.wikipedia.org/wiki/…

数据结构:基于顺序表实现通讯录系统(含源码)

目录 一、前言 二、各个功能的实现 2.1 初始化通讯录 2.2 添加通讯录数据 2.3 查找通讯录数据 2.4 删除通讯录数据 2.5 修改通讯录数据 2.6 展示通讯录数据​编辑 2.7 销毁通讯录数据 三、添加菜单和测试 四、完整源码 sxb.h sxb.c contact.h contact.c test.c 一、前…

【隐私计算篇】混淆电路之深入浅出

入门隐私计算的阶段&#xff0c;一般都会涉及对于混淆电路的学习&#xff0c;这是因为混淆电路是多方安全计算中的基础密码原语&#xff0c;也是隐私保护中重要的技术。为了帮助更好地理解混淆电路的原理&#xff0c;今天对其进行原理以及相关优化手段进行解析和分享。 1. 混淆…

不同角色路由权限配置(六)

一、启用方式 配置开启config/config.ts。同时需要 src/access.ts 提供权限配置 export default {access: {},// access 插件依赖 initial State 所以需要同时开启initialState: {}, };这里以扩展的路由配置为例&#xff0c;配置只有admin权限才能查看的页面 1、在src/acces…

前端web开发HTML+CSS3+移动web(0基础,超详细)——第3天

目录 一&#xff0c;列表-无序和有序的定义列表 二&#xff0c;表格-基本使用与表格结构标签 三&#xff0c;合并单元格 四&#xff0c;表单-input标签 五&#xff0c;表单-下拉菜单 六&#xff0c;表单-文本域 七&#xff0c;表单-label标签 八&#xff0c;表单-按钮 …