统计nginx一小时内独立访客数需提取指定时间窗口日志→提取客户端ip→去重计数;关键在准确截取小时级时间(如%02d/%b/%y:%h)、处理代理真实ip及优化大日志性能。

用 shell 脚本快速统计 Nginx 一小时内独立访客数,核心是:提取指定时间窗口内的日志行 → 提取客户端 IP → 去重计数。关键在于准确截取时间范围,并避免跨小时误算。
确认日志时间格式和字段位置
Nginx 默认日志格式中,时间字段通常在开头,形如:[12/Jan/2024:14:38:22 +0800]。需先用 awk 或 sed 提取并匹配目标小时(比如统计 14 点整到 14:59:59 的请求)。
- 用 awk -F'[' '{print $2}' 可切出时间部分(含后面内容),再用 substr($1,1,13) 截取到“小时”级别(如 12/Jan/2024:14)
- 确保时区一致:Nginx 日志时间默认为服务器本地时区,脚本中不要用 UTC 时间硬匹配,除非你明确配置了
log_format使用$time_iso8601并做了时区转换
按小时过滤并统计独立 IP
假设要统计今天 14 点这一小时的独立访客(IP),可写成单行脚本:
awk -F'[' '/[.*/.*/.*:14:[0-5][0-9]:[0-5][0-9]/ {split($2,a," "); print a[1]} ' /var/log/nginx/access.log | awk '{print $1}' | sort -u | wc -l
更健壮的做法(推荐):
- 用 date -d "1 hour ago" +"%d/%b/%Y:%H" 动态生成目标小时标识,避免写死
- 用 awk '$4 ~ /[12/Jan/2024:14:/ 这类正则直接匹配日志第 4 字段(默认日志格式下,时间在第 4 字段)
- 完整示例(统计上一整小时):
hour=$(date -d 'last hour' +'%d/%b/%Y:%H'); awk -v h="$hour" '$4 ~ "\["h":" {gsub(/[^0-9.]/,"",$1); print $1}' /var/log/nginx/access.log | sort -u | wc -l
说明:gsub(/[^0-9.]/,"",$1) 是为清理 IP 字段中可能混入的双引号或破折号(如 "192.168.1.1" 或 -)
处理大日志文件提升效率
如果日志很大(GB 级),全扫一遍慢,可结合 grep -A / -B 或用 awk 提前退出:
- 用 awk '/^.*14:[0-5][0-9]:[0-5][0-9].*$/ {print $1} /^.*15:00:00/ {exit}' —— 匹配到下一小时起点就停
- 若日志按时间顺序写入(默认如此),加 head -n 100000 预估范围后处理,避免读完全量
- 考虑用 zcat 直接分析压缩日志(如 access.log.1.gz): zcat /var/log/nginx/access.log.1.gz | ...
注意代理环境下的真实 IP
如果用了 CDN 或反向代理(如 LVS、SLB),$remote_addr 是代理 IP,不是真实访客。需确认日志中是否记录了 $http_x_forwarded_for 或 $http_x_real_ip。
- 检查你的
log_format,例如:log_format main '$http_x_forwarded_for - $remote_user [$time_local] ...' - 此时应提取第 1 字段(
$http_x_forwarded_for),并注意它可能是逗号分隔的多个 IP(取最左端):awk '{split($1,a,","); print a[1]}' - 但注意:X-Forwarded-For 可被伪造,生产环境建议只信任可信代理传来的值,或改用
$realip_remote_addr(需启用 ngx_http_realip_module)











