脚本编程

网站预缓存工具,提升网站整体加载速度

Jager · 2月8日 · 2020年 · · 3次已读

由于电信宽带和谐了443端口,近期我花了不少时间折腾了下近半年都没瞅一眼的博客。经过一番折腾(详见前文),博客总算可以运行在家里的NAS上,整体部署方案如下:

网站预缓存工具,提升网站整体加载速度
图1. 张戈博客部署架构图

一、预缓存

从上图可以看到,由于中间用于代理转发的腾讯云CDN和阿里云CDN都是没有缓存的,如果CloudFlare的缓存过期,将需要绕过多层链路回源获取网页内容,相比速度就会慢很多。所以,需要在用户访问之前,先将页面缓存到CloudFlare,这样用户访问就快多了,这就是预缓存的概念。

WordPress插件wp-super-cache以及国内部分CDN都提供了预缓存功能,所以,这是一个很实用的优化。不过CDN提供的热缓存功能都需要用户手工去提交代码,而预热接口则有诸多限制,如图:

网站预缓存工具,提升网站整体加载速度
图2. 阿里云CDN的预热接口文档

相比于这些限制、复杂度,本文分享的预缓存工具就简单粗暴多了,直接模拟浏览器定期访问来实现预缓存,无任何限制!

温馨提示:只要启用了缓存的网站,都可以用到预缓存优化!

其实之前在博客也分享过一个预缓存Shell脚本,确实也可以用,就是效率太低,而且不能指定源站来缓存(除非改造下),于是花了点时间重新写了一个Python版本,支持异步、并发请求网页实现预缓存,而且支持指定具体的主机IP+端口,从而可以支持多CDN、本地缓存等复杂场景。

下面简单介绍下这个新工具的原理及使用方法。

二、工作原理

和之前分享的Shell版本一样:工具会模拟浏览器对网站地图sitemap.xml中的网址进行请求,从而实现这些网页的预缓存。当然前提是你的网址启用了静态缓存或者开启了CDN全站缓存,启用缓存的相关教程可以参考前文:

在相同原理的基础上,这次的工具也增强了一些特性,请继续往下看使用说明。

三、使用说明

1、基于Docker运行

熟悉Docker的朋友可以基于Docker容器来跑这个工具(Docker安装参考前文),依赖插件都已经集成好了,就不需要入侵本地环境了,命令如下:

docker run --rm --net=host -ti jagerzhang/pre-cache:latest \
    --sitemap=https://zhang.ge/sitemap.xml \
    --cacheheader=cf-cache-status

如果是拉取DockerHub的速度太慢,也可以先在本地编译Docker镜像,再跑上面的命令,编译方法如下:

git clone https://github.com/jagerzhang/Pre-cache.git
cd Pre-cache
docker build -t jagerzhang/pre-cache:latest ./

2、基于代码运行

基于代码运行需要先初始化一下Python环境,按装工具所依赖的组件,具体命令如下:

git clone https://github.com/jagerzhang/Pre-cache.git
cd Pre-cache
yum install -y python-pip
pip install --upgrade pip -i https://mirrors.aliyun.com/pypi/simple/
pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/

依赖环境初始化完成后,执行如下命令开始预缓存:

python pre_cache.py \
   --sitemap=https://zhang.ge/sitemap.xml \
   --cacheheader=cf-cache-status

3、基于对象引用

同样工具也支持在其他Python脚本中来作为对象引用,示例代码如下:

from pre_cache import preCache
pre = preCache(sitemap="https://zhang.ge/sitemap.xml",
                   host=None,
                   size=10,
                   timeout=10,
                   cache_header="cf-cache-status",
                   user_agent="Pre-cache/python-requests/2.22.0",
                   verify=False)
pre.start()        

4、执行结果

正常执行结果如下所示:

