站在巨人WordPress的肩膀上学架构
本文最后更新于 1516 天前,其中的信息可能已经有所发展或是发生改变。

站在巨人WordPress的肩膀上学架构

前言

WordPress 可能是很多学习搭建云计算网站的第一课,写了篇 Hello World 就匆匆结束了对 WordPress 的体验。在全球前 1,000 万的网站中,三分之一都使用了 WordPress,像国外的白宫官网、纽约邮报、微软新闻中心、国内的爱范儿等等。因此开源社区的 WordPress 有着大量的开发者贡献代码和思路,帮助我们构建一个强大而成熟的网站。

我们要实现一个架构其实最重要的是三个目标,。 前端访问要,后端运行要,但是实现前两者不能无节制的上升成本,我们要节省成本让利益最大化。。

拆解

那我们把 WordPress 简单拆解一下:WordPress 由 PHP、HTML、CSS、JS和SQL组成。

它的运行非常简单:WebServer —— PHP —— MySQL 因此可以很简单的运行在一台服务器上。

在前期运行它当然没有问题,但是当访问量、文章数上来之后便会力不从心了。 表现就是前后台打开慢,或者是用户频繁按F5就可以让网站出现500报错,因此我们就需要进行架构的优化。同样的,我们自行开发的系统可能也是前期小规模的通过单台服务器即可,但是通过运营人员一次次的努力宣传后,用户量一上来就不行了。

这里有一个很大的误区就是无限的堆叠单台服务器的配置,这在早期物理服务器托管时代比较流行,我买的服务器是双路CPU的,现在只用一颗CPU,后面性能不够了再新增CPU,然后再新增内存条和硬盘。

这样做先不谈架构,在运维上就会变成一场灾难。随着用户量的上升,服务器将越来越不能接受升级、重启等操作带来的业务中断,因为单一系统部署软件复杂,万一一个软件的升级带来的不兼容可能就导致业务崩溃,运维人员维护软件如履薄冰。

单机优化

首先我们需要将单台服务器的性能最大化再考虑后面的架构优化,这是一个环境上线的预先准备工作。

实例配置

操作系统的选择上,整体测试下来不同的系统在云服务器ECS上的表现不一样,我自己的测试是 AliyunLinux 2 和 RHEL/CentOS 是阿里云调教的最好的,可能是阿里用RHEL生态原因,在多核心上BenchMark更好看,同时 AliyunLinux 2 专门为云服务器场景优化,性能可以提升15%左右。

然后在实例类型的选择上,其实 WordPress 并不是很占用CPU(优化后),可以选择入门型这种CPU共享的实例,如t6 t5,有效降低成本。

我们以 WordPress 为例,它是一款 PHP 应用 ,PHP是一个I/O密集型应用,在服务器的选择上保障必要的CPU性能的同时,我们尽可能选择 ESSD云盘,它的时延和每G IOPS 都比SSD云盘和高效云盘表现更好。

在网络上,得益于云计算行业的网络都是BGP网络,各大运营商访问服务器网络都可以获得一致的延时和带宽体验。 但是网络的设计上,很多人都会犯的错误,就是对业务系统对公网IP、私网IP的依赖,一个系统如果无法接受公网、私网IP的变动,会导致系统启动失败、运行失败,这就很糟糕。这会导致你不敢轻易的更换服务器或者IP,轻则无法享受一些采购上的政策优惠,重则会遇到IP因为某些不可抗力不得不改时的束手无策。

Web Server

我们常见的 Web Server 软件有很多,比如说:Apache HTTPD、Nginx、lighttpd、tomcat、LiteSpeed,不同的 Web Server 有着不同的动静态处理性能。

最有名的就是 Nginx 了,它的静态文件处理性能是众所周知的,它有着非常优秀的生态,对于新技术的支持会比Apache HTTPD 好得多,像 Lua支持、Brotli、TLS1.3等都支持的更早更好。所以 Web Server 的选择上 Nginx 是非常不错的选择,还有一些社区的扩展分支如 OpenResty、Tengine 等等。

