前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >shell脚本实现整站缓存和预缓存,进一步提升网站整体加载速度

shell脚本实现整站缓存和预缓存,进一步提升网站整体加载速度

作者头像
张戈
发布2018-03-21 15:00:34
1.8K0
发布2018-03-21 15:00:34
举报
文章被收录于专栏:张戈的专栏张戈的专栏

在 Linux 中,shell 脚本结合系统任务计划 crontab,非常简单就能实现一些复杂程序才能完成的工作,开发成本低,且简单易学。

张戈博客之前也分享过不少 shell 在网站运营方面的妙用,比如:

CCKiller:Linux 轻量级 CC 攻击防御工具,秒级检查、自动拉黑和释放 SEO 技巧:Shell 脚本自动提交网站 404 死链到搜索引擎 Linux/vps 本地七天循环备份和七牛远程备份脚本 nginx 日志切割及 7 天前的历史日志删除脚本 Shell+Curl 网站健康状态检查脚本,抓出中国博客联盟失联站点

感兴趣的可以挑选看一看。

本文继续分享一个 shell 的实用案例:全站缓存和定时预缓存,进一步提供网站速度。

一、何为预缓存

用过 WP-Super-cache 插件的站长肯定都知道,这个插件有一个预缓存功能,开启此功能后,插件会对全站预先缓存一遍,并且后面还会定期更新缓存。

显而易见,全站预缓存的好处就是在用户访问之前,就已经生成了静态缓存,而不是被用户访问触发才生成缓存,那么所有用户来访问几乎都是静态缓存,不管是平均还是总体速度都会有质的提升!当然,最重要还是优化了蜘蛛抓取的速度!

大家去百度站长平台查看那个抓取频次的时候,可以看到蜘蛛的平均耗时数据,我博客做了静态缓存,按理说每个抓取都不会超过 500ms,但是依然会出现一些十几二十秒的请求:

排除蜘蛛抓取的时候存在网络延时或并发负载等情况,还有一个很可能的原因就是蜘蛛正好抓取了一个缓存过期或缓存不存在的页面,也就是说蜘蛛抓取的时候,这个页面缓存正好过期被删除了,那么它抓取的时候就是动态页面,所以耗时就上去了!

因此,全站预缓存还是有必要的。

二、预缓存前身

见识到预缓存的重要性,那么就该想办法实现了。分享方法之前,先说一下灵感来源吧!

记得博客之前分享过各种 WordPress 缓存方案,有 php 代码版本、有 nginx 的 fastcig 缓存等等,当时有人问,有没有办法让 sitemap 也静态缓存(纯代码版本 sitemap)?

当时是对 sitemap.php 伪静态成 sitemap.xml 的,所以是动态数据的,而且就放在根目录,所以直接访问 sitemap.php 也是可以的,由于是全站数据,所以这个文件跑起来很慢!

后来,我用 linux 命令+crontab 就解决了这个需求:将 sitemap.php 放到某个不为人知的目录,然后定时使用 wget 去请求这个文件,并将数据保存为 sitemap.xml 存放到网站根目录就可以了!比如:

代码语言:javascript
复制
#每天在网站根目录生成一个sitemap.xml diypath为sitemap.php的实际位置
0 1 * * * wget -O /home/wwwroot/zhangge.net/sitemap.xml http://zhangge.net/diypath/sitemap.php  >/dev/null 2>&1

Ps:使用这个方法,注意 sitemap.php 里面的 require('./wp-blog-header.php'); 要改成 require('../wp-blog-header.php'); 也就是注意相对位置!

这样一来,就解决了 sitemap.xml 是动态数据问题了!

三、全站预缓存

有了上面的案例,如果实现全站预缓存真的太简单了。

可以有如下多种实现形式:

①、已有缓存功能的博客

对于已有缓存功能的博客,比如安装了缓存插件,或使用了 nginx 缓存,那么只需要从数据库拉出所有文章 id 或别名,然后组成页面地址,最后使用 wget 或 curl 全部请求一遍即可实现缓存,比如:

