Wordpress+nginx的几个优化
最近把几个Wordpress站点做了下优化,总结下:
-
数据库换用SQLite
对于小访问量的站点,即使是优化过内存占用的MySQL依然有不小的资源消耗。正好最近在WP上看到有新的SQLite的插件:https://wordpress.org/plugins/sqlite-integration/ 于是决定试用下。SQLite比之MySQL最大的好处就是不需要一个进程来维护数据库,对于服务器的资源占用更小。在访问量不大的情况下SQLite的性能不比MySQL差太多,并且Wordpress还有各种各样的缓存机制,实际访问数据库的时候更少。
SQLite Integration是由小島登志泰制作的让Wordpress支持SQLite数据库的插件。最好的安装方式是全新安装Wordpress时先把插件解压至wp-content/plugins并且将db.php放到wp-content中,这样安装时Wordpress会自动地建立数据库。对于已有使用MySQL作为数据库的Wordpress,个人的建议是把数据导出后,全新安装再用Importer导入,因为直接转换的数据库某些字段上有问题,会造成部分插件不正常工作。
由于是使用SQLite并且用db.php替换了数据库类,在有SQLite的情况下某些插件是不兼容的,比如W3 Total Cache。具体的列表在http://dogwood.skr.jp/wordpress/sqlite-integration/#plugin-compat中有。不过大多数的插件还是可以正常使用,包括WP Super Cache,所以对我的影响不大。SQLite除了数据库类还有一个非常用户友好的界面,在里面可以很方便的查看数据库是否有问题,执行vacuum清理数据库或者是在WP更新插件以后更新db.php(WP的插件更新无法更新在wp-content中的文件)。
-
php-fpm使用ondemand
不少的php-fpm都是使用的dynamic方式fork子进程处理php请求,当php-fpm进程启动时就会自动fork出pm.start_server规定的数目的子进程,并且在没有php请求的时候也不退出。对于小访问量的网站和低端服务器来说,ondemand应该是一个更节省资源的方案。ondemand仅在有php请求时才fork出子进程处理,并且处理完毕后一段时间内没有请求就会退出。打开ondemand模式在pool.d里面的pool配置文件内修改:
pm = ondemand pm.max_children = 12 ;最大子进程数 pm.process_idle_timeout = 10s ;10s内没有新请求就杀掉子进程 pm.max_requests = 1000 ;每个子进程最大处理1000次请求
并且如果有多个网站的话建议每个网站用一个单独的pool(单独的端口/UNIX socket),这样即使一个网站崩溃也不会让其他的同时502。
-
nginx+fasicgi_cache
nginx中的fastcgi模块提供了对于FastCGI请求的缓存fastcgi_cache,使用这个可以缓存PHP的请求,减小对PHP/数据库的压力。然而nginx自身没有提供对于缓存的手工清理的模块,需要一个第三方的插件ngx_cache_purge来完成这个功能。Debian用户可以安装nginx-naxsi这个包,里面提供了这个插件。
安装完之后使用以下命令测试:
nginx -V 2>&1 | grep nginx-cache-purge -o
出现nginx-cache-purge即代表成功加载。
之后需要在/etc/nginx/nginx.conf中设置:
fastcgi_cache_path /var/run/nginx-cache levels=1:2 keys_zone=WORDPRESS:64m inactive=60m; fastcgi_cache_key "$scheme$request_method$host$request_uri"; fastcgi_cache_use_stale error timeout invalid_header http_500; fastcgi_ignore_headers Cache-Control Expires Set-Cookie; add_header nginx-FastCGI-Cache $upstream_cache_status;
分配了一个64m的缓存用于fastcgi。建议按照http://codex.wordpress.org/Nginx中的方式配置nginx。然后将fastcgi.conf改为以下内容:
fastcgi_index index.php; fastcgi_intercept_errors on; fastcgi_pass unix:/tmp/$server_name.sock; fastcgi_connect_timeout 300s; fastcgi_send_timeout 300s; fastcgi_read_timeout 300s; fastcgi_buffer_size 128k; fastcgi_buffers 256 16k; fastcgi_busy_buffers_size 256k; fastcgi_temp_file_write_size 256k; reset_timedout_connection on; fastcgi_cache_bypass $no_cache; fastcgi_no_cache $no_cache; fastcgi_cache WORDPRESS; fastcgi_cache_valid 200 60m;
同时建立fastcgi_cache的规则,规定哪些内容不缓存:
# fastcgi_cache start set $no_cache 0; # POST requests and urls with a query string should always go to PHP if ($request_method = POST) { set $no_cache 1; } if ($query_string != "") { set $no_cache 1; } # Don't cache uris containing the following segments if ($request_uri ~* "(/wp-admin/|/xmlrpc.php|/wp-(app|cron|login|register|mail).php|wp-.*.php|/feed/|index.php|wp-comments-popup.php|wp-links-opml.php|wp-locations.php|sitemap(_index)?.xml|[a-z0-9_-]+-sitemap([0-9]+)?.xml)") { set $no_cache 1; } # Don't use the cache for logged in users or recent commenters if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") { set $no_cache 1; } location ~ /purge(/.*) { allow 127.0.0.1; deny all; fastcgi_cache_purge WORDPRESS "$scheme$request_method$host$1"; }
最后在global/wordpress.conf中的# Uncomment one of the lines below for the appropriate caching plugin (if used)部分引用上一步建立的fastcgi_cache。
Wordpress里面安装nginx插件,打开Enable Cache Purge和Enable Nginx Timestamp in HTML选项。
重新加载配置之后测试网站的页面:
curl -I /2013/11/1098
第一次结果可能这样:
HTTP/1.1 200 OK Server: nginx Date: Fri, 06 Mar 2015 23:00:52 GMT Content-Type: text/html; charset=UTF-8 Connection: keep-alive Keep-Alive: timeout=5 Vary: Accept-Encoding Set-Cookie: PHPSESSID=2jssffgqjeaac09chl0fhfbis2; path=/; HttpOnly Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache Vary: Cookie X-Pingback: /xmlrpc.php Link: ?p=1098>; rel=shortlink nginx-FastCGI-Cache: MISS
再测试一次应该有:
HTTP/1.1 200 OK Server: nginx Date: Fri, 06 Mar 2015 23:00:54 GMT Content-Type: text/html; charset=UTF-8 Connection: keep-alive Keep-Alive: timeout=5 Vary: Accept-Encoding Set-Cookie: PHPSESSID=2jssffgqjeaac09chl0fhfbis2; path=/; HttpOnly Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache Vary: Cookie X-Pingback: /xmlrpc.php Link: ?p=1098>; rel=shortlink nginx-FastCGI-Cache: HIT
注意到最后一行的nginx-FastCGI-Cache由MISS变为HIT,这样代表nginx的fastcgi_cache起作用了。
PS:nginx打开multi_accept之后php-fpm的子进程很容易僵尸化,不知是否因为同时访问太多的缘故(multi_accept让worker同时接受多个访问)。
本文参考:
http://dogwood.skr.jp/wordpress/sqlite-integration/#plugin-compat
https://rtcamp.com/wordpress-nginx/tutorials/single-site/fastcgi-cache-with-purging/
https://rtcamp.com/tutorials/nginx/upstream-cache-status-in-response-header/