lua累加body_bytes_sent值统计各域名流量

517 views
Skip to first unread message

Evil Mybliss

unread,
May 19, 2014, 5:55:07 AM5/19/14
to open...@googlegroups.com
Hi, 各位老师
      我在通过lua来计算body_bytes_sent值时, 发现得出的值与机器流量相差很大.
       机器上显示流量只有60-70Mb的样子, 可我这个统计出来单个域名就达到了1个G..

        下面是我的存字典的代码:
         local body_size   = ngx.var.body_bytes_sent
         local time        = ngx.time() - ngx.time() % 300
         local domain      = ngx.var.host
         local tf_key      = domain .. "/" .. SerialNub .. "/" .. time
         local total_size  = log_dict:get(tf_key) or 0
         total_size        = total_size + body_size
         log_dict:set(tf_key, total_size)

不知道代码统计是否有问题? 
我这个机器上启动的了4个worker.
然后我搜索看到章老师说关于nginx多个进程是独自的累加器, 是否跟这个有关系呢?

  谢谢. 

Yichun Zhang (agentzh)

unread,
May 19, 2014, 2:40:11 PM5/19/14
to openresty
Hello!

2014-05-19 2:55 GMT-07:00 Evil Mybliss:
> 我在通过lua来计算body_bytes_sent值时, 发现得出的值与机器流量相差很大.
> 机器上显示流量只有60-70Mb的样子, 可我这个统计出来单个域名就达到了1个G..
>

你应当交待一下你所说的“机器流量”具体的统计方法。毕竟有很多不同的统计方法。

> 下面是我的存字典的代码:

你的这段代码是放在什么上下文中的?

它应当放在 log_by_lua* 这样的上下文中。如果放在 body_filter_by_lua
中的话,则会重复统计,结果会比实际值大很多倍。毕竟对于单个请求而言,body filter 可能会被调用多次。

> local body_size = ngx.var.body_bytes_sent
> local time = ngx.time() - ngx.time() % 300
> local domain = ngx.var.host
> local tf_key = domain .. "/" .. SerialNub .. "/" .. time
> local total_size = log_dict:get(tf_key) or 0
> total_size = total_size + body_size
> log_dict:set(tf_key, total_size)
>

上面的 Lua 代码有一个明显的错误是你使用 get() 和 set() 这两个分开的调用来做累加。这两个调用中间并没有原子保护,所以你在
set() 之前由 get() 得到的值很可能已经被其他 nginx worker 进程改写了。正确的做法是使用 incr()
这一个调用,它可以保证原子性:

https://github.com/openresty/lua-nginx-module#ngxshareddictincr

另外,我不清楚你这里使用 SerialNum 和 time 作 key 的动机。

一个建议是先使用最简单的 Lua/nginx 例子和你自己设计的请求来测试你的 Lua 代码,这样方便调试你 Lua 代码里的低级错误。

你这里使用的 $body_bytes_sent 变量是 nginx 核心计算其值,ngx_lua 模块只是暴露接口而已。这个变量在
nginx 用户群中的使用极为广泛,出问题的可能性很低。

> 不知道代码统计是否有问题?

见上。

> 我这个机器上启动的了4个worker.
> 然后我搜索看到章老师说关于nginx多个进程是独自的累加器, 是否跟这个有关系呢?
>

我觉得你应该是断章取义了。你这里使用的共享内存字典 lua_shared_dict 是所有 worker
进程共享的内存区域。你看到的我之前说的独立累加器的建议应当是针对性能优化的,即当每个 worker 使用自己专用的
lua_shared_dict 时,各个 worker 访问自己的区域时锁的开销可以实现最小化。

Regards,
-agentzh

Evil Mybliss

unread,
May 19, 2014, 10:08:57 PM5/19/14
to open...@googlegroups.com
谢谢章老师耐心指点.
这段代码是运行在log_by_lua*上下文里. 
那个SerialNub和time做key是因为我需要将CDN上每个节点的域名流量按5分钟记录送回中央统计接口.
我照您的回答修改了下代码, 我再测试测试.
谢谢.

在 2014年5月20日星期二UTC+8上午2时40分11秒,agentzh写道:
Reply all
Reply to author
Forward
0 new messages