NginxPulse 技术分析文档
1. 项目概述
NginxPulse 是一个轻量级的 Nginx 访问日志分析与可视化面板。该项目通过实时解析 Nginx 访问日志,提供 PV 过滤、IP 归属地查询、客户端解析等核心功能,旨在为中小型网站提供低成本的日志监控与分析解决方案。
1.1 核心特性
- 实时统计分析:定时扫描日志文件,实时更新访问统计
- 智能 PV 过滤:支持基于状态码、URL 模式、IP 列表的访问过滤
- IP 归属地解析:结合远程 API 和本地数据库的多层次 IP 定位策略
- 客户端分析:解析 User-Agent,识别浏览器、操作系统、设备类型
- 轻量级部署:单镜像容器化部署,基于 SQLite 存储,无需额外数据库依赖
1.2 技术栈
| 层次 | 技术选型 |
|---|---|
| 后端 | Go 1.23.x · Gin · Logrus |
| 数据库 | SQLite (modernc.org/sqlite) |
| IP 解析 | ip2region(本地)+ ip-api.com(远程) |
| 前端 | Vue 3 · Vite · TypeScript · PrimeVue · ECharts/Chart.js · SCSS |
| 容器化 | Docker / Docker Compose · Nginx(前端静态部署) |
2. 系统架构设计
2.1 整体架构图
graph TB
subgraph 数据源
NGINX[Nginx 日志文件]
end
subgraph NginxPulse容器
subgraph 前端层
VUE[Vue 3 应用]
NGINX_FRONT[Nginx 静态服务]
end
subgraph 后端层
INGEST[日志摄入模块]
ENRICH[数据增强模块]
ANALYTICS[统计分析模块]
STORE[数据存储层]
API[HTTP API]
end
subgraph 数据层
SQLITE[(SQLite 数据库)]
CACHE[内存缓存]
IPDB[ip2region 本地库]
end
end
subgraph 外部服务
IPAPI[ip-api.com]
end
NGINX --> INGEST
INGEST --> ENRICH
ENRICH --> ANALYTICS
ANALYTICS --> STORE
STORE --> SQLITE
API --> STORE
ENRICH --> CACHE
ENRICH --> IPAPI
ENRICH --> IPDB
VUE --> API
VUE --> NGINX_FRONT
USER[用户] --> NGINX_FRONT
USER --> API2.2 核心模块分析
2.2.1 日志摄入模块 (ingest)
日志摄入模块负责持续监控和解析 Nginx 访问日志:
- 扫描机制:基于游标(cursor)的增量扫描,避免重复解析
- 解析器:使用正则表达式匹配典型 Nginx access log 格式
- 状态持久化:扫描位置保存至
nginx_scan_state.json
2.2.2 数据增强模块 (enrich)
该模块为核心差异点,实现了智能的 IP 归属地查询策略:
快速过滤 → 缓存查询 → 远程批量查询 → 本地兜底查询查询策略详解:
- 快速过滤:空值、本地、回环地址返回"本地",内网地址返回"内网/本地网络"
- 缓存优先:内存缓存最多存储 50,000 条 IP 查询结果
- 远程优先:调用 ip-api.com 批量接口(单批最多 100 个),超时 1.2s
- 本地兜底:使用内嵌的 ip2region.xdb 数据库,50ms 超时
- IPv6 处理:仅走远程查询,失败返回"未知"
2.2.3 统计分析模块 (analytics)
负责按时间维度聚合访问数据,生成多维统计指标:
- PV/UV 统计(按小时/天)
- 状态码分布
- 访问路径排行
- 客户端类型分布
- IP 地域分布
2.2.4 数据存储层 (store)
基于 SQLite 的轻量级存储方案:
- 表结构设计:访问记录表、统计聚合表
- 写入优化:批量插入,事务管理
- 数据持久化:
nginxpulse.db
3. IP 归属地查询策略深度分析
3.1 策略流程图
flowchart TD
A[接收 IP 地址] --> B{快速过滤}
B -->|空值/本地/回环| C[返回: 本地]
B -->|内网地址| D[返回: 内网/本地网络]
B -->|正常公网 IP| E{内存缓存检查}
E -->|命中| F[返回缓存结果]
E -->|未命中| G[远程批量查询]
G --> H{ip-api.com}
H -->|成功且非未知| I[更新缓存并返回]
H -->|超时/失败/未知| J{IP 版本}
J -->|IPv4| K[ip2region 本地查询]
J -->|IPv6| L[返回: 未知]
K --> M{查询结果}
M -->|成功| N[更新缓存并返回]
M -->|超时/失败| L
I --> O[结束]
N --> O
L --> O
F --> O
C --> O
D --> O3.2 策略优势分析
- 性能优先:通过快速过滤和缓存机制,减少 90% 以上的外部查询
- 容错能力:远程失败时自动降级到本地查询,保证服务可用性
- 成本控制:本地库兜底降低对第三方 API 的依赖
- 批量优化:远程查询采用批量方式,减少网络开销
3.3 ip2region 本地库
- 数据来源:内嵌于二进制文件中,首次启动自动解压
- 索引优化:加载向量索引提升查询性能
- 存储路径:
./var/nginxpulse_data/ip2region.xdb
4. PV 过滤机制
4.1 过滤维度
PV(Page View)过滤支持三个维度的配置:
| 维度 | 配置项 | 默认值 | 说明 |
|---|---|---|---|
| 状态码 | PV_STATUS_CODES | [200] | 只统计指定状态码的访问 |
| URL 模式 | PV_EXCLUDE_PATTERNS | 内置规则 | 排除特定资源请求(如静态文件) |
| IP 列表 | PV_EXCLUDE_IPS | 空 | 排除特定 IP 的访问 |
4.2 默认排除规则
项目内置了常见静态资源的排除模式:
- 图片文件:
.jpg,.png,.gif,.ico,.svg - 样式文件:
.css - 脚本文件:
.js - 字体文件:
.woff,.woff2,.ttf,.eot
5. 部署方案
5.1 单镜像容器化
NginxPulse 采用创新的单镜像设计,将前端和后端服务打包在一起:
graph LR
subgraph Docker 镜像
FRONTEND[前端静态文件<br/>/app/dist]
BACKEND[后端二进制<br/>/app/nginxpulse]
NGINX[Nginx 配置<br/>/etc/nginx/conf.d]
end
HOST[宿主机] -->|mount| LOGS[Nginx 日志目录]
HOST -->|mount| DATA[数据持久化目录]
FRONTEND --> NGINX
BACKEND --> SQLITE[(SQLite)]
LOGS --> BACKEND优势:
- 简化部署流程,只需拉取一个镜像
- 减少容器间通信开销
- 配置集中管理
5.2 环境变量配置
| 变量名 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
WEBSITES | JSON | 是* | - | 网站配置(无配置文件时必填) |
CONFIG_JSON | JSON | 否 | - | 完整配置 JSON 字符串 |
LOG_DEST | string | 否 | file | 日志输出:file 或 stdout |
TASK_INTERVAL | duration | 否 | 1m | 日志扫描间隔 |
SERVER_PORT | string | 否 | :8089 | 后端服务监听地址 |
PV_STATUS_CODES | array | 否 | [200] | PV 统计状态码 |
PV_EXCLUDE_PATTERNS | array | 否 | 内置规则 | URL 排除模式 |
PV_EXCLUDE_IPS | array | 否 | 空 | IP 排除列表 |
5.3 持久化数据
var/nginxpulse_data/
├── nginxpulse.db # SQLite 数据库
├── nginx_scan_state.json # 日志扫描游标
└── ip2region.xdb # IP 本地库(首次启动生成)6. 目录结构
.
├── cmd/
│ └── nginxpulse/
│ └── main.go # 程序入口
├── internal/ # 核心业务逻辑
│ ├── app/
│ │ └── app.go # 应用初始化、依赖注入
│ ├── analytics/ # 统计口径与聚合逻辑
│ ├── enrich/
│ │ ├── ip_geo.go # IP 归属地查询(远程+本地)
│ │ └── pv_filter.go # PV 过滤规则实现
│ ├── ingest/
│ │ └── log_parser.go # 日志扫描与解析
│ ├── server/
│ │ └── http.go # HTTP 服务与中间件
│ ├── store/
│ │ └── repository.go # SQLite 数据访问层
│ └── web/
│ └── handler.go # API 路由处理器
├── webapp/ # 前端项目
│ └── src/
│ └── main.ts # Vue 应用入口
├── configs/
│ ├── nginxpulse_config.json # 主配置文件
│ └── nginx_frontend.conf # 内置 Nginx 配置
├── scripts/
│ └── dev_local.sh # 本地开发启动脚本
├── var/ # 运行时数据目录
├── Dockerfile
└── docker-compose.yml7. 二次开发指南
7.1 环境准备
- Go 1.23.x
- Node.js 20+ / npm
- Docker(可选)
7.2 Nginx 日志格式适配
默认解析器支持以下格式:
<ip> - <user> [time] "METHOD /path HTTP/1.x" status bytes "referer" "ua"若使用自定义 log_format,需修改 internal/ingest/log_parser.go 中的正则表达式。
7.3 扩展建议
统计口径扩展:修改 internal/analytics/
API 扩展:在 internal/web/handler.go 添加新路由
数据模型扩展:修改 internal/store/repository.go 中的表结构
8. 技术亮点总结
- 分层缓存策略:快速过滤 → 内存缓存 → 远程批量 → 本地兜底,平衡性能与成本
- 轻量级架构:SQLite + 单镜像部署,降低运维复杂度
- 增量解析:基于游标的日志扫描,避免重复处理
- 容错设计:远程 API 失败时自动降级到本地查询
- 灵活配置:支持配置文件和环境变量两种方式
- 前后端分离:Vue 3 + Go,便于独立迭代
9. 潜在改进方向
- 分布式支持:当前为单机部署,可考虑支持多节点数据聚合
- 告警功能:增加异常访问告警(如某 IP 短时间大量请求)
- 数据导出:支持统计数据的报表导出
- 更多日志格式:支持 Apache、Caddy 等 Web 服务器日志
- 实时性提升:采用 inotify 替代定时扫描,实现准实时处理
参考文献
- 项目地址:https://github.com/likaia/nginxpulse
- ip2region 项目:https://github.com/lionsoul2014/ip2region
- ip-api.com:https://ip-api.com/