nginx实时请求监测的项目实践
项目背景
在分布式服务架构中,nginx作为反向代理和负载均衡的核心组件,其请求处理效率直接影响整体服务的可用性。当线上出现突发流量、接口响应异常或恶意请求攻击时,传统的日志离线分析方式存在滞后性,无法第一时间定位问题。因此我们需要搭建一套nginx实时请求监测系统,实现请求量、响应状态、来源IP等核心指标的实时可视化,帮助运维和开发人员快速排查故障。
核心监测指标设计
结合业务实际需求,我们确定了以下核心监测指标,覆盖请求全链路的关键节点:
请求基础指标:每秒请求数(QPS)、请求方法分布(GET/POST/PUT等)、请求路径Top10
响应状态指标:各状态码(2xx/3xx/4xx/5xx)占比、平均响应时间、慢请求(响应时间>1s)数量
流量特征指标:来源IP Top10、请求体大小分布、User-Agent类型统计
异常告警指标:5xx错误率阈值告警、单IP请求频率超限告警、突发流量预警
技术架构选型
整个监测系统采用轻量级、低侵入性的架构设计,避免对nginx自身性能造成额外影响,整体架构分为三层:
| 层级 | 组件 | 作用 |
|---|---|---|
| 数据采集层 | nginx内置stub_status模块、lua-nginx-module | 采集nginx基础状态与自定义请求日志 |
| 数据传输层 | Filebeat、Kafka | 实时传输日志数据至高吞吐消息队列 |
| 数据处理与展示层 | Flink、Elasticsearch、Grafana | 实时计算指标、存储时序数据、可视化展示 |
具体实现步骤
1. nginx配置与数据采集
首先开启nginx的stub_status模块获取基础状态,同时通过lua-nginx-module扩展自定义请求日志格式,补充响应时间、请求体大小等字段。
配置示例如下:
# 开启stub_status状态监测
server {
listen 8080;
server_name _;
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
}
# 自定义请求日志格式
http {
log_format realtime_log '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$request_time" "$request_length"';
access_log /var/log/nginx/realtime_access.log realtime_log;
}如果需要更细粒度的请求信息,可以通过lua脚本在请求处理阶段注入自定义变量,示例如下:
-- 在log阶段记录请求处理的各阶段耗时
log_by_lua_block {
local request_time = ngx.var.request_time
local upstream_time = ngx.var.upstream_response_time or 0
ngx.log(ngx.INFO, "request_time:", request_time, ", upstream_time:", upstream_time)
}2. 日志实时传输
使用Filebeat采集nginx的访问日志,配置Kafka作为输出目标,避免日志堆积影响本地磁盘,同时保证高并发场景下的数据传输稳定性。
Filebeat配置示例如下:
filebeat.inputs: - type: log enabled: true paths: - /var/log/nginx/realtime_access.log scan_frequency: 1s output.kafka: hosts: ["kafka-node1:9092", "kafka-node2:9092"] topic: nginx-realtime-log partition.round_robin: reachable_only: true required_acks: 1
3. 实时计算与存储
使用Flink消费Kafka中的日志数据,按照1秒的时间窗口进行实时聚合计算,得到各监测指标的结果后写入Elasticsearch。核心计算逻辑示例如下:
// 定义日志数据实体类
public class NginxLog {
private String remoteAddr;
private String request;
private int status;
private double requestTime;
private long timestamp;
// 省略getter、setter方法
}
// 1秒滚动窗口聚合QPS
DataStream<NginxLog> logStream = env.addSource(kafkaConsumer)
.map(log -> JSON.parseObject(log, NginxLog.class))
.assignTimestampsAndWatermarks(
WatermarkStrategy.<NginxLog>forBoundedOutOfOrderness(Duration.ofSeconds(2))
.withTimestampAssigner((log, ts) -> log.getTimestamp())
);
DataStream<Tuple2<String, Integer>> qpsStream = logStream
.windowAll(TumblingEventTimeWindows.of(Time.seconds(1)))
.process(new ProcessAllWindowFunction<NginxLog, Tuple2<String, Integer>, TimeWindow>() {
@Override
public void process(Context context, Iterable<NginxLog> logs, Collector<Tuple2<String, Integer>> out) {
int count = 0;
for (NginxLog log : logs) {
count++;
}
long windowEnd = context.window().getEnd();
out.collect(new Tuple2<>(String.valueOf(windowEnd), count));
}
});
// 写入Elasticsearch
qpsStream.addSink(esSinkBuilder.build());4. 可视化与告警配置
在Grafana中添加Elasticsearch数据源,创建Dashboard展示各监测指标的趋势图,同时配置告警规则:当5xx错误率超过5%时,通过企业微信接口发送告警通知。
告警规则配置示例(Grafana JSON片段):
{
"alert": {
"conditions": [
{
"evaluator": {
"params": [5],
"type": "gt"
},
"operator": {
"type": "and"
},
"query": {
"params": ["A", "5m", "now"]
},
"reducer": {
"params": [],
"type": "last"
},
"type": "query"
}
],
"executionErrorState": "alerting",
"for": "5m",
"frequency": "10s",
"handler": 1,
"name": "nginx-5xx-error-rate-alert",
"notifications": [
{
"uid": "wechat-notify-channel"
}
]
}
}实践效果与优化
系统上线后,线上故障定位时间从原来的平均30分钟缩短至5分钟以内,成功拦截了多次恶意爬虫攻击和突发流量冲击。后续我们针对性能做了两方面优化:
对Filebeat采集的日志做过滤,排除静态资源请求,减少无效数据传输,降低Kafka和Flink的负载
对Elasticsearch的索引做按天滚动,设置7天到期自动删除,避免存储成本过高
总结
本次nginx实时请求监测项目的实践,验证了轻量级架构在实时运维场景的可行性。整套方案无需修改nginx核心逻辑,侵入性低,可快速复制到其他基于nginx的服务场景。后续我们计划补充请求链路的Trace关联能力,实现从nginx入口到后端服务的全链路请求监测,进一步提升问题排查效率。