没有不值得去解决的问题,也没有不值得去学习的技术!

阿里云 OneinStack 实战:将 Redis 7.0.11 升级到 8.10.0,并完成内核优化与回滚保护

阿里云 OneinStack 服务器 Redis 从 7.0.11 升级到 8.10.0 后的版本与运行状态对比截图

WordPress 性能优化手记

如 如图1 所示,站点健康直接提示这是一个可能对性能或安全性产生重大影响的问题,需要优先解决。

(1) 从站点健康警告到全绿通关

PHP Fatal error: Uncaught RedisException: OOM command not allowed when used memory > 'maxmemory'. in /data/wwwroot/.../wp-content/plugins/w3-total-cache/Cache_Redis.php:150

(2) 解决 WordPress + Polylang 批量处理标签时遇到的 Redis OOM 错误

采用 ondemand 模式,适合 1 核小内存机器,空闲时释放进程。最终配置如下:如图4

(3) 一次WordPress站点504错误的排查与优化实录

优化前最终基准数据:历史累计504错误129条(6月3日峰值126条,为爬虫批量爬标签导致)。

(4) 从单日126次504超时到彻底稳定:WordPress 1核2G服务器极限优化全记录(附全部实操命令)

WebPageTest 核心指标

(5) WordPress性能基准测试与CDN选型实录:从国内拨测到海外WebPageTest,1核2G服务器如何面向全球

页面底部提示“此响应不是合法的 JSON 响应”。

(6) WordPress 标签保存失败?Nginx 限流规则惹的祸 —— 一次完整的 429 问题排查与解决

表示页面仍然是动态生成,没有缓存命中。

(7) WordPress + Nginx + W3 Total Cache 缓存未生效排查全过程(OneinStack 实战)

图7:带 Query String 后,W3TC 显示 Requested URI contains query

(8) WordPress CPU 再次满载:动态参数如何穿透 CDN 与 W3TC 页面缓存

图1:阿里云 ECS 在 14:33~14:42 期间 CPU 使用率持续接近 100%,而内存使用率整体较为稳定

(9) WordPress 服务器 CPU 再次满载:从 Nginx 499、PHP-FPM、Redis 到 W3TC 冷缓存的完整排查

图4:W3TC 最终使用 300 秒 × 7 页,并切换到中英文联合 Sitemap

(10) 从 CPU 告警到双域名预缓存:W3 Total Cache、EdgeOne 与 Cloudflare 96 小时缓存优化实战

WordPress 所有归档模板中使用 Language Visibility 和 WPCode Shortcode 添加中英文 Adsterra 广告

(11) WordPress 三域名架构再次踩坑:Adsterra 归档广告不生效,最终定位到 W3TC Object Cache

WordPress 多语言多域名缓存排查:修复 Polylang + W3 Total Cache 跨 Host 缓存失效问题

(12) WordPress 多语言多域名缓存排查:修复 Polylang + W3 Total Cache 跨 Host 缓存失效问题

WordPress 多域名环境下中文文章详情页未显示 Polylang 语言切换器

(13) WordPress 多域名下 Polylang 语言切换器延迟:W3TC Redis 跨 Host 缓存排查记录

图8:选择 2 核 4 GiB 后显示的实际补差价、2 Mbps 带宽和重启选项

(14) 从 CPU 再次告警到 ECS 升配:WordPress 服务器从 1 核 2G 升级到 2 核 4G 实录

**Alt:** WordPress 生产环境完成 PHP 8.5.9 升级,终端显示 OPcache、Imagick、Redis、Nginx、WordPress 版本及中英文站和后台域名均正常返回 HTTP 200

(15) OneinStack 生产环境将 PHP 8.1.19 升级到 PHP 8.5.9:Imagick 编译失败与 WordPress 多域名缓存验收

阿里云 OneinStack 服务器升级完成,终端显示 Nginx 1.30.4、OpenSSL 3.5.7、PCRE 8.45 和 PHP 8.5.9,Nginx 配置检查成功

(16) 阿里云 OneinStack 实战:将 Nginx 1.24.0 升级到 1.30.4,并同步升级 OpenSSL 3.5.7