代码语言:javascript
复制
#!bin/bash
#我博客使用的是数据别名,所以是select post_name,如果是固定链接是ID,那么就是select ID了
for post in $(mysql -uroot -p数据库密码 -e "use 数据库名称;select post_name from wp_posts where post_type='post' and post_status='publish';"|sed -n '2,$p')
do
        #使用wget请求页面,并将数据丢到“黑洞文件”,也就是不保存,只是触发博客的缓存功能
        wget -O /dev/null  "http://zhangge.net/${post}.html"
        sleep 0.5 #暂停0.5s,避免带来高负载
done

但是,各个博客的固定地址可能不一样,所以这样拼接 ID 或别名,不能照搬,而且分类、tag 等都没覆盖到位,甚是遗憾。

我也懒得研究如何从数据库弄出所有页面,最后用了一招偷懒的办法:从 sitemap.xml 中获取页面地址!

几乎每个网站都会有一个 sitemap.xml 文件,如果你网站没有,那么还是先参考前文弄一个吧!

所以脚本可以改成如下代码:

代码语言:javascript
复制
#/bin/bash
#进入到网站根目录,请按实际填写
cd /home/wwwroot/zhangge.net/

#从sitemap.xml中取出所有页面地址, 每隔0.5秒请求一次,触发缓存。
for url in $(awk -F"<loc>|</loc>" '{print $2}' sitemap.xml)
do
        wget -O /dev/null  $url
        sleep 0.5
done

将此代码按实际修改后保存为 g_cache.sh ,上传到 Linux 系统,比如就放到 /root 目录,先手工执行看看是否成功:

bash /root/g_cache.sh

如图,如果没有报错(图中的骇人速度无需在意,和磁盘 IO 有关),最后新增一个任务计划即可:

代码语言:javascript
复制
#每天凌晨3点全站预缓存一遍 0 3 * * * bash /root/g_cache.sh  >/dev/null 2>&1

duang 的一下,就搞定了!

②、没有缓存的博客

没有缓存的博客,说明你不喜欢缓存,可能也没必要开启缓存,所以下面只是为了保持文章的完整性而写的,大家选择性看看就好!

没有缓存的博客,要全站预缓存有 2 个途径:

安装缓存插件或开启其他缓存后,再用方法①实现 我就不开启缓存,但是我还是要用全站预缓存,你说怎么办吧!

第 1 个途径就没必要啰嗦了,简单分享第 2 种如何实现吧。

从第①步中可以看到,我们只请求页面,但是不保存数据,全部扔黑洞了。那如果我将数据保存为对应的 html 文件,并存放在网站对应的目录下呢?那不就实现了和 cos-real-html 插件一样的静态缓存了吗?

很明显还是可以的!代码如下:

代码语言:javascript
复制
#!/bin/bash
#网站根目录,请按实际填写
base_dir=/data/wwwroot/zhangge.net

#不缓存名单,填写不需要缓存的页面地址关键词,以分割号隔开
white_list="go.html|goto.html"

#定义缓存文件夹名称
cache_store=html_cache

