小站迁移到Spartan Host上也有半年多了,尽管到中国的线路在晚高峰时期可以说是很不好,不过总还是可堪一用。但是最近在后台操作的时候总有卡顿,有时候甚至会直接无法打开,JetPack也时常发邮件提醒站点掉线。不得已,只好尝试排查一下。
首先检查一下系统占用,Spartan给的Control Panel给出的占用率高到爆炸,着实吓我一跳。
接下来用top命令检查一下具体的资源占用情况:
top
top命令可以显示当前运行的进程,及其PID、CPU和内存占用等信息,类似图中的结果。
在这一步就发现了问题:有一个叫containerd的进程占用了不少CPU。查了一下发现,containerd是docker的组成部分。这个属于遗留问题,是我以前尝试用docker搭建Typecho博客还有几个测速页面遗留下的残迹。这些空壳页面和docker占用的CPU不算很少,但是也很好排查和解决。我检查了一下docker里正在运行的容器:
docker ps -a
发现typecho博客的对应容器还在运行,而且也只有这一个容器。那么把docker从容器、镜像到包都删除就可以解决。
先停止运行的容器,再删除所有容器和镜像,最后结束docker服务:
sudo docker kill $(docker ps -a -q) sudo docker rm $(docker ps -a -q) sudo docker rmi $(docker images -q) systemctl stop docker
然后检查docker的相关包:
yum list installed | grep docker
搜索到三个结果:
containerd.io.x86_64 1.3.9-3.1.el7 @docker-ce-stable docker-ce.x86_64 3:19.03.14-3.el7 @docker-ce-stable docker-ce-cli.x86_64 1:19.03.14-3.el7 @docker-ce-stable
卸载掉即可。
yum remove docker-ce.x86_64 docker-ce-cli.x86_64 containerd.io.x86_64 -y
本来以为卸载掉docker就解决问题了,但显然事情没有这么简单。没多久,CPU的负载又上去了。这一次再检查,发现两个惊喜:
一个是MySQL,另外一个是PHP,两个进程的CPU占用率都异常地高。这两个是WordPress的重要组件,当然不能一删了事。既然如此,只好检查一下记录,看看是什么导致了这么高的占用率。
我先从MySQL下手,它有一个很好的功能叫做慢日志。慢日志会记录超过一个时间阈值的查询操作,可以有效地反映出是什么拖慢了运行速度,并导致了高占用和卡顿。当然,首先它得处于开启状态。这里可以用SSH登录MySQL或者使用网页端的phpMyAdmin,先来检查一下:
SHOW VARIABLES LIKE 'slow_query%'
很走运,我恰好开了慢日志:
Variable_name Value slow_query_log ON slow_query_log_file /*******/mysql-slow.log
而且查出了慢日志的路径。打开一看,记录竟然有1.8M之大。这恐怕没多少人有耐心细看,当然我也没有。所以MySQL也提供了简单的分析工具mysqldumpslow,据说只要安装了MySQL一般都会带有此工具。不巧的是,我恰巧没有,所以改用了pt-query-digest。有三种安装方式可选:
wget http://www.percona.com/get/pt-query-digest chmod +x pt-query-digest wget percona.com/get/percona-toolkit.rpm rpm -ivh percona-toolkit-2.2.13-1.noarch.rpm wget percona.com/get/percona-toolkit.tar.gz tar -zxvf percona-toolkit-2.2.13.tar.gz cd percona-toolkit-2.2.13 perl Makefile.PL make && make install
安装完后,可以用如下命令对mysql-slow.log进行分析。
pt-query-digest /*******/mysql-slow.log > slow_report.log
参考详解 慢查询 之 mysqldumpslow。
分析的结果很有趣,占据前几名的慢查询记录是这样的:
# Rank Query ID Response time Calls R/Call V # ==== ============ =============== ===== ======= = # 1 0x665212F** 2337.5847 28.5% 101 23.1444 21.22 SELECT wp_options # 2 0x9D781DC** 749.3945 9.1% 57 13.1473 12.29 SELECT wp_options # 3 0xDB78C57** 600.6963 7.3% 40 15.0174 12.70 SELECT wp_terms wp_term_taxonomy wp_term_relationships # 4 0xE0ED4FC** 515.7171 6.3% 41 12.5785 20.61 SELECT wp_postmeta # 5 0xC0BA5A2** 491.8532 6.0% 24 20.4939 15.03 SELECT wp_wfconfig # 6 0x6837082** 390.9320 4.8% 27 14.4790 11.07 SELECT wp_wfblocks? # 7 0x37DD036** 229.8844 2.8% 17 13.5226 14.36 SELECT wp_usermeta # 8 0xBC8F025** 192.8420 2.4% 13 14.8340 13.05 SELECT wp_yoast_indexable # 9 0x6ADC8F4** 192.4062 2.3% 19 10.1266 2.84 SELECT wp_terms wp_term_taxonomy # 10 0xAC0C338** 146.5066 1.8% 16 9.1567 2.65 SHOW COLUMNS
wp_wf*是wordfence的数据库,看起来插件对MySQL的运行影响不小。为此我清理了一些效果并不很大的插件,比如说Wordfence、JetPack等等。然后回到排第一、二的两个wp_options记录,分析结果的EXPLAIN分别显示:
# EXPLAIN /*!50100 PARTITIONS*/ SELECT option_name, option_value FROM wp_options WHERE autoload = 'yes' # EXPLAIN /*!50100 PARTITIONS*/ SELECT option_value FROM wp_options WHERE option_name = 'siteurl' LIMIT 1
本来我以为第一条是WordPress数据库的一处性能优化中提到的那样,是没有建立索引导致的速度缓慢。但实际上已经建立了索引,因此按照文中操作会报错”Duplicate key name ‘autoload’.”好在经过一番网上冲浪得到提示,有可能是安装插件过多而未清理导致的。因此我进入wp_options表检查长的项目,
SELECT LENGTH(option_value),option_name FROM wp_options WHERE autoload='yes' ORDER BY length(option_value) DESC LIMIT 20;
也确实发现了一些已经卸载的插件所遗留的项目,删除即可。至于第二条,我并没有什么头绪,猜想是当初迁移域名时留下的错误。
在调整优化了MySQL和WordPress后,本站的运行速度快了不少,目前也没有再出现未响应或离线的情况。因此,php的问题暂不做排查和处理,以观后效,如果仍然出现问题或需要调整,我会在下一次优化完后再进行更新。特作此记录,或许对读者亦可资参考。