Zibll站点极致性能优化思路解析,最快1.5ms网站响应打开

我把一台 4C4G 的 WordPress 网站优化到 1.5ms 打开,500 并发零失败

服务器配置:雨云十堰4核4G,Debian 13

网站:Zibll 主题 + WordPress 7.0 + PHP 8.5+EdgeONE

只是将我个人环境和优化过程分享给大家,实际需要根据真实情况进行略微调整,例如可不使用redis集群

优化前

打开一个页面要 610 毫秒以上,每次请求要查 7~10 次数据库,人一多直接 503。

优化后

未登录的游客打开页面只要 1.5 毫秒登录用户 16 毫秒SQL 查询降到 3 次,500 个人同时访问全部成功,没有一个报错。

参考网站:【sunzishaokao.com】云港网络

下面我就把这套完整的优化过程拆开,用大白话讲清楚每个地方改了什么、为什么要改、具体怎么操作。不管你是用宝塔面板还是纯命令行,都可以跟着做。


一、Redis Sentinel 高可用集群(缓存永不断)

为什么搞这个?

WordPress 慢的最大原因就是每次都去数据库里捞数据。所以我们要把经常访问的数据(比如文章、配置、用户 session)全部塞进 Redis 内存里。但单机 Redis 一挂,整个网站缓存就没了,所有请求又都打到 MySQL 上,瞬间卡死。所以我们直接搭一套 Redis 主从 + 哨兵自动切换,坏一个节点不影响网站。但是不能没有Redis,否则瞬时流量会导致缓存雪崩,MySQL无法扛住大流量

1.1 整体架构

画个图就好懂了:

你的 WordPress(PHP)
    ↓
HAProxy 端口 6390(自动找谁是 Master,只往 Master 写)
    ↓
3 个哨兵(Sentinel) 互相监控,一旦 Master 挂了,5 秒内投票选新 Master
    ↓
4 个 Redis 节点(:6379 宝塔自带的,:6380 :6381 :6382 是 Docker 跑的)
平时 1 主 3 从,挂了自动切

简单说:不管哪个 Redis 挂掉,WordPress 完全感觉不到,因为 HAProxy 会自动把请求转到新老大。

1.2 怎么搭?

所有配置文件都放在 /www/wwwroot/redis-sentinel-ha/ 下面。

docker-compose.yml 里定义了 7 个容器:

  • redis-master(端口 6380)

  • redis-slave-1(端口 6381)

  • redis-slave-2(端口 6382)

  • redis-sentinel-1/2/3(哨兵,分别用 26379、26380、26381)

  • redis-haproxy(代理,端口 6390)

宝塔装的那个 Redis(端口 6379)也用 replicaof 命令加入这个集群,变成第 4 个从节点。

