- 截止到目前系统架构图
- 访问静态资源文件压测
- HTTP请求参数
- 压测线程属性
- 压测效果: 平均值50ms、95值: 402ms、吞吐量TPS: 3577/sec
- 访问静态资源优化方案
- 对名词的一些解释
- ECS: elastic cloud service 弹性云服务器
- CDN: content delivery network 内容分发网络: 是指一组在地理上分散的服务器,它们协同工作以提供互联网内容的快速交付.也就是说用户能够更快的访问.
CDN参考链接 - OSS: object storage service 对象存储服务
- 加入CDN后的网络架构图
- 静态资源请求从CDN中获取,如果CDN中没有则回源到nginx
- 动态资源请求nginx获取.
- 静态请求CDN如何操作
- DNS用CNAME解析到CDN源站
- 回源缓存设置
- 强推失效
- cache control响应头(请求头中也有这个参数)
- cache control响应头的取值
- private: 客户端可以缓存
- public: 客户端和代理服务器都可以缓存
客户端向服务端发送http请求并获得响应,中间可能会经过nginx反向代理或正向代理,也有可能会经过CDN(内容分发)网络.当设置为public时,这些中间代理服务器也可以缓存. - max-age=xxx: 缓存的内容将在xxx秒后失效
- no-cache: 强制向服务器再验证一次
将缓存存储在客户端,但是在使用缓存的时候需要向服务器验证一次缓存是否可用. - no-store: 不缓存请求的任何返回内容
- cache control响应头取值的选取
- no-cache中的向服务器再验证一次: 验证的是缓存的有效性判断
- ETag: 资源唯一标识
通过将请求资源内容进行MD5加密或hash处理,生成一个唯一标识ETag,再第一次服务器向客户端返回数据的时候将ETag返回给客户端.再一次向服务器端发送http请求的时候,带上ETag,将ETag值和服务器端本地ETag内容做比较,若一致,返回304(内容从上次请求后没有改变),直接使用缓存的即可. - If-None-Match: 客户端发送的匹配ETag标识符
- Last-Modified: 资源最后被修改的时间
- If-Modified-Since: 客户端发送的匹配资源最后修改时间的标识符
注: 当缓存过期,想要从缓存中获取数据,ETag并不是必须的,如果没有ETag,可以判断last-modified,向服务器端发送if-modified-since请求,如果返回304,则从本地缓存中获取,如果返回200,则从服务器端获取.
对于ETag字段,如果客户端有ETag字段,则向服务器端发送if-none-match请求,如果服务器端返回304,则读取本地缓存,如果返回200,则从服务器端获取.
- ETag: 资源唯一标识
- 浏览器三种刷新方式
- 回车刷新或a链接: 看cache-control对应的max-age是否仍然有效,有效则直接from cache,若cache-control中为no-cache,则进入缓存协商机制.
- F5刷新或command+R刷新: 去掉cache-control中的max-age或直接设置max-age为0,然后进入缓存协商机制.
- ctrl+F5或command+shift+R刷新: 去掉cache-control和协商头,强制刷新.即再重新从服务器端获取一次.
- 缓存协商机制
比较last-modified和ETag到服务端,若服务器端判断没有变化,则返回304,从缓存中获取数据;否则返回200,从服务器端请求数据.
- CDN自定义缓存策略
CDN是介于客户端浏览器和nginx服务器中间的一个代理层.CDN既充当浏览器客户端的服务器角色,也充当了nginx服务器的客户端角色.
- 可以自定义目录过期时间
不管服务器端定义的max-age是多少,CDN可以自定义 - 可以自定义后缀名过期时间
对.html、.css等不同文件做不同过期时间处理 - 可以自定义对应权重
比如可以自定义后缀名过期时间权重比目录过期时间权重大, 则遵循后缀名过期时间 - 可以通过界面或api强制CDN对应目录刷新(不一定能保证成功)
忽略设置的所有规则,强制回源获取最新内容.
总结: - 如果源站没有缓存配置则遵从阿里云默认缓存配置
- 如果原站有缓存配置,则有限遵从控制台缓存配置
- 如果控制台没有缓存配置,则遵从源站的缓存配置.
- 静态资源部署策略
- 静态资源部署策略一: 静态资源文件部署三种方式
- css、js、img等元素使用带版本号部署,例如a.js?v=1.0不便利,且维护困难
- css、js、img等元素使用带摘要部署(比如基于文件内容生成hashcode,文件内容不变则hashcode值不变,文件内容变化则hashcode值变化),例如a.js?v=45edw,存在先部署html还是先部署资源的覆盖问题.
如果先部署js,则html还是引用的老的js,会出现js资源找不到等问题.如果先部署html,新的js还没有部署,html还是引用的老的js. - css、js、img等元素使用摘要做文件名部署,例如45edw.js,新老版本并存且可回滚,资源部署完后再部署html.有新老版本两个js文件,而上面的方式只有一个js文件.(推荐)
- 静态资源部署策略二: 静态资源文件生命周期设置方式
- 带摘要的静态资源部署方式保持生命周期内不会变,max-age可以设置的很长,无视失效更新周期
- html文件设置no-cache或较短max-age,以便于更新(一般也可以)
- html文件仍然可以设置为较长的max-age,依靠动态的获取版本号,请求发送到后端,比较从后端获取的版本号和当前版本号是否相同.若不相同,异步下载最新的版本号的html后展示渲染在前端.(三者中最好的方式)
- 静态资源部署策略三
- 动态请求也可以静态化成json资源推送到cdn上
- 依靠异步请求获取后端节点对应资源状态做紧急下架处理
先展示老的静态资源,同时发送一个很小的异步ajax请求,获取版本号,比对版本号是否一样,如果不一样,则向后端发送一个http请求,获取最新的静态资源,覆盖掉老的静态页面上的内容. - 通过跑批紧急推送cdn内容以使其下架等操作.
当内容发生改变,版本号发生变更,可以推动cdn内容使其下架.
- 无头浏览器
- 无头浏览器指的是没有图形用户界面的浏览器. 在类似于流行网络浏览器的环境中提供对网页的自动控制,但是通过命令行界面或使用网络通信来执行.
- 通常用来:
- Web应用程序中的测试自动化。
- 拍摄网页截图
- 对JavaScript库运行自动化测试
- 收集网站数据
- 自动化网页交互
- 全页面静态化
- 定义
在服务端完成html、css,甚至js的load渲染成纯html文件后直接以静态资源的方式部署到cdn上. - phantomjs是什么
phantomjs实现了一个无头(无界面)的webkit浏览器。虽然没有界面,但dom渲染、js运行、网络访问、canvas/svg绘制等功能都很完备,在页面抓取、页面输出、自动化测试等方面有广泛的应用。 - phantomjs应用
- 修改需要全页面静态化的实现,采用initView和hasInit方式防止多次初始化.
- 编写对应轮询生成内容方式
- 将全静态化页面生成后推送到cdn
- phantomjs全页面静态化代码实现(采用initView和hasInit方式防止多次初始化)
-
客户端安装phantomjs
- 下载phantomjs
- 将压缩包放在自己安装目录下,比如/usr/local,并解压缩
-
在phantomjs目录下新建js目录,并在js目录下创建getitem.js文件
var page = require("webpage").create(); // 导入fs文件系统模块 var fs = require("fs"); // function为回调函数 page.open("http://miaoshaserver:8090/resources/getitem.html?id=1", function(status){ console.log("status = " + status); var isInit = "0"; // 每隔1s执行一次 setInterval(function(){ // 如果isInit值不为1,则一直执行initView()方法, if(isInit != "1"){ page.evaluate(function(){ initView(); }); isInit = page.evaluate(function(){ return hasInit(); }); }else{ // 覆盖写入到getitem.html fs.write("getitemphantom.html", page.content, "w"); // 结束执行 phantom.exit(); } }, 1000); });
-
修改getitem.html文件
<body> <div> ... <!-- 设置一个隐藏域,初始值为0,表示没有缓存--> <input type="hidden" id="isInit" value="0"> </div> </body> function hasInit(){ return $("#isInit").val(); } function setHasInit(){ $("#isInit").val("1"); } function initView(){ var isInit = hasInit(); // 当isInit值为"1"的时候说明已经向服务器端请求过一次了,return if(isInit === "1"){ return; } $.ajax({ type:"GET", url:"http://" + g_host + "/item/get", data:{ "id":getParam("id") }, xhrFields:{withCredentials:true}, success:function (data) { if(data.status == "success"){ g_itemVO = data.data; reloadDom(); // 不断刷新,为了让下单按钮在秒杀开始时亮起 setInterval(reloadDom, 1000); // 将isInit值设为为"1",直接返回,无需再向服务器请求 setHasInit(); }else{ alert("获取信息失败,原因为"+data.data.errMsg); } }, error:function (data) { alert("获取信息失败,原因为"+data.responseText); } }); } // jQuery(document).ready()这个方法在dom载入就绪时对其进行操纵并调用执行它所绑定的函数。 jQuery(document).ready(function(){ ... initView(); });
-
将getitem.html部署到nginx服务器端
scp getitem.html root@nginx服务器ip:/usr/local/openresty/nginx/html/resources/
-
使用phantomjs执行getitem.js文件,会生成一个getitemphantom.html文件,该文件中隐藏域的值已经设置成为1了.
# /usr/local/phantomjs目录下 sudo bin/phantomjs js/getitem.js
从页面访问上可以看出
-
用户如果用浏览器打开 getitemphantom.html 会发现没有网络请求,这是一个完全静态化的 html 页面,把这个页面放到 CDN 上去,就可以在 CDN 层面完全命中,不会再有请求打到源站服务器上去了;