阿里云 OneinStack 服务器 Redis 从 7.0.11 升级到 8.10.0 后的版本与运行状态对比截图

(17) 阿里云 OneinStack 实战:将 Redis 7.0.11 升级到 8.10.0,并完成内核优化与回滚保护

在完成 Nginx、OpenSSL 和 PHP 等组件升级后,我继续检查了这台阿里云 ECS 上的 Redis。

服务器使用 OneinStack 环境,Redis 并不是通过 RPM 安装,而是部署在:

Plaintext
/usr/local/redis

升级前运行的版本为:

Plaintext
Redis 7.0.11

这次我的目标并不是简单替换一个 redis-server 文件,而是尽量把升级前审计、数据备份、内核参数优化、旁路编译、兼容性验证、生产切换和回滚方案都做完整,最终将 Redis 升级到:

Plaintext
Redis 8.10.0
jemalloc 5.3.0

整个生产切换最终成功,WordPress 中文站、英文站和管理站均正常运行。


一、升级前的 Redis 环境

升级前,Redis 的主要情况如下:

  • Redis 版本:7.0.11
  • 运行模式:standalone
  • 监听地址:127.0.0.1:6379
  • 配置文件:/usr/local/redis/etc/redis.conf
  • 数据目录:/usr/local/redis/var
  • systemd 服务:redis-server.service
  • 服务用户:redis
  • 最大内存:1GB
  • 淘汰策略:allkeys-lru
  • AOF:未启用
  • 定时 RDB:已关闭
  • 已加载模块:无
  • PHP Redis 扩展:6.3.0
  • WordPress 缓存插件:W3 Total Cache

服务器总内存约为 3.6GiB,Redis 升级前已经使用约 880MiB 内存,缓存键数量约 30 万。

Redis 的缓存命中率很高,而且绝大多数键都设置了过期时间,说明它主要承担 WordPress 对象缓存和页面相关缓存,而不是保存不可丢失的业务数据。

不过,这并不意味着升级时可以直接清空 Redis。

如果一次性丢失 30 万个缓存键,WordPress、PHP-FPM 和远程 RDS 可能会在短时间内承受较大的缓存重建压力。因此,我仍然决定尽量保留现有缓存数据。


二、升级前发现的两个系统问题

在正式升级之前,我先检查了服务器的内核参数。

结果发现:

Plaintext
vm.overcommit_memory = 0

Redis 日志中也一直存在对应警告:

Plaintext
WARNING Memory overcommit must be enabled!

Redis 在执行 RDB 后台保存时需要通过 fork() 创建子进程。如果未启用内存过量分配,即使服务器还有可用内存,也可能因为内核的分配判断导致后台保存失败。

因此,我将其调整为:

Plaintext
vm.overcommit_memory = 1

并写入持久配置:

Plaintext
/etc/sysctl.d/99-redis-overcommit.conf

配置内容如下:

INI
# Redis background saving and fork reliability
vm.overcommit_memory = 1

同时执行:

Bash
sysctl -w vm.overcommit_memory=1

Transparent Huge Pages 仍然开启

最初的 THP 状态为:

Plaintext
enabled: [always] madvise never
defrag: always defer defer+madvise [madvise] never

这表示 Transparent Huge Pages 仍然处于启用状态。

为了避免 Redis 在复制内存页、执行 RDB 保存或高频访问时产生额外延迟,我创建了一个 systemd 服务,在系统启动时自动关闭 THP。

最终状态变成:

Plaintext
always madvise [never]
always defer defer+madvise madvise [never]

至此,Redis 所需的两个重要系统参数均完成了调整:

Plaintext
vm.overcommit_memory = 1
Transparent Huge Pages = never

三、先生成一份最新的 RDB

升级前的 Redis 配置中包含:

Plaintext
save ""
appendonly no

也就是说:

  • 定时 RDB 保存已经关闭;
  • AOF 也没有启用。

当时磁盘上的 dump.rdb 还是 2026 年 6 月 5 日生成的,已经严重过期。

因此,在更换任何二进制文件之前,我先手动执行:

Bash
/usr/local/redis/bin/redis-cli BGSAVE

