Linux 日志太多,如何设计合理的日志策略

Linux 日志太多,如何设计合理的日志策略

Linux服务器磁盘突然告警“/var/log 已满 95%”,然后服务卡死、进程挂掉、甚至系统重启都卡住——这种场景几乎每个做过线上服务的同学都踩过坑。日志是运维的眼睛,但眼睛太多也会把硬盘“撑瞎”。

本文系统聊聊:在Linux服务器上,如何设计一套合理、可扩展、不容易把磁盘撑爆的日志策略。从基础配置到高级架构,从单机到分布式,全流程覆盖。目标是:日志该有的都有,不该占的别占,排查问题时还能快速找到。全文干货为主,建议直接收藏,下次磁盘又满的时候直接对照执行。

一、为什么日志会“爆炸”?先搞清楚根因

Linux日志主要来源:

  • 系统日志:rsyslog / systemd-journald(/var/log/messages、secure、kern.log 等)
  • 服务日志:nginx、apache、mysql、redis、tomcat、java应用等
  • 应用日志:业务代码自己打的(Spring Boot、Node.js、Python Flask/Django 等)
  • 容器/编排日志:Docker daemon、Kubernetes kubelet/pod logs

爆炸常见原因:

  1. 日志级别太低(DEBUG/ALL)上线没改回INFO/WARN
  2. 高并发业务每秒打几千行日志
  3. 没有轮转(rotation)或轮转策略太宽松
  4. 没有压缩、没有清理旧日志
  5. journald 默认无限增长(尤其是老系统没配限制)
  6. 多实例/容器日志都写宿主机同一目录

设计日志策略的核心目标:可控体积 + 可检索 + 高可用 + 低成本

二、基础层:单机日志轮转与清理(logrotate + journald)

2.1 logrotate —— Linux 日志轮转的王牌工具

几乎所有主流发行版都预装了 logrotate,它通过 cron 每天/每周执行一次。

默认配置文件:/etc/logrotate.conf + /etc/logrotate.d/ 目录下每个服务的独立配置文件。

推荐的通用最佳实践配置模板(适用于大多数服务):