[[email protected] ~]# docker run -ti --net=host jagerzhang/pre-cache:latest --host=127.0.0.1:8443 --sitemap=https://zhang.ge/sitemap.xml --cacheheader=x-cache-redis
站点地图:https://zhang.ge/sitemap.xml
指定主机:127.0.0.1:8443
并发数量:20
超时时间:10秒
缓存标识:x-cache-redis
UA 标识:Pre-cache/python-requests/2.22.0
预缓存开始:
---------------------------------------------------------
缓存标识头缺失页面:https://zhang.ge/5072.html 
不可缓存页面:https://zhang.ge/roll.html 缓存标识头:X-Cache-Redis: BYPASS
不可缓存页面:https://zhang.ge/goodarticles 缓存标识头:X-Cache-Redis: BYPASS
不可缓存页面:https://zhang.ge/tag/google 缓存标识头:X-Cache-Redis: BYPASS
---------------------------------------------------------
预缓存完成,页面总数:897,耗时16秒
已被缓存页面数:893
不可缓存页面数:3
缓存标识头缺失页面数:1

Ps:为了让大家快速看到效果,这里就直接贴张戈博客的预缓存命令了,大家浅尝辄止,就不要无聊扫我的网站了。

上面就是快速尝鲜使用这个工具的方法,下面详细介绍工具参数。

5、参数介绍

--help、-h 参数打印帮助信息:

[[email protected] ~]# python pre_cache.py --help
usage: pre_cache.py [-h] -s SITEMAP [-S SIZE] [-t TIMEOUT] [-H HOST]
                    [-c CACHEHEADER] [-U USERAGENT] [-v VERIFY]

网站预缓存脚本,支持使用CDN或本地有静态缓存的网站.

optional arguments:
  -h, --help            show this help message and exit
  -s SITEMAP, --sitemap SITEMAP
                        网站地图sitemap地址
  -S SIZE, --size SIZE  并发请求数量,默认20
  -t TIMEOUT, --timeout TIMEOUT
                        单个请求的超时时间,默认10s
  -H HOST, --host HOST  指定真实主机,比如 127.0.0.1:8080
  -c CACHEHEADER, --cacheheader CACHEHEADER
                        缓存标识,比如: x-cache
  -u USERAGENT, --useragent USERAGENT
                        指定UA标识,默认 Pre-cache/python-
                        requests/__version__
  -v VERIFY, --verify VERIFY
                        是否校验SSL,默认不校验       

其他参数如帮助信息所示,简单说明如下:

参数必须默认值说明
--sitemap / -s指定网站地图sitemap文件网址,必须为xml文件格式。
--cacheheader / -c指定响应头里面的缓存标识名称,比如CF为cf-cache-status,不指定不影响功能,但是无统计信息。
--host / -H指定具体主机来访问页面,即绕过CDN或代理访问真实主机,支持端口,比如 127.0.0.1:8080。
--size / -S20指定预缓存时并发访问的数量,并非越大越好,需要自定测试整体耗时来得出最佳值。
--useragent / -u见说明自定义请求时的User-Agent标识来模拟客户端,默认值:Pre-cache/python-requests/xx.xx。
--timeout / -t10指定单个请求的超时时间,默认10秒。
--verify / -vFalse是否验证SSL证书,保持默认即可,开启验证可能无法支持指定--host来预缓存。

这里,挑几个比较核心的参数继续展开说明下。

--sitemap

整个工具的原理是先请求sitemap内容,然后对sitemap里面的url进行爬扫,因此--sitemap这个参数是必须参数,指定为网站的sitemap地址即可,比如:--sitemap=https://zhang.ge/sitemap.xml,需要注意的是这个xml必须是xml格式,这里推荐使用我博客之前分享的sitemap纯代码版本。如果是用插件生成的,可能是多个sitemap地址,然后有一个汇总的sitemap导航,这种情况的话只需要将这个参数指定为具体的分页sitemap地址,且需要分别执行多次。

--cacheheader

这个参数是指定网页被缓存后,Header头部中的HIT标识,常见的头部标识如下:

缓存类型头部名称常见值
Nginx 缓存X-Cache/或自定义HIT,MISS,EXPIRED,BYPASS
CloudFlarecf-cache-statusHIT,MISS,EXPIRED,DYNAMIC
腾讯云CDNx-cache-lookupHIT/MISS/EXPIRED/BYPASS From Upstream/XXX
阿里云CDNX-CacheHIT,MISS,EXPIRED,BYPASS

