WordPress速度优化历程

博客建立的第一年,我主要采用WP插件的方式优化访问速度,效果不错但是反应速度仍然偏慢,换VPS了正好又是寒假,想着手解决一下这个问题。

Stage One

  • 使用插件:Autoptimize

这款插件功能挺多的,能自动优化HTML/Javascript/CSS。对于兼容性比较好的主题,全部勾上基本没问题了。

然而用完之后,访问速度还是很慢,所以我开始质疑这款插件的效果(后来发现是自己太幼稚了,那台OpenVZ不能开BBR,1G内存而且疑似高度超售,php能跑得快、网速好才怪呢)。

Stage Two

  • 使用插件:Autoptimze、Async Javascript、Redis object cache
  • <head>修改:preload、preconnect(手动修改)
  • 主题文件修改(解决国内Google Font不可用的问题)

后来在折腾缓存的时候,偶然发现Redis可以用来给Wordpress加速(一开始也想搞memcache的,发现这台宝塔面板的机子做个Redis然后给WP装个插件弄起来更方便一点)。

一开始我想不靠这些插件轻装上阵,然而发现Wordpress的臃肿不是闹着玩的,Jetpack这种有免费图像缓存、Downtime监视功能的插件又不能不要,目光又回到了WordPress插件上。

同时在这个阶段我又发现了PageSpeed Insights,可以方便地对网站性能情况进行打分。或者,使用另一款GTmetrix,虽然高峰时期未注册用户要排队测试,但是不像PageSpeed Insights成绩会抽风,而且给出一些莫名其妙让人哭笑不得的优化建议(例如指出Google自家Analytics、AdSense在网页中内嵌的js需要优化等,自己打自己的脸,充分展示了大厂的宫斗风)。

测试过程中又穿插上解决国内google fonts无法使用的问题,根据浏览器页面的html源码(字体名称)在主题php中找到了字体加载路径,在未被墙的主机上下载了字体文件并上传到服务器上,替换掉主题php中的路径,搞定。顺便搞了波
font-display: fallback; ,(虽然对主题中的material-icons并没有什么卵用,但是评测分数提升了一些)。

Preload通俗来说就是告知浏览器,网页会在后面用到一些资源,可以提前进行下载。preload字体的话,直接在<head>里写就行(能插header的插件市场里一堆,就连管广告的Ad Inserter都带个修改header/footer的功能),我参考了这里(这篇文章详细介绍了preload的各种用法),在<head>里插入了下面几行代码:

<!--
请根据自己站点使用的字体信息编辑如下内容
-->
<link rel="preload" href="/wp-content/themes/realistic/font/KFOmCnqEu92Fr1Mu4mxK.woff2" as="font" type="font/woff2" crossorigin/>
<link rel="preload" href="/wp-content/themes/realistic/font/KFOlCnqEu92Fr1MmSU5fBBc4.woff2" as="font" type="font/woff2" crossorigin/>
<link rel="preload" href="/wp-content/themes/realistic/font/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2" as="font" type="font/woff2" crossorigin/>

此外,还有preconnect,作用是写在<head>里,让客户端提前连接站点,减少加载时间。和下文pagespeed的dns-prefetch有相似之处,但dns-prefetch只是查询DNS,并不连接。

