wordpress支撑百万文章解决方案

作为一个博客系统,wordpress在易用性和可扩展性上都非常出色。后题用户体验是非友好,插件众多。然而由于定位的问题,wordpress无法支撑大量文章。当文章数量达到上万的时候,有些主题的前台可能会非常卡。当文章数量达到数十万的时候,wordpress后台可能会特别卡。更何况大部分插件并没有在性能上下功夫,插件越多,wordpress越卡。那么有没有什么方案能让wordpress支撑大量文章?十万,百万,甚至更多?

支撑百万数据并不是存入一百万文章就可以了。实际上百万文章对mysql来说毫无压力。在mysql中,百万文章仅仅是百万条记录而已。导致缓慢的是mysql的查询。对于百万条记录的数据库,一次全表扫描的代价是十分昂贵的!很不幸,wordpress的经常会干一些扫描全表的事情!

整体优化

需要去掉所有查询中带有的SQL_CALC_FOUND_ROWS,这会扫描表,速度十分慢!对于大量的数据,查询的数目应该是缓存过后,或者是事先计算好的!

需要去掉所有的COUNT操作,这也会导致扫描条件中的所有行,如果条件没有索引,将会导致扫描全表!

由于wordpress查询复杂,针对每一种查询设置一个计数器不太现实,可以考虑使用查询结果缓存的方式来减少扫描全表的次数。缺点就是计数会有延迟。

首页优化

一般来说,达到百万文章级别的站点,首页应该是一个展示很多分类文章的页面。但是由于wp在初始化的时候就会根据url中的查询去数据库查询一些文章,首页是根据时间倒序查询,因此当不需要最新文章的时候,可以利用钩子去掉这部分查询。

文章页优化

看看文章页面,似乎没有什么费时间的查询,基本上就是id查询内容,用到了索引,但是其中有一个翻页的问题,其中有一个翻页的功能是可以筛选出相同分类的上下篇文章,这种查询的sql语句如下

mysql> SELECT p.ID FROM wp_posts AS p
  
INNER JOIN wp_term_relationships AS tr ON p.ID = tr.object_id INNER JOIN wp_term_taxonomy tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE p.post_date > '2017-07-04 09:57:50' AND p.post_type = 'post' AND tt.taxonomy = 'category' AND tt.term_id IN (4) AND p.post_status = 'publish' ORDER BY p.post_date ASC LIMIT 1;

使用explain看看

mysql> explain SELECT p.ID FROM wp_posts AS p INNER JOIN wp_term_relationships AS tr ON p.ID = tr.object_id INNER JOIN wp_term_taxonomy tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE p.post_date > '2017-07-04 09:57:50' AND p.post_type = 'post' AND tt.taxonomy = 'category' AND tt.term_id IN (4) AND p.post_status = 'publish' ORDER BY p.post_date ASC LIMIT 1\G
 *************************** 1. row ***************************
 id: 1
 select_type: SIMPLE
 table: tt
 type: const
 possible_keys: PRIMARY,term_id_taxonomy,taxonomy
 key: term_id_taxonomy
 key_len: 106
 ref: const,const
 rows: 1
 Extra: Using temporary; Using filesort
 *************************** 2. row ***************************
 id: 1
 select_type: SIMPLE
 table: tr
 type: ref
 possible_keys: PRIMARY,term_taxonomy_id
 key: term_taxonomy_id
 key_len: 8
 ref: const
 rows: 5576
 Extra:
 *************************** 3. row ***************************
 id: 1
 select_type: SIMPLE
 table: p
 type: eq_ref
 possible_keys: PRIMARY,type_status_date
 key: PRIMARY
 key_len: 8
 ref: aikanwen.tr.object_id
 rows: 1
 Extra: Using where
 3 rows in set (0.19 sec)

看起来就是个灾难现场,这种查询会随着分类的增加而变得奇慢无比,因为有时候分类和标签可能会达到几万几十万个!

分类优化

同首页,只查询分类的最新一些文章,甚至是提前生成的静态页面。

插件优化

wordpress最常用的插件可能是wp_postviews了,但是对于百万文章的wordpress来说,这个插件可能是个灾难(如果你用到了它的排行榜的话)。

这个排行榜会使用一个如下的查询

SELECT wp_posts.ID FROM wp_posts INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) WHERE 1=1 AND ( 
 wp_postmeta.meta_key = 'views'
) AND wp_posts.post_type IN ('post', 'page', 'attachment') AND (wp_posts.post_status = 'publish' OR wp_posts.post_author = 1 AND wp_posts.post_status = 'private') GROUP BY wp_posts.ID ORDER BY wp_postmeta.meta_value+0 DESC LIMIT 0, 10;

这种查询也是一个灾难,对于wp来说,wp_post_meta表中根本没有meta_key 和 meta_value的索引,也是根本无法使用索引做排序,所以只能使用filesort,需要全表扫描。可以看看explain。

mysql> explain SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) WHERE 1=1 AND ( wp_postmeta.meta_key = 'views' ) AND wp_posts.post_type IN ('post', 'page', 'attachment') AND (wp_posts.post_status = 'publish' OR wp_posts.post_author = 1 AND wp_posts.post_status = 'private') GROUP BY wp_posts.ID ORDER BY wp_postmeta.meta_value+0 DESC LIMIT 0, 10 \G;
 *************************** 1. row ***************************
 id: 1
 select_type: SIMPLE
 table: wp_postmeta
 type: ALL
 possible_keys: post_id,meta_key
 key: NULL
 key_len: NULL
 ref: NULL
 rows: 67053
 Extra: Using where; Using temporary; Using filesort
 *************************** 2. row ***************************
 id: 1
 select_type: SIMPLE
 table: wp_posts
 type: eq_ref
 possible_keys: PRIMARY,type_status_date,post_author
 key: PRIMARY
 key_len: 8
 ref: aikanwen.wp_postmeta.post_id
 rows: 1
 Extra: Using where
 2 rows in set (0.17 sec)