如果不在上述类别或者自定义过,我们也可以通过浏览器开发者模式查看,方法为:浏览器打开页面-->F12-->NETWORK-->刷新-->查看响应头:

网站预缓存工具,提升网站整体加载速度
图3. 查看头信息

一般出现有HIT,MISS,EXPIRED,BYPASS 值的就是我们这个参数需要指定的名称,比如图中的 cf-cache-status,那我们运行工具的时候只需要指定为 --cacheheaer=cf-cache-status 即可。当然,如果有多层缓存时,需要注意甄别。比如CDN有个HIT,本地Nginx也有个HIT,那么看你需要缓存那个就指定哪个了。

--host

这个参数就比较实用了,可以指定真实IP来访问网页,且支持自定义端口。比如 --host=127.0.0.1 或 --host=127.0.0.1:8080,指定后工具将会请求到指定的主机进行资源拉取实现指定节点预缓存。比如张戈博客开了CDN缓存同时本地也开启了Nginx缓存,我就可以如下分2步执行:

# 先本地预缓存:
python pre_cache.py \
   --sitemap=https://zhang.ge/sitemap.xml \
   --host=127.0.0.1:8443 \     # 指定本地WEB服务监听的8443端口
   --cacheheader=x-cache-redis # 我这边自定义了一个缓存头

# 然后CDN预缓存(这里需要伪造一下浏览器UA,否则CloudFlare拦截大部分请求,当然伪造后也会有少量拦截,影响不大):
python pre_cache.py \
   --sitemap=https://zhang.ge/sitemap.xml \
   --cacheheader=cf-cache-status \
   --useragent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36"

其他参数比较简单,就不展开赘述了,看上文的表格即可。

6、定时任务

上文已经详细介绍了如何运行这个工具,那接着我们需要通过crontab添加一个定时任务,定期进行预缓存。比如我博客需要在本地、百度云加速以及CloudFlare 3个层面做预缓存,那么就将基于Docker运行的命打包成shell脚本,并按照先预缓存本地,然后再缓预存CDN的顺序:

#!/bin/bash
source /etc/profile
# 注意:通过crontab执行docker是没有tty终端的,所以下面的docker的参数不能有-t
# 本地预缓存
docker run --net=host --rm -i \
    jagerzhang/pre-cache:latest \
    --sitemap=https://zhang.ge/sitemap.xml \
    --cacheheader=x-cache-redis
    --host=127.0.0.1:18443 \
    --size=50
    
# 百度云加速预缓存
docker run --net=host --rm -i \
    jagerzhang/pre-cache:latest \
    --sitemap=https://zhangge.net/sitemap.xml \
    --cacheheader=cf-cache-status \
    --size=50 

# CloudFlare预缓存
docker run --net=host --rm -i \
    jagerzhang/pre-cache:latest \
    --sitemap=https://zhang.ge/sitemap.xml \
    --cacheheader=cf-cache-status \
    --size=20 \
    --useragent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36"

然后在系统crontab里面添加一个定时任务,每小时执行一次:

# 进入定时任务编辑,插入如下命令行:
[[email protected] ~]# crontab -e 
* 1 * * * bash /domp/opt/pre_cache.sh >/dev/null 2>&1
# :wq保存退出

这样就能实现定期网站预缓存了,其他网站可以参考添加。

四、工具反馈

以上就是这个工具的详细介绍了,整体设计、代码逻辑都比较简单,目前这个工具已经上传到了Github,并且在Docker Hub制作了Docker镜像,大家使用后觉得实用的话可以给个星星,有什么建议也可以留言或github提issue:

EnJoy it!

