如何基于Promtail、Loki和Grafana统计近30天独立用户IP?
问题描述
我在Kubernetes集群中部署了Promtail、Loki、Grafana和Prometheus。Nginx-ingress生成JSON格式日志,Promtail提取字段并添加http_host标签后发送至Loki。我需要通过Grafana以Loki为数据源,统计5分钟、日、周、月维度的独立用户IP(对应字段http_x_forwarded_for)数。
通过logcli导出20天日志并用pandas统计,真实独立IP数为563个,但在Grafana中选择相同时间范围,尝试三种方法均失效:
- LogQL聚合查询
5分钟、1天、7天维度正常,但超过7天提示「单查询达到最大系列数(500)」,无数据返回。count(sum by (http_x_forwarded_for) (count_over_time({job="$job", http_host="$http_host"} | json | __error__="" [5m]))) - Grafana转换统计基础日志
查询语句:
通过Grafana转换提取字段、筛选并去重计数,但受限于Grafana的5000行日志限制,仅统计到324个独立IP,远低于真实值。{job="$job", http_host="$http_host", http_x_forwarded_for!=""} | json | __error__="" - 格式化日志后Grafana统计
查询语句:
再通过Grafana转换分组统计行数,仅得到276个独立IP,同样远低于真实值。{job="$job", http_host="$http_host"} | json | __error__="" | line_format "{{.http_x_forwarded_for}}"
请问如何正确统计近30天的独立用户IP?
解决方案
方法1:调整Loki系列数限制(临时应急)
Loki默认max_query_series限制为500,可修改Loki配置文件的limits_config部分调高该值:
limits_config: max_query_series: 2000 # 根据实际IP基数调整,比如设为1000-2000
修改后重启Loki服务,再执行原LogQL查询即可。注意该值不宜过大,避免影响Loki查询性能。
方法2:优化LogQL查询,增大聚合窗口
针对长周期查询,将count_over_time的时间窗口从[5m]调整为更大的区间(如[1h]),减少生成的系列数:
count(sum by (http_x_forwarded_for) (count_over_time({job="$job", http_host="$http_host"} | json | __error__="" [1h])))
每个IP每小时仅生成一个系列,长周期下总系列数会大幅降低,避免触发系列数限制。
方法3:用Prometheus预聚合独立IP数(长期推荐)
如果需要长期统计多维度独立IP,更高效的方式是用Prometheus做预聚合:
- 在Promtail中配置
relabel_configs,对http_x_forwarded_for做哈希摘要后作为标签(避免直接用IP做标签导致Prometheus基数爆炸):relabel_configs: - source_labels: [http_x_forwarded_for] target_label: ip_hash action: replace replacement: "{{hash}}" - 用自定义脚本或Exporter定期查询Loki获取IP并去重,将独立IP数指标推送到Prometheus;或利用Prometheus的
count_values函数基于哈希标签统计。 - 在Grafana中直接使用Prometheus数据源查询预聚合指标,长周期查询性能更高且无系列数限制。
方法4:使用Loki的distinct操作(Loki 2.4+版本支持)
若你的Loki版本≥2.4,可直接用distinct操作去重统计IP:
count(distinct({job="$job", http_host="$http_host"} | json | __error__="" | http_x_forwarded_for != "" | unwrap http_x_forwarded_for))
该查询直接返回时间范围内的独立IP数量,无需复杂聚合,可规避系列数过多问题。
内容的提问来源于stack exchange,提问作者aams.eam
相关产品推荐
相关产品推荐