后台保存顺利完成:

Plaintext
Background saving started
RDB 后台保存成功
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:7

新的 RDB 文件约为:

Plaintext
263M

此次后台保存时,Redis 的 Fork Copy-on-Write 峰值只有约 6MB,说明保存过程对服务器内存造成的额外压力很小。

我随后备份了以下内容:

  • Redis 7.0.11 所有二进制文件
  • redis.conf
  • 最新 dump.rdb
  • systemd 服务文件
  • Redis Server、Memory、Persistence 和 Keyspace 信息
  • 所有备份文件的 SHA-256

第一份完整备份目录为:

Plaintext
/root/redis-upgrade-backup-20260805-185250

备份总大小约为 334MB。


四、最初计划编译 Redis 8.10.0 全部内容

这次选择的目标版本为:

Plaintext
Redis 8.10.0

源码包下载完成后,文件信息如下:

Plaintext
文件大小:21550621 字节
SHA-256:f1baa4b28befd417aa6577ebeedde9e9fc7814cfcc299b2a6d2fd99ef7420a6c

源码包可以正常解压,顶层目录和版本信息也完全正确:

Plaintext
redis-8.10.0
#define REDIS_VERSION "8.10.0"

但在编译过程中,遇到了一个与 Redis 8 源码包结构有关的问题。


五、顶层 make 会同时编译多个附加模块

我最初尝试通过顶层 make 构建 Redis。

虽然 Redis 核心的 redis-serverredis-cliredis-benchmark 都已经成功生成,但顶层构建还继续尝试编译:

  • RedisBloom
  • RediSearch
  • RedisJSON
  • RedisTimeSeries

随后出现了 Python 依赖错误:

Plaintext
ModuleNotFoundError: No module named 'dataclasses'

RedisTimeSeries 在链接阶段还出现了:

