:root{--puock-block-not-tran:100%}

我是如何让WordPress加载速度起飞的

65次阅读
没有评论

共计 5118 个字符,预计需要花费 13 分钟才能阅读完成。

WordPress 是世界上使用最广泛的网站系统之一,其官方宣称全球有 43% 的网站使用了 WordPress,这其中包括了 BBC America、英国联合国儿童基金会等网站,然而在中国,WordPress 受限于网络环境因素影响,使用起来只能说是差强人意,但是很多国产的小众 CMS(或 Blog)程序在扩展性、通用性和灵活性上都远不如 WordPress,以至于最终都换回了 WordPress,即便用户在访问它时,可能没有那么痛快。

Topstalk 一直以来都在使用 WordPress 作为 Blog 的网站平台,由于时(懒)间(惰)的关系,一直以来仅仅做了简单的优化,网页加载速度普遍在 2 秒之内,在可以接受的临界范围上徘徊。截止 2022 年 3 月 8 号,Topstalk 已经不间断运行了一千五百余天,我决定对 Topstalk 全站点的访问速度问题进行针对性优化,最终实现了动态网页处理时间缩短至之前的十二分之一,基本上可以做到在 0.1 秒左右完成,网站访问时间缩短至之前的六分之一,基本上可以实现 0.4 秒内的全内容加载。其实加载速度可以做的更短,但是我并不想以损失功能性和美观来一味的追求速度。

是什么拖慢了我的网站速度?

网站访问速度符合木桶效应,任意一个环节的迟缓,都会拖垮整个网站的加载时间,当然这也不全是在服务端就能解决的问题,例如用户的 DNS 解析速度、网络节点转发效率(例如用户经过了多层的内网路由,或者在企业中存在上网行为审计设备,以及 Qos 等因素),网络质量等原因,但这并不是我们能够解决的问题。

当用户访问一个站点时,首先通过 DNS 解析服务器解析到域名的指向,有可能是一个 IP 地址,也有可能是 CDN 节点(的域名),浏览器会带着请求,访问这个指向地址,访问请求从你设备的网卡向外发送,到家里的路由器进行 NAT 转换,再发送给 ISP(互联网服务提供商),考虑到现在 ISP 为了节省 IPv4 资源普遍开始组大内网,你的请求会在整个区域的内网中,再次找到网关进行 NAT 转换,进入到互联网,进入城市级别的各种路由节点中去,根据 IP 地址分配的规则,进入省域网络进行跨省的路由,直到请求被发送至服务器所在的城市,服务器机房的流量在 Qos 中权重较高,同时大多数主流机房都是直接接入骨干网络中去的,所以这最后一段的节点跳转会很少,进入机房的内网后,经过各类节点的流转最终访问到服务器,有点儿像我们出远门,从家里开车出发,进入小区道路,到城市道路,转入城市主干道,上高速,好在这整个流程在互联网的环境中,可以在几毫秒中完成,即便是跨越了多个地域,也不过是几十毫秒,对此环节感兴趣的朋友可以了解一下路由追踪,可以看到您访问某个位置时经过了哪些主要节点。上述内容绝大多数情况下我们无法改变,所以不在我们的优化范围内,但是也有变相的优化方案,会在后面展开聊聊。

当流量进入服务器后,由网卡通过 PCI- E 通道交给 CPU,CPU 根据系统层面(包括内核、系统防火墙)的设定,将请求交给逻辑程序,我们称之为前置或(正向)代理,一般由 Nginx、Apache 等程序去受理,并根据运行维护人员(站长)设定的规则调用脚本语言运算程序(例如 PHP,后文也会使用 PHP 举例)执行用户请求的 PHP 文件(我们暂且先不谈 http 和 https 握手的问题),理想情况下,这一部分可以实现纳秒级响应,所谓不理想情况一般是指磁盘 IO 负载高,或者磁盘 IO 延时造成的无法及时将请求的文件装入内存执行,还有 CPU 负载较高无法及时处理运算等情况,这部分内容显然不是造成网络访问瓶颈的主要问题,但也不容忽视,当 PHP 脚本本身存在问题,或者服务器配置跟不上、配置存在问题,也会成为网站速度拖后腿的原因。

PHP 开始处理用户请求的文件并生成 html 文件,这个过程如果不需要查询数据库的话,通常 200KB 以内的 html 文件在 0.001 秒内即可完成运算和生成,如果需要查询数据库的话,PHP 会根据用户请求文件的脚本,请求数据库,数据库一般不像前置程序或者 PHP 那么的轻,尤其是在大库还没有建立索引或者库中内容逻辑杂乱或过于有规律时,会大幅降低数据库效率,导致数据库负载增加,造成反馈给 PHP 数据时产生延时。