不过整体使用下来,我发现 LiteSpeedTech 公司的 LiteSpeed Enterprise Web Server (简称LSWS)和 OpenLiteSpeed(简称OLS)会更适合 PHP 应用,它的 LSAPI 运行 PHP 以及 LSCache 对 PHP 应用有着非常好的支持,特别是针对 WordPress、 Magento、Joomla、PrestaShop、Drupal、MediaWiki、Laravel 有着很好的支持。大家可以在 LLStack 体验 LiteSpeed 环境。

非 PHP 应用如 JAVA、Node.JS 还是推荐 Nginx 或它的扩展分支来作为 Web Server。

PHP

PHP 的性能调优上尽量选择最新的稳定版,比如说截止发稿PHP最新版是 7.4,那么我们可以使用 PHP7.4 或者 7.3 这两个版本。 目前 PHP 的版本策略是 2+1 模式,即 2 年活跃支持,1年安全支持。PHP 版本越新性能越好,同时安全漏洞也会更少。

PHP 之外,其他语言也是,JAVA 的话很多程序还在 JAVA 1.6 上运行。今年年初 Python2 已经停止官方维护了,但是仍有大量的应用基于 Python

提速的关键是两个缓存机制:字节码缓存对象缓存

字节码缓存

当一个 PHP 文件被解释执行的时候,首先是被编译成名为 opcodes 的中间代码,然后才被底层的虚拟机执行。 如果PHP文件没有被修改过,opcode 始终是一样的。这就意味着编译步骤白白浪费了 CPU 的资源。

此时 opcode 缓存就派上用场了。通过将 opcode 缓存在内存中,它能防止冗余的编译步骤,并且在下次调用执行时得到重用。设置 opcode 缓存只需要几分钟的时间,应用便会因此大大加速,实在没有理由不用它。目前 Zend 官方提供的 zend_OPCache 是效率最高的字节码缓存扩展。

对象缓存

有时缓存代码中的单个对象会很有用,比如有些需要很大开销获取的数据或者一些结果集不怎么变化的数据库查询。你可以使用一些缓存软件将这些数据存放在内存中以便下次高速获取。如果你获得数据后把他们存起来,下次请求直接从缓存里面获取数据,在减少数据库负载的同时能极大提高性能。

计算存储分离

当业务系统到一定规模后,数据会变成越来越重要的企业数字化资产。数据的范围很宽泛,首先是最核心的数据库里的数据(结构化数据)这个我们在下个主题讨论数据库的优化,还有就是企业的非结构化数据比如说头像、配图、附件等等。

非结构化数据虽然说并没有数据库来的重要,但是如果数据一旦丢失也会产生严重的影响。试想一个企业OA系统,如果存储的附件全部丢失,意味着这个企业的内部资料全部丢失了。在 WordPress 中,附件最重要的作用就是阅读体验,如果一个网站图片全部丢失读者几乎是没有兴趣进行阅读的。

虽然云服务器的云盘已经有99.9999999%(九个九)的数据可靠性了,但是它的性价比并不高,同时读取附件也会耗费服务器I/O性能。这时候将存储转移到阿里云的对象存储OSS则是最好的选择。虽然云盘支持扩容,但是它的弹性是不够的,比如说我买了1T的云盘,当我用到800G~900G我就会考虑开始扩容了,那么其实我一直会浪费10~15%的容量,而且前期我的容量也不是有高使用率的

对象存储可以做到99.999999999%(十二个九)的数据可靠性,同时没有容量和性能的上限、瓶颈,它最大的特点是按量付费,我使用了851G那么我就支付851G的成本即可,而不是我使用了851G却要支付1T的费用,并且用不到1T我就会要进行扩容。

将存储存放到OSS后,不仅提升了非结构化数据的读取性能还降低了成本。

如何在 WordPress 中使用OSS将本地化存储搬上云端请参考:

《将 WordPress 图像媒体全部迁移至对象存储,降低服务器存储压力》

CDN加速

前面我们讲了将非结构化数据存储到OSS,提升了读取性能还降低了成本,两全其美。

这里 CDN 也可以实现两全其美的事情,那就是在提升访问速度的同时还能降低网络成本。