<!--
域名列表请根据自己的情况填写
-->
<link href='https://1.gravatar.com' rel=preconnect />
<link href='https://secure.gravatar.com' rel=preconnect />
<link href='https://adservice.google.com' rel=preconnect />
<link href='https://www.googletagmanager.com' rel=preconnect />
<link href='https://www.googletagservices.com' rel=preconnect />
<link href='https://www.google-analytics.com' rel=preconnect />
<link href='https://pagead2.googlesyndication.com' rel=preconnect />
<link href='https://tpc.googlesyndication.com' rel=preconnect />
<link href='https://stats.wp.com' rel=preconnect />
<link href='https://widgets.wp.com' rel=preconnect />
<link href='https://c0.wp.com' rel=preconnect />
<link href='https://i0.wp.com' rel=preconnect />
<link href='https://i1.wp.com' rel=preconnect />
<link href='https://i2.wp.com' rel=preconnect />
<link href='https://s.wp.com' rel=preconnect />
<link href='https://s0.wp.com' rel=preconnect />
<link href='https://s1.wp.com' rel=preconnect />
<link href='https://s2.wp.com' rel=preconnect />
<link href='https://pixel.wp.com' rel=preconnect />
<link href='https://public-api.wordpress.com' rel=preconnect />
<link href='https://www.gravatar.com' rel=preconnect />
<link href='https://googleads.g.doubleclick.net' rel=preconnect />

详细配置之后,分数从初始40分左右提高到56分(移动端)。扣分项主要还是TTFB和阻塞渲染的时长这两项。

Stage Three

  • Nginx模块:ngx_pagespeed(其实pagespeed也有Apache的Module)
  • 插件:Redis object cache
  • <head>修改:preload、preconnect (手动修改)

用了Cloudflare,56分的成绩在国内某些网络下(没错,说的就是你这个辣鸡联通,就是因为你,Cloudflare成了名副其实的减速CDN)是远远不够用的,还得再找提分点。偶然的机会盯上了pagespeed模块。谷歌出品,必属精品BBR就是谷歌出的一款服务器module,所以想着试试。

Ubuntu 18.04的安装过程(安装前请在此处查看最新版本,推荐使用稳定版):

sudo apt-get install build-essential zlib1g-dev libpcre3 libpcre3-dev unzip uuid-dev
#推荐不要再动除了NPS_VERSION以外的其他内容。
#[check the release notes for the latest version]
NPS_VERSION=1.13.35.2-stable
cd
wget https://github.com/apache/incubator-pagespeed-ngx/archive/v${NPS_VERSION}.zip
unzip v${NPS_VERSION}.zip
nps_dir=$(find . -name "*pagespeed-ngx-${NPS_VERSION}" -type d)
cd "$nps_dir"
NPS_RELEASE_NUMBER=${NPS_VERSION/beta/}
NPS_RELEASE_NUMBER=${NPS_VERSION/stable/}
psol_url=https://dl.google.com/dl/page-speed/psol/${NPS_RELEASE_NUMBER}.tar.gz
[ -e scripts/format_binary_url.sh ] && psol_url=$(scripts/format_binary_url.sh PSOL_BINARY_URL)
wget ${psol_url}
tar -xzvf $(basename ${psol_url})  # extracts to psol/

既然是nginx原来没有的module,当然要下载nginx源码重新编译安装啦,因为我用的宝塔面板,所以找到nginx源码位置/www/server/nginx/src。

cd /www/server/nginx/src
#需要查看原来安装的nginx的配置
nginx -V
#会出现一些代码,直接复制,然后./configure时在末尾加上--add-module=$HOME/$nps_dir ${PS_NGX_EXTRA_FLAGS}
#安装前推荐关闭nginx
sudo service nginx stop
./configure --user=www --group=www --prefix=/www/server/nginx --with-openssl=/www/server/nginx/src/openssl --add-module=$HOME/$nps_dir ${PS_NGX_EXTRA_FLAGS} --add-module=/www/server/nginx/src/ngx_devel_kit --add-module=/www/server/nginx/src/lua_nginx_module --add-module=/www/server/nginx/src/ngx_cache_purge --add-module=/www/server/nginx/src/nginx-sticky-module --with-http_stub_status_module --with-http_ssl_module --with-http_v2_module --with-http_image_filter_module --with-http_gzip_static_module --with-http_gunzip_module --with-stream --with-stream_ssl_module --with-ipv6 --with-http_sub_module --with-http_flv_module --with-http_addition_module --with-http_realip_module --with-http_mp4_module --with-ld-opt=-Wl,-E --with-openssl-opt='enable-tls1_3 enable-weak-ssl-ciphers' --with-ld-opt=-ljemalloc --with-cc-opt=-Wno-error
make
sudo make install

