blog.navy82.icu / index / 08 ↑ 返回索引
#08 2026-08-28 故障分析 / Redis / Windows / 版本升级 阅读 –

Redis 内存分配器异常崩溃 · Windows 移植版版本缺陷

根因定位2 次崩溃fork 失败升级根治

Windows 移植版 Redis 5.0.14.1(tporadowski 分支)因内存分配器(zmalloc/jemalloc)适配缺陷与fork 模拟不稳定,两天内出现 ABORT / EXCEPTION_ACCESS_VIOLATION 随机崩溃、fork operation failed、以及配置参数损坏导致的一次启动失败,上层 ASP.NET Core 应用随之反复崩溃重启。处置方案:升级 Redis 到最新版本(生产首选 Linux 官方版),附临时规避与内存硬件排查方法。

本案例目录

CHART 01 // Redis 崩溃时间线

crash · restart · startup failure
08-26 09:16ABORTQFork 子进程 676B realloc 失败zmalloc_default_oom
08-26 09:17FORKfork operation failedRDB 保存失败·重试成功
08-28 22:47崩溃#1EXCEPTION_ACCESS_VIOLATIONBUG REPORT
08-28 22:47拉起自动重启成功DB 加载 0.047s
08-28 22:52启动失败unknown conf: maxmemory?policy参数损坏
08-28 23:04崩溃#2再次 REDIS BUG REPORT随机崩溃
08-28 23:05accept 异常在非套接字上 accept再次自动重启

CHART 02 // 三类异常 · 同一根因

three symptoms · one root cause
ABORTzmalloc676B realloc 失败 → 主动终止jemalloc 适配缺陷
ACCESS_VIOLATION内存内存访问越界 → 进程崩溃同源
fork failedRDBBGSAVE 子进程创建失败无原生 fork

三者均指向 Windows 移植版 Redis 5.0.14.1 版本缺陷 · 升级到最新版本根治。

服务器:[Windows 服务器](主机名已隐去)· 故障日期:2026-08-28 日志来源:Windows 事件日志(Application 日志)导出(2026-08-24 ~ 2026-08-29),附完整 REDIS BUG REPORT 脱敏说明:主机名、应用名、数据库名、应用路径、手机号等敏感信息均已隐去。

环境与系统信息

项目 信息
操作系统 Windows Server(主机名已隐去)
应用 IIS + ASP.NET Core 医疗 CRM(应用名已隐去)
缓存中间件 Redis 5.0.14.1(Windows 第三方移植版,tporadowski 分支,commit ec77f72d,64 bit)
部署形态 独立服务进程,崩溃后自动拉起
故障时间 2026-08-26(早期征兆)· 2026-08-28(崩溃 / 启动失败)

故障现象

2026-08-28 下午起,服务器上的业务应用进入反复崩溃重启循环,同时 Redis 服务不定期随机崩溃:

  • Redis 两次输出 REDIS BUG REPORT 后进程崩溃(EXCEPTION_ACCESS_VIOLATION 内存访问违规 + 栈回溯),每次崩溃后数秒内由自动拉起机制恢复;
  • 期间一次重启因配置文件存在非法参数 maxmemory?policy(应为 maxmemory-policy)而直接失败;
  • 一次重启后 accept 客户端连接报错(在非套接字上执行 accept),随即再次自动重启;
  • 更早的 2026-08-26,Redis 已出现过 fork operation failed(RDB 后台保存 fork 失败)与一次 ABORT 主动终止;
  • 崩溃前后,上层 ASP.NET Core 应用进程被 IIS 反复回收(关闭→启动循环,每次 30~60 秒),HIS 数据同步类调度任务批量报「没有获取到要同步的数据 / failed to execute as scheduled due to blocking」。

现象特征:服务短暂中断后自动恢复,但不定期随机崩溃,且与业务负载无关。

关键日志摘录

以下日志为原样摘录(时间戳与 PID 保留,主机名等敏感信息以 [占位符] 代替),可对照时间线阅读。时间均为北京时间(UTC+8)。

① Redis 崩溃 · REDIS BUG REPORT(08-26 09:16:53)

