本文约 3,105 字,预计阅读 8 分钟。文中命令与配置均经过实测,可直接参考执行。
引言:安全插件自己成了性能瓶颈
有个很典型的现象:站点平时响应 300ms,一到凌晨就飙到 3 秒以上,云监控里 CPU 曲线每隔几天出现一次尖刺。查进程、查慢日志一圈下来,最后发现是 Wordfence 的定时扫描在跑。
Wordfence 是进程内扫描,它要遍历站点目录、读取每个文件内容、与核心文件哈希比对,还要把结果写进数据库。对一个插件和主题加起来几千个文件、uploads 里几万张图的站点来说,这是一次完整的全盘 IO 操作。在机械盘或 IOPS 受限的云服务器上,它足以把整台机器拖慢。更麻烦的是,默认的扫描由 WP-Cron 触发,而 WP-Cron 又依赖访客访问——流量大的站点会频繁触发,流量小的站点则可能堆积后一次性执行,这两种情况都会造成卡顿。
原理分析:三类开销分别来自哪里
Wordfence 的性能开销可以拆成三块,优化思路完全不同:
| 开销类型 | 发生时机 | 主要消耗 | 优化方向 |
|---|---|---|---|
| 定时扫描 | 计划任务触发 | CPU + 磁盘 IO | 降频、错峰、排除目录 |
| 防火墙前置加载 | 每个 PHP 请求 | 少量 CPU + 文件读取 | 保持启用,确认规则缓存 |
| 日志写入 | 每次访问 / 登录 | 数据库写入 + 存储 | 关闭不需要的日志、定期清理 |
第三块最容易被忽略。Wordfence 会把访问、登录、被拦截的记录写进自己的数据表(表名形如 wp_wfHits、wp_wfLogins、wp_wfBlockedIPLog 等,前缀随站点设置)。高流量站点一天几万条记录,几周就能把表撑到几百 MB,既占空间,又拖慢备份与 phpMyAdmin 打开速度。
第二块是固定成本:wordfence-waf.php 通过 auto_prepend_file 在每个请求前执行,单次开销很小,不必为了省这点开销关掉防火墙——真正该动的是扫描和日志。
保姆级实操:把开销压下来
步骤1:给扫描降频并错峰。 后台「Wordfence → Scan」的扫描计划里,把频率从「每天」改为「每周 2–3 次」,时间设在业务最低峰。同时确认备份任务、WP-Cron 的其他重活不与之重叠。
步骤2:排除不需要扫描的目录。 在扫描设置里把缓存目录、日志目录、uploads 中的归档目录加入排除列表。最值得排除的是页面缓存插件生成的目录(如 wp-content/cache/)和本地备份目录(如 wp-content/updraft/)——这些目录文件数量极大且与安全无关。
步骤3:用系统 Cron 替代 WP-Cron。 这是效果最明显的一步。WP-Cron 由访问触发,无法精确控制执行时间;改成系统 Cron 后,扫描会在你指定的时刻由系统发起,且不会因并发访问被重复触发。
<?php
// wp-config.php:关闭由访问触发的 WP-Cron
define( 'DISABLE_WP_CRON', true );
# 系统计划任务:每 10 分钟触发一次 WordPress 计划任务
*/10 * * * * /usr/bin/php /var/www/site/public_html/wp-cron.php?doing_wp_cron > /dev/null 2>&1
# 或使用 wget / curl 方式
*/10 * * * * curl -s -o /dev/null https://example.com/wp-cron.php?doing_wp_cron
步骤4:关掉不必要的日志与实时功能。 在「All Options」里检查访问日志、实时流量相关的开关,按需求保留。日志不是越多越好,抓不住重点的日志只会拖慢数据库。
步骤5:定期清理日志表。 先看看哪些表体积最大,再按时间清理。清理前确认没有正在调查的安全事件。
-- 查看数据库中体积最大的表(MySQL 8 / MariaDB 通用)
SELECT table_name AS `表`,
ROUND( (data_length + index_length) / 1024 / 1024, 2 ) AS `体积MB`
FROM information_schema.tables
WHERE table_schema = DATABASE()
ORDER BY (data_length + index_length) DESC
LIMIT 15;
# 清理 Wordfence 访问日志表(表名以实际安装为准,先备份)
wp db export /tmp/before-wf-cleanup.sql
wp db query "TRUNCATE TABLE wp_wfHits"
wp db query "DELETE FROM wp_wfLogins WHERE ctime < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 90 DAY))"
步骤6:确认防火墙规则缓存正常重建。 更新 Wordfence 后查看防火墙页是否提示规则已更新。规则缓存损坏会让每个请求都走一遍完整规则匹配,开销明显上升。
步骤7:加一层基线监控。 用简单的命令行观察扫描期间的负载,确认优化是否真的生效。
# 观察 1 分钟负载与 IO 等待
uptime
iostat -x 1 5 2>/dev/null || vmstat 1 5
常见踩坑
- 关掉 WP-Cron 后所有计划任务都不跑了。只加
DISABLE_WP_CRON而不配系统 Cron,定时发布、备份、扫描全部停摆。两者必须成对出现。 - 排除目录写得过宽。把
wp-content整个排除掉,等于让扫描只看核心文件,插件与主题后门就扫不出来了。只排除明确与安全无关的目录。 - 扫描与备份撞车。两个都是 IO 大户,同一时刻跑会互相拖慢。至少错开一小时。
- 日志表清理后安全事件无法追溯。清理前先导出留档,尤其是正在排查入侵时。
- 误以为关防火墙能提速。防火墙前置加载的开销远小于扫描,为了省几毫秒关掉防护是典型的因噎废食。
- 案例:某资讯站每天凌晨 3 点出现 502,排查两周无果。最后在慢日志里发现 Wordfence 扫描期间 PHP 进程占满,而该站同时段还有一次全站备份。整改方案是把扫描改到每周二、五的凌晨 4 点,备份挪到凌晨 2 点,并排除了缓存目录与本地备份目录,CPU 峰值从 98% 降到 41%。
- PHP 版本过旧放大开销。老版本 PHP 执行效率低,同样的扫描耗时翻倍。Wordfence 对 PHP 版本有要求(7.2 以上,推荐 8.x),升级往往比调参更有效。
- 共享主机上被资源限制掐断。扫描跑到一半被主机商杀进程,会留下不完整状态。这类环境更适合用外部扫描服务,而不是本地全量扫描。
总结
优化 Wordfence 的优先级很清晰:先做扫描降频与错峰(收益最大、成本最低),再做排除目录,然后是系统 Cron 改造,最后是日志表定期清理。做完这四步,绝大多数「安全插件拖慢服务器」的抱怨都会消失。判断标准也很简单:在扫描时段观察 CPU 与 IO 曲线,如果仍出现长时间满载,就继续降低扫描频率或缩小扫描范围,而不是一关了之。更多关于防火墙与阈值本身的设置,参考Wordfence 配置教程:防火墙与扫描规则;若你更在意登录环节的保护,可结合用插件做双因素认证(2FA)一起做。
