脚本编程

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

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

由于电信宽带和谐了 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.tencent.com/pypi/simple/
pip install -r requirements.txt -i https://mirrors.tencent.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、执行结果

正常执行结果如下所示:

[root@localhost ~]# 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 参数打印帮助信息:

[root@localhost ~]# 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,默认不校验     
  -d, --debug   是否显示 Debug 信息, 默认关闭  

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

参数必须默认值说明
--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 来预缓存。
--debug / -dFalse 是否显示 Debug 信息, 默认关闭,运行时加入 --debug 参数即可打开

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

--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 里面添加一个定时任务,每小时执行一次:

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

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

四、工具反馈

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

EnJoy it!

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

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

    • avatar
      Jager 2020-2-8 · 23:28

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

      • vimtutor 2020-2-25 · 23:35

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

      • nini 2020-11-2 · 13:34

        你的博客很优秀

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

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

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

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

    • avatar
      Jager 2020-2-11 · 9:12

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

      • nini 2020-11-2 · 13:51

        创造性

  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的程序吗

    • avatar
      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

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

  29. 谜语大全 2020-8-16 · 16:37

    还没有这么高深的技术,不会docker,目前只学会了用composer

  30. 六速博客 2020-10-12 · 0:29

    学一学

  31. visitorzero 2020-10-13 · 16:19

    慕名而来 膜拜一下大佬

  32. visitorzero 2020-10-13 · 16:19

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

  33. 一芦居 2020-10-21 · 13:47

    真有技术含量,以前看过不少技术文章,感觉都是从你这里摘抄的。

  34. cc 2020-11-15 · 0:56

    VPS 用过 nginx_helper 做缓存了.
    但是就是不能 给 cf 预缓存 .
    不知道什么情况了.

    root@ko:~/oneinstack/tools# ./web-cdn.sh
    站点地图:https://mtkkk.com/sitemap.xml
    指定主机:127.0.0.1
    并发数量:50
    超时时间:10秒
    缓存标识:x-cache-redis
    UA  标识:Pre-cache/python-requests/2.22.0
    预缓存开始:
    ---------------------------------------------------------
    ---------------------------------------------------------
    预缓存完成,页面总数:4,耗时0秒
    已被缓存页面数:4
    站点地图:https://mtkkk.com/sitemap.xml
    并发数量:20
    超时时间:10秒
    缓存标识:cf-cache-status
    UA  标识: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
    预缓存开始:
    ---------------------------------------------------------
    缓存标识头缺失页面:https://mtkkk.com/ 
    缓存标识头缺失页面:https://mtkkk.com/hello-world/ 
    缓存标识头缺失页面:https://mtkkk.com/sample-page/ 
    缓存标识头缺失页面:https://mtkkk.com/category/uncategorized/ 
    ---------------------------------------------------------
    预缓存完成,页面总数:4,耗时0秒
    缓存标识头缺失页面数:4
    指定的缓存标识头 cf-cache-status 可能不对,未能找到这个头信息.
    root@ko:~/oneinstack/tools# vim web-cdn.sh
    root@ko:~/oneinstack/tools# ./web-cdn.sh
    站点地图:https://mtkkk.com/sitemap.xml
    指定主机:127.0.0.1
    并发数量:50
    超时时间:10秒
    缓存标识:x-cache-redis
    UA  标识:Pre-cache/python-requests/2.22.0
    预缓存开始:
    ---------------------------------------------------------
    ---------------------------------------------------------
    预缓存完成,页面总数:4,耗时0秒
    已被缓存页面数:4
    站点地图:https://mtkkk.com/sitemap.xml
    并发数量:20
    超时时间:10秒
    缓存标识:cf-cache-status
    UA  标识:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36
    预缓存开始:
    ---------------------------------------------------------
    缓存标识头缺失页面:https://mtkkk.com/ 
    缓存标识头缺失页面:https://mtkkk.com/hello-world/ 
    缓存标识头缺失页面:https://mtkkk.com/sample-page/ 
    缓存标识头缺失页面:https://mtkkk.com/category/uncategorized/ 
    ---------------------------------------------------------
    预缓存完成,页面总数:4,耗时0秒
    缓存标识头缺失页面数:4
    指定的缓存标识头 cf-cache-status 可能不对,未能找到这个头信息.
    
  35. 三悟自媒体 2021-6-1 · 15:09

    我看对博主这个文章目录了。

  36. 三悟自媒体 2021-6-1 · 15:13

    老大给分享一下你的目录插件吧

  37. ps插件网 2021-8-28 · 14:33

    我也用的腾讯cdn,不得不说,加了cdn就是不一样

  38. 言之在线 2021-10-17 · 10:56

    对我来说,太难了,感谢分享,慢慢学习中!

  39. 奇点工厂 2021-11-1 · 11:38

    大佬你的博客技术文章很不错,网站没备案的情况下有啥好的方法可以针对网站国内加速。