当 PHP 将 html 文件生成完毕后,会原路反回给用户,从用户的网卡请求至接受到返回 html 的这段时间,就是该 html 文件在浏览器中显示的所谓 TTFB。

但对于 WordPress 和大多数 PHP 程序来说,至此并没有结束,浏览器得到服务器返回的 html 文件后开始渲染网页,根据 html 文件中的内容,浏览器将从源站(您的服务器或其他的服务器)获取其他静态资源,包括但不仅限于图片、字体、js 脚本等数据,此时就需要考虑到服务器的带宽问题了,当您的服务器出口带宽为 1Mbps(俗称兆,全称兆比特每秒)时,代表您的服务器在 1 秒的单位时间中,最多可以传送 1 兆比特(bit,简写为 b),每 8 比特为 1 字节(Byte,简写为 B),您的实际速度在进行单位转换后,得出 128KB/s,即千(K)字节(B)每秒(s),那么如果您的 html 文件为 200KB,各类资源文件为 4.8MB 时,凑整计算此时这个页面完全加载完成有 5MB 大小,除以您的服务器出口带宽速度 128KB/s,得出在理想情况下需要 40 秒的时间才可加载完成,如果有多个用户同时访问共同抢占带宽这个时间还会更长。

html 加载的各类 css、js、font 资源文件,为了避免资源的重复存储的同时加快访问速度,有一些大型科技公司会将比较通用的、流行的资源文件通过 CDN 等技术进行全球分发,供自身和大家使用,例如 Google 字体服务,但是因众所周知的原因,在中国大陆访问 Google 的各种服务都不太顺畅,就导致一些很基础的资源文件加载时间超长,也有可能直接无法加载,导致网页变形或网站整体加载速度非常缓慢。

如何解决?

既然请求需要跨越千山万水去访问服务器的事实无法改变,我们首先要做到服务器节点离受众群体尽可能的近,例如我们针对北京市用户开设的网站,就可以选择将服务器部署在北京的机房,尽可能避免数据传输经过更多的节点,毕竟在不同时间段不同环境下不同情况中,ISP 不可能保证每一个数据包都能得到平等对待,也不可能做到任何节点任何时间都不存在性能(转发)瓶颈,减少数据流转是直接的解决方案之一,除此之外,当然也可以通过变相提高数据流转时的 Qos 权重或者采用更加高效、高速的网络通道去减少节点之间的流转次数,同时优化数据传输,例如使用阿里云推出的全站加速服务,将域名 cname 记录指向至全站加速服务域名,当用户访问您的站点时,将会请求至离用户最近的阿里云全站加速节点,由节点代替用户去请求服务器数据,并返回服务器传回的数据,与 CDN 不同的是全站加速并不会缓存动态资源,不会造成返回数据过时的情况发生(例如网站已经更新了内容,但是因为 CDN 缓存的数据还未超过有效期,则用户访问不会显示最新的网站内容,具体情况举例的话,可以理解为充值了但是显示余额还是零,但实际上网站已经更新了数据),同时还可以配置一些静态文件的缓存规则、(html)智能压缩等功能,实现类 CDN 的效果。

网站的服务器也应尽可能选择合理的配置,包括独享性能的处理器(此处指非共享型的云服务器),合理的内存容量和出口带宽,更高 IO 和更低延时的硬盘,避免将前置代理、PHP、数据库同时部署在同一个服务器中抢占资源(至少不要将数据库与前置代理、PHP 部署在一起)。在部署基于 PHP 语言的平台程序时(例如 WordPress),应避免部署过时的版本、非官方的版本,通常来说更高的版本除了带来更多的特性外,也会带来性能的提升(运算效率的提升)。如果平台程序支持,也应尽可能跟进最新的 PHP 版本,从 PHP7.0 开始,PHP 不仅修复了已知的安全漏洞,增加了更多的新特性,其运行效率也得到了极大的提升,即便是对小站点来说改善也是肉眼可见的。

大多数动态网站不可避免的会与数据库进行交互,每一次访问到涉及查询数据库的 PHP 脚本时,即便数据库的内容没有变化,也不会影响 PHP 执行对数据库的查询,这显然是非常低效的,此时我们可以通过 Redis 或 Memcached 对数据库进行缓存,两者均是基于内存的数据库缓存程序,避免了大量不必要的数据库查询,降低数据库负载的同时提升了 PHP 查询效率,尤其是对于大库来说,是非常有效的解决方案,同理,APCu 和 Opcache 可以在内存中缓存 PHP 的执行结果(并非最终 html 文件,而是函数级的缓存),减少多次请求同一个 PHP 脚本时的重复运算,但是还是需要针对不同的情况搭配更合适的缓存程序,不要一股脑全部部署,冗余的缓存并不会对执行效率有提升。