(其他系统的安装及配置步骤目前从略,请参考此处,现在只贴出部分server部分配置代码,但官方文档指出可以在http部分全局开启,然后各分站点详细配置;更详细的配置选项请参考官网文档。)

警示:请仔细检查下面的配置是否符合站点需要,不正确的配置会导致资源无法访问或者应用运行缓慢。

#启用Pagespeed
pagespeed on;

# Nginx对于缓存要可写。为了最佳性能,可以使用tmpfs(载入运存中,因为动辄需要上G的空间,不推荐非独服使用)。
pagespeed FileCachePath /var/ngx_pagespeed_cache;
# 下面几个单位应该分别是KB/毫秒/个吧(CacheSize建议设置为站点总资源大小的5倍)
pagespeed FileCacheSizeKb            512000;
pagespeed FileCacheCleanIntervalMs   3600000;
pagespeed FileCacheInodeLimit        500000;

#Redis/Memcached请根据服务器实际,选择性开启,只能二选一。
#启用Redis支持(目前为实验性,有长时间使用后Redis进程无故停止的报告,而且个人测试发现会使WP Super Cache优化的TTFB失效)
#pagespeed RedisServer "127.0.0.1:6379";
#启用Memcached支持
#pagespeed MemcachedServers "host1:port1,host2:port2,host3:port3";

# Ensure requests for pagespeed optimized resources go to the pagespeed handler
# and no extraneous headers get set.
location ~ ".pagespeed.([a-z].)?[a-z]{2}.[^.]{10}.[^.]+" {
  add_header "" "";
}
location ~ "^/pagespeed_static/" { }
location ~ "^/ngx_pagespeed_beacon$" { }

