nginx_lua如何记录下载文件的适时流量

260 views
Skip to first unread message

Toad Zhou

unread,
Apr 8, 2013, 10:24:13 PM4/8/13
to open...@googlegroups.com
http://a.com/test.zip?key=xxx&uid=123&time=156185 
一个这样的下载URL我要按每个uid去统计他们的实时下载流量,能足够精确的最好。key是一段加密的校验uid和time(过期时间),这个不用管我已经实现。
现在我不知道用lua如何来获取到他们的每个用户的实时下载流量!? 获取用户可以不用GET改用COOKIE也可以,有一个标记就成。求大牛们给点思路谢谢了!

agentzh

unread,
Apr 9, 2013, 2:28:14 PM4/9/13
to openresty
Hello!

2013/4/8 Toad Zhou:
> 现在我不知道用lua如何来获取到他们的每个用户的实时下载流量!? 获取用户可以不用GET改用COOKIE也可以,有一个标记就成。求大牛们给点思路谢谢了!
>

当前请求的实时下载流量可以通过读取 $bytes_sent 或者 $body_bytes_sent 这两个标准 Nginx
变量来实现。前者是包括响应头在内的总流量,后者是响应体的流量。细节见这里:

http://wiki.nginx.org/HttpLogModule#log_format

你可以在 log_by_lua 或者 body_filter_by_lua 等上下文中读取此变量并作相应的处理。特别地,在 Lua
中访问这两个变量时,分别使用记法 ngx.var.bytes_sent 或者 ngx.var.body_bytes_sent.
下面是一个例子:

location /t {
echo hello world;
log_by_lua '
print("bytes sent: ", ngx.var.bytes_sent)
print("body bytes sent: ", ngx.var.body_bytes_sent)
';
}

使用 HTTP 1.1 访问此 /t 接口时,在 nginx 的错误日志文件中可以得到下面两行:

[notice] 12627#0: *1 [lua] [string "log_by_lua"]:2: bytes sent: 144
while logging request
[notice] 12627#0: *1 [lua] [string "log_by_lua"]:3: body bytes sent:
12 while logging request

如果你需要做实时流量控制,可以配合共享内存字典等东西来汇总和存储这些数据。

Regards,
-agentzh

Toad Zhou

unread,
Apr 10, 2013, 12:01:09 AM4/10/13
to open...@googlegroups.com
非常感谢你的解答,按你说的方法我试了一下有点眉目。不过还是有点问题 用ngx.var.bytes_send返回的全是空,用ngx.var.body_bytes_send可以

lua_shared_dict log_dict 5M;
    server {
        listen 8080;
        root /tmp/haha;
        location / {
        log_by_lua "
            local log_dict = ngx.shared.log_dict
            log_dict:set('body_bytes_sent',ngx.var.body_bytes_sent)
        ";
        }

        location = /status {
        default_type 'text/plain';

            content_by_lua "
local log_dict = ngx.shared.log_dict

local body_send=log_dict:get('body_bytes_sent')
ngx.say(body_send)
";
        }
    }

上面的这个配置是可以获取到下载的流量,不过我在下载的时候点暂停的时候,再去新开一个下载他就会一直卡在这里,这是一个阻塞的。而且暂停的时候获取的取一直是208, 不知道什么原因。还请老师指点一下 谢谢!

在 2013年4月10日星期三UTC+8上午2时28分14秒,agentzh写道:

wgm.china

unread,
Apr 10, 2013, 1:14:23 AM4/10/13
to openresty
你如果在log_by_lua中来把,ngx.var.body_bytes_sent的值写到dict中,我测试有一个问题就是这个操作不是及时的,我测试过程中,通过/status读取的值和实际流量不同步。我用迅雷在限速状态中下载,读取到的值更新频度没有规律。
 