这种排序一次,基本就是个灾难。别说百万,十万文章蜘蛛都能搞挂了。

事实上,在文章达到百万的时候,涉及到数据库读写的插件最好都不要乱用,一不小心就是个灾难。

后台优化

后台页面在打开的时候会查询当前作者的所有文章以及各个状态的文章数量,这会扫描全表,别说百万文章了,就算二十万文章也会卡死。

最好的办法就是去掉这些查询,然而去掉这些查询会让后台展示不正常,因此只能利用缓存将这些数量存起来,这样后台的速度就很快了。虽然会有展示不及时的问题,但是到了这个文章量,这已经不是主要的问题了。

全站缓存

这是最重要的一步了,再多的优化也只能保证你的百万文章站点能正常打开,但是如果访问的人一多,站点依然会卡死,甚至服务器宕机。这个时候就必须上全站缓存。看了一下市面上所有的缓存插件,也只有一个满足要求了——imwpcache。

imwpcache支持永不过期的缓存,并且支持使用sqlite作为缓存,这比使用文件缓存更好。文件缓存太分散,几万文章还好,当达到了百万时候,清理这些缓存简直是一个灾难。

总结

经过这些优化之后,支撑百万文章基本不是问题。对于普通用户来说,做到这些可能会比较困难,尤其是主题。现在市面上主题基本不会考虑这么多的文章量,文章量一上来,网站基本就瘫痪了,所以目前最佳策略还是用缓存插件,当然如果你有动手能力,也可以尝试一下去掉这些耗资源的查询,虽然可能会损失一些功能,但是能支撑这么多文章足以弥补这些损失。

你可能还喜欢下面这些文章

Redis主从模式下从库过期的key仍然能够被读到的解决方案

Redis主从模式下,当对一个key设定过期时间,到期之后从库依然能够读取到数据。这个问题困扰了我很久,相信很多人都遇到过这种问题了。(前提是你不去读主库,并且redis版本在3.2以下)。经过一番搜寻,发现很多人遇到的问题和我一样。主Redissetex test 20 1+OKget test$11ttl test:18从Redisget test$11ttl test:7以上都没问题,然而过几秒再看从Redisttl test:-1get test$11test这个key已经过期了,然而还是可以获取到test的值。在使用Redis做锁的时候,如果直接取读从库的值,这就有大问题了。为什么从

js保存用户自定义的样式重新载入会闪烁的解决方案

在制作一个页面的时候,有需要前台js保存用户自定义的样式的需求,但是保存之后,重新刷新页面,会显示原来的样式,然后再变更为现在的自定义的样式。这是一个有闪烁的例子,点击打开保存样式之后,再重新强制刷新几次,可以看到页面在载入的时候会出现闪烁的情况。强迫症患者表示这不能接受,页面这么小的情况都闪烁的这么厉害,这页面大了,加载速度慢了,自定义样式还得等着加载完成之后才能显示,就失去了自定义的意义了。上面的闪烁是可以理解的,css渲染完成之后,js给body增加了一个class,浏览器又会重新渲染,因此会出现短暂的闪烁那么在渲染到head的时候,此时再用js给head标签里面增加css呢?这样不就在

使用expect之后无法使用rz和sz的解决方法

在机器太多的时候,我们会使用expect来自动化登录,然而使用expect之后就不能使用rz和sz了。经过一番寻找之后,发现有一个解决方案,在脚本之前增加一个export LC_CTYPE=en_US注意,这个语句放到登录脚本里面就可以了,不要放到.bash_profile里面,如果放到bash_profile里面可能你当前的终端语言都变了,中文可能会乱码。这个缺点是远程机器里面的中文可能会乱码了,如果有更好的解决方案,我会在这里更新。

如何避免GIT修改文件权限导致的提交变更

默认情况下当文件权限变更的时候,GIT会认为该文件有变更,提交的时候会将权限变更的文件一并提交上去,这样会让我们的代码修改记录变得混乱。解决方案解决方案很简单,忽略文件权限的变更。使用如下命令:

记录一下使用中PDO出现的一个问题:Cannot execute queries while other unbuffered queries are active. Consider using PDOStatement::fetchAll().

在使用PDO的时候,一条sql语句打死都不执行,dump一下errorInfo试试,出现这样的错误信息问题描述居然告诉我还有语句没有执行完成?当前的查询未能执行,逗我么!考虑使用fetchAll,或者开启缓冲查询,行,你说得对….问题出现的使用场景服务器服务器为linux,安装了一个什么面板套件之类的,不是自家机器,也懒得去折腾,在本地的windows环境并没有该问题。程序笔者在对数据库的一个计数字段进行更新的时候,首先会先查询这个记录是否存在,如果存在则进行更新,如果不存在则先插入。问题就出现在记录不存在的时候,当我查询这条不存在的记录时候,发现这个记录不存在,然后进行插入,发现之前的查

赞赏

微信赞赏支付宝赞赏

《wordpress支撑百万文章解决方案》有2条评论

  1. 我也在使用这款插件,不错,而且不会占用cpu资源,我是选择sqlite缓存方式,目前的唯一问题是设置过期时间,但是到时间后不会删除缓存文件,希望站长开发者后期能解决。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注