32 条回应
  1. vimtutor 2020-2-8 · 22:26

    大佬你的博客真是有技术含量,跟你一对比,俺那小破静态网站真是无地自容。学到了不少知识

    • Jager 2020-2-8 · 23:28

      你那是术业有专攻,我这是运维万金油,啥都沾一点。话说小姐姐还在鹅厂么,你公众号人气真旺~

      • vimtutor 2020-2-25 · 23:35

        在呢~可别提我那个公众号了,快2个月没更新了

  2. 简单生活 2020-2-10 · 23:33

    大佬牛逼PLUS。。。学习了!

  3. Even 2020-2-11 · 0:41

    感谢博主提供了很好的思路,不过找到了类似的插件可以把功能移植过来。(https://wordpress.org/plugins/preload-fullpage-cache/)

    • Jager 2020-2-11 · 9:12

      嗯,你这个类似wp-super-cache里面的预缓存插件,支持本地缓存的预缓存。
      不过我这个思路是适合任何缓存的方案,比如缓存到CDN这种,比较直观粗暴吧。

  4. porndodo 2020-2-16 · 20:01

    不让出门,只能刷刷博客了!

  5. 心灵博客 2020-2-20 · 21:21

    折腾的乐趣

  6. VC安全网 2020-2-23 · 2:07

    大佬,wpsupercache不能缓存首页和分类 只能缓存html文章页和page页面 ,折腾两天没搞定,请教下是插件问题还是网站问题,怎么解决勒 。。

  7. 赚零花 2020-2-24 · 20:00

    感谢大佬的分享,不过你这个评论,每次打字都会抖动有点不舒服啊

  8. 六六社 2020-2-25 · 23:11

    大佬。你的博客技术含量那不是一般的高啊,基本上将我看到的所有特效以及优化全部用上去了吧

  9. 吃瓜 2020-2-26 · 19:30

    我能说我看了好几遍,我还看不懂嘛,初中文化。。。。

  10. Ann 2020-3-1 · 15:10

    作为零基础学习一下前端?

  11. Yqchilde 2020-3-3 · 0:33

    哇,张哥这个python程序是python2的,我简单改了下函数py3,但是运行却报错了,请问有py3的程序吗

    • jager 2020-3-8 · 17:29

      你看看报啥错?

  12. 王光卫博客 2020-3-3 · 12:28

    这样会不会增加服务器的负荷呢

  13. Jack Wang 2020-3-4 · 11:06

    大佬真是多技术丰富丫。在这一个站能学大很多东西。

  14. 哈灵游戏 2020-3-5 · 16:01

    不明觉厉,学习中

  15. dqzboy 2020-3-7 · 10:17

    学习了,感谢大佬分享

  16. 小伙 2020-3-12 · 21:12

    虽然是文盲但能感觉很牛B。这个文章说的缓存是提前给CND,wp-super-cache区别是缓存到本地,
    大佬是这样嘛?

  17. 绿软吧 2020-3-19 · 14:34

    感谢分享

  18. 三喜 2020-3-20 · 12:29

    感谢分享,这一震一震真不习惯...

  19. 楚狂人 2020-3-21 · 7:57

    折腾就是玩博客的乐趣,这下速度更快了啊~

  20. 龙笑天 2020-3-21 · 16:52

    把图片等静态文件CDN一下 速度感觉还OK~

  21. 赣榆沙子 2020-3-25 · 8:50

    大佬网站速度真快为 我的网站速度卡死了今天研究下加速看到你的文章实验下

  22. 小谈谈BH1XAQ 2020-3-29 · 13:25

    原来张大佬的博客在群晖上啊。。。服气!

  23. 麦杰机械 2020-4-24 · 16:35

    学到了好多东西,喜欢看你的博客

  24. 创业博客 2020-4-30 · 22:56

    这个也太专业了。。

  25. 唐国健博客 2020-7-2 · 16:00

    我也把网站从阿里云迁移到群晖了。家里有动态公网IP,但是没有80,433端口!没你那技术,所以买了一个公网盒子,带一个固定全开放的ip,感觉还不错!家里开web.节约100元的vps钱

  26. 乐心湖 2020-7-4 · 11:48

    这波秀到我了,文里介绍的预缓存长见识了

  27. GAL游戏盒子 2020-7-5 · 0:23

    学习了

  28. 杜老师说 2020-7-12 · 23:50

    杜老师说到此一游,期待回访!