# 压缩CSS
pagespeed EnableFilters rewrite_css;
# 合并CSS
pagespeed EnableFilters combine_css;
# 内嵌CSS
pagespeed EnableFilters inline_css;
# Flatten CSS imports
pagespeed EnableFilters flatten_css_imports;
# 重写CSS,优化加载渲染页面的CSS规则
pagespeed EnableFilters prioritize_critical_css;
# 移动CSS至JS之上
pagespeed EnableFilters move_css_above_scripts;
# 移动CSS到<head>中
pagespeed EnableFilters move_css_to_head;
# google字体直接写入html 目的是减少浏览器请求和DNS查询
pagespeed EnableFilters inline_google_font_css;
# 压缩js
pagespeed EnableFilters rewrite_javascript;
# 合并js
pagespeed EnableFilters combine_javascript;
# 延迟加载Javascript
pagespeed EnableFilters defer_javascript;
# 内联Javascript
pagespeed EnableFilters inline_javascript;
# 限制内联的js文件最大大小,便于大型js文件的静态缓存
pagespeed JsInlineMaxBytes 2560;
# 合并heads,只保留一个
pagespeed EnableFilters combine_heads;
# 将http-equiv元信息转换成HTTP头
pagespeed EnableFilters convert_meta_tags;
# html字符转小写
pagespeed LowercaseHtmlNames on;
# 移除 html 空白
pagespeed EnableFilters collapse_whitespace;
# 移除 html 注释
pagespeed EnableFilters remove_comments;
# DNS 预加载
pagespeed EnableFilters insert_dns_prefetch;
# 优化内嵌样式属性
pagespeed EnableFilters rewrite_style_attributes;
# 压缩图片
pagespeed EnableFilters rewrite_images;
# 不加载显示区域以外的图片
pagespeed EnableFilters lazyload_images;
# 禁止在onload事件后立即加载图片(不推荐启用),在极端情况下(如多图页面)可能会导致用户体验极差
#pagespeed LazyloadImagesAfterOnload off;
# 图片预加载
pagespeed EnableFilters inline_preview_images;
# 移动端图片自适应重置
pagespeed EnableFilters resize_mobile_images;
# 响应式图像,需启用rewrite_images
pagespeed EnableFilters responsive_images;
# 增强响应式图像的功能,在用户放大时加载高分辨率图像
# 此项启用后会在页面内自动插入一段js以实现功能
#pagespeed EnableFilters responsive_images_zoom;
# 雪碧图片,图标很多的时候很有用
pagespeed EnableFilters sprite_images;
# 扩展缓存 改善页面资源的可缓存性
pagespeed EnableFilters extend_cache;
pagespeed XHeaderValue "Powered By ngx_pagespeed";
pagespeed SupportNoScriptEnabled false;
# admin直接访问 <域名>/pagespeed_admin 就可以打开管理员界面了。
pagespeed Statistics on;
pagespeed StatisticsLogging on;
pagespeed LogDir /var/log/pagespeed;
pagespeed AdminPath /pagespeed_admin;
# 缩写站内链接地址
pagespeed EnableFilters trim_urls;
# 复用页面内已经加载过的图片
pagespeed EnableFilters dedup_inlined_images;
# 当属性值等于默认值时,移除HTML文件中的这些值,减少流量且便于压缩
pagespeed EnableFilters elide_attributes;
# 提示浏览器提前加载用到的JS/CSS
pagespeed EnableFilters hint_preload_subresources;
# 去除HTML中不必要的引号
pagespeed EnableFilters remove_quotes;
# 去除HTML中的注释
pagespeed EnableFilters remove_comments;
# 将对噪声敏感的非动画GIF/PNG转换为无损WebP
pagespeed EnableFilters convert_to_webp_lossless;
# 将动画GIF转换为WebP
pagespeed EnableFilters convert_to_webp_animated;
# 将静态GIF转换为PNG
pagespeed EnableFilters convert_gif_to_png;
# 将非噪声敏感的PNG转换为JPG
pagespeed EnableFilters convert_png_to_jpeg;
# 将非噪声敏感的JPG转换为WebP
pagespeed EnableFilters convert_jpeg_to_webp;
# 允许清空缓存
pagespeed EnableCachePurge on;
# 无视no-transform,进行优化
pagespeed DisableRewriteOnNoTransform off;
# 优化JS引用的图片
pagespeed InPlaceResourceOptimization on;
pagespeed EnableFilters in_place_optimize_for_browser;

警示:对于部分网页,上述功能全开会出现问题,需要详细调试加以排除。

然后我停用了插件,发现自己还是too young, too simple……

几乎没什么卵用,阻塞渲染的资源还是那几个JS和死活搞不定的CSS。

Stage Four

  • Nginx模块:ngx_pagespeed
  • 插件:Autoptimize、Redis object cache
  • <head>修改:Preload、Preconnect(手动修改)

于是又请回了Autoptimize,至于Async Javascript就不用了,因为pagespeed对js的异步加载处理的很好了。

在再次尝试Autoptimze启用CSS优化的时候发现存在主题样式错乱的问题,遂关闭之,单用JS优化足够了。

分数好像又高了那么一丢丢(或许是心理作用)。

Stage Five

  • Nginx模块:ngx_pagespeed
  • 插件:Redis object cache、WP Super Cache
  • <head>修改:Preload、Preconnect(手动修改)

启用WP Super Cache,尝试从Wordpress层面生成静态页面,进一步优化TTFB。暴力地开启了预生成静态页面的功能,当爬虫/非注册用户访问的时候,直接提供已经生成的静态页面。最终优化TTFB到0.1秒左右(原来是1秒以上)。详细的非官方配置指导,请参照这里

此外,在查看Pagespeed Console时,发现了下图所示信息。