#从sitemap.xml中取出所有页面地址
for url in $(awk -F"<loc>|</loc>" '{print $2}' $base_dir/sitemap.xml | sed '/^$/d' | egrep -v $white_list)
do
    #取出页面地址的request路径,比如cat/1.html
    cache_dir=${url#http*://*/}

    #判断首页并删除旧缓存文件
    echo $cache_dir | grep "http*://" >/dev/null
    if [[ 0 -eq $? ]];then
        cache_dir=$cache_store

        # 如果不带参数执行脚本,则跳过已有缓存,即若带任意参数则重建所有缓存
        if [[ -z $1 ]];then
            test -f $cache_store/index.html && continue
        fi
    else
        cache_dir=$cache_store/$cache_dir
        if [[ -z $1 ]];then
            test -f $cache_store/index.html && continue
        fi
    fi

    #创建缓存目录
    mkdir -p $cache_dir

    #将页面内容保存到对应缓存目录下的index.html文件,类似于wp-super-cache
    wget -O $cache_dir/index.html $url 
    
    sleep 0.5
done

按照实际情况,修改代码中的网站根目录和缓存白名单,保存为 g_cache.sh 上传到服务器,接着我们需要新增一个 Nginx 伪静态,其实就和之前 wp-super-cache 的一样:

代码语言:javascript
复制
location / {
    try_files $uri $uri/ /index.php?$args; #WordPress 默认伪静态规则,我在下面新增如下规则即可
        if (-f $request_filename) {
               break;
           }
           set $cache_file '';
           set $cache_uri $request_uri;
           if ($cache_uri ~ ^(.+)$) {
               #请注意:下面这行代码的路径对应缓存代码中的CACHE_ROOT定义的路径:
               set $cache_file /html_cache/$1/index.html;
           }
           # 只有当缓存文件存在时,才进行 rewrite
           if (-f $document_root$cache_file) {
               #rewrite ^(.*)$ $cache_file break;
               rewrite ^ $cache_file last;
           }
           # 所有其他请求,转给 wordpress 处理
           if (!-e $request_filename) {
               rewrite . /index.php last;
           }

    }

保存之后,reload 重载 nginx 以生效。

最后,如下新建计划任务,定时执行 g_cache.sh:

代码语言:javascript
复制
# 每周一凌晨3点点全站刷新预缓存(如脚本注释,带上任意参数则重建全站缓存)
0 3 * * * bash /root/g_cache.sh all >/dev/null 2>&1

# 每小时检查缓存,如果存在没有缓存的文章,则生成(针对新文章发布)
0 */1 * * * bash /root/g_cache.sh >/dev/null 2>&1

如此就实现了 wp-super-cache 预缓存和 cos-real-hmtl 的静态缓存功能了。

四、最后的啰嗦

其实,个人觉得本文最大的亮点是最后一个脚本,及实现了缓存,也实现了预缓存,神马缓存插件、神马伪静态都可以丢一边了!而且,只要网站有 sitemap.xml 文件,那么就可以实现静态缓存,而且不局限与建站程序是什么!

但是,除了爽,我们还是有一些要注意的细节,请务必仔细看看。

①、hosts 解析

由于是在服务器本地全站抓取,为了提高速度,缩短路径,强烈推荐在 hosts 中将网站域名解析到服务器 IP,不在走外部 DNS 解析,以减少解析时间,或者 CDN 消耗。

很简单,编辑 /etc/hosts 文件,在里面插入一条解析即可,比如:

127.0.0.1  zhangge.net

最后,保存即可。

②、生成间隔

文章中分享的计划任务都是 1 天一次,如果你觉得有必要缩短间隔,可以自行修改 crontab 语句,具体可以搜索下 crontab 配置,了解 crontab 中 分 时 日 月 周得定义,此处不再赘述。

③、缓存删除

本文只分享了如何生成缓存,并没有说如何自动删除缓存。整体上来说,反正 crontab 会定期重新生成缓存的,原则上并不用去理会自动刷新缓存。

但是,往往一些强迫症看到评论不刷新,文章修改了也不刷新,就抓耳挠腮,好不舒服。所以这里还是指明一条出路。。。

对于已有缓存功能的网站,使用这个预缓存脚本,实际上不会有任何影响,之前有自动刷新缓存的话,现在依然会刷新,无需操作。

对于使用最后一个脚本的网站,也就实现了和之前分享的 php 生成 html 缓存同样的功能,如果想更新文章或提交评论的时候删除这个缓存,可以参考博客之前的文章,修改下缓存路径即可搞定:

WP Super Cache 静态缓存插件纯代码版(兼容多域名网站)

哦了,分享到此,有事留字。。。


最新补充:偷懒用 sitemap.xml 的方法感觉有点 Low,所以还是提供一下没有 sitemap.xml 的方案吧!为了不和上面的内容混淆,还是另起一页,有需求的可以看看,没需求的请忽略。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016年04月16日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、何为预缓存
  • 二、预缓存前身
  • 三、全站预缓存
    • ①、已有缓存功能的博客
      • ②、没有缓存的博客
      • 四、最后的啰嗦
        • ①、hosts 解析
          • ②、生成间隔
            • ③、缓存删除
            相关产品与服务
            内容分发网络 CDN
            内容分发网络(Content Delivery Network,CDN)通过将站点内容发布至遍布全球的海量加速节点,使其用户可就近获取所需内容,避免因网络拥堵、跨运营商、跨地域、跨境等因素带来的网络不稳定、访问延迟高等问题,有效提升下载速度、降低响应时间,提供流畅的用户体验。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档