[性能优化系列] 03. 文件缓存

前文介绍了通过gzip减少流量传输,通过设置Cache-Control减少静态资源的请求,本文继续探讨,如何通过缓存的方式,减少对数据库的压力,从而提升页面响应时间。

动态页面性能损耗分析

以Typecho为例(大部分的cms类站点都是类似的架构),用户的http请求,从index.php进入web服务,然后PHP代码加载各种组件,接着路由到具体的action或者controller,并在controller中加载model,查询数据库,组装页面,最后渲染模板并输出给浏览器。

[性能优化系列] 03. 文件缓存

但是,对于大多数页面或者post,作者完成创作之后,绝大部分时间都不会再改变的了,但每次请求这个文章(举例,譬如:https://www.typechodev.com/servers/aliyun_coupons.html)的时候,都需要走一次所有流程,并从数据库查询文章内容,明显是不合适的。因此,我们可以在整个网站的入口处做优化,将文章内容缓存起来,下次请求过来时,如果发现有缓存,则直接返回缓存内容,从而减少对后端数据库等的压力,从而提升响应时间和网站并发处理能力。

动手实现自己的缓存逻辑

首先我们测试一下启用文件缓存前的接口性能

网上有很多已经做好的文件缓存插件,同学们可以自己去找找。笔者没有用过这类插件,所以没办法给什么建议。不过这种页面缓存技术非常简单,我们也可以自己简单实现一下。

首先我们看一下typecho的入口文件:

<?php
/** 载入配置支持 */
if (!defined('__TYPECHO_ROOT_DIR__') && !@include_once 'config.inc.php') {
    file_exists('./install.php') ? header('Location: install.php') : print('Missing Config File');
    exit;
}

/** 初始化组件 */
Typecho_Widget::widget('Widget_Init');

/** 注册一个初始化插件 */
Typecho_Plugin::factory('index.php')->begin();

/** 开始路由分发 */
Typecho_Router::dispatch();

/** 注册一个结束插件 */
Typecho_Plugin::factory('index.php')->end();

这个时候,使用ab -n 1000 -c 100 "https://www.typechodev.com/theme/56.html"命令进行测试,测试结果:

Concurrency Level:      100
Time taken for tests:   27.302 seconds
Complete requests:      1000
Failed requests:        994
   (Connect: 0, Receive: 0, Length: 994, Exceptions: 0)
Total transferred:      28776775 bytes
HTML transferred:       28576775 bytes
Requests per second:    36.63 [#/sec] (mean)
Time per request:       2730.203 [ms] (mean)
Time per request:       27.302 [ms] (mean, across all concurrent requests)
Transfer rate:          1029.31 [Kbytes/sec] received

接着我们修改index.php逻辑,增加文件缓存机制

修改后的index.php

<?php
/** 载入配置支持 */
if (!defined('__TYPECHO_ROOT_DIR__') && !@include_once 'config.inc.php') {
    file_exists('./install.php') ? header('Location: install.php') : print('Missing Config File');
    exit;
}

$path = $_SERVER["REQUEST_URI"];
$tmp_file = "/tmp/".md5($path).".html";
if(file_exists($tmp_file) && is_readable($tmp_file)){
    $content = file_get_contents($tmp_file);
    echo $content;
    die();
}
ob_start();

/** 初始化组件 */
Typecho_Widget::widget('Widget_Init');

/** 注册一个初始化插件 */
Typecho_Plugin::factory('index.php')->begin();

/** 开始路由分发 */
Typecho_Router::dispatch();

/** 注册一个结束插件 */
Typecho_Plugin::factory('index.php')->end();

$content = ob_get_contents();
ob_end_clean();
file_put_contents($tmp_file, $content);
echo $content;

我们再通过diff看看两者的差异,更清楚看到改动的内容:

[性能优化系列] 03. 文件缓存

可见,改动的地方非常少,总括来说就是:

  1. 页面开始的地方判断是否有缓存文件,有则直接输出
  2. 页面最后将内容缓存起来,以供下次请求使用

同样使用ab -n 1000 -c 100 "https://www.typechodev.com/theme/56.html"命令进行测试,结果如下:

Concurrency Level:      100
Time taken for tests:   2.658 seconds
Complete requests:      1000
Failed requests:        0
Total transferred:      28786000 bytes
HTML transferred:       28640000 bytes
Requests per second:    376.22 [#/sec] (mean)
Time per request:       265.803 [ms] (mean)
Time per request:       2.658 [ms] (mean, across all concurrent requests)
Transfer rate:          10575.99 [Kbytes/sec] received

缓存前后对比,接口成功率大幅上升(缓存前成功率不到10%,缓存后成功100%),请求平均耗时大幅降低(缓存前平均耗时2730ms,缓存后平均耗时265ms,不到1/10)。

小结

通过上述这种简单的方式,可以10倍提升网站的处理能力。同学们可以自动动手试试。代码能力强的同学,甚至可以加各种缓存策略,进一步优化缓存效果,这个就看自己需求了。


版权声明:未经书面授权禁止转载、摘编、复制或建立镜像。对既成事实本站将保留所有的权利。

评论已关闭