翻车现场1(Cache-Control没有设置为public[默认为private])
目前原因还不是很明确
翻车现场2(严格来说不能算是翻车,因为外站资源没办法处理的,此处主要是由于使用了Jetpack的图像加速功能,但这及家伙在国内也是名副其实的减速功能,大量图像资源储存在外站)
翻车现场3(尝试从缓存中加载时发现资源已过期)

想到自己博客上的资源是上传了就不会再动的,此外非本域名的一些内容Pagespeed似乎不会进行优化,所以进一步改进pagespeed配置以及nginx对特定资源的expire/Cache-Control设置尝试改善问题。

# 为非本域名,但仍然由你掌控的资源优化(Authorizing domains)
# 大致要求是添加的站点是由你控制的,也启用了pagespeed
# !!!!!!!
# !请根据自己网站实际情况进行调整
# !!!!!!!
# 
#pagespeed Domain https://foo.yourdomain.com;

# 下面的几种文件类型基本涵盖Wordpress的大多数内容了
# 请根据站点实际进行调整
# expires 对于长期不变的资源设置长一点,或者直接max
# Cache-Control public一定要加上,否则pagespeed没办法缓存
# 对Wordpress效果不明显,疑似php资源无法缓存

location ~ .*.(gif|jpg|jpeg|png|bmp|swf|ico)$
{
	add_header Cache-Control public,max-age=5184000;
	expires      60d;
}

location ~ .*.(js|css|json)?$
{
	add_header Cache-Control public,max-age=2592000;
	expires      30d;
}
    
location ~ .*.(woff|woff2)$
{
    	add_header Cache-Control public,max-age=2592000;
	expires		30d;
}

此外,还可以改善gzip配置来尝试解决问题,也可以试试Brotli,和Pagespeed的配置方式一样,也需要编译安装(此处略)。

# 当然写在nginx配置里啦
gzip on;
gzip_min_length 256;
gzip_buffers 4 16k;
gzip_http_version 1.1;
gzip_comp_level 4;
gzip_types
	application/atom+xml
	application/javascript
	application/json
	application/ld+json
	application/manifest+json
	application/rss+xml
	application/geo+json
	application/vnd.ms-fontobject
	application/x-font-ttf
	application/x-web-app-manifest+json
	application/xhtml+xml
	application/xml
	application/rdf+xml
	font/collection
	font/opentype
	font/otf
	font/ttf
	image/bmp
	image/svg+xml
	image/x-icon
	text/cache-manifest
	text/css
	text/javascript
	text/plain
	text/vcard
	text/vnd.rim.location.xloc
	text/vtt
	text/x-component
	text/x-cross-domain-policy;
gzip_vary on;
gzip_proxied any;
gzip_disable "MSIE [1-6]\.";

如果不恰当地设置pagespeed Domain就会变成这样……

翻车现场4(不恰当的设置pagespeed Domain导致pagespeed重写url时写成了无法访问的url)
我承认前面那几个woff是自己写相对路径写错了

还是老老实实地改回来吧。

折腾完这一波,发现Pagespeed Insights得分又降了回来,好气啊。同时发现Pagespeed Console还是那样子,算了算了(听说用了这玩意要常访问站点才能更快有效果?而且好像改一遍nginx设置就会自动清一遍缓存)。

结束语

优化终究是有限度的,要么采取插件(或者模块)的形式,要么就升级硬件配置。前者影响代码结构,后者在同样动态生成页面时对TTFB(响应时间)影响更大。当代码优化到极限后,还想白嫖提升速度?不存在的。

因为自己是初学者,所以可能本文会有很多大佬觉得很naive的地方,原理不是很清楚,配置可能也有误或者显得多余,希望大佬在评论区里纠正交流一下。

最后吐槽个Cloudflare,我都对博客域名停用Add HTML的那个APP了,然而还在博客的<head>里乱拉屎(插用不到的JS)。

修订日志

20190930:试验性地增加优化JS引用图片的设置项,灵感源于此博文,在此表示感谢

label, ,

1条评论

  1. Edwin 2019年9月19日 回复

发表评论

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据