Plaintext
undefined reference to `main'

最终顶层 make 返回失败:

Plaintext
WARNING: The following module(s) failed to build:
redisbloom redisearch redisjson redistimeseries

ERROR: make build finished with module failure(s)

不过,日志同时明确显示:

Plaintext
Build complete.
redis-server: /root/redis-8.10.0/src/redis-server

也就是说,失败的是附加模块,而不是 Redis 核心。


六、为什么没有继续解决四个模块的编译问题

这台服务器上的 Redis 主要供 WordPress 和 W3 Total Cache 使用。

升级前执行:

Plaintext
MODULE LIST

结果为空。

WordPress 当前使用的是 Redis 的基础能力,例如:

  • GET
  • SET
  • DEL
  • EXPIRE
  • Hash
  • List
  • Set
  • Sorted Set

并不依赖以下命令:

Plaintext
FT.SEARCH
JSON.SET
TS.ADD
BF.ADD

因此,RedisBloom、RediSearch、RedisJSON 和 RedisTimeSeries 对当前网站并不是必需组件。

如果为了编译这四个模块,继续安装或升级 Python、Rust、CMake、LLVM 以及多个模块自己的依赖,不仅不会提升 WordPress 的缓存性能,还会显著增加服务器的维护复杂度。

最终我决定采用:

Plaintext
Redis 8.10.0 核心
不安装 RedisBloom
不安装 RediSearch
不安装 RedisJSON
不安装 RedisTimeSeries

这里的“一次到位”,并不等于把所有暂时用不到的功能全部安装,而是把当前真正需要的部分升级完整,并保证后续能够稳定维护。


七、只编译 Redis 核心目标

通过检查 src/Makefile,可以看到 Redis 核心提供了明确目标:

Plaintext
redis-server
redis-cli
redis-benchmark
redis-check-rdb
redis-check-aof
redis-sentinel

因此,我不再运行顶层 make,而是直接在 src 目录中构建需要的核心程序:

Bash
make -C src -j2 \
    MALLOC=jemalloc \
    DISABLE_WERRORS=yes \
    redis-server \
    redis-cli \
    redis-benchmark

这次成功完成:

Plaintext
CC release.o
LINK redis-server
LINK redis-cli
LINK redis-benchmark
明确的核心目标检查成功

生成的版本为:

Plaintext
Redis server v=8.10.0
redis-cli 8.10.0
malloc=jemalloc-5.3.0

随后,我建立了一个独立旁路目录:

Plaintext
/root/redis-8.10.0-core-stage

目录中包含:

Plaintext
redis-server
redis-cli
redis-benchmark
redis-check-rdb -> redis-server
redis-check-aof -> redis-server
redis-sentinel -> redis-server

这样可以在不修改生产目录的情况下,对新版本进行完整测试。


八、使用 Redis 8.10.0 检查旧版 RDB

我使用新编译的 Redis 8.10.0 检查了 Redis 7.0.11 生成的 RDB:

Bash
/root/redis-8.10.0-core-stage/bin/redis-check-rdb \
    /root/redis-upgrade-backup-20260805-185250/var/dump.rdb

检查结果为:

Plaintext
Checksum OK
RDB looks OK
303294 keys read
303242 expires
4364 already expired

这说明:

  • RDB 文件结构正常;
  • 校验和正常;
  • Redis 8.10.0 可以识别 Redis 7.0.11 生成的数据;
  • 文件中存在部分已经过期的缓存键,这属于正常现象。

九、先在 16379 端口测试 Redis 8.10.0

为了进一步降低风险,我没有直接替换生产服务,而是使用端口 16379 启动了一个临时 Redis 8.10.0 实例。

临时实例没有加载生产 RDB,也没有占用大量内存,只用于验证:

  • 原有 Redis 配置是否能被 8.10.0 识别;
  • Redis Server 能否正常启动;
  • Redis CLI 能否读写;
  • PHP Redis 扩展能否连接;
  • systemd 和系统动态库是否存在兼容问题。

启动结果:

Plaintext
PONG
redis_version:8.10.0
redis_mode:standalone
tcp_port:16379
mem_allocator:jemalloc-5.3.0

Redis CLI 读写测试成功:

Plaintext
redis_cli_value=ok

PHP Redis 扩展测试也成功:

Plaintext
php_redis_value=ok

测试完成后,临时实例正常停止。

整个验证期间,生产 Redis 7.0.11 始终保持运行,没有停止,也没有替换二进制。


十、为什么 MODULE LIST 中出现了 vectorset

临时 Redis 8.10.0 启动后,MODULE LIST 并不是完全为空,而是出现了:

Plaintext
vectorset

这不是此前放弃编译的 RedisBloom、RediSearch、RedisJSON 或 RedisTimeSeries。

Vector Set 是与当前 Redis 8 核心程序一起构建的能力,因此最终方案更准确地说是:

Plaintext
Redis 8.10.0 核心
包含 Vector Set
不包含 RedisBloom
不包含 RediSearch
不包含 RedisJSON
不包含 RedisTimeSeries

它不会影响现有 WordPress 缓存,也不需要额外处理。


十一、正式切换前再次生成 RDB

在生产切换前,我再次执行了一次 BGSAVE

此次保存耗时约 8 秒:

Plaintext
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:8

切换前 Redis 中共有:

Plaintext
302735 个键

随后创建了第二份、也是正式切换时使用的完整备份:

Plaintext
/root/redis-cutover-backup-20260805-193515

同时生成了独立回滚脚本:

Plaintext
/root/redis-rollback-20260805-193515.sh

回滚脚本可以完成:

  • 停止当前 Redis;
  • 恢复 Redis 7.0.11 二进制;
  • 恢复旧配置;
  • 恢复升级前 RDB;
  • 恢复 systemd 服务;
  • 启动 Redis 7.0.11;
  • 检查版本和 PING。

只有在备份和回滚脚本都创建成功后,生产切换才正式开始。


十二、正式将 Redis 7.0.11 切换到 8.10.0

生产切换步骤为:

  1. 停止 Redis 7.0.11;
  2. 将旁路目录中的 Redis 8.10.0 二进制复制到 /usr/local/redis/bin
  3. 重建 redis-check-rdbredis-check-aofredis-sentinel 链接;
  4. 使用原有 redis.conf 启动 Redis 8.10.0;
  5. 等待 RDB 加载完成;
  6. 验证版本、键数量、内存、PHP 和 WordPress。

Redis 7.0.11 正常停止后,Redis 8.10.0 成功启动:

Plaintext
Redis 8.10.0 已开始响应
PONG
redis_version:8.10.0
redis_mode:standalone
tcp_port:6379

日志显示 Redis 8.10.0 成功读取了 Redis 7.0.11 生成的 RDB:

Plaintext
Loading RDB produced by version 7.0.11
RDB memory usage when created 881.41 Mb
Done loading RDB, keys loaded: 301533, keys expired: 1170
DB loaded from disk: 2.787 seconds
Ready to accept connections tcp

从停止 Redis 7 到 Redis 8 开始接受连接,实际中断时间非常短。


十三、升级后键数量为什么减少

切换前键数量为:

Plaintext
302735

切换后首次检查为:

Plaintext
301533

两者相差约 1200 个键。

这并不是升级导致的数据丢失。

Redis 日志已经明确记录:

Plaintext
keys expired: 1170

这些键在 RDB 加载时已经过期,因此不会再进入新实例。

此外,Redis 中的缓存键仍在持续到期和重新生成,后续再次检查时,键数量已经增长到:

Plaintext
301868

这说明 WordPress 和 W3 Total Cache 正在继续正常使用 Redis。


十四、WordPress 和 PHP 验证结果

Redis 8.10.0 启动后,我分别通过 Redis CLI 和 PHP Redis 扩展进行了读写测试。

结果如下:

Plaintext
redis_cli_value=ok
php_redis_value=ok

随后直接绕过 CDN,通过本机源站检查三个站点:

Plaintext
www.shuijingwanwq.com/wp-json/        200
en.shuijingwanwq.com/wp-json/         200
admin.shuijingwanwq.com/wp-login.php  200

这说明:

  • 中文站正常;
  • 英文站正常;
  • 管理站正常;
  • PHP Redis 扩展可以正常连接 Redis 8.10.0;
  • W3 Total Cache 没有因为 Redis 升级而失效。

自动回滚最终没有被触发。


十五、升级后的内存与缓存情况

升级完成约 3 分钟后,Redis 内存状态为:

Plaintext
used_memory_human:872.55M
used_memory_rss_human:837.40M
maxmemory_human:1.00G
maxmemory_policy:allkeys-lru
mem_fragmentation_ratio:0.96
mem_allocator:jemalloc-5.3.0

统计信息为:

Plaintext
total_commands_processed:21184
rejected_connections:0
evicted_keys:0
keyspace_hits:162630
keyspace_misses:769

当时缓存命中率约为 99.5%。

虽然 872.55M 已经占到 1GB 限制的约 85%,但目前:

  • 没有发生键淘汰;
  • 没有拒绝连接;
  • 命中率非常高;
  • 服务器仍有约 2.1GiB 可用内存;
  • Redis RSS 也低于 used_memory

因此,我暂时没有立即提高 maxmemory

当前继续保留:

Plaintext
maxmemory 1024mb
maxmemory-policy allkeys-lru

后续观察 24 至 72 小时。

只有出现以下情况时,才考虑将上限调整到:

Plaintext
1280mb

判断条件主要包括:

  • used_memory 长时间接近 1GB;
  • evicted_keys 持续增长;
  • keyspace_misses 明显增加;
  • 缓存命中率出现持续下降。

对这台总内存只有 3.6GiB 的 WordPress 综合服务器来说,不适合直接将 Redis 提高到 1.5GB 或更高,还需要给 PHP-FPM、Nginx、系统缓存和 RDB 后台保存预留空间。


十六、两条日志提示是否需要处理

PID 文件提示

systemd 启动过程中出现:

Plaintext
Can't open PID file /var/run/redis/redis.pid (yet?)

但紧接着服务已经正常进入:

Plaintext
active (running)

Redis 主进程也被 systemd 正确识别。

这是 Type=forking 服务启动时,systemd 检查 PID 文件与 Redis 写入 PID 文件之间的短暂时序提示,不代表 Redis 启动失败。

暂时没有必要为了消除这一条提示,改造现有 systemd 服务模式。

未设置 Redis 密码

Redis 8.10.0 日志中还有:

Plaintext
WARNING: Redis does not require authentication.
Redis will accept connections from any local client.

当前 Redis 只监听:

Plaintext
127.0.0.1:6379

并且配置了:

Plaintext
protected-mode yes

Redis 只供同一台服务器上的 PHP 和 WordPress 使用。

如果现在新增密码,还需要同步修改 W3 Total Cache 和所有 Redis 客户端配置。因此,这条提示暂时不作为本次升级后的处理项目。


十七、最终升级结果

这次 Redis 升级的最终状态为:

Plaintext
Redis 7.0.11 → Redis 8.10.0:成功
jemalloc 5.3.0:正常
RDB 数据迁移:成功
30 万级缓存键加载:成功
RDB 加载时间:2.787 秒
Redis CLI 读写:成功
PHP Redis 扩展兼容:成功
WordPress 中文站:正常
WordPress 英文站:正常
WordPress 管理站:正常
vm.overcommit_memory:已调整为 1
Transparent Huge Pages:已关闭
自动回滚:未触发

升级后,Redis 服务保持:

Plaintext
active
enabled
PONG

十八、暂时保留升级文件

为了方便观察和回滚,我暂时保留以下文件:

Plaintext
/root/redis-upgrade-backup-20260805-185250
/root/redis-cutover-backup-20260805-193515
/root/redis-rollback-20260805-193515.sh
/root/redis-8.10.0
/root/redis-8.10.0-core-stage
/root/redis-8.10.0.tar.gz

其中最重要的是正式切换备份和回滚脚本:

Plaintext
/root/redis-cutover-backup-20260805-193515
/root/redis-rollback-20260805-193515.sh

这些文件至少保留 7 天。

确认 Redis 8.10.0 连续稳定运行后,再删除重复源码、临时测试目录和较早的备份。


总结

这次升级过程中,真正耗时的部分并不是 Redis 7 到 Redis 8 的数据兼容,而是 Redis 8.10.0 源码包默认构建流程中附带的多个扩展模块。

最终没有为了“全部编译成功”而继续安装一系列当前用不到的依赖,而是根据 WordPress 的真实需求,明确只编译和部署 Redis 核心。

通过旁路目录、RDB 检查、临时端口测试、PHP Redis 验证、最终 RDB 备份和自动回滚脚本,生产切换被控制在一个非常小的风险范围内。

最终结果也证明,这种方式更适合当前服务器:

  • Redis 核心完成升级;
  • WordPress 缓存数据得到保留;
  • PHP 和 W3 Total Cache 保持兼容;
  • 内核参数得到优化;
  • 没有引入不必要的模块依赖;
  • 整个切换过程没有触发回滚。

对于只将 Redis 用作 WordPress 对象缓存的服务器来说,稳定、可回滚、容易维护,比把所有扩展模块全部编译进去更重要。

OneinStack 生产环境将 PHP 8.1.19 升级到 PHP 8.5.9:Imagick 编译失败与 WordPress 多域名缓存验收

WordPress 网站维护、性能优化与博客运营咨询

本站已持续运营超过 10 年,累计发布 1000+ 篇原创技术文章,长期实践 WordPress 网站建设、CDN / Cloudflare 配置、缓存优化、Google SEO、广告变现和多语言网站运营。

如果你的 WordPress 网站遇到访问慢、缓存异常、插件冲突、广告不显示、SEO 基础结构混乱、CDN 配置不确定等问题,可以联系我做一次远程技术排查。

适合以下用户:
✅ 个人博客站长
✅ WordPress 网站运营者
✅ 独立开发者与内容创作者
✅ SaaS 产品官网运营团队
✅ 希望优化网站速度与稳定性的站点

服务内容:
✅ WordPress 速度优化
✅ Cloudflare / CDN / 缓存配置排查
✅ 插件冲突与页面异常排查
✅ AdSense 广告显示问题排查
✅ SEO 基础结构检查
✅ 博客运营与商业化咨询

如需了解方案或交流相关问题,请直接联系我,并注明:WordPress 维护咨询

联系方式:
Telegram:@shuijingwan
微信:13980074657
邮箱:shuijingwanwq@gmail.com

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理