在业务流量增长之后,单台Nginx每天产生的访问日志可能轻松突破几个GB。如果还靠运维手动拖文件或者用脚本定时切割上传,既容易丢数据也难以及时排查故障。Nginx配合Filebeat的组合,核心思路是让Nginx负责把请求记录成结构化的文本,Filebeat以极低开销持续监听文件变化,把增量日志推到消息队列或搜索引擎。这种方式不依赖复杂的Java服务,部署包只有几十MB,非常适合边缘节点和容器环境。

一、Nginx日志格式的设计与输出控制
要让Filebeat后续处理轻松,第一步是在Nginx里把日志格式定义清楚。默认的组合日志格式虽然通用,但字段顺序固定、缺少上游响应时间等信息。建议在http块中用log_format指令自定义一种带JSON结构的格式,这样Filebeat可以直接按字段解析,而不用写复杂的正则。注意在Nginx配置中提及标签名时要转义,例如真正的<log_format>并不是HTML标签,只是配置指令,但习惯上我们仍以指令名称呼它。
下面给出一个常用的JSON日志格式示例,包含客户端IP、请求时间、状态码、响应大小以及上游处理耗时。把它放在http段内,然后在server或location中通过access_log引用即可。如果有多台后端,还可以加上upstream_addr方便链路追踪。
http {
log_format json_log escape=json '{
"time": "$time_iso8601",
"remote_addr": "$remote_addr",
"request": "$request",
"status": $status,
"body_bytes": $body_bytes_sent,
"request_time": $request_time,
"upstream_time": "$upstream_response_time"
}';
server {
listen 80;
access_log /var/log/nginx/access.log json_log;
}
}
使用JSON格式后,日志文件每行都是独立对象,即使某一行缺少字段也不会破坏整体结构。相比传统空格分隔格式,后期用Filebeat的decode_json_fields处理器可以一行命令完成展开。不过要留意磁盘IO,如果单机QPS过万,最好把日志放到独立盘,并开启buffer参数减少写次数。
二、Filebeat采集配置与资源占用优化
Filebeat的核心配置文件是filebeat.yml,其中inputs部分决定监听哪些文件。针对Nginx,我们通常设置type: log,路径指向/var/log/nginx/access.log,并打开json.keys_under_root让字段平铺。Filebeat默认会记录每个文件的采集偏移量到registry文件,因此进程重启也不会重复发送,这一点在多实例滚动发布时非常关键。
为了进一步降低资源占用,可以限制harvester的并发数和扫描间隔。比如设置scan_frequency: 10s表示每十秒检查一次文件是否有新增,而不是实时阻塞读取。同时用close_inactive: 5m让长时间无数据的文件句柄被释放。以下配置展示了基础采集段:
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/nginx/access.log
json.keys_under_root: true
json.add_error_key: true
scan_frequency: 10s
close_inactive: 5m
queue.mem:
events: 4096
flush.min_events: 512
flush.timeout: 5s
在容器环境里,Filebeat常以Sidecar模式跑在Nginx同一个Pod中,此时要挂载同样的日志卷。由于Filebeat自身用Go写就,常驻内存约十兆出头,CPU在普通采集下低于百分之五。如果日志量极大,可以开启backoff策略避免网络阻塞导致的内存堆积。另外,使用processors剔除不需要的字段,比如agent.version或ecs冗余信息,能显著减少传输体积。
三、数据投递与避免重复采集的实践方案
Filebeat支持直接输出到Elasticsearch、Logstash或Kafka。轻量方案推荐先发到Logstash做简单过滤再入ES,这样Filebeat侧配置最简。在output段配置目标地址和索引模板即可。需要注意的是,如果Nginx做了日志轮转,Filebeat通过inode和文件名双重识别,能自动切换到新文件继续读,不会漏也不会重。
多实例场景下最容易出问题是同一份日志被不同Filebeat重复采集。解决方法是给每个实例分配独立的registry路径,或者在Kubernetes里用DaemonSet确保一个节点只有一个采集器。此外,可以在Nginx层按容器ID分文件输出,Filebeat用include_lines做粗滤。下面的输出配置演示了带负载均衡的Logstash投递:
output.logstash:
hosts: ["10.0.0.11:5044", "10.0.0.12:5044"]
loadbalance: true
index: "nginx-access-%{+yyyy.MM.dd}"
processors:
- drop_fields:
fields: ["agent", "ecs", "host.architecture"]
当系统跑起来后,建议用Elasticsearch的ILM策略对索引做冷热分离,避免小日志把热节点撑爆。整个Nginx加Filebeat的链路,从配置到上线一般半小时可完成,相比传统Logagent方案省下的不仅是内存,还有排查复杂度。只要守住JSON格式统一和registry隔离两个要点,即便在百节点规模下也能保持日志链路清晰可靠。