text
# 示例:/etc/logrotate.d/nginx
/var/log/nginx/*.log {
    daily                   # 每天轮转(或 weekly / size 100M)
    rotate 7                # 保留7份(一周)
    missingok               # 日志文件不存在不报错
    dateext                 # 轮转文件带日期,如 access.log-20260204
    dateformat -%Y%m%d      # 日期格式
    compress                # 压缩旧日志(默认 gzip)
    delaycompress           # 延迟压缩(当前正在写的文件不压缩)
    notifempty              # 空文件不轮转
    create 0640 www-data adm   # 创建新日志文件时的权限和属主
    sharedscripts           # 多个文件共用 postrotate 脚本
    postrotate
        [ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
    endscript
}

关键参数解释与推荐值

  • daily / weekly / monthly:中小型服务 daily,大日志服务 weekly
  • rotate 4~12:合规要求留3~6个月则 rotate 90~180,普通业务7~30天够用
  • size 50M / 100M:混合使用 size + time,例如 size 100M + daily,文件超100M且当天就轮转
  • compress + compresscmd /usr/bin/xz + compressext .xz:用 xz 代替 gzip,压缩比更高(节省50%+空间)
  • maxage 30:超过30天的无论多少份都删(防止长期积累)
  • minage 1:防止当天轮转的文件立刻被删

针对高频写日志的服务(如nginx、业务jar)额外优化

  • 用 copytruncate(复制后截断原文件)代替 create + 信号重启,适合不能重启写文件的进程 但注意:可能丢失极少量日志(截断瞬间)
  • 或让应用自己支持 reopen(如java -XX:+PrintGCDateStamps + 配置 logback reopen)

测试配置是否正确(强烈推荐上线前跑):

Bash
logrotate -d -f /etc/logrotate.d/your-service   # debug 模式,模拟不实际执行
logrotate -v /etc/logrotate.d/your-service      # verbose 执行一次

2.2 systemd-journald 配置(现代系统必调)

CentOS 8+/Ubuntu 20.04+ 默认用 journald,很多日志直接进 /var/log/journal 而不是传统文件。

默认 journald 可能无限增长!必须限制。

编辑 /etc/systemd/journald.conf(或 drop-in /etc/systemd/journald.conf.d/override.conf):

ini
[Journal]
Storage=persistent          # 持久化到磁盘(默认 volatile 只存内存)
SystemMaxUse=4G             # journal 总大小上限 4GB(推荐物理内存的10-20%)
SystemKeepFree=20%          # 至少保留20%磁盘空间
SystemMaxFileSize=500M      # 单个 journal 文件最大 500MB
MaxRetentionSec=30d         # 最多保留30天(或 MaxFileSec=7d)
SyncIntervalSec=1m          # 同步间隔,减少频繁写盘
RateLimitIntervalSec=30s
RateLimitBurst=1000         # 限流,防止日志风暴

修改后重启服务:

Bash
systemctl restart systemd-journald

查看当前使用:

Bash
journalctl --disk-usage

查询日志:

Bash
journalctl -u nginx -S "2026-02-01"   # 从某天开始
journalctl --since "1 hour ago" -p err   # 最近1小时 error 级别

三、中级层:日志分级 + 降噪 + 结构化

3.1 日志级别分环境管理

  • 开发/测试:DEBUG / TRACE 全开
  • 生产:INFO 或 WARN 起步,ERROR 必须有
  • 监控/告警日志单独输出(不混业务日志)

Spring Boot 示例(logback-spring.xml):

XML
<springProfile name="production">
    <root level="INFO">
        <appender-ref ref="ASYNC_FILE" />
    </root>
</springProfile>

3.2 避免日志风暴

  • 加采样:比如每分钟只记录一次同类错误
  • 用 MDC / traceId 代替重复打印上下文
  • 敏感信息脱敏(身份证、手机号、密码等)

3.3 结构化日志(JSON)

现代最佳实践:所有应用输出 JSON 格式,便于后续 ELK / Loki 解析。

logback 示例:

XML
<appender name="JSON" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <encoder class="net.logstash.logback.encoder.LogstashEncoder" />
    ...
</appender>

输出示例:

JSON
{"@timestamp":"2026-02-04T18:10:00","level":"INFO","message":"处理订单成功","traceId":"abc123","orderId":456}

四、高级层:集中式日志收集 + 存储

单机轮转只能治标,真正解决“日志太多”的是集中化 + 采样 + 对象存储

主流方案对比(2026年主流):

方案采集端轻量存储成本查询性能推荐场景
ELK StackFilebeat中等中大型企业,自建
Loki + GrafanaPromtail中高Kubernetes、云原生
GraylogSidecar中等需要权限控制、告警
云服务Agent按量无运维团队、快速上线

推荐最小化自建方案(Loki + MinIO / S3):

  1. Promtail 采集 → Loki 存储(索引只存元数据,日志本体压缩存对象存储)
  2. 日志保留:热数据7天,冷数据90天(S3 Glacier)
  3. Grafana 做看板 + 告警

采集端轻量化

  • Filebeat / Promtail 只采集,不解析
  • 关闭本地文件轮转,让收集器自己处理

五、监控与应急机制

必须有这些告警:

  • 磁盘使用率 > 80%(/var/log 单独监控)
  • journald 大小 > 2GB
  • 单日志文件增长速度 > 100MB/h
  • 错误日志速率 > 100条/分钟

应急自愈脚本示例(crontab 每5分钟跑):

Bash
#!/bin/bash
USED=$(df -h /var/log | awk 'NR==2 {print $5}' | tr -d '%')
if [ "$USED" -gt 90 ]; then
    find /var/log -type f -name "*.gz" -mtime +14 -delete
    journalctl --vacuum-time=7d
    # 或者 kill 高日志进程(慎用)
fi

结语

一套合理的日志策略应该满足:“够用、不浪费、可查、可追溯、可审计”

推荐分层路径:

  1. 小型项目/单机:logrotate + journald 限制 + INFO级别
  2. 中型业务:结构化JSON + Filebeat → Elasticsearch / Loki
  3. 大型/分布式:Loki + 对象存储 + 采样 + 冷热分离 + 告警自愈

日志不是越多越好,而是越“有用”越好。把 DEBUG 留在本地,把 ERROR 送到大脑,把 TB 级的原始日志安心扔到冷存储。

Telegram
Telegram@IDCSELL