插件窝 干货文章 如何使用nginx lua实现网站统计中的数据收集

如何使用nginx lua实现网站统计中的数据收集

local 数据 Lua ngx 230    来源:    2025-04-21

使用Nginx Lua实现网站数据收集

Nginx结合Lua模块(OpenResty)可以高效地实现网站数据收集功能。下面我将介绍完整的实现方案。

方案概述

  1. 使用Nginx的access阶段收集基础访问数据
  2. 通过Lua脚本处理更复杂的用户行为数据
  3. 将数据发送到后端存储系统(Redis/Kafka/数据库等)

实现步骤

1. 安装OpenResty或Nginx+Lua模块

# 推荐直接安装OpenResty
wget https://openresty.org/package/centos/openresty.repo
sudo mv openresty.repo /etc/yum.repos.d/
sudo yum install -y openresty

2. 基础配置

在nginx.conf中添加Lua支持:

http {
    lua_package_path "/path/to/lua/scripts/?.lua;;";
    lua_shared_dict stats 10m;  # 共享内存区域用于临时存储

    init_by_lua_block {
        -- 初始化全局变量和连接池
        local redis = require "resty.redis"
        local red = redis:new()
        -- 可以在这里初始化数据库连接等
    }
}

3. 基础访问日志收集

server {
    location / {
        access_by_lua_block {
            -- 获取基础信息
            local ngx_var = ngx.var
            local request_uri = ngx_var.request_uri
            local http_referer = ngx_var.http_referer or "direct"
            local http_user_agent = ngx_var.http_user_agent or "unknown"
            local remote_addr = ngx_var.remote_addr

            -- 获取cookie中的用户ID
            local cookies = ngx_var.http_cookie
            local user_id = "anonymous"
            if cookies then
                user_id = string.match(cookies, "user_id=([^;]+)") or user_id
            end

            -- 构造数据对象
            local log_data = {
                time = ngx.now(),
                uri = request_uri,
                referer = http_referer,
                ua = http_user_agent,
                ip = remote_addr,
                user_id = user_id,
                status = ngx.status
            }

            -- 发送到后端存储
            local cjson = require "cjson"
            local redis = require "resty.redis"
            local red = redis:new()

            local ok, err = red:connect("127.0.0.1", 6379)
            if ok then
                red:rpush("web_stats", cjson.encode(log_data))
                red:set_keepalive(10000, 100)
            end
        }
    }
}

4. 高级用户行为跟踪

对于更复杂的行为跟踪(如页面停留时间、点击事件等),可以使用JavaScript+API的方式:

location /api/track {
    content_by_lua_block {
        local args = ngx.req.get_uri_args()
        local event_type = args.event or "pageview"
        local duration = args.duration or 0
        local element = args.element or ""

        -- 验证数据并处理
        if not ngx.var.http_referer then
            ngx.exit(403)
        end

        -- 构造事件数据
        local event_data = {
            time = ngx.now(),
            event = event_type,
            duration = tonumber(duration),
            element = element,
            referer = ngx.var.http_referer,
            user_agent = ngx.var.http_user_agent,
            ip = ngx.var.remote_addr
        }

        -- 发送到Kafka或其他消息队列
        local kafka = require "resty.kafka"
        local producer = kafka:new("kafka_cluster", {
            broker_list = {
                { host = "kafka1", port = 9092 },
                { host = "kafka2", port = 9092 }
            }
        })

        local ok, err = producer:send("web_events", nil, cjson.encode(event_data))
        if not ok then
            ngx.log(ngx.ERR, "failed to send event to kafka: ", err)
        end

        ngx.say("ok")
    }
}

5. 数据聚合与实时统计

可以使用Lua的共享内存进行简单的实时统计:

init_by_lua_block {
    -- 初始化计数器
    local stats = ngx.shared.stats
    stats:set("pageviews", 0)
    stats:set("visitors", 0)
    -- 其他需要统计的指标...
}

access_by_lua_block {
    -- 在访问时更新统计
    local stats = ngx.shared.stats
    stats:incr("pageviews", 1)

    -- 基于IP的独立访客统计
    local ip = ngx.var.remote_addr
    local key = "visitor:" .. ip
    local seen = stats:get(key)
    if not seen then
        stats:set(key, 1, 3600)  -- 1小时过期
        stats:incr("visitors", 1)
    end
}

优化建议

  1. 性能优化

    • 使用连接池管理数据库/Redis连接
    • 对于高流量站点,考虑批量发送数据而非每次请求都发送
    • 使用Nginx的缓冲和异步机制
  2. 数据可靠性

    • 实现失败重试机制
    • 考虑本地缓存+定期同步的方案
    • 添加数据校验逻辑
  3. 隐私合规

    • 实现IP匿名化处理
    • 提供用户选择退出跟踪的机制
    • 遵守GDPR等数据保护法规
  4. 扩展性

    • 设计可插拔的数据处理管道
    • 支持多种后端存储系统
    • 实现配置化管理

完整示例项目结构

/etc/nginx/
├── nginx.conf
└── lua/
    ├── init.lua           # 初始化脚本
    ├── stats/             # 统计模块
    │   ├── core.lua       # 核心功能
    │   ├── storage.lua    # 存储适配器
    │   └── utils.lua      # 工具函数
    └── config.lua         # 配置文件

通过这种架构,你可以灵活地扩展数据收集功能,同时保持Nginx的高性能特性。