=== REDIS BUG REPORT START: Cut & paste starting from here ===
Redis version: 5.0.14.1
[16596] 26 Aug 09:16:53.792 # --- ABORT
[16596] 26 Aug 09:16:53.803 # --- STACK TRACE
redis-server.exe!StackTraceInfo(...)
redis-server.exe!AbortHandler(...)
redis-server.exe!raise(...)
redis-server.exe!abort(...)
redis-server.exe!zmalloc_default_oom(D:\dev\GitHub\redis\src\zmalloc.c:108)
redis-server.exe!zrealloc(D:\dev\GitHub\redis\src\zmalloc.c:176)
redis-server.exe!sdssplitlen(D:\dev\GitHub\redis\src\sds.c:861)
redis-server.exe!loadServerConfigFromString(D:\dev\GitHub\redis\src\config.c:193)
redis-server.exe!loadServerConfig(D:\dev\GitHub\redis\src\config.c:975)
redis-server.exe!QForkChildInit(D:\dev\GitHub\redis\src\config.c:975)
redis-server.exe!main(...)
[16596] 26 Aug 09:16:54.344 # === REDIS BUG REPORT END ===
Please report this bug by following the instructions at:
https://github.com/tporadowski/redis/wiki/Submitting-an-Issue
Suspect RAM error? Use redis-server --test-memory to verify it.

崩溃栈把整条链路写得很清楚:zmalloc_default_oom ← zrealloc ← sdssplitlen ← loadServerConfigFromString ← QForkChildInit。即 QFork(fork 模拟)子进程初始化时重载配置、拆分配置字符串,一次仅 676 字节的 realloc 失败,触发 abort() 主动终止。一次 676 字节的分配失败在正常情况下绝不该发生 —— 这是 Windows 移植版 jemalloc 内存分配器缺陷,不是物理内存不足。

② fork 失败 · RDB 后台保存(08-26 09:17:29)

[4104] 26 Aug 09:17:29.436 # fork operation failed
[4104] 26 Aug 09:17:29.459 # Background saving terminated by signal 1
[4104] 26 Aug 09:17:29.560 * 10 changes in 300 seconds. Saving...
[4104] 26 Aug 09:17:29.644 * Background saving started by pid 16416
[4104] 26 Aug 09:17:30.150 # fork operation complete
[4104] 26 Aug 09:17:30.169 * Background saving terminated with success

Redis 做 RDB 快照依赖 fork 子进程;Windows 没有 Linux 原生的 fork,移植版用 QFork 模拟,间歇性失败。本例 fork 失败后重试即成功 —— 属典型的偶发故障;但失败窗口内 RDB 快照无法生成,只依赖 RDB 持久化的话存在数据丢失风险。

③ 崩溃 #2 · EXCEPTION_ACCESS_VIOLATION(08-28 22:47:58)

=== REDIS BUG REPORT START: Cut & paste starting from here ===
Redis version: 5.0.14.1
[4104] 28 Aug 22:47:58.454 # --- EXCEPTION_ACCESS_VIOLATION
[4104] 28 Aug 22:47:58.454 # --- STACK TRACE

④ 自动重启恢复(08-28 22:47:59)

[15412] 28 Aug 22:47:59.633 # Redis is starting...
[15412] 28 Aug 22:47:59.634 # Redis version=5.0.14.1, bits=64, commit=ec77f72d, modified=0, pid=15412, just started
[15412] 28 Aug 22:47:59.634 # Configuration loaded
[15412] 28 Aug 22:47:59.634 # DB loaded from disk: 0.047 seconds
[15412] 28 Aug 22:47:59.634 # Ready to accept connections

⑤ 重启失败 · 配置参数损坏(08-28 22:52:10)

redis Invalid argument during startup: unknown conf file parameter : maxmemory?policy

maxmemory?policy 应为 maxmemory-policy。参数名被异常字符污染后,Redis 启动参数校验直接拒绝启动,加剧了「崩溃后起不来」的风险窗口。

⑥ accept 客户端连接异常(08-28 23:05:27)

redis Accepting client connection: accept: 在非套接字上尝试了...

故障时间线

以下时间均为北京时间(UTC+8),对应日志中的 UTC 时间 +8h。

时间 事件
08-26 09:16:53 Redis ABORT 主动终止:QFork 子进程初始化时 676 字节 zrealloc 失败(zmalloc_default_oom,PID [16596])
08-26 09:17:29 fork operation failed,RDB 后台保存 fork 失败,重试后成功(间歇性)
08-28 22:47:58 Redis 崩溃 #1:EXCEPTION_ACCESS_VIOLATION + STACK TRACE(主进程 PID [4104])
08-28 22:47:59 自动拉起成功(PID [15412]),DB 加载 0.047s,恢复可用
08-28 22:52:10 重启失败:unknown conf file parameter : maxmemory?policy
08-28 22:52:50 重启成功(PID [19672])
08-28 23:04:31 Redis 崩溃 #2:再次输出 REDIS BUG REPORT
08-28 23:04:33 自动重启成功(PID [9176])
08-28 23:05:27 accept 客户端连接异常 → 自动重启(PID [15972])
08-28 23:05 后 上层应用进程反复被 IIS 回收(关闭→启动循环),持续数小时

根因定位

