网页404 Debug Report
本文最后更新于37 天前,其中的信息可能已经过时,如有错误请发送邮件到everfades1218@gmail.com

服务器:腾讯云 VM-0-16-ubuntu,宝塔面板
技术栈:nginx + PHP + MySQL 5.7.44 + WordPress + Argon
排查日期:2026-09-14

2026.9.14——by Everfades

如果您有宝贵的意见或建议,请发邮件至:everfades1218@gmail.com或everfades@foxmail.com

在使用Typora阅读前,请将文件→偏好设置→Markdown→内联公式 勾选上,以免显示出错!


一、故障时间线

时间(CST) 事件
迁移期间 站点从 IP 49.232.244.149 迁移到域名 www.everfades.cn,运行过 fix-urls.php 做全库 URL 替换
09-14 04:40 MySQL binlog flush 失败,binlog_error_action=ABORT_SERVER 触发,MySQL 主动结束运行
09-14 10:03 systemctl start mysqld 失败,报 “server quit without updating PID file”,且 .err 日志无任何新记录
09-14(排查前) 用户在 WordPress 后台修改固定链接,此后子页面全部 404
09-14 10:27 前台启动 mysqld,定位到 binlog 损坏,MySQL 自动截断修复,成功启动

​ 注:404 和 MySQL 崩溃是两个独立的问题,只是碰巧在同一时期暴露。404 由固定链接变更触发,MySQL 崩溃由 binlog 写入失败触发。排查过程中修好 404 之后,才让 MySQL 的问题显露出来。


二、第一层:分类页 404

现象

在 WordPress 后台改过固定链接后https://www.everfades.cn/category/artical/以及其他子页面均返回 404,但everfades.cn首页正常。

关键排查动作:区分 404 的类型

这是整个排查中最省时间的一步。WordPress 站点的 404 有两种,外观不同,原因完全不同:

404 外观 含义 故障层
白底黑字,只有 “404 Not Found” 和 “nginx” 请求根本没进 PHP,nginx 按字面找文件没找到 Web server 层(rewrite 规则)
带 Argon 主题的导航栏、配色 请求进了 WordPress,但没匹配到内容 应用层(固定链接结构 / 分类 slug)

确认是裸 nginx 404后,方向立刻定死在 rewrite 层,不必再去查分类 slug、分类目录前缀、主题模板这些应用层因素。

原理

WordPress 的pretty permalink是虚拟 URL,磁盘上不存在对应的目录或文件:

  • 首页 / → 对应真实存在的 index.php,不需要 rewrite
  • /category/artical/ → 磁盘上没有 category/artical/ 这个目录,必须靠 rewrite 把请求交给 index.php,再由 WordPress 内部路由解析成”分类归档页”

nginx 的默认行为是按字面查找路径,找不到就返回自己的 404,PHP 完全不会被执行。

这解释了”首页能开、子页面全部404″这个看似矛盾的现象。

修复

宝塔面板 → 网站 → 点击站点 → 左侧 伪静态 → 下拉框选择 wordpress → 保存。

写入以下规则:

location /
{
     try_files $uri $uri/ /index.php?$args;
}

rewrite /wp-admin$ $scheme://$host$uri/ permanent;

核心是 try_files $uri $uri/ /index.php?$args;,三段依次尝试:

  1. $uri —— 找同名真实文件(图片、CSS、JS 走这里,直接由 nginx 返回,不经过 PHP)
  2. $uri/ —— 找同名真实目录
  3. /index.php?$args —— 都没有,把请求连同原查询参数交给 WordPress

第二条 rewrite /wp-admin$ 是给后台地址补尾斜杠,避免 /wp-admin 不带斜杠时的跳转异常。

收尾动作

伪静态生效后,进 WordPress 后台 设置 → 固定链接,什么都不改直接点”保存更改”。这会让 WordPress 重建内部 rewrite 规则表,与 nginx 侧对齐。


三、第二层:Error establishing a database connection

​ 伪静态修好后,再次打开子页面,页面报这个错Error establishing a database connection。

这条报错来自 WordPress 本身(wp-db.php),能看到它意味着:

  • nginx 正确地把请求转给了 PHP
  • PHP 正常执行
  • WordPress 代码被加载,走到了连接数据库这一步

也就是说第一层的 rewrite 问题确实解决了,现在暴露的是下一个独立问题。

服务状态

× mysqld.service - LSB: start and stop MySQL
     Active: failed (Result: exit-code) since Mon 2026-09-14 10:03:57 CST
    Process: 987 ExecStart=/etc/init.d/mysqld start (code=exited, status=1/FAILURE)
     mysqld[987]: Starting MySQL.... * The server quit without updating PID file

​ MySQL 服务处于 failed 状态。数据库连不上的原因很直接:服务根本没在运行。

“The server quit without updating PID file” 是 init 脚本的通用报错 —— mysqld 进程退出了,PID 文件没生成,init 脚本只能报告这个表象。它不包含任何根因信息,必须去看 MySQL 自己的错误日志。


四、第三层:MySQL 启动即失败

.err 日志里的最后一条崩溃记录:

2026-09-13T20:40:08.486997Z 27638 [ERROR] /www/server/mysql/bin/mysqld:
Binary logging not possible. Message: An error occurred during flush stage
of the commit. 'binlog_error_action' is set to 'ABORT_SERVER'.
Server is being stopped.
20:40:08 UTC - mysqld got signal 6 ;

​ 报错原因:MySQL 写 binlog(二进制日志)失败时,binlog_error_action 决定后续行为。默认值 ABORT_SERVER 的含义是——binlog 一旦写不进去,MySQL 宁可主动停止服务,也不继续接受写入。因为继续跑会导致 binlog 记录与实际数据不一致,会破坏主从复制和时间点恢复的可靠性,比停机更严重。

​ 后面的 signal 6(SIGABRT)和一大段 backtrace 是这次主动 abort 的产物,不是独立的 bug,也不指向硬件故障——尽管日志里那段模板文字提到了 “bug”、”corrupt”、”malfunctioning hardware”。这是 MySQL 崩溃处理的通用输出。

binlog flush 失败最常见的诱因是磁盘空间不足,所以第一假设是磁盘满,但磁盘空间还有40多个G,不可能不够用。

​ 触发 binlog 写入失败还有其他可能:

可能原因 为什么 df -h 看着正常
tmpdir 所在分区满 /tmp 常是小容量 tmpfs,与 /www 是不同挂载点
文件系统被内核挂成只读 云盘 I/O 错误后内核 remount 为 ro 自保,空间照常显示
inode 耗尽 df -h 看空间,要 df -i 才看得到 inode
数据目录属主/权限错误 与容量无关
binlog index 与实际文件不一致 与容量无关

​ 随后我在”VM-0-16-ubuntu.err”中查看日志,注意到最新一条日志截止到2026-09-13 20:40:08 UTC,换算一下就是2026-09-14 04:40:08 CST(UTC+8),随后再没有任何日志。

​ 这个空白本身就是诊断信息。 能写进 .err 的前提是 mysqld 已经初始化到了错误日志子系统。如果它在更早的阶段就失败——解析配置、检查数据目录、打开日志文件——报错只会走 stderr,被 init 脚本吞掉或丢进 systemd journal,.err 里一个字都不会留。

​ 所以”启动失败但无日志”直接指向:失败发生在日志可写之前。

前台启动

绕开 init 脚本和日志重定向,在终端查看报错:

/www/server/mysql/bin/mysqld --user=mysql --console

此处有几点注意:

  • 必须带 --user=mysql。以 root 身份运行会在数据目录里生成 root 属主的文件,反过来制造权限问题
  • --console 强制输出到 stderr,绕过 log-error 重定向
  • 会占住终端。启动成功就一直挂着(说明问题在 init 脚本层),失败则立即退出并打印原因

binlog 尾部损坏

真正的原因立刻显现:

2026-09-14T02:27:31.201920Z 0 [Note] Recovering after a crash using mysql-bin
2026-09-14T02:27:31.290350Z 0 [ERROR] Error in Log_event::read_log_event():
    'read error', data_len: 66, event_type: 19
2026-09-14T02:27:31.294421Z 0 [Note] Crashed binlog file ./mysql-bin.000012
    size is 21385216, but recovered up to 21385047.
    Binlog trimmed to 21385047 bytes.

完整的链路如下:

  1. 今早 04:40 的 ABORT_SERVER 是在 binlog 写入中途发生的
  2. mysql-bin.000012 尾部因此留下一个残缺的 event —— 文件实际大小 21385216 字节,但最后一个完整 event 只到 21385047 字节,多出 169 字节的半截数据
  3. 此后每次启动,MySQL 走到 “Recovering after a crash using mysql-bin” 阶段,读到这个坏 event,read_log_event() 报错,启动中止
  4. 这个阶段发生在错误日志子系统就绪之前,所以 .err 里没有任何记录

两个疑点在这里合上了:启动失败的原因,以及日志为什么是空的,是同一件事的两面。

修复:MySQL 自行完成

这次前台启动过程中,MySQL 把损坏部分处理掉了:

Binlog trimmed to 21385047 bytes.

把 binlog 截断到最后一个完整 event 的边界。这个操作是持久化的——写回了文件,坏 event 不会再挡路。

同时 InnoDB 的崩溃恢复也顺利跑完:

InnoDB: Database was not shutdown normally!
InnoDB: Starting crash recovery.
InnoDB: Rollback of non-prepared transactions completed
InnoDB: 5.7.44 started; log sequence number 8237452629

最后:

/www/server/mysql/bin/mysqld: ready for connections.
Version: '5.7.44-log'  socket: '/tmp/mysql.sock'  port: 3306

数据没有丢失。 InnoDB 的 redo log 保证了已提交事务的持久性,被截断的只是 binlog 尾部那个未完成事务的记录。

后续只需要Ctrl+C 干净关闭前台进程,然后 systemctl start mysqld 走正常服务启动即可,所有子界面均恢复正常了~


附:两条关键日志原文

触发点——今早 04:40 CST 的崩溃:

2026-09-13T20:40:08.486997Z 27638 [ERROR] /www/server/mysql/bin/mysqld:
Binary logging not possible. Message: An error occurred during flush stage
of the commit. 'binlog_error_action' is set to 'ABORT_SERVER'.
Server is being stopped.

根因与自动修复——10:27 CST 前台启动:

2026-09-14T02:27:31.201920Z 0 [Note] Recovering after a crash using mysql-bin
2026-09-14T02:27:31.290350Z 0 [ERROR] Error in Log_event::read_log_event():
    'read error', data_len: 66, event_type: 19
2026-09-14T02:27:31.294421Z 0 [Note] Crashed binlog file ./mysql-bin.000012
    size is 21385216, but recovered up to 21385047.
    Binlog trimmed to 21385047 bytes.
2026-09-14T02:27:31.460300Z 0 [Note] /www/server/mysql/bin/mysqld: ready for connections.
文末附加内容
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