为什么天猫超市、苏宁、京东购买的自营商品到货会那么快?我可以上午买下午到,半夜买上午到,这样办公白领的购物体验还是提升很多的,这都得益于就近仓储的优势,比如说我要买的商品的制造地是甘肃兰州,本来我要买就得从兰州发货,但通过一些自营电商购买,我在杭州滨江区,那么物流仓储就会从杭州富阳的仓储中心快速分配到末端配送站,然后分配快递小哥帮助我们配送。

CDN 其实也是这个逻辑,将用户要访问的非结构化文件就近存放到CDN的缓存节点,这样用户访问的速度就更快了。我在新疆喀什要访问一个华东1杭州地域的网站,这个跳数和延时都会很大,但是使用CDN后,那我就可以从乌鲁木齐的某个电信机房获取缓存文件,这样我的访问速度和延迟都会降低了。

然后CDN为什么还可以在提速的同时节约成本呢?如果要玩外服的游戏,我购买网游加速器还要花不菲的包月成本,为什么CDN不经帮我加速了,同时还能节省成本呢?这个解释还是可以用快读的模式来,咱们将东西从杭州寄到杭州,和杭州寄到新疆,哪个更便宜?肯定是路径更短的更便宜,网络访问路径短了,自然也能省钱。

WordPress 上使用 CDN 有很多丰富的插件,在OSS中提到的插件也可以直接使用CDN。 CDN 一个是加速非结构化数据的好手,OSS 是存储非结构化数据的大师,所以OSS+CDN是强强联手,非常好的搭档。

在 WordPress 主题目录下的 functions.php 文件中,加入以下代码实现CDN替换功能:

//静态文件CDN加速
if ( !is_admin() ) {
    add_action('wp_loaded','mf8biz_ob_start');

    function mf8biz_ob_start() {
        ob_start('mf8biz_aliyun_cdn_replace');
    }   
function mf8biz_aliyun_cdn_replace($html){
    $local_host = 'www.mf8.biz'; //源站域名
    $aliyun_host = 'statics.mf8.biz'; //CDN加速域名
    $cdn_exts   = 'css|js|png|jpg|jpeg|gif|ico'; //扩展名(使用|分隔)
    $cdn_dirs   = 'wp-content|wp-includes'; //目录(使用|分隔)

    $cdn_dirs   = str_replace('-', '\-', $cdn_dirs);

    if ($cdn_dirs) {
        $regex  =  '/' . str_replace('/', '\/', $local_host) . '\/((' . $cdn_dirs . ')\/[^\s\?\\\'\"\;\>\<]{1,}.(' . $cdn_exts . '))([\"\\\'\s\?]{1})/';
        $html =  preg_replace($regex, $aliyun_host . '/$1$4', $html);
    } else {
        $regex  = '/' . str_replace('/', '\/', $local_host) . '\/([^\s\?\\\'\"\;\>\<]{1,}.(' . $cdn_exts . '))([\"\\\'\s\?]{1})/';
        $html =  preg_replace($regex, $aliyun_host . '/$1$3', $html);
    }
    return $html;
}
}

站库分离

早期我们可以将数据库和应用放在同一台服务器上运行,但是前面讲到一旦到了后期就会出现运维的灾难。

数据库是一个业务系统的重中之重,特别是针对一些金融、电商类的场景,如果数据库一旦出错轻则业务暂停,重则会导致业务崩快。例如移动支付场景肯定不能接受数据库损坏的瞬间,买家已经付款并银行卡已经扣费,但是卖家并没有收到款项,这就对业务造成过影响了,如果这个消费数值是几亿元的量级,就有很大的问题了。

站库分离是很重要的步骤,将数据库和应用程序的运维分离开来。但是云计算时代,有了云数据库,这个工作就会变的愉快很多。首先调试数据库其实是比较难的,现在很多开发同学都会担任一些DevOps,但也只是开发者和运维的结合,但很少有同学还会点亮DBA(数据库管理专家)的技能,比如说设计一个数据库,我们要规划备份方案、调优方案等等,规划多少的RTO(丢多少)和RPO(丢多久)等等,让一个非专业的同学头大,同时企业聘请一个专业的DBA也会增加用人成本。

