出家如初,成佛有余

使用Redis突破WordPress性能瓶颈

Posted in 技术相关 by chuanliang on 2014/03/12

    利用游迹语音助手已有技术倒腾的微信公众平台精品内容聚合站www.lewuxian.com  是基于wordpress搭建的,起初爬取数据量小时候性能倒不成其为问题,但数据量到10万左右,明显感觉wordpress性能越来越差,打开首页基本上要耗上10多秒,采用标准套路对系统进行了如下一些优化:

1、使用nginx对图片、css、js等文件反向代理缓存:为节省服务器资源,图片没有下载到本地,采用外链方式,这块应该存在瓶颈,而且也没必要每一 次发起新请求。因此采用nginx反向代理做缓存方式对图片请求做缓存。同时对css、js文件等开启gzip压缩、设置缓存失效时间等。

2、尝试了各种Wordpress各种缓存插件:W3 Total Cache、Super Cache、WP-FFPC、APC Object Cache Backend+Batcache、Memcached Object Cache、DB Cache Reloaded Fix等插件,什么gzip压缩、client cache等等都尝试了,效果都不是很明显。相比较而言,Memcached Object Cache+DB Cache Reloaded Fix效果还算显著,打开速度提升到7秒左右。但打开速度还是让人着急。

3、优化mysql:查看mysql slow log,发现有大量的wp_posts慢查询,尝试调整mysql 各种buffer、sort参数、增加索引等等,把各种wordpress调优手段都尝试了,效果还是不显著,首页打开速度始终停留在6秒左右就无法优化 了。那些查询缓慢的sql似乎也没有太多可优化的空间了。

突然明白了,为何年前lewuxian.com放在国外dreamhost的VPS服务器上时候,突然被dreamhost告知因对数据库资源占用过高,被禁掉了。起初还以为是因为VPS主机性能+网络问题导致访问缓慢,也没深究。

想想也是,使用wordpress有多少个人博客文章量能够过10万。人家的优化方案确实也无太多参考价值。

试图通过页面静态化方式来解决慢的问题,也试了wordpress的几个静态化插件,效果也不明显,最终把问题定位在:

1、由于爬取时候直接采用后台插入数据库方式,因此不用利用诸多插件在发布时候预先生成的静态页面或缓存方式,导致必须在用户访问时候才去查询数据库后再缓存

2、详情页的性能瓶颈不高,最大的瓶颈是首页和分页各页面的内容。由于爬取时候首页和各个翻页页面的内容持续变化,更新频率较高,各种插件的缓存机制并无效

既然wp_posts数据量如此大,能不能对wp_posts做sharding、partition,查了一下,针对wordpress的似乎并无现成的sharding方案。

难道只能再增加单台数据库服务器配置和读写分离了?绝望之际,想到前一阵用redis感觉效率确实高,google了一下redis+wordpress,还确实有老外有解决方案,方案还挺靠谱。

主要参考了这两篇文章:

http://www.jeedo.net/lightning-fast-wordpress-with-nginx-redis/

http://www.jimwestergren.com/wordpress-with-redis-as-a-frontend-cache/

安装使用极为简单,搭建好后,做了一下测试,效果显著,缓存过的页面打开基本上在1秒之内。

随之而来又有一个新问题:jeedo的代码虽然针对jim的代码做了优化,但对首页和翻页内容的缓存也满足不了需要:

首页和各个分页页面内容变化后,怎样主动去更新首页和分页内容的缓存?

考虑到实时更新的性能问题,因此没必要在插入时候实时更新缓存,大的思路确定如下:

1、定时(例如每10分钟)针对首页及访问频繁的分页(例如10页)的内容作一下失效,重新生成缓存内容,以保证首页及分页内容的相对时效性;

2、每天凌晨对所有分页内容重新生成缓存。

虽然不完美,但修改简单,也能够满足目前需要。

在jeedo代码基础上,增加了如下机制:

1、增加定时刷新缓存的url参数,例如?flush=y ,定时对分页页面内容定时失效并重新缓存。

2、在crontab中配置,每10分钟用curl调用一下脚本

3、在crontab中配置,每天凌晨用curl调用,重新对所有翻页页面内容失效并重新缓存

*/10 * * * * curl http://www.lewuxian.com/?flush=y
1 1 * * * curl http://www.lewuxian.com/?flush=y&total=10000

修改代码:

$flush = $_REQUEST[‘flush’];
// check if a cache of the page exists
if (!empty($flush) && $flush === “y”){
require(‘./wp-blog-header.php’);
$total=$_REQUEST[‘total’];
if(empty($total)){
$total=10;
}
for($page=1;$page<$total;$page++){
$url=”http://”.$_SERVER[‘HTTP_HOST’].”/?paged=”.$page;
$ukey=md5($url);
$redis->hdel($dkey, $ukey);
$log=fopen(“/var/log/cache_flush.log”,”a”);
date_default_timezone_set(‘Asia/Shanghai’);
$showtime=date(“Y-m-d H:i:s”);
fwrite($log,”cache of page: “. $url .  ”  at: ” . $showtime . “\n”);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
$output = curl_exec($ch);
curl_close($ch);
fclose($log);

}

}
else if ($redis->hexists($dkey, $ukey) && !$loggedin && !$submit) {

 

目前看来效果还不错。

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s

%d 博主赞过: