Apache 日志轮转触发 SVN 更新异常

Apache 日志轮转触发 SVN 更新异常:一次 SIGHUP 与 E175002 的实战排查

结论先行: 当 Apache 同时承载 SVN HTTP 服务时,日志轮转后执行 service httpd reload 可能向 Apache 主进程发送 SIGHUP。如果此时 Jenkins 正在执行 svn update,活跃的 SVN/DAV REPORT 请求可能受到影响,并表现为 svn: E175002。更稳妥的处理方式是把轮转后的操作调整为 graceful,并通过时间关联、日志和复测确认效果。

一、故障背景

最近在一台提供 SVN HTTP 访问的 Apache 服务器上,Jenkins 构建任务出现 SVN 更新失败。环境大致如下:

  • 服务组件: Apache HTTP Server、SVN、Jenkins
  • Apache: 2.2.15
  • SVN: 1.8.11
  • 日志轮转: /etc/logrotate.d/httpd
  • 访问方式: Jenkins 通过 HTTP 协议访问 SVN 仓库

这类故障的特殊点在于:Apache 不只是普通 Web 服务,还在承载 SVN 的 WebDAV 协议请求。一次看似常规的"日志轮转后重载",可能刚好打断构建中的 SVN 更新过程。

二、故障现象

Jenkins 在预构建 Shell 阶段依次执行:

bash 复制代码
svn cleanup
svn update

svn cleanup 正常完成;svn update 已开始更新工作副本、创建版本目录并拉取资源文件,随后失败:

text 复制代码
svn: E175002: REPORT of '/M_00003/!svn/me':
200 OK (http://devsvn.uuzuonline.net)

Failed build for hudson.tasks.Shell@47e96163
ERROR: pre-build step failed to setup environment
Finished: FAILURE

与此同时,在 Apache 的归档错误日志中发现:

text 复制代码
[Fri Oct 16 03:46:10 2026] [notice] SIGHUP received. Attempting to restart

这意味着 Apache 在该时刻接收到了 SIGHUP,并进入重启处理逻辑。

三、为什么 200 OK 仍会让 SVN update 失败?

初看错误信息很容易产生疑问:既然服务端返回了 200 OK,为什么 SVN 还会报错?

关键在于:SVN 的 REPORT 不是一个只看 HTTP 状态码的普通请求。客户端除了要求收到 HTTP 200,还需要接收到完整且符合 SVN/WebDAV 协议预期的响应内容。

在以下情况下,客户端可能已经收到 200 OK,但仍然失败:

  1. Apache 重启过程影响了正在传输的响应流;
  2. REPORT 的 XML 或目录清单没有完整传输;
  3. KeepAlive 连接在请求过程中被关闭或复用失败;
  4. Apache 子进程切换期间,请求被中断、截断或出现协议解析异常。

因此,下面这条错误并不表示请求完整成功:

text 复制代码
E175002: REPORT ... 200 OK

它更准确的含义是:HTTP 头部可能已经正常返回,但 SVN 客户端没有拿到一个可用的完整协议响应。

四、定位日志轮转行为

查看 Apache 的 logrotate 配置:

bash 复制代码
cat /etc/logrotate.d/httpd

发现其中包含:

conf 复制代码
/var/log/httpd/*log {
    compress
    olddir oldlog
    daily
    rotate 7
    missingok
    notifempty
    sharedscripts
    delaycompress
    postrotate
        /sbin/service httpd reload > /dev/null 2>/dev/null || true
    endscript
}

这里最关键的是:

bash 复制代码
/sbin/service httpd reload

继续检查系统服务脚本:

bash 复制代码
grep -n -A 15 -B 5 'reload' /etc/init.d/httpd

可以看到 reload() 最终执行类似逻辑:

bash 复制代码
LSB=1 killproc -p ${pidfile} $httpd -HUP

也就是说,service httpd reload 并不是一个纯配置检查动作,而是会向 Apache 主进程发送 SIGHUP。

这与错误日志中的内容完全对应:

text 复制代码
SIGHUP received. Attempting to restart

由此可以建立完整链路:

text 复制代码
logrotate 执行
    ↓
postrotate 调用 service httpd reload
    ↓
init 脚本向 Apache 主进程发送 SIGHUP
    ↓
Apache 进入常规重启处理
    ↓
正在执行的 SVN HTTP/DAV 请求可能受影响

五、为什么不建议简单删除 postrotate?

有人看到问题后,第一反应是直接删掉 postrotate。这并不推荐。

日志轮转时,logrotate 会对旧日志重命名或移动,并创建新的活动日志文件。如果 Apache 不重新打开日志文件描述符,它可能继续写入已经被移动到 oldlog 目录的旧文件。

最终会出现两个问题:

  • 新的 access_log、error_log 看起来不再有日志;
  • 实际日志继续写入归档文件,影响排障和监控采集。

因此,正确方向不是"取消 Apache 重新打开日志",而是:

保留日志重开动作,但将对业务请求影响较大的常规重启,调整为更温和的平滑重启。

六、推荐方案:reload 改为 graceful

先备份原配置:

bash 复制代码
cp -a /etc/logrotate.d/httpd /etc/logrotate.d/httpd.bak

将原配置:

conf 复制代码
postrotate
    /sbin/service httpd reload > /dev/null 2>/dev/null || true
endscript

修改为:

conf 复制代码
postrotate
    /sbin/service httpd graceful > /dev/null 2>&1 || true
endscript

完整示例:

conf 复制代码
/var/log/httpd/*log {
    compress
    olddir oldlog
    daily
    rotate 7
    missingok
    notifempty
    sharedscripts
    delaycompress
    postrotate
        /sbin/service httpd graceful > /dev/null 2>&1 || true
    endscript
}

reload 与 graceful 的区别

操作 常见信号 典型行为 对 SVN 活跃请求的风险
reload SIGHUP 常规重启处理,子进程重建 较高
graceful SIGUSR1 尽量让旧请求处理完成,再平滑切换 较低

需要强调:graceful 不是"完全无影响"。它仍会触发 Apache 的平滑重启和日志重开,只是比直接以 SIGHUP 进行常规重启更适合存在长请求的服务场景。

七、实施前必须确认的一件事

不同发行版、不同版本的 /etc/init.d/httpd 实现可能不同。不要假定 graceful 一定发送 SIGUSR1,应先在服务器上确认:

bash 复制代码
grep -n -A 10 -B 3 '^graceful' /etc/init.d/httpd

预期可以看到类似:

bash 复制代码
killproc -p ${pidfile} $httpd -USR1

只有确认 graceful 走的是平滑重启逻辑,修改才有意义。

八、验证步骤

1. 检查 Apache 配置

bash 复制代码
/sbin/service httpd configtest

预期:

text 复制代码
Syntax OK

2. 检查 logrotate 规则

bash 复制代码
logrotate -dv /etc/logrotate.d/httpd

-d 为调试模式,不会真正执行轮转。-v 用于输出详细过程,便于确认匹配到的日志文件和脚本逻辑。

3. 在低峰窗口验证日志持续写入

变更后,检查活动日志和归档日志:

bash 复制代码
ls -lh /var/log/httpd/
ls -lh /var/log/httpd/oldlog/

观察活动日志是否继续增长:

bash 复制代码
tail -f /var/log/httpd/access_log

如果日志文件命名不同,请替换为实际文件名。

4. 验证 SVN 服务

优先使用独立测试工作副本,而不是直接操作 Jenkins 正在使用的生产工作目录:

bash 复制代码
svn info
svn update --non-interactive

同时观察 Apache 错误日志,确认是否再次出现:

text 复制代码
E175002: REPORT of '/M_00003/!svn/me'

九、怎样确认本次故障的因果关系?

目前我们可以确认:

  • 日志轮转配置会触发 httpd reload;
  • reload 会发送 SIGHUP;
  • Apache 在对应时段记录了重启尝试;
  • Jenkins 的 SVN 更新出现 E175002。

但要把"高度相关"升级为"确认根因",还需要进行时间关联。

建议核对:

text 复制代码
Jenkins 中 svn update 的失败时间
        ↕
Apache error_log 中 SIGHUP 的时间
        ↕
Apache access_log 中对应 REPORT 请求的时间

可重点检查:

bash 复制代码
grep -nE 'SIGHUP|restart|graceful|child pid|segfault|DAV|svn' \
  /var/log/httpd/oldlog/error_log-20261016

如果已知 Jenkins 节点 IP,则定位其 REPORT 请求:

bash 复制代码
grep 'JENKINS_IP' /var/log/httpd/oldlog/access_log-20261016 \
  | grep '"REPORT '

如果 Jenkins 失败时间与 SIGHUP 相差数秒到几十秒,并且同一时间段存在对应的 REPORT /M_00003/!svn/me 请求,那么这条因果链就有较强证据支持。

十、一个容易忽略的运维改进

很多生产配置习惯这样写:

bash 复制代码
/sbin/service httpd graceful > /dev/null 2>&1 || true

它的优点是:即使重开日志失败,也不会导致 logrotate 返回失败。

但缺点也明显:所有失败都会被吞掉。 如果 Apache 没有成功 graceful,新日志可能无法被正常打开,故障会隐藏很久。

如果运维体系允许,建议至少记录一次系统日志:

conf 复制代码
postrotate
    if ! /sbin/service httpd graceful; then
        logger -t logrotate-httpd "httpd graceful failed after log rotation"
    fi
endscript

这样既不会阻断日志轮转流程,也能在系统日志中保留异常线索。

十一、回滚方案

若变更后发现 Apache 日志未持续写入、SVN 请求异常或服务行为不符合预期,可以恢复原配置:

bash 复制代码
cp -a /etc/logrotate.d/httpd.bak /etc/logrotate.d/httpd

恢复后不建议马上执行强制轮转。应先检查 Apache 服务状态、当前日志文件及文件描述符写入情况,再安排下一次维护窗口验证。

十二、总结

这次问题提醒我们:日志轮转不是纯粹的文件维护操作,它常常隐含服务重载行为。

对于只提供静态页面的 Apache,短暂 reload 可能不容易暴露问题;但对于承载 SVN、WebDAV、长连接或大文件传输的 Apache,一次不恰当的重载就可能变成构建链路中的偶发故障。

本次处理建议可以总结为四点:

  1. 不直接删除 postrotate,避免 Apache 持续写入旧日志;
  2. 将 httpd reload 替换为经验证的 httpd graceful;
  3. 通过 Jenkins、Apache 错误日志和访问日志建立时间关联;
  4. 在低峰维护窗口完成验证,确认日志轮转、日志写入与 SVN 更新均稳定。

运维中的"无感操作"往往只是没有碰巧撞上业务高峰。把重载行为、信号语义和请求链路串起来,才能真正找到偶发故障的原因。

相关推荐
2301_322414280421 小时前
基于web的校园失物招领管理系统59695-计算机毕设 原创(免费领源码+部署教程+开发环境)
mysql·nginx·php·apache·thinkphp·phpstudy·wampserver
nvd111 天前
深入剖析 Apache Flink 流批双引擎的动态扩缩容架构:机制演进、状态重对齐与生产落地推导
架构·flink·apache
青企通1 天前
传统企业数字化转型的技术路径:从需求建模到小程序 MVP 的落地方法
小程序·php·apache
鶴哥只手遮天1 天前
Apache Subversion 1.15 源码深度剖析-第 3 章 文件系统层(FS 抽象与 FSFS 后端)
svn·开源
鶴哥只手遮天1 天前
Apache Subversion 1.15 源码深度剖析-第 6 章 工作副本:WC-NG 与 pristineless
svn·开源
VX_bysjlw9851 天前
基于PHP的论坛系统设计与实现 35136-计算机毕设原创(免费领源码+带部署教程)
开发语言·php·apache·laravel·thinkphp·phpstudy·wampserver
运维小文2 天前
apache nifi 2.90部署+运维手册
大数据·运维·数据分析·apache·nifi
解道Jdon3 天前
FigCraft把Figma用Rust从零重写了一遍
ide·windows·git·svn·eclipse·github·visual studio
todoitbo3 天前
把 XAMPP 搬到鸿蒙 PC:在鸿蒙 PC 上跑 Apache httpd 2.4.69实战项目
华为·apache·harmonyos·鸿蒙·开源鸿蒙·鸿蒙pc