而云数据库就是一个数据库开箱即用的方案了,我们不用担心数据库遇到高危漏洞时的安全风险,云数据库做出升级方案,和云监控搭配的监控图标也可以很直观的反馈数据情况,以及 CloudDBA 功能,基于专家的规则经验,自动判断数据库问题。

云数据库的优势还有很多,篇幅限制就不展开讲太多了,大家可以去了解一下云数据库和PolarDB。 后者在完美兼容 MySQL、PostgreSQL 和高度兼容 Oracle 的技术上实现了更高的性能,MySQL 最高可达到 600%的性能提升,但相较RDS成本仅提升10%。

扩展工具:

DTS,DTS 是一款支持多种数据源的可视化数据迁移工具,可以帮助我们快捷直观的将自建数据库的数据迁移至云数据库,也可以做数据同步订阅使用。

DBS,DBS是一款专业型的数据库备份工具,可以快捷的将数据库备份至OSS中,实时增量备份实现秒级RPO。

在 WordPress 中实现站库分离很简单,将源站数据库上的数据通过 DTS 或者备份恢复的方式迁移到云数据库即可。然后修改 wp-config.php 文件,将define( 'DB_HOST', 'localhost' );中的 localhost修改成云数据库的连接地址即可。

内存缓存加速

WordPress 使用 MySQL 数据库来缓存内部应用程序对象(导航栏、菜单栏等),生成这些对象的资源成本成本很高。由于数据库还处理页面请求的查询,因此它可能是最常见的性能瓶颈,并且经常导致加载时间增加。

Redis 是一个开源的键值对存储数据库,既可以用作内存级存储,也可以用作缓存。Redis是一种数据结构服务器,可以单独作为 NoSQL 数据库服务,也可以与关系数据库(如MySQL)结合以加快访问处理速度。当涉及对象缓存时,在像WordPress这样的动态网站上使用,该对象缓存可缓存重复的访问内容。

因为 Redis 是基于内存的服务,内存访问的速度和效率比就算是给予 NVMe SSD 的磁盘也来的更快,所以使用 Redis 来做为 PHP 的对象缓存来加速 WordPress 的效率会更好,访问速度更快,这在文章数极大的场景下网站的使用体验会好很多。


Redis 我们可以自建也可以购买阿里云的云数据库,早期如果成本考虑是可以自建在自己的服务器上的。如果是本机的 Redis Server,建议使用 UNIX Socket 的方式效率会比 TCP 来的更高。

在 WordPress 使用 Redis 作为对象缓存,需要 PHP 安装实现 phpredis 这个 PECL 扩展,不然的话会基于 predis 方式实现,这个效率没有 PECL 扩展效率来的高,然后安装相关的 Redis 对象缓存插件即可。

相关教程推荐:

《WP 使用走 Unix Sockets 的 Redis 作为对象缓存》

《使用云数据库 Redis 版为 WP 做缓存》

还有将 Redis 缓存应用到 Web Server 的方式,减少对 php 的请求来进一步提速,这适合能接受静态页面的CMS类网站,不太适合动态内容多的网站:

《用 Nginx+Redis Cache 给 WordPress 提速》

《LiteSpeed Cache for WordPress – 免费的超性能企业级缓存插件》

《为 WordPress 开启 LS-Cache 缓存》

负载均衡

云服务器的特性主要就是体现在横向、纵向的弹性扩容上,纵向的话其实很好理解就是我们单台 ECS 配置不够用了马上升级一下配置,不过这种场景比较适合于一个网站稳健的发展状态,而且波动不大。或者说服务器有较长时间的资源占用而非短时间的,比如说台风网肯定是 5~10 月这段时间访问量较高,那么我们就可以在春末的时候升一段配置,夏天再升级一段配置,初秋稍微降一点,秋末降至平稳状态。