直接原因:Windows 移植版 Redis 5.0.14.1(tporadowski 分支)内存分配器缺陷

日志中的三类异常——zmalloc_default_oom / EXCEPTION_ACCESS_VIOLATION / fork operation failed——全部指向 Windows 第三方移植版 Redis 5.0.14.1 的版本缺陷:

异常 本质 证据
ABORT + zmalloc_default_oom 内存分配器缺陷 崩溃栈中一次仅 676 字节的 zrealloc 失败即触发 abort(),远低于任何内存上限,非真实 OOM
EXCEPTION_ACCESS_VIOLATION 内存访问违规 与 ABORT 同源,均为内存分配流程出错
fork operation failed fork 模拟不稳定 移植版用 QFork 模拟 Linux fork,RDB 后台保存时子进程创建间歇性失败

关键旁证:

  1. 崩溃发生在 QFork 子进程:栈顶 QForkChildInit → loadServerConfig → sdssplitlen → zrealloc,即 fork 出的子进程在初始化阶段就触发分配器缺陷;
  2. BUG REPORT 自带提交指引:明确引导上报到 github.com/tporadowski/redis——该仓库即此移植版所属(官方 Redis 早已停止对 Windows 原生支持);
  3. 崩溃与业务数据量无关:一次 676 字节的分配失败,空负载也可能随机触发。

触发因素:配置文件参数异常

maxmemory?policy 应为 maxmemory-policy。参数名被异常字符污染后,Redis 启动参数校验直接拒绝启动,进一步压缩了「崩溃后自动恢复」的可靠性。

为什么影响业务

  • Redis 崩溃瞬间连接断开,依赖它的上层应用请求异常堆积,进程被 IIS 反复回收,形成长时间不可自愈的循环;
  • fork operation failed 时 RDB 快照无法生成,若只依赖 RDB 持久化,故障期间存在数据丢失风险;
  • 自动拉起机制只能缓解「瞬时断连」,无法消除「随机崩溃」的根因。

处置流程

解决方案:升级 Redis 到最新版本

  1. 备份当前数据:确认 RDB / AOF 文件完整,拷贝异地备份:
[备份 Redis 数据目录下的 dump.rdb / appendonly.aof 到本地与异地备份区]
  1. 升级 Redis 到最新稳定版(根治三类崩溃):
# 首选:Linux 官方 Redis(Docker 一键迁移,生产推荐)
docker run -d --name redis \
  -v /data/redis:/data \
  -p 6379:6379 \
  redis:latest redis-server /etc/redis/redis.conf

若必须留在 Windows:升级到新版 Windows 移植分支(6.x / 7.x,已修复大量 zmalloc / fork 问题),或改用官方支持的 Windows 方案。

  1. 迁移并修复配置:修正参数名,maxmemory?policy → maxmemory-policy,并按实际资源设置合理的 maxmemory:
maxmemory-policy noeviction
  1. 验证:启动后执行
redis-cli ping                # PONG
redis-cli info memory         # used_memory 正常,无异常分配
redis-cli --test-memory 128   # 内存分配器自检
  1. 接入高可用兜底:配置哨兵 / 多实例 + 进程自动重启,单实例崩溃不再影响业务。

升级前的临时规避(如无法立即升级)

# redis.conf 临时规避(缓解,非根治)
save ""                    # 关闭 RDB 自动保存,避免触发 fork(改用 AOF 或手动 save)
appendonly yes             # 开启 AOF,防丢数据
active-defrag no           # 关闭自动碎片整理(该功能易触发 jemalloc 分配异常)
maxmemory-policy noeviction

附带问题:排查物理内存硬件

崩溃提示 Suspect RAM error? Use redis-server --test-memory to verify it.,可按需排除硬件因素:

  • redis-server --test-memory(内存分配器自检);
  • Windows 内存诊断 / memtest86+ 完整跑一轮;
  • 检查系统事件日志是否存在内存相关硬件错误(如 WHEA)。本次崩溃为 676 字节分配失败,大概率与硬件无关。

预防措施

  1. 版本管理:跟踪中间件版本,弃用无官方维护的移植版;升级走变更流程、低峰执行、留回滚预案;
  2. 持久化保障:开启 AOF,RDB / AOF 双写,避免 fork 失败导致数据丢失;
  3. 关闭高风险特性:active-defrag 默认关闭,按需开启并验证;
  4. 高可用:Redis 部署哨兵 / 集群,避免单点崩溃影响业务;
  5. 监控告警:对 Redis 进程存活、fork 失败、崩溃重启接入告警——本次多次崩溃全程无告警;
  6. 应用侧:连接层加重试与降级,崩溃瞬间的请求不直接压到数据库。