Java多级缓存是为了解决什么的?
前言
提到缓存,想必每一位软件工程师都不陌生,它是目前架构设计中提高性能最直接的方式。
缓存技术存在于应用场景的方方面面。从网站提高性能的角度分析,缓存可以放在浏览器,可以放在反向代理服务器,还可以放在应用程序进程内,同时可以放在分布式缓存系统中。
从用户请求数据到数据返回,数据经过了浏览器,CDN,Nginx代理缓存,应用服务器,以及数据库各个环节。每个环节都可以运用缓存技术。
缓存的请求顺序是:用户请求 → HTTP 缓存 → CDN 缓存 → Nginx代理缓存 → 进程内缓存 → 分布式缓存。
在技术的架构每个环节都可以加入缓存,我们看看每个环节是如何应用缓存技术的。
2. HTTP缓存
通常 HTTP 缓存策略分为两种:
- 强缓存
- 协商缓存。
从字面意思我们可以很直观的看到它们的差别:
- 强缓存即强制直接使用缓存。
- 协商缓存就得和服务器协商确认下这个缓存能不能用。
强缓存
强缓存不会向服务器发送请求,直接从缓存中读取资源,在 chrome 控制台的 network 选项中可以看到该请求返回 200 的状态码,并且size
显示from disk cache
或from memory cache
;
协商缓存
协商缓存会先向服务器发送一个请求,服务器会根据这个请求的 request header 的一些参数来判断是否命中协商缓存,如果命中,则返回 304 状态码并带上新的 response header 通知浏览器从缓存中读取资源。
2.1 HTTP 缓存控制
在 HTTP 中,我们可以通过设置响应头以及请求头来控制缓存策略。
强缓存可以通过设置Expires
和Cache-Control
两种响应头实现。如果同时存在,Cache-Control
优先级高于Expires
。
Expires
Expires 响应头,它是 HTTP/1.0 的产物。代表该资源的过期时间,其值为一个绝对时间。它告诉浏览器在过期时间之前可以直接从浏览器缓存中存取数据。由于是个绝对时间,客户端与服务端的时间时差或误差等因素可能造成客户端与服务端的时间不一致,将导致缓存命中的误差。如果在Cache-Control
响应头设置了 max-age
或者 s-max-age
指令,那么 Expires
会被忽略。
Expires: Wed, 21 Oct 2015 07:28:00 GMT
Cache-Control
Cache-Control
出现于 HTTP/1.1。可以通过指定多个指令来实现缓存机制。主要用表示资源缓存的最大有效时间。即在该时间端内,客户端不需要向服务器发送请求。优先级高于 Expires。其过期时间指令的值是相对时间,它解决了绝对时间的带来的问题。
Cache-Control: max-age=315360000
Cache-Control
有很多属性,不同的属性代表的意义也不同。
可缓存性
- public
表明响应可以被任何对象(包括:发送请求的客户端,代理服务器,等等)缓存。
- private
表明响应只能被单个用户缓存,不能作为共享缓存(即代理服务器不能缓存它)
- no-cache
不使用强缓存,需要与服务器验协商缓存验证。
- no-store
缓存不应存储有关客户端请求或服务器响应的任何内容,即不使用任何缓存。
过期
- max-age=
缓存存储的最大周期,超过这个周期被认为过期。
- s-maxage=
设置共享缓存。会覆盖max-age
和expires
,私有缓存会忽略它
- max-stale[=]
客户端愿意接收一个已经过期的资源,可以设置一个可选的秒数,表示响应不能已经过时超过该给定的时间。
- min-fresh=
客户端希望在指定的时间内获取最新的响应
重新验证和重新加载
- must-revalidate
如页面过期,则去服务器进行获取。
- proxy-revalidate
与must-revalidate
作用相同,但是用于共享缓存。
其他
- only-if-cached
不进行网络请求,完全只使用缓存。
- no-transform
不得对资源进行转换和转变。例如,不得对图像格式进行转换。
协商缓存可以通过 Last-Modified
/If-Modified-Since
和ETag
/If-None-Match
这两对 Header 来控制。
2.2 Last-Modified、If-Modified-Since
Last-Modified
与If-Modified-Since
的值都是 GMT 格式的时间字符串,代表的是文件的最后修改时间。
1.在服务器在响应请求时,会通过Last-Modified
告诉浏览器资源的最后修改时间。
2. 浏览器再次请求服务器的时候,请求头会包含Last-Modified
字段,后面跟着在缓存中获得的最后修改时间。
3. 服务端收到此请求头发现有if-Modified-Since
,则与被请求资源的最后修改时间进行对比,如果一致则返回 304 和响应报文头,浏览器只需要从缓存中获取信息即可。如果已经修改,那么开始传输响应一个整体,服务器返回:200 OK
<img src="images/image-20220718222822409.png" alt="image-20220718222822409" style="zoom:80%;" />
但是在服务器上经常会出现这种情况,一个资源被修改了,但其实际内容根本没发生改变,会因为Last-Modified
时间匹配不上而返回了整个实体给客户端(即使客户端缓存里有个一模一样的资源)。为了解决这个问题,HTTP/1.1 推出了Etag
。Etag 优先级高与Last-Modified
。
2.3 Etag、If-None-Match
Etag
都是服务器为每份资源生成的唯一标识,就像一个指纹,资源变化都会导致 ETag 变化,跟最后修改时间没有关系,ETag
可以保证每一个资源是唯一的。
在浏览器发起请求,浏览器的请求报文头会包含 If-None-Match
字段,其值为上次返回的Etag
发送给服务器,服务器接收到次报文后发现 If-None-Match
则与被请求资源的唯一标识进行对比。如果相同说明资源没有修改,则响应返 304,浏览器直接从缓存中获取数据信息。如果不同则说明资源被改动过,则响应整个资源内容,返回状态码 200。
3. CDN缓存
CDN:Content Delivery Network,即内容分发网络,它是构建在现有网络基础上的虚拟智能网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、调度及内容分发等功能模块,使用户在请求所需访问的内容时能够就近获取,以此来降低网络拥塞,提高资源对用户的响应速度。
本地存储和浏览器缓存带来的性能提升主要针对的是浏览器端已经缓存了所需的资源,当发生二次请求相同资源时便能够进行快速响应,避免重新发起请求或重新下载全部响应资源。
这些方法对于首次资源请求的性能提升是无能为力的,若想提升首次请求资源的响应速度,除了资源压缩、图片优化等方式,还可借助CDN技术。
3.1 使用CDN网络资源获取过程
如果使用了CDN网络,则资源获取的大致过程是这样的。
1.由于DNS服务器将对CDN的域名解析权交给了CNAME指向的专用DNS服务器,所以对用户输入域名的解析最终是在CDN专用的DNS服务器上完成的。
2. 解析出的结果IP地址并非确定的CDN缓存服务器地址,而是CDN的负载均衡器的地址。
3. 浏览器会重新向该负载均衡器发起请求,经过对用户IP地址的距离、所请求资源内容的位置及各个服务器复杂状况的综合计算,返回给用户确定的缓存服务器IP地址。
4. 对目标缓存服务器请求所需资源的过程。
这个过程也可能会发生所需资源未找到的情况,那么此时便会依次向其上一级缓存服务器继续请求查询,直至追溯到网站的根服务器并将资源拉取到本地。
3.2 CDN网络的核心功能包括两点:
缓存与回源
缓存指的是将所需的静态资源文件复制一份到CDN缓存服务器上;
回源指的是如果未在CDN缓存服务器上查找到目标资源,或CDN缓存服务器上的缓存资源已经过期,则重新追溯到网站根服务器获取相关资源的过程。
4. Nginx代理缓存
用户请求在达到应用服务器之前,会先访问 Nginx 负载均衡器,如果发现有缓存信息,直接返回给用户。
如果没有发现缓存信息,Nginx 回源到应用服务器获取信息。
另外,有一个缓存更新服务,定期把应用服务器中相对稳定的信息更新到 Nginx 本地缓存中。
Nginx设置缓存有两种方式:
- proxy_cache_path和proxy_cache
- Cache-Control和Pragma
对于站点中不经常修改的静态内容(如图片,JS,CSS),可以在服务器中设置expires过期时间,控制浏览器缓存,达到有效减小带宽流量,降低服务器压力的目的。
<img src="images/image-20220718224542963.png" alt="image-20220718224542963" style="zoom: 67%;" />
第一步:客户端第一次向Nginx请求数据A;
第二步:当Nginx发现缓存中没有数据A时,会向服务端请求数据A;
第三步:服务端接收到Nginx发来的请求,则返回数据A到Nginx,并且缓存在Nginx;
第四步:Nginx返回数据A给客户端应用;
第五步:客户端第二次向Nginx请求数据A;
第六步:当Nginx发现缓存中存在数据A时,则不会请求服务端;
第七步:Nginx把缓存中的数据A返回给客户端应用。
默认情况下,NGINX尊重Cache-Control源服务器的标头。它不缓存响应Cache-Control设置为Private,No-Cache或No-Store或Set-Cookie在响应头。NGINX只缓存GET和HEAD客户端请求。
如下配置可覆盖这些默认值:
- proxy_buffering默认为on,若proxy_buffering设置为off,则NGINX不会缓存响应。
- proxy_ignore_headers可以配置忽略Cache-Control:
location /images/ {proxy_cache my_cache;proxy_ignore_headers Cache-Control;proxy_cache_valid any 30m;# ...
}
5. 进程缓存
通过了客户端,CDN,Nginx代理缓存,我们终于来到了应用服务器。应用服务器上部署着一个个应用,这些应用以进程的方式运行着,那么在进程中的缓存是怎样的呢?
进程内缓存又叫托管堆缓存,以 Java 为例,这部分缓存放在 JVM 的托管堆上面,同时会受到托管堆回收算法的影响。
由于其运行在内存中,对数据的响应速度很快,通常我们会把热点数据放在这里。
在进程内缓存没有命中的时候,我们会去搜索进程外的缓存或者分布式缓存。这种缓存的好处是没有序列化和反序列化,是最快的缓存。缺点是缓存的空间不能太大,对垃圾回收器的性能有影响。
目前比较流行的实现有 Ehcache、GuavaCache、Caffeine。这些架构可以很方便的把一些热点数据放到进程内的缓存中。
这里我们需要关注几个缓存的回收策略,具体的实现架构的回收策略会有所不同,但大致的思路都是一致的:
- FIFO(First In First Out):先进先出算法,最先放入缓存的数据最先被移除。
- LRU(Least Recently Used):最近最少使用算法,把最久没有使用过的数据移除缓存。
- LFU(Least Frequently Used):最不常用算法,在一段时间内使用频率最小的数据被移除缓存。
在分布式架构的今天,多应用中如果采用进程内缓存会存在数据一致性的问题。
这里推荐两个方案:
- 消息队列方案
应用在修改完自身缓存数据和数据库数据之后,给消息队列发送数据变化通知,其他应用订阅了消息通知,在收到通知的时候修改缓存数据。
- 定时任务修改方案
为了避免耦合,降低复杂性,对“实时一致性”不敏感的情况下。每个应用都会启动一个定时任务,定时从数据库拉取最新的数据,更新缓存。
进程内缓存有哪些使用场景呢?
- 场景一:只读数据,可以考虑在进程启动时加载到内存。当然,把数据加载到类似 Redis 这样的进程外缓存服务也能解决这类问题。
- 场景二:高并发,可以考虑使用进程内缓存,例如:秒杀。
6. 分布式缓存
说完进程内缓存,自然就过度到进程外缓存了。
与进程内缓存不同,进程外缓存在应用运行的进程之外,它拥有更大的缓存容量,并且可以部署到不同的物理节点,通常会用分布式缓存的方式实现。
分布式缓存是与应用分离的缓存服务,最大的特点是,自身是一个独立的应用/服务,与本地应用隔离,多个应用可直接共享一个或者多个缓存应用/服务。
为了提高缓存的可用性,会在原有的缓存节点上加入 Master/Slave 的设计。当缓存数据写入 Master 节点的时候,会同时同步一份到 Slave 节点。
一旦 Master 节点失效,可以通过代理直接切换到 Slave 节点,这时 Slave 节点就变成了 Master 节点,保证缓存的正常工作。
每个缓存节点还会提供缓存过期的机制,并且会把缓存内容定期以快照的方式保存到文件上,方便缓存崩溃之后启动预热加载。
6.1 缓存雪崩
当缓存失效,缓存过期被清除,缓存更新的时候。请求是无法命中缓存的,这个时候请求会直接回源到数据库。
如果上述情况频繁发生或者同时发生的时候,就会造成大面积的请求直接到数据库,造成数据库访问瓶颈。我们称这种情况为缓存雪崩。
从如下两方面来思考解决方案:
缓存方面:
- 避免缓存同时失效,不同的 key 设置不同的超时时间。
- 增加互斥锁,对缓存的更新操作进行加锁保护,保证只有一个线程进行缓存更新。缓存一旦失效可以通过缓存快照的方式迅速重建缓存。对缓存节点增加主备机制,当主缓存失效以后切换到备用缓存继续工作。
设计方面,这里给出了几点建议供大家参考:
- 熔断机制:某个缓存节点不能工作的时候,需要通知缓存代理不要把请求路由到该节点,减少用户等待和请求时长。
- 限流机制:在接入层和代理层可以做限流,当缓存服务无法支持高并发的时候,前端可以把无法响应的请求放入到队列或者丢弃。
- 隔离机制:缓存无法提供服务或者正在预热重建的时候,把该请求放入队列中,这样该请求因为被隔离就不会被路由到其他的缓存节点。
- 如此就不会因为这个节点的问题影响到其他节点。当缓存重建以后,再从队列中取出请求依次处理。
62. 缓存穿透
缓存一般是 Key,Value 方式存在,一个 Key 对应的 Value 不存在时,请求会回源到数据库。
假如对应的 Value 一直不存在,则会频繁的请求数据库,对数据库造成访问压力。如果有人利用这个漏洞攻击,就麻烦了。
解决方法:如果一个 Key 对应的 Value 查询返回为空,我们仍然把这个空结果缓存起来,如果这个值没有变化下次查询就不会请求数据库了。
将所有可能存在的数据哈希到一个足够大的 Bitmap 中,那么不存在的数据会被这个 Bitmap 过滤器拦截掉,避免对数据库的查询压力。
6.3 缓存击穿
在数据请求的时候,某一个缓存刚好失效或者正在写入缓存,同时这个缓存数据可能会在这个时间点被超高并发请求,成为“热点”数据。
这就是缓存击穿问题,这个和缓存雪崩的区别在于,这里是针对某一个缓存,前者是针对多个缓存。
解决方案:导致问题的原因是在同一时间读/写缓存,所以只有保证同一时间只有一个线程写,写完成以后,其他的请求再使用缓存就可以了。
比较常用的做法是使用 mutex(互斥锁)。在缓存失效的时候,不是立即写入缓存,而是先设置一个 mutex(互斥锁)。当缓存被写入完成以后,再放开这个锁让请求进行访问。
Java最新课程:
Java零基础视频教程(2022最新Java入门,含斯坦福大学练习题+力扣算法题
Java基础入门:
java零基础自学首Java入门教程(含Java项目和Java真题)
Javaweb核心基础
JavaWeb基础教程,Java web从入门到企业实战完整版
Spring Cloud最全微服务架构:
史上最全面的springcloud微服务技术栈
SSM框架教程:
SSM框架教程_Spring+SpringMVC+Maven高级+Spring
SpringBoot2全套视频教程:
SpringBoot2全套视频教程,springboot零基础到项目实战
相关文章:
Java多级缓存是为了解决什么的?
前言 提到缓存,想必每一位软件工程师都不陌生,它是目前架构设计中提高性能最直接的方式。 缓存技术存在于应用场景的方方面面。从网站提高性能的角度分析,缓存可以放在浏览器,可以放在反向代理服务器,还可以放…...
MongoDB--》索引的了解及具体操作
目录 索引—index 索引的类型 索引的管理操作 索引的使用 索引—index 使用索引的原因:索引支持在MongoDB中高效地执行查询。如果没有索引,MongoDB必须执行全集合扫描,即扫描集合中的每个文档,以选择与查询语句匹配的文档。这…...
Python open()函数详解:打开指定文件
在 Python 中,如果想要操作文件,首先需要创建或者打开指定的文件,并创建一个文件对象,而这些工作可以通过内置的 open() 函数实现。open() 函数用于创建或打开指定文件,该函数的常用语法格式如下:file ope…...
CentOS Stream 9尝鲜安装教程
作者:IT圈黎俊杰 一、下载CentOS Stream 9安装介质 在CentOS官网可以下载到CentOS Stream 9的安装介质,正面列出ISO介质的下载链接地址: https://download.cf.centos.org/9-stream/BaseOS/x86_64/iso/CentOS-Stream-9-20221019.0-x86_64-dv…...
Ambire AdEx 2023 年路线图
Ambire AdEx 是为简化 web3 显示广告而建立的,领先于时代。到 2023 年,它将专注于服务用户需求,同时保持其作为区块链隐私解决方案的核心,反对传统的数字广告模式。 回顾 2022 年 2022 年,AdEx 网络处理了超过 1 亿次展…...
两种特征提取方法与深度学习方法对比的小型金属物体分类分析研究
本文讨论了用于对包括螺丝、螺母、钥匙和硬币在内的小型金属物体进行分类的两种特征提取方法的效率:定向梯度直方图 (HOG) 和局部二进制模式 (LBP)。首先提取标记图像的所需特征并以特征矩阵的形式保存。使用三种不同的分类方法(非参数 K 最近邻算法、支…...
传奇私服搭建网站的几种方法
搭建网站的几种方法:一些人,连简单的搭建网站都不会,还要请技术帮忙,真是牛B,这里简单介绍下几种办法一:2003系统下,直接使用IIS,这个太简单了,桌面上就有IIS,…...
i.MX8MP平台开发分享(clock篇)- 各类clock的注册
专栏目录:专栏目录传送门 平台内核i.MX8MP5.15.71文章目录 1、关键数据结构1.1 clk_hw1.2 clk_hw_onecell_data2.一个clk的注册过程2.1 fixed clk2.2 pll14xx2.3 fixed factor2.4 mux2.5 composite2.6 gate1、关键数据结构 1.1 clk_hw clk_hw是描述一个时钟信息的最小单元。…...
java ssm计算机系统在线考试平台idea
本系统主要包括以下功能模块学生、教师、班级、考试评阅、在线考试、试题内容、考试等模块,通过这些模块的实现能够基本满足日常计算机系统平台的操作。 本文着重阐述了计算机系统平台的分析、设计与实现,首先介绍开发系统和环境配置、数据库的设计&…...
C语言(字符串函数)
这章的内容记得引用<string.h>头文件 目录 1.strlen() 2.strcat() 3.strncat() 4.strcmp() 5.strncmp() 6.strcpy() 7.strncpy() 8.sprintf() 8.strchr() 9.strpbrk() 10.strrchr() 11.strstr() 1.strlen() 用于统计字符串的…...
Maxwell工作流程详解
要介绍maxwell的工作原理,首先需要讲一下mysql主从复制的原理 mysql主从复制原理: 如上图,左边是master主节点,右边是slave从节点 工作流程: 1.往主节点mysql的数据库中写入数据,产生数据变化,…...
13- EM算法与GMM高斯混合 (聚类算法) (算法)
最大期望算法(EM算法) ,曾入选“数据挖掘十大算法”中,是最常见的隐变量估计方法,在机器学习中有极为广泛的用途,例如常被用来学习高斯混合模型的参数。EM算法是在概率模型中寻找参数最大似然估计或者最大后验估计的算法ÿ…...
【新】华为OD机试 - 二叉树层次遍历(Python)| 刷完获取OD招聘渠道
二叉树层次遍历 题目 有一棵二叉树 每一个节点用一个大写字母标识 最多26个节点 现有两组字母 分别表示后序遍历(左孩子指向右孩子指向父节点) 和中序遍历(左孩子指向父节点指向右孩子) 请输出层次遍历的结果 输入 输入为两个字符串 分别为二叉树的后序遍历和中序遍历结…...
工作记录------@Accessors(chain = true)引起的BUG,Excel导入时获取不到值
工作记录------Accessors(chain true)引起的BUG,Excel导入时获取不到值 如题所示 背景:在进行文件excel文件导入时,发现实体类获取到的属性值都为null。 框架:com.alibaba.excel 2.2.0的版本。 结论:首先说下结论 如…...
JavaEE-HTTP协议(二)
目录HTTP请求的方法GET方法POST 方法其他方法“报头”User-AgentRefererCookieHTTP响应200 OK404 Not Found403 Forbidden405 Method Not Allowed500 Internal Server Error504 Gateway Timeout302 Move temporarily301 Moved PermanentlyHTTP请求的方法 GET方法 GET 是最常用…...
代理的基本原理和多线程的基本原理
目录爬虫代理常见代理多线程并发和并行Python中的多进程和多线程爬虫时我们不到一杯茶的功夫就出现了403.打开网页一看会说您的IP访问频率太高,出现这种情况是因为网站采取了一些反爬虫措施,限制某个IP在一定时间内的请求次数,如果超过一定的…...
T38,数的递归
描述 输入一棵节点数为 n 二叉树,判断该二叉树是否是平衡二叉树。 在这里,我们只需要考虑其平衡性,不需要考虑其是不是排序二叉树 平衡二叉树(Balanced Binary Tree),具有以下性质:它是一棵空…...
QT+ OpenGL 变换
文章目录QT OpenGL变换向量的运算矩阵矩阵与向量相乘代码实现QT OpenGL 本篇完整工程见gitee:QTOpenGL 对应点的tag,由turbolove提供技术支持,您可以关注博主或者私信博主。 变换 我们需要改变物体的位置 现有解决办法(每一帧,…...
【算法】前缀和
作者:指针不指南吗 专栏:算法篇 🐾要学会在纸上打草稿,这个很重要🐾 文章目录1.什么是前缀和?2.怎么求前缀和?3.前缀和有什么用?4.进阶二维:矩阵和前缀和 主打一个记公式 1.什么是前…...
《Redis实战篇》七、Redis消息队列
7.1 Redis消息队列-认识消息队列 什么是消息队列:字面意思就是存放消息的队列。最简单的消息队列模型包括3个角色: 消息队列:存储和管理消息,也被称为消息代理(Message Broker)生产者:发送消息…...
android组件化
学习流程:1.开源最佳实践:Android平台页面路由框架ARouter-阿里云开发者社区 (aliyun.com)2.中文ARouter使用API:https://github.com/alibaba/ARouter/blob/master/README_CN.md3.看当前文档后面的代码4.这是通俗易懂的文章:https…...
华为OD机试真题Python实现【特异性双端队列】真题+解题思路+代码(20222023)
🔥系列专栏 华为OD机试(Python)真题目录汇总华为OD机试(JAVA)真题目录汇总华为OD机试(C++)真题目录汇总华为OD机试(JavaScript)真题目录汇总文章目录 🔥系列专栏题目输入输出示例一输入输出解题思路核心知识点Python 代码实现代码运行结果版权说明<...
24.架构能力
文章目录24. 架构能力24.1 Competence of Individuals: Duties, Skills, and Knowledge of Architects 个人能力:架构师的职责、技能和知识24.2 Competence of a Software Architecture Organization 软件架构组织的能力24.3 Summary 小结24.4 For Further Reading …...
前端原生 CSS 跑马灯效果,无限轮播(横竖版本,带渐变遮罩,简单实用)
一、横版跑马灯 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevice-wid…...
4.8 注解与自定义注解
文章目录1.概述2.注解的分类2.1 JDK注解2.2 元注解2.2.1 Target ElementType…2.2.2 Retention RetentionPolicy…3 自定义注解1.概述 在注解刚出现时,曾受到过好多程序员的鄙夷,觉得这就是多此一举的操作; 但随着时间的推移,越…...
webpack 的热更新是如何做到的?原理是什么?
Hot Module Replacement,简称 HMR,在不需要刷新整个页面的同时更新模块,能够提升开发的效率和体验。热更新时只会局部刷新页面上发生了变化的模块,同时可以保留当前页面的状态,比如复选框的选中状态等。 在 webpack 中…...
嵌入式ARM设计编程(一) 简单数据搬移
文章和代码已归档至【Github仓库:hardware-tutorial】,需要的朋友们自取。或者公众号【AIShareLab】回复 嵌入式 也可获取。 一、实验目的 熟悉实验开发环境,掌握简单ARM汇编指令的使用方法。 二、实验环境 硬件:PC机 软件&am…...
【Selenium】十分钟手把手带你学会WebDriver API
目录 1、定位元素【8种】 2、操作测试对象 3、添加等待 4、弹窗类型 5、浏览器的操作 6、键盘事件 7、选择框 8、上传文件 1、定位元素【8种】 元素定位是自动化测试的核心,想要去操作一个对象,第一步就是需要我们先去识别这个对象。每个对象就会…...
3DMAX高级弯曲插件使用教程
3dMax高级弯曲插件是对3dmax原生“弯曲(Bend)”修改器的一个增强,给用户更多控制弯曲修改器的参数设置,它让用户输入宽度,插件脚本将移动中心以获得正确的宽度。 主要特性: - 使用智能捕捉捕捉到自定义网格…...
前端面试题之性能优化大杂烩
主要内容为下面几大类:移动端、图片、JavaScript、css、html、页面内容、服务器、cookie。 移动端性能优化: 保持单个文件小于25KB 移动网站页面要求下载资源,如果文件过大,会大大减慢页面加载速度。 打包内容为分段multipart文…...
品牌设计得公司/seo引擎优化外包公司
转自 https://blog.csdn.net/ethercat_i7/article/details/77479316 在DC同步模式下,Ethercat主站能否在规定的时间内发送过程数据帧,是影响整个系统性能的关键因素,本文介绍如何使用Wireshark抓取总线上的Ethercat数据包,并将主…...
学校ftp服务器做网站/百度入口网站
近期,国内知名产业数字化研究咨询机构爱分析,公布了《2021爱分析云计算厂商全景报告》。ZStack入选了该报告私有云类别并成为重点调研对象,ZStack的云计算“硬实力”再度受到权威专家与用户的高度认可。 数字化推动生产力发展已经是当下时代大…...
可视化拖拽网站建设软件/潍坊网站开发公司
MySQL提供循环语句,允许我们根据条件重复执行一个SQL代码块其中有三个循环语句:WHILE,REPEAT和LOOP,我们接下来分别看下。首先是WHILE语句来看下语法:WHILE expression DOstatements END WHILEWHILE循环在每次迭代开始…...
克拉玛依市建设局官方网站/百度平台推广
GROUP BY GROUP BY语句用来与聚合函数(aggregate functions such as COUNT, SUM, AVG, MIN, or MAX.)联合使用来得到一个或多个列的结果集。 语法如下: SELECT column1, column2, ... column_n, aggregate_function (expression) FROM tables …...
哪里可以免费做网站/神马站长平台
题意:就是一个快速排序,理解快速排序就没啥了; 代码: #include <stdio.h>void swap(int a[], int i, int j) {int t a[i];a[i] a[j];a[j] t; }int partition(int a[], int p, int r) {int i p;int j r 1;int x a[p…...
找人做网站不算诈骗罪吗/seo关键词排名优化推荐
我觉得下面文章讲的非常不错,适合nodejs入门学习。 七天学会NodeJS...