除了数据库、PHP 执行结果之外,我们甚至可以将 PHP 输出的 html 文件进行缓存,例如通过 WordPress 插件 WP Super Cache 来实现,当第一位用户访问某个 PHP 脚本时,输出的 html 将被缓存至指定文件夹内,在动态页面没有变化时,始终展示已经缓存的 html 文件,相当于尽可能将 WordPress 缓存成为一个静态网站,搭配上合理的 Nginx 或 Apache 伪静态规则,即便是性能非常有限的服务器也可以提供超高的并发量,您可以参考 WP Super Cache 插件帮助文档,配置适合自己站点的伪静态规则,或者插件也支持通过插件本身的 PHP 脚本去调用 html 文件,但是要知道前置程序的伪静态规则调用 html 要比 PHP 脚本实现的方式,对运算资源的节省是相当大的,运行起来是相当高效的,毕竟这种方式甚至不用执行任何 PHP,因此我非常推荐使用前置程序伪静态规则的方式调用 WP Super Cache 生成的 html 文件,如果您觉得还是不够,甚至可以将 WP Super Cache 生成的 html 文件保存在一个内存映射出来的文件夹中,还有什么能比从内存中调用更快的方案呢?

至此,服务器端的优化已基本完成,针对用户端浏览器渲染 html 期间对各类资源文件的调用,我推荐使用阿里云对象存储 OSS 产品和内容分发网络 CDN 产品,对象存储 OSS 是一个带有网络的存储空间,您可以通过各种方式实现对各类文件的调用(get,下载),其特别适合保存各类静态文件,且出口带宽不限制,适合高并发调用场景,CDN 原理与全站加速较为类似,CDN 仅缓存静态文件,当用户访问静态文件时,会请求距离用户最近的 CDN 节点,如 CDN 节点未缓存该文件,则会回源发送 get 请求,并按规则将该文件缓存至本节点,当用户(或其他同城市用户)再次访问时,命中缓存文件,则无需回源发送 get 请求,由 CDN 节点直接将已经缓存的文件发送给用户,有效降低服务器流量和负载,同样 CDN 也是不限制带宽的,但是请不要将动态网站配置进 CDN 的缓存规则中,前文已经提到过原因,故不再赘述。通过以上方案即可实现网站动静态分离,针对 WordPress 来说,具体实现方法是通过 WordPress 插件,自动化将 PHP 生成的 html 文件中的静态资源替换成您的 CDN 域名,CDN 配置回源规则为 OSS 域名,这样用户浏览器渲染 html 加载各类静态文件时,会访问 CDN 去加载,而 CDN 会去 OSS 中请求静态文件,最后再将 OSS 的镜像规则添加 404 时回源至你的网站,即可打通整条链路。

除了站点特有的静态资源外,一些相对较大的或较为通用的静态资源,例如字体,我们可以使用国内的各种加速服务,这样子连 CDN 缓存都免了。

综上所述,如果您按照我推荐的方案去加速您的 WordPress,依然按上文中提到的 200KB 的 html 内容和 4.8MB 的各类静态资源来计算,通过全站加速的压缩,html 文件大小仅为 50KB 左右,各类静态文件均通过 CDN、国内镜像服务去实现,在理想情况下能够得到 0.2 秒左右的单页面全内容加载速度。

附加选项

如果您使用的是 Linux 服务器,可以参考我发布的文章开启 TCP Fast Open 和 Google BBR,以在心理上加快一下访问速度,之所以说是心理上,是因为如果用户是直接请求的您服务器,确实可以提高握手效率和对拥塞的控制,但是如果加上了 CDN 或者全站加速,则只能实现对 CDN 和全站加速的访问优化,且还不清楚这两款产品的具体技术细节,是否支持此技术。

总结

  1. 服务器性能合理;

  2. 带宽充足;

  3. 应用层配置合理,程序无问题;

  4. 尽可能实现静态化;

  5. 使用 CDN 加速静态资源使用全站加速加速动态资源,并配置合理缓存规则;

  6. 尽可能避免加载墙外资源。

介绍了这么多,刚入门的站长可能会听的一头雾水,毕竟里面涉及的内容较多,不便于展开太过详细,当然,如果您不想自己动手,我可以提供技术支持服务。

图一中存在大量 304,后面附一张状态码 200 的加载速度图。

正文完
 0
评论(没有评论)