lua_shared_dict log_dict 5M;
    server {
  listen 8080;
  root html;

     location / {
  log_by_lua "
      local log_dict = ngx.shared.log_dict
      log_dict:set('body_bytes_sent',ngx.var.body_bytes_sent)
      log_dict:set('set_time',os.time())
  ";
  }
 
    location = /status {
  default_type 'text/plain';
  content_by_lua "
  local log_dict = ngx.shared.log_dict
 

  local body_send=log_dict:get('body_bytes_sent')
  local set_time=log_dict:get('set_time')
  ngx.say('num:',body_send)
  ngx.say('set time:',set_time)
  ";
   }
 
 
 
 
 
2013-04-10

wgm.china

发件人:Toad Zhou
发送时间:2013-04-10 12:01
主题:Re: [openresty] nginx_lua如何记录下载文件的适时流量
收件人:"openresty"<open...@googlegroups.com>
抄送:
 
--
--
邮件来自列表“openresty”,专用于技术讨论!
订阅: 请发空白邮件到 openresty...@googlegroups.com
发言: 请发邮件到 open...@googlegroups.com
退订: 请发邮件至 openresty+...@googlegroups.com
归档: http://groups.google.com/group/openresty
官网: http://openresty.org/
仓库: https://github.com/agentzh/ngx_openresty
教程: http://openresty.org/download/agentzh-nginx-tutorials-zhcn.html
 
 

agentzh

unread,
Apr 10, 2013, 6:44:56 PM4/10/13
to openresty
Hello!

2013/4/9 Toad Zhou:
> 非常感谢你的解答,按你说的方法我试了一下有点眉目。不过还是有点问题
> 用ngx.var.bytes_send返回的全是空,用ngx.var.body_bytes_send可以
>

你这里是笔误吧?应当是“sent”和“send”.

注意 $bytes_sent 是 nginx 1.2.5 以后才变成通用 Nginx 变量,你需要使用足够新的 Nginx:

http://nginx.org/en/CHANGES-1.2

我那个示例在测试时使用的是 nginx 1.2.7.

>
> 上面的这个配置是可以获取到下载的流量,不过我在下载的时候点暂停的时候,再去新开一个下载他就会一直卡在这里,这是一个阻塞的。而且暂停的时候获取的取一直是208,
> 不知道什么原因。还请老师指点一下 谢谢!
>

我看不懂你这里的描述。你使用的是什么方式来提供下载的?使用了第三方的WebDAV 模块?我在 Nginx 核心中没有看到会生成 208 响应的地方。

另外,可以提供问题请求对应的 Nginx 调试日志供诊断之用:

http://wiki.nginx.org/Debugging#Debugging_log

Regards,
-agentzh

agentzh

unread,
Apr 10, 2013, 6:49:32 PM4/10/13
to openresty
Hello!

2013/4/9 wgm.china:
> 你如果在log_by_lua中来把,ngx.var.body_bytes_sent的值写到dict中,我测试有一个问题就是这个操作不是及时的,我测试过程中,通过/status读取的值和实际流量不同步。我用迅雷在限速状态中下载,读取到的值更新频度没有规律。
>

迅雷这样的下载软件一般会同时开启多个线程,分多个 HTTP 请求同时进行下载。你的配置中,应当在共享内存中进行累加,而不是反复改写。

另外,log_by_lua 总是运行在请求结束的时候,如果你需要更及时的流量统计,应当使用 body_filter_by_lua,这样
nginx 每发送一个数据块,你的 Lua 代码都有机会执行。(不过,你要小心 $bytes_sent
在同一个请求中已经是当前请求的累加结果了。)

建议在测试时,总是先使用 curl 这样简单可控的客户端,以方便排查低级错误。

Best regards,
-agentzh
Message has been deleted

Toad Zhou

unread,
Apr 11, 2013, 2:01:09 AM4/11/13
to open...@googlegroups.com
Hello!

累加结果这个我明白,就是简单的测试一下,生产环境我会针对UID记录到REDIS中。现在的问题是用curl测不出来阻塞情况,而浏览器下载的时候会有一个连接占着不关闭的问题,我用浏览器去下载一个http://xxx/test.zip这样的URL时,他在没下载完的时候时候你再打开一个同样 的url,他是处于阻塞状态浏览器会在那等待,他要等第1个下载完 第2个下载才会开始下载。 如果我第一个下载在chrome当中点暂停那么第2个URL下载将一直处于等待状态。除非你第1个下载完或点击取消才可以。log_by_lua 和body_filter_by_lua效果是一样的。  

在 2013年4月11日星期四UTC+8上午6时49分32秒,agentzh写道:

kindy

unread,
Apr 11, 2013, 2:06:57 AM4/11/13
to openresty
什么会阻塞等待?

如果不能同时发起2个curl请求,应该跟log_by_lua 和 body_filter_by_lua 无关。
如果说的是请求不完成,计数 不更新,使用 log_by_lua 的时候会发生,使用 body_filter_by_lua 应该不会的。

话说,使用 curl 配合 --limit-rate <speed> 应该可以达到类似效果。当然,使用浏览器也完全可以。
       --limit-rate <speed>
              Specify the maximum transfer rate you want curl to use. This feature is useful if you have a limited pipe and you'd like your transfer not to use your entire  bandwidth.

              The  given  speed is measured in bytes/second, unless a suffix is appended.  Appending 'k' or 'K' will count the number as kilobytes, 'm' or M' makes it megabytes, while
              'g' or 'G' makes it gigabytes. Examples: 200K, 3m and 1G.



2013/4/11 Toad Zhou <toad...@gmail.com>

--
--
邮件来自列表“openresty”,专用于技术讨论!
订阅: 请发空白邮件到 openresty...@googlegroups.com
发言: 请发邮件到 open...@googlegroups.com
退订: 请发邮件至 openresty+...@googlegroups.com
归档: http://groups.google.com/group/openresty
官网: http://openresty.org/
仓库: https://github.com/agentzh/ngx_openresty
教程: http://openresty.org/download/agentzh-nginx-tutorials-zhcn.html
 
 



--
- - - - - - - - - - - -
林青(Kindy Lin)

Toad Zhou

unread,
Apr 11, 2013, 6:35:05 AM4/11/13
to open...@googlegroups.com
我用我的chrome会卡在那,我也郁闷为毛会卡在那里。

在 2013年4月11日星期四UTC+8下午2时06分57秒,kindy写道:

agentzh

unread,
Apr 11, 2013, 2:23:28 PM4/11/13
to openresty
Hello!

2013/4/10 Toad Zhou:
> 累加结果这个我明白,生产环境我会针对UID记录到REDIS中。现在的问题是用curl测不出来阻塞情况,我用浏览器下载一个http://xxx/test.zip的时候他不会关闭的,这时候你再打开一个同样
> 的url他是处于阻塞状态,他要等第一个下载完第2个下载才会开始动。
> 如果我第一个下载在chrome当中点暂停那么第2个URL下载将一处于等待状态。除非你第一下下载完或点击取消才可以。log_by_lua
> 和body_filter_by_lua效果是一样的。
>

貌似你忽略了我上一封邮件中的最后的问题和建议,我再重复一遍:

“你使用的是什么方式来提供下载的?使用了第三方的WebDAV 模块?我在 Nginx 核心中没有看到会生成 208 响应的地方。

另外,可以提供问题请求对应的 Nginx 调试日志供诊断之用:

http://wiki.nginx.org/Debugging#Debugging_log

值得一提的是,磁盘读取是阻塞操作,你可以配置多个 nginx worker 进程(如果你目前只配置了一个 worker 的话)。

Regards,
-agentzh
Message has been deleted

Toad Zhou

unread,
Apr 11, 2013, 10:45:10 PM4/11/13
to open...@googlegroups.com
抱歉,我不知道什么是WebDAV  不知道chrome是不是用的这个下载模块。 不过问题已经找到,因为我测试的时候下载的都是同一个文件比如http://xxx.com/test.zip  如果换成test2 test3这样测试就没有问题。后来发现 原来chrome同一个下载URL只能有一个正在下载。IE等浏览器不受影响。
另外 我上面提到208 不是http响应208 而是说我点chrome的暂停的时候 body_bytes_sent的值是208    我也发现我的沟通有问题,语文没学好。。。。

非常感谢agentzh 老师的细心解答!

在 2013年4月12日星期五UTC+8上午2时23分28秒,agentzh写道:
Reply all
Reply to author
Forward
0 new messages