但是如果我们是一个电商网站突然运营想搞一个秒杀活动,一个游戏公司要组织一场在线PK大赛。 这种情况下呢,都是瞬时遭遇的流量高峰和应用高占用,过了这段时间突然就回到了平稳的状态。如果我们一直以能处理瞬时高峰的配置长时间运行势必会造成大量的资源浪费,这时候就需要一个按量的横向扩容了。

横向扩容也就是增加服务器数量而非升级配置,但是我们需要将数个服务器整合成一个服务器集群,通过均衡负载 SLB 让服务器集群看起来就像还是“一台”服务器在进行操作,当然了均衡负载也不一定需要使用 SLB,也可以自建或者采购其他的均衡负载产品。然后每一台服务器都应该做到无状态服务,不可以保存应用的状态信息(如 session)和相关数据(如数据库、日志等)。如果应用中有保存状态信息需求,可以考虑把状态信息保存到伸缩组之外的独立的状态服务器、数据库(如 云数据库)和集中日志存储(如 日志服务)中去。

很多教程可能一开始就是负载均衡一步到位,这样对运维是有一定要求的,不利于新手架构学习。在做好计算存储分离、站库分离、内存加速(Redis共享session)后再做负载均衡的难度会显著降低。

相关教程推荐:

《配置自动横向扩展的同城双中心服务集群》

《使用SLB+DNS轻松实现网站的IPV6双栈兼容》

搜索请求优化

WordPress 默认搜索方式是LIKE%query% 等查询的组合。其不允许进行模糊搜索,如果有用户犯了简单的拼写错误,就获得有效的搜索。WordPress 的另一个限制是,它只能搜索和匹配标题和内容中的单词,而不能与类别和分类法进行匹配。

同时搜索是非常消耗数据库资源的一种方式,并且搜索结果不会进行缓存,如果你想攻击一个WordPress网站,只需要对一个搜索结果页频繁进行F5就可以让数据库资源消耗到瓶颈后停止服务,这样整个WordPress网站都将无法提供服务。

同理其他应用程序也会遇到这个问题,因此我们会选择使用专业的搜索引擎来进行索引,并提供给用户更专业的结果。目前第三方的搜索引擎方案有百度的站内搜索(很久没更新,不支持HTTPS)、谷歌的CSE(国内无法访问)。因此我们可以选择自定义性和功能更丰富的开源搜索引擎 Elasticsearch。

在 WordPress 上接入使用 Elasticsearch 是非常方便的,0 coding。只需要安装 ElasticPress 插件并编辑 wp-config.php 文件:

/** ElasticPress */
define( 'EP_HOST', 'http://127.0.0.1:9200' );

定义一下 ElasticSearch 的地址即可使用。

安全架构

安全也是服务器架构中非常重要的一点,只要是暴露在公网上的业务就有可能成为被攻击的对象,因此我们需要积极的构建云上安全体系进行防御常见的安全攻击,同时也要保障自己的云产品不被劫持为肉鸡对外发送攻击加重互联网安全态势。

其实攻击者视角是来自方方面面的,360°无死角的盯着咱们的业务进行攻击,而安全又是一个典型的木桶的短板模型,即便其他的安全措施做的再好,只要存在一个明显的安全短板,就会导致整个业务系统的不安全。而防守者视角往往是单一的,通常是见招拆招式的的,甚至有些时候当安全事件已经发生了,很多人都无法及时做出对安全事件的反应。

这是我根据阿里云安全团队安全三步走的基础上修改来的云上安全体系构建路线图,本文我们重点聚焦云上安全第0步——安全基础建设。因为很多云上用户在没有做好第0步的时候就开始购买一些第一二步云安全产品,就会出现木桶短板效应,花费了高昂的费用却没有起到响应的安全作用。

推荐相关阅读:

《不花一分钱构建阿里云上第零步安全体系》

当然了在 WordPress 上也有很多可以免费体验的PHP软件级的WAF插件,帮助防御一定的攻击,提升网站安全性,不过相比阿里云WAF这样的专业性WAF肯定是有所欠缺的。

插件:

SiteGuard WP PluginNinjaFirewallWordPress SecurityWordfence Security

备份机制

