4、日志采集进阶:使用 journalctl、logrotate、fluentd 进行日志管理与采集
日志这东西,平时没人管,一出事它就是唯一的救命稻草。我见过太多升级失败的案例,最后能定位到根因,靠的就是日志里那几行不起眼的记录。但前提是——你得会管它,会采它。
这一章我们聊三个工具:journalctl、logrotate、fluentd。它们分别解决日志的查看、轮转和采集问题。说白了,一个帮你查,一个帮你省磁盘,一个帮你把日志送到该去的地方。
4.1 journalctl:systemd 日志的瑞士军刀
现在大部分 Linux 发行版都用 systemd,日志自然也就归 journald 管。journalctl 就是它的命令行客户端。我个人习惯,排查问题时第一件事就是跑 journalctl -xe,看最后几行有没有明显报错。
4.1.1 基本用法
| 命令 | 作用 |
|---|---|
journalctl -u nginx.service |
查看指定服务的日志 |
journalctl --since "10 min ago" |
只看最近 10 分钟的日志 |
journalctl -p err -b |
只看本次启动以来的错误级别日志 |
journalctl -o json-pretty |
以 JSON 格式输出,方便程序解析 |
-p err -b 缩小范围,再根据时间戳用 --since 精确锁定。别一上来就全量输出,几千行日志看得眼晕。
4.1.2 日志持久化
默认情况下,journald 的日志存在内存里,重启就没了。这显然不行。我建议你改一下配置:
# /etc/systemd/journald.conf
Storage=persistent
Compress=yes
SystemMaxUse=1G
RuntimeMaxUse=200M
改完重启服务:systemctl restart systemd-journald。这样日志会写到 /var/log/journal/ 目录下,重启也不会丢。
/var/log/journal/ 目录不存在,需要手动创建并设置权限:mkdir -p /var/log/journal && systemd-tmpfiles --create --prefix /var/log/journal。否则配置不生效。
4.2 logrotate:日志轮转的老司机
日志如果不轮转,磁盘迟早会被撑爆。我曾经接手过一个系统,日志文件 50GB,直接导致根分区满了,服务全挂。嗯,从那以后我每次部署都会检查 logrotate 配置。
4.2.1 核心配置
logrotate 的配置文件在 /etc/logrotate.conf 和 /etc/logrotate.d/ 目录下。每个服务一个配置文件,清晰好管理。
# /etc/logrotate.d/nginx
/var/log/nginx/*.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
postrotate
/usr/sbin/nginx -s reopen
endscript
}
| 参数 | 说明 |
|---|---|
daily |
每天轮转一次 |
rotate 7 |
保留最近 7 个归档文件 |
compress |
轮转后压缩为 .gz |
delaycompress |
延迟一次再压缩,方便查最近日志 |
postrotate |
轮转后执行的命令,通知 nginx 重新打开日志文件 |
nginx -s reopen,rsyslog 用 kill -HUP。忘了这一步,日志就写不进去了。
4.2.2 手动测试
配置完别直接等 cron 执行,先手动跑一下验证:
logrotate -d /etc/logrotate.d/nginx # 调试模式,只模拟不执行
logrotate -f /etc/logrotate.d/nginx # 强制轮转
我每次改完配置都会跑 -d 看看有没有语法错误,确认无误再用 -f 执行一次。这个习惯帮我避免过好几次线上事故。
4.3 Fluentd:统一日志采集层
当服务器多了,日志就不能只留在本地了。你需要一个统一的采集层,把日志集中起来。Fluentd 就是干这个的。它用 Input → Filter → Buffer → Output 的管道模型,灵活又稳定。
4.3.1 架构概览
4.3.2 实战配置:采集 Nginx 日志到 Elasticsearch
下面是一个我在生产环境用过的配置。它从 Nginx 的 access.log 采集日志,解析成结构化数据,然后写入 Elasticsearch。
# /etc/fluentd/fluent.conf
<source>
@type tail
path /var/log/nginx/access.log
pos_file /var/log/fluentd/nginx-access.pos
tag nginx.access
<parse>
@type nginx
</parse>
</source>
<filter nginx.access>
@type record_transformer
<record>
hostname "#{Socket.gethostname}"
</record>
</filter>
<match nginx.access>
@type elasticsearch
host localhost
port 9200
index_name fluentd.nginx.${tag}
flush_interval 5s
</match>
pos_file,导致 Fluentd 每次重启都从头读日志,ES 里重复数据一大堆。pos_file 记录读取位置,保证重启后从断点续传,这个一定要配。
4.3.3 Buffer 参数调优
Buffer 是 Fluentd 的稳定器。参数调不好,要么丢数据,要么内存爆炸。我一般这样配:
<buffer>
@type file
path /var/log/fluentd/buffer
flush_mode interval
flush_interval 5s
retry_max_times 3
retry_wait 2s
chunk_limit_size 8MB
total_limit_size 1GB
</buffer>
| 参数 | 推荐值 | 说明 |
|---|---|---|
flush_interval |
5s | 每 5 秒刷一次,平衡实时性和吞吐 |
chunk_limit_size |
8MB | 单个 chunk 大小,避免单次写入过大 |
total_limit_size |
1GB | 总 buffer 上限,防止磁盘写满 |
retry_max_times |
3 | 失败重试次数,避免无限重试阻塞管道 |
4.4 三剑客配合使用
实际生产环境里,这三个工具是配合着用的:
- journald 负责系统级日志的收集和存储
- logrotate 负责本地日志文件的轮转和压缩
- Fluentd 负责把日志从各个节点采集到中央存储
举个例子:Fluentd 的 @type tail 读取 Nginx 日志时,logrotate 正好在轮转文件。如果 Fluentd 没处理好文件切换,就会丢日志。解决办法是让 logrotate 的 postrotate 通知 Fluentd 重新打开文件,或者用 copytruncate 模式避免文件句柄变化。