Redis 是一个高级的 key-value 存储系统,类似 memcached,所有内容都存在内存中,因此每秒钟可以超过 10 万次 GET 操作。
我下面提出的解决方案是在 Redis 中缓存所有输出的 HTML 内容而无需再让 WordPress 重复执行页面脚本。这里使用 Redis 代替 Varnish 设置简单,而且可能更快。
安装 Redis
如果你使用的是 Debian 或者衍生的操作系统可使用如下命令安装 Redis:
<font face="Courier New">1</font> | apt-get install <font face="Courier New">redis-server</font> |
或者阅读 安装指南
使用 Predis 作为 Redis 的 PHP 客户端
你需要一个客户端开发包以便 PHP 可以连接到 Redis 服务上。
这里我们推荐 Predis. 上传 predis.php 到 WordPress 的根目录。
前端缓存的 PHP 脚本
步骤1: 在 WordPress 的根目录创建新文件 index-with-redis.php ,内容如下:
<font face="Courier New">001</font> | <font face="Courier New"><?php </font> |
<font face="Courier New">002</font> | <font face="Courier New"> </font> |
<font face="Courier New">003</font> | <font face="Courier New">// Change these two variables: </font> |
<font face="Courier New">004</font> | <font face="Courier New"> </font> |
<font face="Courier New">005</font> | <font face="Courier New">$seconds_of_caching</font> = 60*60*24*7; // 7 days. |
<font face="Courier New">006</font> | <font face="Courier New"> </font> |
<font face="Courier New">007</font> | <font face="Courier New">$ip_of_this_website</font> = '204.62.14.112' ; |
<font face="Courier New">008</font> | <font face="Courier New"> </font> |
<font face="Courier New">009</font> | <font face="Courier New"> </font> |
<font face="Courier New">010</font> | <font face="Courier New"> </font> |
<font face="Courier New">011</font> | <font face="Courier New">/* </font> |
<font face="Courier New">012</font> | <font face="Courier New"> </font> |
<font face="Courier New">013</font> | <font face="Courier New">- This file is written by Jim Westergren, copyright all rights reserved. </font> |
<font face="Courier New">014</font> | <font face="Courier New"> </font> |
<font face="Courier New">015</font> | <font face="Courier New">- See more here: www.jimwestergren.com/wordpress-with-redis-as-a-frontend-cache/ </font> |
<font face="Courier New">016</font> | <font face="Courier New"> </font> |
<font face="Courier New">017</font> | <font face="Courier New">- The code is free for everyone to use how they want but please mention my name and link to my article when writing about this. </font> |
<font face="Courier New">018</font> | <font face="Courier New"> </font> |
<font face="Courier New">019</font> | <font face="Courier New">- Change $ip_of_this_website to the IP of your website above. </font> |
<font face="Courier New">020</font> | <font face="Courier New"> </font> |
<font face="Courier New">021</font> | <font face="Courier New">- Add ?refresh=yes to the end of a URL to refresh it's cache </font> |
<font face="Courier New">022</font> | <font face="Courier New"> </font> |
<font face="Courier New">023</font> | <font face="Courier New">- You can also enter the redis client via the command prompt with the command "redis-cli" and then remove all cache with the command "flushdb". </font> |
<font face="Courier New">024</font> | <font face="Courier New"> </font> |
<font face="Courier New">025</font> | <font face="Courier New">*/</font> |
<font face="Courier New">026</font> | <font face="Courier New"> </font> |
<font face="Courier New">027</font> | <font face="Courier New"> </font> |
<font face="Courier New">028</font> | <font face="Courier New"> </font> |
<font face="Courier New">029</font> | <font face="Courier New">// Very necessary if you use Cloudfare: </font> |
<font face="Courier New">030</font> | <font face="Courier New"> </font> |
<font face="Courier New">031</font> | <font face="Courier New">if</font> (isset( $_SERVER [ 'HTTP_CF_CONNECTING_IP' ])) { |
<font face="Courier New">032</font> | <font face="Courier New"> </font> |
<font face="Courier New">033</font> | $_SERVER [ 'REMOTE_ADDR' ] = $_SERVER [ 'HTTP_CF_CONNECTING_IP' ]; |
<font face="Courier New">034</font> | <font face="Courier New"> </font> |
<font face="Courier New">035</font> | <font face="Courier New">} </font> |
<font face="Courier New">036</font> | <font face="Courier New"> </font> |
<font face="Courier New">037</font> | <font face="Courier New"> </font> |
<font face="Courier New">038</font> | <font face="Courier New"> </font> |
<font face="Courier New">039</font> | <font face="Courier New">// This is from WordPress: </font> |
<font face="Courier New">040</font> | <font face="Courier New"> </font> |
<font face="Courier New">041</font> | define( 'WP_USE_THEMES' , true); |
<font face="Courier New">042</font> | <font face="Courier New"> </font> |
<font face="Courier New">043</font> | <font face="Courier New"> </font> |
<font face="Courier New">044</font> | <font face="Courier New"> </font> |
<font face="Courier New">045</font> | <font face="Courier New">// Start the timer: </font> |
<font face="Courier New">046</font> | <font face="Courier New"> </font> |
<font face="Courier New">047</font> | <font face="Courier New">function</font> getmicrotime( $t ) { |
<font face="Courier New">048</font> | <font face="Courier New"> </font> |
<font face="Courier New">049</font> | list( $usec , $sec ) = explode ( " " , $t ); |
<font face="Courier New">050</font> | <font face="Courier New"> </font> |
<font face="Courier New">051</font> | <font face="Courier New">return</font> ((float) $usec + (float) $sec ); |
<font face="Courier New">052</font> | <font face="Courier New"> </font> |
<font face="Courier New">053</font> | <font face="Courier New">} </font> |
<font face="Courier New">054</font> | <font face="Courier New"> </font> |
<font face="Courier New">055</font> | <font face="Courier New">$start</font> <font face="Courier New">= microtime(); </font> |
<font face="Courier New">056</font> | <font face="Courier New"> </font> |
<font face="Courier New">057</font> | <font face="Courier New"> </font> |
<font face="Courier New">058</font> | <font face="Courier New"> </font> |
<font face="Courier New">059</font> | <font face="Courier New">// Initiate redis and the PHP client for redis: </font> |
<font face="Courier New">060</font> | <font face="Courier New"> </font> |
<font face="Courier New">061</font> | include ( "predis.php" ); |
<font face="Courier New">062</font> | <font face="Courier New"> </font> |
<font face="Courier New">063</font> | <font face="Courier New">$redis</font> = new Predis\Client( '' ); |
<font face="Courier New">064</font> | <font face="Courier New"> </font> |
<font face="Courier New">065</font> | <font face="Courier New"> </font> |
<font face="Courier New">066</font> | <font face="Courier New"> </font> |
<font face="Courier New">067</font> | <font face="Courier New">// few variables: </font> |
<font face="Courier New">068</font> | <font face="Courier New"> </font> |
<font face="Courier New">069</font> | <font face="Courier New">$current_page_url</font> = "http://" . $_SERVER [ 'HTTP_HOST' ]. $_SERVER [ 'REQUEST_URI' ]; |
<font face="Courier New">070</font> | <font face="Courier New"> </font> |
<font face="Courier New">071</font> | <font face="Courier New">$current_page_url</font> = str_replace ( '?refresh=yes' , '' , $current_page_url ); |
<font face="Courier New">072</font> | <font face="Courier New"> </font> |
<font face="Courier New">073</font> | <font face="Courier New">$redis_key</font> = md5( $current_page_url ); |
<font face="Courier New">074</font> | <font face="Courier New"> </font> |
<font face="Courier New">075</font> | <font face="Courier New"> </font> |
<font face="Courier New">076</font> | <font face="Courier New"> </font> |
<font face="Courier New">077</font> | <font face="Courier New">// This first case is either manual refresh cache by adding ?refresh=yes after the URL or somebody posting a comment </font> |
<font face="Courier New">078</font> | <font face="Courier New"> </font> |
<font face="Courier New">079</font> | <font face="Courier New">if</font> (isset( $_GET [ 'refresh' ]) || substr ( $_SERVER [ 'REQUEST_URI' ], -12) == '?refresh=yes' || ( $_SERVER [ 'HTTP_REFERER' ] == $current_page_url && $_SERVER [ 'REQUEST_URI' ] != '/' && $_SERVER [ 'REMOTE_ADDR' ] != $ip_of_this_website )) { |
<font face="Courier New">080</font> | <font face="Courier New"> </font> |
<font face="Courier New">081</font> | require ( './wp-blog-header.php' ); |
<font face="Courier New">082</font> | <font face="Courier New"> </font> |
<font face="Courier New">083</font> | $redis ->del( $redis_key ); |
<font face="Courier New">084</font> | <font face="Courier New"> </font> |
<font face="Courier New">085</font> | <font face="Courier New"> </font> |
<font face="Courier New">086</font> | <font face="Courier New"> </font> |
<font face="Courier New">087</font> | <font face="Courier New">// Second case: cache exist in redis, let's display it </font> |
<font face="Courier New">088</font> | <font face="Courier New"> </font> |
<font face="Courier New">089</font> | } else <font face="Courier New">if</font> ( $redis ->exists( $redis_key )) { |
<font face="Courier New">090</font> | <font face="Courier New"> </font> |
<font face="Courier New">091</font> | <font face="Courier New">$html_of_current_page</font> = $redis ->get( $redis_key ); |
<font face="Courier New">092</font> | <font face="Courier New"> </font> |
<font face="Courier New">093</font> | <font face="Courier New">echo</font> $html_of_current_page ; |
<font face="Courier New">094</font> | <font face="Courier New"> </font> |
<font face="Courier New">095</font> | <font face="Courier New">echo</font> "<!-- This is cache -->" ; |
<font face="Courier New">096</font> | <font face="Courier New"> </font> |
<font face="Courier New">097</font> | <font face="Courier New"> </font> |
<font face="Courier New">098</font> | <font face="Courier New"> </font> |
<font face="Courier New">099</font> | <font face="Courier New">// third: a normal visitor without cache. And do not cache a preview page from the wp-admin: </font> |
<font face="Courier New">100</font> | <font face="Courier New"> </font> |
<font face="Courier New">101</font> | } else <font face="Courier New">if</font> ( $_SERVER [ 'REMOTE_ADDR' ] != $ip_of_this_website && strstr ( $current_page_url , 'preview=true' ) == false) { |
<font face="Courier New">102</font> | <font face="Courier New"> </font> |
<font face="Courier New">103</font> | require ( './wp-blog-header.php' ); |
<font face="Courier New">104</font> | <font face="Courier New"> </font> |
<font face="Courier New">105</font> | <font face="Courier New">$html_of_current_page</font> = file_get_contents ( $current_page_url ); |
<font face="Courier New">106</font> | <font face="Courier New"> </font> |
<font face="Courier New">107</font> | $redis ->setex( $redis_key , $seconds_of_caching , $html_of_current_page ); |
<font face="Courier New">108</font> | <font face="Courier New"> </font> |
<font face="Courier New">109</font> | <font face="Courier New">echo</font> "<!-- Cache has been set -->" ; |
<font face="Courier New">110</font> | <font face="Courier New"> </font> |
<font face="Courier New">111</font> | <font face="Courier New"> </font> |
<font face="Courier New">112</font> | <font face="Courier New"> </font> |
<font face="Courier New">113</font> | <font face="Courier New">// last case: the normal WordPress. Should only be called with file_get_contents: </font> |
<font face="Courier New">114</font> | <font face="Courier New"> </font> |
<font face="Courier New">115</font> | } else <font face="Courier New">{ </font> |
<font face="Courier New">116</font> | <font face="Courier New"> </font> |
<font face="Courier New">117</font> | require ( './wp-blog-header.php' ); |
<font face="Courier New">118</font> | <font face="Courier New"> </font> |
<font face="Courier New">119</font> | <font face="Courier New">} </font> |
<font face="Courier New">120</font> | <font face="Courier New"> </font> |
<font face="Courier New">121</font> | <font face="Courier New"> </font> |
<font face="Courier New">122</font> | <font face="Courier New"> </font> |
<font face="Courier New">123</font> | <font face="Courier New"> </font> |
<font face="Courier New">124</font> | <font face="Courier New"> </font> |
<font face="Courier New">125</font> | <font face="Courier New">// Let's display some page generation time (note: CloudFlare may strip out comments): </font> |
<font face="Courier New">126</font> | <font face="Courier New"> </font> |
<font face="Courier New">127</font> | <font face="Courier New">$end</font> <font face="Courier New">= microtime(); </font> |
<font face="Courier New">128</font> | <font face="Courier New"> </font> |
<font face="Courier New">129</font> | <font face="Courier New">$t2</font> = (getmicrotime( $end ) - getmicrotime( $start )); |
<font face="Courier New">130</font> | <font face="Courier New"> </font> |
<font face="Courier New">131</font> | <font face="Courier New">if</font> ( $_SERVER [ 'REMOTE_ADDR' ] != $ip_of_this_website ) { |
<font face="Courier New">132</font> | <font face="Courier New"> </font> |
<font face="Courier New">133</font> | <font face="Courier New">echo</font> "<!-- Cache system by Jim Westergren. Page generated in " . round ( $t2 ,5). " seconds. -->" ; |
<font face="Courier New">134</font> | <font face="Courier New"> </font> |
<font face="Courier New">135</font> | <font face="Courier New">} </font> |
<font face="Courier New">136</font> | <font face="Courier New"> </font> |
<font face="Courier New">137</font> | <font face="Courier New">?></font> |
或者直接下载 index-with-redis.php
步骤2:将上述代码中的 IP 地址替换成你网站的 IP 地址
步骤3:在 .htaccess 中将所有出现 index.php 的地方改为 index-with-redis.php ,如果你使用的是 Nginx 则修改 nginx.conf 中的 index.php 为 index-with-redis.php(并重载 Nginx : killall -s HUP nginx)。
性能测试
- 没有 Redis 的情况下,平均首页执行 1.614 秒,文章页 0.174 秒(无任何缓存插件)
- 使用 Redis 的情况下,平均页面执行时间 0.00256 秒
我已经在我的博客中使用了如上的方法进行加速很长时间了,一切运行良好。
其他建议
我的环境是 Nginx + PHP-FPM + APC + Cloudflare + Redis. 安装在一个 nano VPS 中,无缓存插件。
请确认使用了 gzip 压缩,可加快访问速度。
访问 wp-admin
要访问 wp-admin 必须使用 /wp-admin/index.php 代替原来的 /wp-admin/.