很多用户会认为租用的阿里云ECS云服务器的云盘有 99.9999999% 的数据可靠性,这个是不是就意味着我放在云上的数据不会丢。这时候客户还会意识到说数据的三盘副本,一些客户在文件误删的时候就会说:“你们阿里云有三盘副本,我现在这个云盘里的文件我不小心误删了,那另外两个盘上的副本快取出来帮我恢复一下。”

其实这时候就有必要澄清一下,三盘副本主要是为了防止系统错误导致的文件丢失的情况,并不能防止因为误删除或者病毒进程删除文件导致的逻辑错误,具体如下图:

我们需要积极的通过构建快照来解决因为逻辑错误导致的数据丢失的问题。

阿里云的快照操作很方便,是完全图形化的且是中文界面的,并且支持手动或者自动方式创建快照,并且支持快照制作成镜像后跨地域复制到其他地域进行多维度容灾。同时,快照备份是存储在更高可靠且更具性价比的对象存储OSS上的,这个成本是非常可观的。

我们还可以单独将网站文件备份到 OSS 和 NAS 这样的更廉价存储的地方,做增量或者全量的备份。在数据备份上还是和数据库的数据可用性一样,规划设计RTO(丢多少)和RPO(丢多久),在这个道路上还是一个很长的路。

推荐阅读:

ECS快照帮助文档 | ECS快照使用视频教程

《使用 AliCloud Duplicity 将服务器文件备份至 OSS》

在 WordPress 也有很多备份插件,支持FTP和S3协议(兼容阿里云OSS),可以用作方便的备份方式:

UpdraftPlusBackWPUpBackUpWordPress 等等

日志分析

服务器日志很多人可能都将它看作是“鸡肋”,食之无用、弃之可惜,觉得他很占地方。很多存储买的比较小的服务器,它的磁盘经常会以为存储大量日志被占用,导致I/O异常,然后人会选择关掉日志。

其实日志有很多游泳的信息,包括服务器的状态、相关软件的报错信息、访客数据、访客行为,以及一些安全审计等等。日志很多人可能直接通过编辑器甚至是记事本直接打开,那这样用处确实是不大,所以一个好的架构师一定要学会分析日志,利用好日志。

一般来说 WordPress 日志包括:Web Server日志(Nginx、Apache、LiteSpeed 的日志)、PHP日志、数据库日志、邮件日志(如果有)、操作系统日志、WordPress Debug 记录和相关插件日志等等。

我们可以用阿里云的日志服务或者ELK三剑客之一的Logstacsh来进行分析,WordPress 日志开启,还需要修改 wp-config.php 文件,加入下面语句:

define( 'WP_DEBUG_LOG', true ); //开启debug日志
define( 'WP_DEBUG_DISPLAY', false ); //隐藏debug消息到页面输出

define( 'SAVEQUERIES', true );  //将数据库查询保存到数组中,可以用于帮助分析,选填

如果大家不想用更专业日志分析工具,也可以通过如下插件快速实现,只不过专业日志是存储到服务器的,这个成本会比存储到 OSS 高的多:

WP Security Audit LogSimple HistoryUser Activity LogWP Log ViewerLog-Hero

结语

架构的学习是漫漫长路,很多新人在学习架构的时候都会反馈缺少实践的平台,得益于 WordPress 丰富的生态,我们可以很好的利用它来结合各大软件,我这里指出的也只是一些基础思路,也欢迎大家指正错误的地方。

架构也是不是一定要套用的,也不是一尘不变的。比如说 WordPress 作为 CMS 的场景下可能不太有必要应用大数据,但是当 WordPress 安装 WooCommerce 插件成为一个电商网站后,其实就有可能有大数据个性化推荐的需求了。 我也看到也有 WordPress 网站被改造成一个咖啡自助系统,在完成点单后传输到物联网咖啡机上自动作出咖啡来,那么就可能一些物联网架构的需求了。

布置两个小作业,相关的思路还可以套用在同样是PHP 的 Discuz 和 微擎 上,根据我的实践这两个软件都可以实现上述架构。

上一篇
下一篇