当前位置:首页 > 文章列表 > 文章 > linux > Linux logrotate copytruncate 与信号重开日志有什么区别

Linux logrotate copytruncate 与信号重开日志有什么区别

来源:17golang原创 2026-11-14 06:45:47 0浏览 收藏

我在生产环境第一次遇到“日志已经轮转,服务却还在往旧文件写”的问题时,真正卡住的不是 logrotate 语法,而是把“文件名”误当成了“进程正在写的文件”。copytruncate 和“重命名后让服务重新打开日志”解决的是两条不同路径:前者保留原 inode 并原地清空,后者让进程关闭旧文件描述符,再按新路径打开新 inode。

结论先放在这里
  • 应用支持可靠的日志重开时,优先使用普通 rename/create,再在 postrotate 中通知服务;这样不会让进程长期持有旧 inode。
  • 应用无法配合重开时,copytruncate 是实用的兼容方案,但复制和截断之间存在极短窗口,繁忙日志可能丢记录。
  • HUP 不是 logrotate 自动施加的魔法,它只有在应用明确实现“收到信号后重开日志”时才有意义。

先看文件句柄为什么决定轮转结果

进程写日志时通常已经打开了一个文件描述符。这个描述符指向文件对象和 inode,而不是每次写入都重新按字符串查找 /var/log/app.log。因此,轮转时只改变路径名,并不会自动把已有描述符切到新文件。

# 只读观察路径、inode 和打开文件,先确认服务到底写向哪个文件
LOG=/var/log/app.log
PID=1234

# 路径当前对应的 inode;轮转前后对比这个数字
stat -c 'path=%n inode=%i size=%s' "$LOG"

# 查看进程打开的文件描述符,实际环境中请按服务 PID 替换 1234
ls -l /proc/"$PID"/fd | grep '/var/log/'

如果 logrotate 先把旧文件改名,又创建了一个同名新文件,路径名会指向新 inode,但服务原来的 fd 仍指向已经改名的旧 inode。此时磁盘上可能同时出现“新路径文件”和“deleted 但仍被进程占用的旧文件”。下面的结构图只解释这种关系,是静态说明图,不是运行截图。

Linux logrotate 中路径名、inode、进程文件描述符以及 rename、copytruncate 两条路径的关系说明图
图1:路径名、inode 和进程文件描述符的关系说明图。

copytruncate 的便利与丢日志窗口

copytruncate 的思路是先把当前日志复制为轮转文件,再对原文件执行原地截断。因为原路径和原 inode 仍然存在,进程不需要关闭 fd,也不需要认识任何信号;这正是它在无法控制第三方程序时的价值。

/var/log/app.log {
    # 保留 7 份轮转文件,按周轮转
    weekly
    rotate 7
    compress
    delaycompress

    # 复制当前内容后,原地把正在使用的文件截断为 0
    copytruncate
    missingok
    notifempty
}

它的代价也很具体:复制和截断不是一个不可分割的瞬间。服务可能在复制已经读过的范围后又写入新记录,随后截断动作把这段尚未进入副本的内容清掉;日志越大、写入越密集,越应该认真评估这个窗口。复制本身还会带来额外 I/O,压缩则可能继续放大轮转时的磁盘压力。

所以我通常只把 copytruncate 当作兼容性方案,而不是默认最佳方案。它适合低到中等日志量、应用不能重开、少量丢失可接受的场景;对审计日志、计费日志或不能缺行的流水,不能只因为配置简单就选择它。

用 postrotate 和 HUP 让服务重新打开日志

当应用提供“重新打开日志”的能力时,更干净的路径是让 logrotate 先完成 rename/create,再在 postrotate 中通知服务。服务收到约定信号后,应关闭旧 fd、重新按路径打开日志,并继续写入新 inode。这里的关键是应用行为,而不是信号名称本身。

/var/log/app.log {
    # 先重命名旧文件并创建新文件,保留服务需要的属主和权限
    daily
    rotate 14
    create 0640 appuser appgroup
    compress
    delaycompress
    missingok
    notifempty

    # 只有 app 明确支持 HUP 重开日志时才这样通知
    postrotate
        /bin/systemctl kill -s HUP --kill-who=main app.service
    endscript
}

如果服务由 systemd 管理,也可以把重开动作写入单元的 ExecReload,再让 logrotate 调用对应的 reload 命令。不要把“发送了 HUP”当成完成证明:应用可能没有安装处理器,也可能异步处理信号。生产上应让服务自己记录“日志已重新打开”的状态,至少在轮转后用文件描述符和新旧 inode 做一次有计划的检查。

[Service]
# 下面的信号只适用于应用约定 HUP 表示重新加载或重开日志
ExecReload=/bin/kill -HUP $MAINPID

按生产约束选择并保留回退路径

这两种方式不是“新旧语法”的比较,而是“进程是否能协作”的选择。下面这张图把轮转动作、信号通知和回退条件放在同一条时间线上,方便在上线前和服务负责人对齐。

Linux logrotate copytruncate 与 rename、postrotate、HUP 重开日志的流程和选择条件说明图
图2:copytruncate 与信号重开日志的流程对比说明图。
约束优先方案主要风险
应用支持可靠重开,日志不能长期写旧文件rename/create + postrotate 通知信号未处理、权限错误或重开失败
第三方程序无法控制,少量丢失可接受copytruncate复制与截断之间的短暂丢失窗口、额外 I/O
审计、计费等不能缺记录优先使用应用原生轮转或集中日志方案不要把 copytruncate 当成无损保证
多文件共用一个服务结合 sharedscripts 与服务重开协议脚本重复执行或只重开了部分文件

我的上线清单通常只有四项:第一,确认应用文档对重开信号的约定;第二,确认 create 的属主和权限不会让服务下一次打开失败;第三,确认轮转脚本的执行用户有权改名、创建和通知服务;第四,保留一次可回退的配置变更,不要在高峰期第一次验证信号行为。

相关问题

copytruncate 会不会让进程自动写到轮转后的新文件?

不会。它保留原 inode,只是把内容截断,再让同一个 fd 继续写。这里的“新文件”只是轮转副本,服务并没有重新打开路径。

发送 HUP 后为什么旧日志仍在增长?

常见原因是应用没有把 HUP 定义为重开日志、信号发给了错误的进程,或服务有多个 worker 而只重开了主进程。应回到应用的信号协议和实际 fd 检查,不要只看 logrotate 命令返回码。

systemd 的 reload 和重启是一回事吗?

不是。reload 通常要求服务继续运行并重新加载配置或重开资源;重启会引入进程退出和重新启动的影响。是否支持 reload、哪个信号有效,必须以具体服务的单元和应用文档为准。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
tmpfiles.d d 与 D 类型清理规则有何区别tmpfiles.d d 与 D 类型清理规则有何区别
上一篇
tmpfiles.d d 与 D 类型清理规则有何区别
React useOptimistic 多次提交同时进行时怎样合并状态
下一篇
React useOptimistic 多次提交同时进行时怎样合并状态
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    1019次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    1021次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    1155次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    1122次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    963次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码