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 ] &amp;&amp; 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

#备注:pagespeed也支持以dynamic module的方式被编译及加载,关于dynamic module的详细信息请参考nginx文档。

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

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

#启用Pagespeed
pagespeed on;

#配置共享内存元数据缓存
pagespeed CreateSharedMemoryMetadataCache "/var/ngx_pagespeed_cache/" 51200;
# Nginx对于缓存要可写。为了最佳性能,可以使用tmpfs(载入RAM中,不推荐RAM<1G设备使用)。
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";
#pagespeed MemcachedServers "host1:port1,host2:port2,host3:port3";

# Content-Security-Policy 头部
pagespeed HonorCsp on;
# 压缩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 GlobalAdminPath /pagespeed_global_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;

# 设置LoadFromFile,直接从服务器本地加载文件,避免了模拟http访问时遇到的各种Cache Control问题
# 需要针对自己服务器的静态资源情况进行修改
pagespeed LoadFromFile "https://foo.yourdomain/virtual_path" "/path/to/your/real/resources";

# pagespeed的EnableFilters是支持用","连接的,在nginx里可以写在http{}部分,只占用一行空间,且不用在server{}内重复配置,更为清爽。

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

然后我停用了插件,发现自己还是too young, too simple……几乎没什么卵用,阻塞渲染的资源还是那几个JS和死活搞不定的CSS。