关键 Redis 参数:

  • 每个节点最多用 384MB 内存(总共 1.5GB 缓存空间)

  • 满了就按最近最少使用淘汰(allkeys-lru

  • 关闭持久化(纯缓存用,不要 RDB/AOF,快了不止一点)

  • 开启主动碎片整理和异步删除,防止内存膨胀

HAProxy 的配置也很聪明:它定期给每个 Redis 发 INFO replication 命令,看谁回复里带 role:master,就只把请求发给它。这样主从切了也没事。

故障测试:故意杀掉 Master 节点,5 秒后哨兵们投票,从节点自动升级成新 Master,网站全程没断过。

1.3 Redis DB 分配

为了不同业务互不干扰,我们把不同数据存在不同编号的库里:

  • DB0:放 PHP Session(用户登录状态)

  • DB1:主站点缓存(对象缓存 + 页面缓存)


二、Linux 系统内核调优(让系统更能扛)

2.1 改内核参数

新建文件 /etc/sysctl.d/99-perf-optimize.conf,把下面这些粘进去:

# 网络相关
net.core.somaxconn = 4096
net.core.netdev_max_backlog = 8192
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.ip_local_port_range = 10000 65535
net.ipv4.tcp_fastopen = 3
net.ipv4.tcp_max_tw_buckets = 8192
net.ipv4.tcp_rmem = 4096 87380 8388608
net.ipv4.tcp_wmem = 4096 65536 8388608
​
# 虚拟内存
vm.swappiness = 1
vm.overcommit_memory = 1
vm.dirty_ratio = 10
vm.dirty_background_ratio = 5
​
# 文件句柄
fs.file-max = 1048576

然后执行 sysctl -p 让它生效。

大白话解释:

  • somaxconn 和 backlog 都放大,就是让系统能同时接待更多排队连接,别动不动就拒绝。

  • 加快 TIME_WAIT 状态的回收,避免端口被占满。

  • 把 swap 倾向调到 1,意思是尽量用物理内存,别用硬盘充当内存,不然网站会突然卡成狗。

  • 文件句柄数调大,免得高并发时报 “too many open files”。

2.2 修改文件限制

新建 /etc/security/limits.d/99-perf.conf

* soft nofile 655360
* hard nofile 655360
* soft nproc 65535
* hard nproc 65535

这样一来,Nginx、PHP、MySQL 都能打开足够多的文件。

顺便把透明大页(THP)关掉,这东西会导致内存分配延迟突然飙升

echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag

IO 调度器改成 mq-deadline(适合云服务器)。

实测效果:优化后 TIME_WAIT 连接数从 1600 多降到 600 多,系统负载从 1.9 降到了 0.72。


三、MySQL 5.7 优化(榨干数据库性能)

3.1 改 /etc/my.cnf

核心就是给 InnoDB 分配更多内存当缓存,关闭查询缓存(MySQL 5.7 开了反而慢),调大各种缓冲区。我直接列出变化对比:

参数 旧值 新值 干啥的
innodb_buffer_pool_size 64M 1G 给 InnoDB 1G 内存当缓存,数据库总共才 256M,全装进去
max_connections 100 300 允许更多同时连接
query_cache_size 32M 0 关闭查询缓存,避免锁竞争
skip-name-resolve OFF ON 不反解 DNS,连接更快
innodb_flush_method - O_DIRECT 绕过系统缓存,避免双重缓冲
innodb_flush_log_at_trx_commit 1 2 每秒刷一次日志,性能提升 2 倍,丢 1 秒数据可接受
innodb_io_capacity 200 1000 告诉 MySQL 磁盘能跑多少 IOPS,云盘设 1000
sort_buffer_size 256K 4M 排序更快
join_buffer_size 512K 4M 连表查询更快
tmp_table_size 32M 128M 临时表放内存,不写磁盘
sync_binlog 1 0 binlog 由系统决定何时刷盘,减少磁盘写入
long_query_time 3 1 超过 1 秒就记慢查询
expire_logs_days 10 3 binlog 只保留 3 天

改完重启 MySQL。

3.2 清理数据库垃圾

WordPress 用久了里面一堆废数据,直接跑 SQL 清理:

-- 删掉文章修订版
DELETE FROM wp_posts WHERE post_type = 'revision';
-- 删除孤立的元数据(文章删了但 meta 还在)
DELETE pm FROM wp_postmeta pm LEFT JOIN wp_posts p ON pm.post_id = p.ID WHERE p.ID IS NULL;
-- 删除过期的临时数据
DELETE FROM wp_options WHERE option_name LIKE '%_transient_timeout_%' AND option_value < UNIX_TIMESTAMP();
-- 优化碎片
OPTIMIZE TABLE wp_options, wp_posts, wp_postmeta, wp_usermeta;

3.3 清理 autoload 膨胀

WordPress 每次请求都会把所有 autoload=yes 的 option 从数据库加载到内存。我一看吓一跳,有 1111 条,占 828KB。实际很多是已经卸载的插件和主题留下的垃圾。

手动清理掉已经卸载的主题配置、插件配置,优化后剩下 813 条,356KB,直接少了一半多。

效果:缓存命中率 99.88%,慢查询归零,临时表写磁盘的现象几乎没了。


四、PHP 8.5 优化(让代码飞起来)

4.1 OPcache(代码缓存)

PHP 默认每次请求都要把 .php 文件读进来编译一遍,傻得要命。开 OPcache 后,编译好的字节码常驻内存,重复请求直接拿现成的,快了不知道多少倍。

编辑 /www/server/php/85/etc/php.ini[opcache] 部分:

opcache.memory_consumption = 256
opcache.max_accelerated_files = 20000
opcache.interned_strings_buffer = 32
opcache.revalidate_freq = 60
opcache.enable_file_override = 1
opcache.fast_shutdown = 1
  • 给 OPcache 256M 内存,能缓存 2 万个文件(全站 PHP 文件才 1500 多个)

  • 60 秒检查一次文件是否更新(线上没所谓,开发时嫌慢可以手动清缓存)

  • 打开 fast_shutdown 能稍微再快一点

打开后缓存命中率直接拉到 99.99%

4.2 JIT(即时编译)

PHP 8 加的 JIT 能让热点代码直接变成本地机器码,省去解释执行的开销。不过 WordPress 里大量用了 eval 和动态调用,JIT 能优化的地方有限,但聊胜于无,开了总比不开强。

opcache.jit = tracing
opcache.jit_buffer_size = 128M
opcache.jit_hot_func = 127
opcache.jit_hot_loop = 61

注意:这台服务器有个内核 bug,huge_code_pages 如果打开会导致 PHP 崩溃,必须设为 0。

4.3 PHP-FPM 进程管理

宝塔默认是 ondemand 模式,没请求时进程全死,来请求了现创建,浪费几十毫秒。改成静态模式,固定起 20 个进程候着。

/www/server/php/85/etc/php-fpm.conf

pm = static
pm.max_children = 20
pm.max_requests = 1000
listen.backlog = 8192

固定 20 个进程,每个大概占 100MB,总共 2G,4G 内存绰绰有余。

  • 每个进程处理 1000 个请求后自动重启,防止内存泄漏。

  • 监听队列设大,不怕瞬时流量。

4.4 其他

  • 把单脚本内存上限从 128M 提到 256M,给 Zibll 主题足够空间。

  • 关掉前台显示错误(防止泄露路径),打开 session 懒写(Lazy write,减少 IO)。

  • 把 PHP session 存到 Redis 集群里(session.save_path = "tcp://127.0.0.1:6390"),这样主从切换时登录状态也不丢。


五、Nginx 优化(把静态资源和匿名访问变成火箭)

5.1 Gzip 压缩

文本文件压缩再发给浏览器,一下子能省 80% 流量。在 nginx.conf 的 http 块里加上:

gzip on;
gzip_min_length 1k;
gzip_comp_level 6;
gzip_types text/plain application/javascript text/css application/xml application/json image/svg+xml;
gzip_vary on;
gzip_proxied any;

原本首页 216KB,压缩后只传 34KB,减少了 84%

5.2 静态文件缓存

图片、CSS、JS、字体这些文件万年不变,直接让浏览器缓存起来,下次直接读本地,请求都不发。

在站点的 Nginx 配置文件里加:

location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ { expires 30d; access_log off; }
location ~ .*\.(js|css)?$ { expires 12h; access_log off; }
location ~ .*\.(eot|otf|ttf|woff|woff2|svg)$ { expires 365d; access_log off; }

还把记录这些静态文件的访问日志也关了,省磁盘 IO。

5.3 FastCGI Cache(这是给游客的大杀器)

这是什么? Nginx 可以把 PHP 执行完生成的 HTML 页面直接存成文件,下次有同样的请求直接返回这个文件,根本不经过 PHP 和 MySQL,快得离谱。

怎么开?

先在全局配置里定义缓存目录和参数(/www/server/panel/vhost/nginx/0.fastcgi_cache.conf):

fastcgi_cache_path /www/server/fastcgi_cache levels=1:2 keys_zone=WORDPRESS:128m inactive=30m max_size=512m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_cache_lock on;

然后写一个专门的 PHP 处理器配置 enable-php-85-cache.conf,里面加了很多判断条件:

  • 如果是 POST 请求,不缓存

  • 如果是搜索结果页,不缓存

  • 如果有 utm_ 等跟踪参数,不缓存

  • 如果 URL 包含 /wp-admin/login/cart 等动态地址,不缓存

  • 如果 Cookie 里有 wordpress_logged_in,说明是登录用户,不缓存(因为他们看到的东西不一样)

全部不满足,就认为是个普通的游客访问,直接把返回的 HTML 存缓存,下次直接给。

同时在响应头里加个 X-Cache-Status,方便看命中没命中。

效果:游客打开页面从 610ms 直接变成 1.5ms,快了整整 400 倍!


六、WordPress 本身优化(从代码层面再砍一刀)

6.1 wp-config.php 加几行

define('DISABLE_WP_CRON', true);      // 禁用自带定时任务,改成系统 crontab 跑
define('WP_POST_REVISIONS', 3);       // 只保留 3 个修订版
define('AUTOSAVE_INTERVAL', 120);     // 两分钟自动保存一次
define('EMPTY_TRASH_DAYS', 3);        // 回收站只保留 3 天
define('DISALLOW_FILE_EDIT', true);   // 禁止后台编辑文件,安全
define('WP_MEMORY_LIMIT', '256M');
define('WP_MAX_MEMORY_LIMIT', '512M');

然后把 WP-Cron 交给系统 crontab:

*/5 * * * * /www/server/php/85/bin/php /www/wwwroot/<你的目录>/wp-cron.php --allow-root >/dev/null 2>&1

6.2 Object Cache Pro 直连 Redis HA

WordPress 的对象缓存插件我用的是 Object Cache Pro,配置里直接把 Redis 地址写成 HAProxy 的 6390 端口:

define('WP_REDIS_CONFIG', [
   'host' => '127.0.0.1',
   'port' => 6390,
   'database' => 1,
   'persistent' => true,   // 长连接,省去每次连接开销
   'timeout' => 0.5,
   'compression' => 'zstd',
   'serializer' => 'igbinary',
   'async_flush' => true,
   'split_alloptions' => true,
   'prefetch' => true,
]);

6.3 Must-Use 插件:两把性能小刀

/wp-content/mu-plugins/ 下放两个文件,它们会自动执行,不用后台启用。

000-perf-optimize.php:干掉所有没用但费性能的东西。

  • 禁止 WordPress 每次加载页面时检查核心/插件/主题更新(每个请求省了至少一条 UPDATE 查询)

  • 去掉头部无用的 link(rsd、wlwmanifest、短链接、Emoji 脚本等)

  • 禁用 XML-RPC 的 pingback 功能(防攻击又省资源)

  • 关闭 Object Cache 的统计上报(省去分析开销)

001-page-cache.php:给登录用户也做页面缓存! 游客有 Nginx 缓存了,登录用户因为 Cookie 被跳过了,怎么办?这个插件在 WordPress 启动前就检查 Redis 里有没有存好的 HTML,有就立刻返回,完全不碰 PHP 和数据库。

  • 缓存 key 里带用户哈希,不同用户缓存独立

  • 只缓存 GET 请求,自动跳过后台、搜索、支付等动态页面

  • TTL 设 120 秒,过期自动重建

  • 一旦用户执行了 POST 操作(发评论、修改资料),在请求结束时自动清掉该用户的所有缓存,保证数据是最新的

效果:登录用户首次打开 500ms,缓存命中后降到 16~38ms,快了 20~30 倍!


七、最终效果,用数据说话

8.1 性能对比表

场景 优化前 优化后 提升
游客访问(缓存命中) 610ms 1.5ms 400倍
登录用户首次/缓存未命中 610ms 500ms 快 22%
登录用户缓存命中 610ms 16~38ms 20~38倍
SQL 查询次数 7~10次 3次 减少 70%
200 并发测试 大量 503 全部成功 -
500 并发测试 全部 503 全部成功 -
Gzip 压缩率 未开启 84% 216KB→34KB
OPcache 命中率 0% 99.99% -
autoload 数据量 828KB 356KB 减少 57%

8.2 缓存怎么配合的

一个请求进来:
├─ 是游客,且是 GET 普通页面
│   └─ Nginx 直接给 HTML(1.5ms),没命中才去叫 PHP 生成
├─ 是登录用户,且是 GET 普通页面
│   └─ MU 插件从 Redis 取 HTML(16ms),没命中才启动 WordPress
├─ 是 POST / PUT / DELETE 操作
│   └─ 正常走 PHP,处理完自动把该用户的页面缓存全清掉
└─ 是后台 / API / 搜索等特殊地址
      └─ 老实走 PHP,不缓存

8.3 压力测试

内网用 curl 模拟 500 个并发请求游客首页,缓存命中后 3.2 秒全部完成,成功率 100%,相当于每秒处理 156 个请求。登录用户的缓存命中后,平均响应 28ms。


九、跟着做的完整命令(复制粘贴版)

注意:尖括号里的内容改成你自己的真实值,比如 <你的域名>

9.1 搭建 Redis Sentinel 集群

mkdir -p /www/wwwroot/redis-sentinel-ha
# 把写好的 docker-compose.yml 和 haproxy.cfg 上传到这个目录
chmod 644 /www/wwwroot/redis-sentinel-ha/haproxy.cfg
​
# 备份宝塔 Redis 配置
cp /www/server/redis/redis.conf /www/server/redis/redis.conf.bak
# 编辑 redis.conf,在末尾加上:
# replicaof 127.0.0.1 6380
# replica-announce-ip 127.0.0.1
# replica-announce-port 6379
# maxmemory 384mb
# maxmemory-policy allkeys-lru
# appendonly no
# activedefrag yes
​
# 启动 Docker 集群
cd /www/wwwroot/redis-sentinel-ha
docker compose up -d
​
# 重启宝塔 Redis(以从节点身份加入)
redis-cli -p 6379 SHUTDOWN NOSAVE
/www/server/redis/src/redis-server /www/server/redis/redis.conf
​
# 检查集群状态
redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster
redis-cli -p 6390 PING

9.2 PHP Session 改到 Redis 集群

sed -i 's|session.save_path = "tcp://127.0.0.1:6379"|session.save_path = "tcp://127.0.0.1:6390"|' /www/server/php/85/etc/php.ini
sed -i 's|session.save_path = "tcp://127.0.0.1:6379"|session.save_path = "tcp://127.0.0.1:6390"|' /www/server/php/85/etc/php-cli.ini
/etc/init.d/php-fpm-85 restart

9.3 启用 Nginx FastCGI 缓存

# 把站点 Nginx 配置里的 PHP 处理器引用改成带缓存的版本
sed -i 's|include enable-php-85.conf;|include enable-php-85-cache.conf;|' /www/server/panel/vhost/nginx/<你的域名>.conf
​
# 检查配置并重载
nginx -t && /etc/init.d/nginx reload
​
# 验证:第一次访问是 MISS,第二次就是 HIT
curl -sS -I -H "Host: <你的域名>" http://127.0.0.1/ | grep X-Cache

9.4 清理优化数据库

MYSQL_PW="你的数据库root密码"
DB="你的数据库名"
TP="wp_"
​
mysql -uroot -p"$MYSQL_PW" "$DB" -e "
DELETE FROM ${TP}posts WHERE post_type='revision';
DELETE pm FROM ${TP}postmeta pm LEFT JOIN ${TP}posts p ON pm.post_id=p.ID WHERE p.ID IS NULL;
DELETE FROM ${TP}options WHERE option_name LIKE '%_transient_timeout_%' AND option_value < UNIX_TIMESTAMP();
OPTIMIZE TABLE ${TP}options, ${TP}posts, ${TP}postmeta, ${TP}usermeta, ${TP}users, ${TP}comments;
"
​
# 清理 autoload 垃圾(根据你网站情况调整)
mysql -uroot -p"$MYSQL_PW" "$DB" -e "
DELETE FROM ${TP}options WHERE option_name LIKE 'litespeed%';
DELETE FROM ${TP}options WHERE option_name LIKE '%supercache%';
DELETE FROM ${TP}options WHERE option_name LIKE 'wpseo_%';
OPTIMIZE TABLE ${TP}options;
"

9.5 应用 PHP OPcache + JIT 配置

修改好 php.ini 后:

/etc/init.d/php-fpm-85 restart
php -i | grep "opcache.jit "   # 输出应包含 tracing

9.6 安装 MU-Plugin

mkdir -p /www/wwwroot/<你的目录>/wp-content/mu-plugins
# 把 000-perf-optimize.php 和 001-page-cache.php 上传进去
chmod 644 /www/wwwroot/<你的目录>/wp-content/mu-plugins/*.php
chown www:www /www/wwwroot/<你的目录>/wp-content/mu-plugins/*.php
/etc/init.d/php-fpm-85 restart

000-perf-optimize.php

<?php
/**
 * 性能优化 MU-Plugin
 * 禁用不必要的功能和查询,减少每次页面加载的开销
 */

// 1. 禁用 WordPress 核心、插件、主题的更新检查
//    这些检查每次页面加载都会往数据库写 UPDATE 查询,纯属浪费
remove_action('init', 'wp_schedule_update_checks');

// 短路更新检查的 transient,直接返回空结果,让 WordPress 以为没有任何更新
add_filter('pre_site_transient_update_core', function () {
    return (object) array(
        'last_checked'    => time(),
        'version_checked' => '7.0',
        'updates'         => array(),
    );
});
add_filter('pre_site_transient_update_plugins', function () {
    return (object) array(
        'last_checked' => time(),
        'response'     => array(),
        'translations' => array(),
    );
});
add_filter('pre_site_transient_update_themes', function () {
    return (object) array(
        'last_checked' => time(),
        'response'     => array(),
        'translations' => array(),
    );
});

// 2. 移除网页头部(head)里一堆没用的链接标签
remove_action('wp_head', 'rsd_link');                      // Really Simple Discovery
remove_action('wp_head', 'wlwmanifest_link');              // Windows Live Writer
remove_action('wp_head', 'wp_generator');                  // WordPress 版本号
remove_action('wp_head', 'wp_shortlink_wp_head');          // 短链接
remove_action('wp_head', 'rest_output_link_wp_head', 10); // REST API 链接
remove_action('wp_head', 'wp_oembed_add_discovery_links'); // oEmbed 发现链接
remove_action('wp_head', 'wp_oembed_add_host_js');         // oEmbed JS
remove_action('wp_head', 'feed_links_extra', 3);           // 分类 Feed 等
remove_action('wp_head', 'feed_links', 2);                 // 通用 Feed

// 3. 禁用 Emoji 相关的脚本和样式
remove_action('wp_head', 'print_emoji_detection_script', 7);
remove_action('wp_print_styles', 'print_emoji_styles');

// 4. 关闭 Object Cache Pro 的统计上报(省去每次请求的分析开销)
add_filter('objectcache.analytics', '__return_false');

// 5. 禁用 XML-RPC 的 pingback(安全 + 省资源)
add_filter('xmlrpc_methods', function ($methods) {
    unset($methods['pingback.ping']);
    return $methods;
});

001-page-cache.php

<?php
/**
 * Redis 页面缓存(针对登录用户)
 *
 * 缓存策略:
 *  - Key 格式:pgc:<用户哈希>:<md5(域名+URI)>
 *  - TTL:120 秒
 *  - 任何 POST/PUT/DELETE 请求结束后,自动清除当前用户所有缓存
 *
 * 注意:游客的页面缓存由 Nginx fastcgi_cache 负责,这个插件只处理登录用户。
 */

$is_get = (($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'GET');

// 不处理 AJAX、Cron、XML-RPC、REST 请求和后台页面
if (
    (defined('DOING_AJAX') && DOING_AJAX) ||
    (defined('DOING_CRON') && DOING_CRON) ||
    (defined('XMLRPC_REQUEST') && XMLRPC_REQUEST) ||
    (defined('REST_REQUEST') && REST_REQUEST) ||
    is_admin()
) {
    return;
}

// ========== 非 GET 请求:注册清除缓存回调,然后结束 ==========
if (!$is_get) {
    function _pgcache_invalidate() {
        $user_hash = 'anon';
        foreach ($_COOKIE as $name => $value) {
            if (strpos($name, 'wordpress_logged_in') === 0) {
                $user_hash = 'u' . substr(md5($name . $value), 0, 16);
                break;
            }
        }
        try {
            $r = new Redis();
            if ($r->connect('127.0.0.1', 6390, 0.3)) {
                $r->select(1); // DB1 存放页面缓存
                $keys = $r->keys("pgc:$user_hash:*");
                if (!empty($keys)) {
                    $r->del($keys);
                }
                $r->close();
            }
        } catch (Exception $e) {
            // 静默失败,不影响正常请求
        }
    }
    register_shutdown_function('_pgcache_invalidate');
    return;
}

// ========== 以下是 GET 请求处理 ==========

// 1. 检查是否是需要跳过的路径
$uri = $_SERVER['REQUEST_URI'] ?? '';
$skip_paths = [
    '/wp-admin', '/wp-login', '/wp-json', '/xmlrpc', '/wp-cron',
    '/feed', '/sitemap', '/wp-comments', '/cart', '/checkout',
    '/netcard', '/user-sign', '/search', '/oauth', '/newposts', '/bbs-edit',
    '/author/', '/message', '/notification', '/notify',
    '/uc_', '/user-center', '/my-account', '/dashboard',
    '/wp-content/uploads', '/cdn-cgi',
];
foreach ($skip_paths as $p) {
    if (stripos($uri, $p) !== false) {
        return; // 动态页面不缓存
    }
}

// 2. 检查查询参数,跳过含有跟踪参数或特殊参数的请求
$query = $_SERVER['QUERY_STRING'] ?? '';
if (preg_match('/(utm_|preview|gclid|fbclid|nonce|_wpnonce|add-to-cart|p=|action=)/', $query)) {
    return;
}
// 允许分页、排序等简单参数,其他复杂查询不缓存
if (!empty($query) && !preg_match('/^(paged|page|cat|tag|orderby|order|type|status|tab)=/', $query)) {
    return;
}

// 3. 生成缓存 Key
function _pgcache_key() {
    $user_hash = 'anon';
    foreach ($_COOKIE as $name => $value) {
        if (strpos($name, 'wordpress_logged_in') === 0) {
            $user_hash = 'u' . substr(md5($name . $value), 0, 16);
            break;
        }
    }
    $host = $_SERVER['HTTP_HOST'] ?? 'localhost';
    return 'pgc:' . $user_hash . ':' . md5($host . ($_SERVER['REQUEST_URI'] ?? '/'));
}

// 4. 尝试从 Redis 取出缓存并直接输出
function _pgcache_try_serve() {
    $key = _pgcache_key();
    try {
        $r = new Redis();
        if (!$r->connect('127.0.0.1', 6390, 0.3)) {
            return;
        }
        $r->select(1);
        $html = $r->get($key);
        $r->close();

        if ($html && strlen($html) > 500) {
            // 简单判断是不是 HTML 内容
            if (substr($html, 0, 1) === '<' || substr($html, 0, 9) === '<!DOCTYPE') {
                header('Content-Type: text/html; charset=UTF-8');
                header('X-Page-Cache: HIT');
                echo $html;
                exit;
            }
        }
    } catch (Exception $e) {
        // 静默失败
    }
    if (!headers_sent()) {
        header('X-Page-Cache: MISS');
    }
}
_pgcache_try_serve();

// 5. 如果缓存未命中,等 WordPress 生成完页面后,把结果存进 Redis
ob_start(function ($html) {
    if (http_response_code() !== 200) {
        return $html;
    }
    if (strlen($html) < 1000) {
        return $html; // 太短的内容不缓存(可能是错误页)
    }
    if (stripos($html, '<html') === false && stripos($html, '<!DOCTYPE') === false) {
        return $html; // 不是完整 HTML,不缓存
    }

    $key = _pgcache_key();
    try {
        $r = new Redis();
        if ($r->connect('127.0.0.1', 6390, 0.3)) {
            $r->select(1);
            $r->setex($key, 120, $html); // 120 秒过期
            $r->close();
        }
    } catch (Exception $e) {
        // 静默失败
    }
    return $html;
});

9.7 全量验证

# 1. 服务状态
docker ps | grep redis
ps aux | grep php-fpm | grep pool | wc -l   # 应该是 20
redis-cli -p 6390 PING
mysql -uroot -p -e "SELECT 1"
​
# 2. 缓存测试
curl -sS -I -H "Host: <你的域名>" http://127.0.0.1/ | grep X-Cache
# 游客 → X-Cache-Status: HIT
curl -sS -I -H "Host: <你的域名>" -H "Cookie: wordpress_logged_in_test=1" http://127.0.0.1/ | grep X-Page-Cache
# 登录用户 → X-Page-Cache: HIT
​
# 3. 速度测试
curl -sS -o /dev/null -w "响应时间: %{time_total}s\n" -H "Host: <你的域名>" http://127.0.0.1/
​
# 4. 简单并发测试
for i in {1..200}; do curl -sS -o /dev/null -w "%{http_code}\n" -H "Host: <你的域名>" http://127.0.0.1/ & done; wait
# 应该全是 200
​
# 5. Redis 主从状态
for port in 6379 6380 6381 6382; do echo "端口 $port 角色: $(redis-cli -p $port INFO replication | grep ^role:)"; done

十、避坑和注意事项

  1. huge_code_pages 必须关:这台服务器内核有 bug,开了 PHP 会挂。

  2. JIT 效果有限:WordPress 太多动态特性,不能完全指望 JIT,但开着无害。

  3. 页面缓存 120 秒过期:不怕内容更新不及时,因为任何 POST 操作都会立刻清除缓存。

  4. OPcache 每 60 秒检查文件:改代码后最慢 1 分钟生效,着急的话手动重启 PHP。

  5. 宝塔会覆盖配置:在宝塔面板里改过 PHP/MySQL 设置后,记得回头检查我们手动改的那些参数有没有被复原,最好在面板里也同步设置一下。

  6. 如果你有多个站点:它们共用同一个 fastcgi_cache 缓存区,通过域名自动区分,不会串。

  7. 固定链接用数字 ID/%post_id%.html 比文章名查询快得多,数据库压力更小。


整套优化从系统底层到应用层全都过了一遍,核心思路就是“能缓存就缓存,能提前准备好就不现做,能用内存就别用磁盘”。照着做完,你的 Zibll + WordPress 网站也能在低配服务器上跑出火箭一样的速度。

 


广告:

© 版权声明
THE END
喜欢就支持一下吧
点赞7打赏 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容