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 failureCHART 02 // 三类异常 · 同一根因
three symptoms · one root cause三者均指向 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 后台保存时子进程创建间歇性失败 |
关键旁证:
- 崩溃发生在 QFork 子进程:栈顶
QForkChildInit→loadServerConfig→sdssplitlen→zrealloc,即 fork 出的子进程在初始化阶段就触发分配器缺陷; - BUG REPORT 自带提交指引:明确引导上报到
github.com/tporadowski/redis——该仓库即此移植版所属(官方 Redis 早已停止对 Windows 原生支持); - 崩溃与业务数据量无关:一次 676 字节的分配失败,空负载也可能随机触发。
触发因素:配置文件参数异常
maxmemory?policy 应为 maxmemory-policy。参数名被异常字符污染后,Redis 启动参数校验直接拒绝启动,进一步压缩了「崩溃后自动恢复」的可靠性。
为什么影响业务
- Redis 崩溃瞬间连接断开,依赖它的上层应用请求异常堆积,进程被 IIS 反复回收,形成长时间不可自愈的循环;
fork operation failed时 RDB 快照无法生成,若只依赖 RDB 持久化,故障期间存在数据丢失风险;- 自动拉起机制只能缓解「瞬时断连」,无法消除「随机崩溃」的根因。
处置流程
解决方案:升级 Redis 到最新版本
- 备份当前数据:确认 RDB / AOF 文件完整,拷贝异地备份:
[备份 Redis 数据目录下的 dump.rdb / appendonly.aof 到本地与异地备份区]
- 升级 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 方案。
- 迁移并修复配置:修正参数名,
maxmemory?policy→maxmemory-policy,并按实际资源设置合理的maxmemory:
maxmemory-policy noeviction
- 验证:启动后执行
redis-cli ping # PONG
redis-cli info memory # used_memory 正常,无异常分配
redis-cli --test-memory 128 # 内存分配器自检
- 接入高可用兜底:配置哨兵 / 多实例 + 进程自动重启,单实例崩溃不再影响业务。
升级前的临时规避(如无法立即升级)
# 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 字节分配失败,大概率与硬件无关。
预防措施
- 版本管理:跟踪中间件版本,弃用无官方维护的移植版;升级走变更流程、低峰执行、留回滚预案;
- 持久化保障:开启 AOF,RDB / AOF 双写,避免 fork 失败导致数据丢失;
- 关闭高风险特性:
active-defrag默认关闭,按需开启并验证; - 高可用:Redis 部署哨兵 / 集群,避免单点崩溃影响业务;
- 监控告警:对 Redis 进程存活、fork 失败、崩溃重启接入告警——本次多次崩溃全程无告警;
- 应用侧:连接层加重试与降级,崩溃瞬间的请求不直接压到数据库。