前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >nginx联合lua打造大数据日志采集系统个性化需求

nginx联合lua打造大数据日志采集系统个性化需求

作者头像
神秘的寇先森
发布2018-12-26 14:50:59
2.1K0
发布2018-12-26 14:50:59
举报
文章被收录于专栏:Java进阶之路

上篇文章介绍了nginx.conf的参数和变量及实现根据给定的参数实现日志动态分发。但是如果参数不固定呢?比如上篇我固定参数arg2值为click,view,look,content四个,那如果生产系统中增加了一个类型play,search呢?难道每次增加一个参数都要Kill掉nginx然后修改配置文件增加if代码块吗?这显然是低效的。那如何实现这个功能呢? 答案:Lua可以帮到你

Lua简介

Lua 是一个简洁、轻量、可扩展的脚本语言,也是号称性能最高的脚本语言,用在很多需要性能的地方,比如:游戏脚本,nginx,wireshark的脚本,当你把他的源码下下来编译后,你会发现解释器居然不到200k,非常变态。。。很多应用程序使用Lua作为自己的嵌入式脚本语言,以此来实现可配置性、可扩展性。 Lua原生支持的数据类型非常之少,它只提供了nil、数字(缺省是双精度浮点数,可配置)、布尔量、字符串、表、子程序、协程(coroutine)以及用户自定义数据这8种。但是其处理表和字符串的效率非常之高,加上元表的支持,开发者可以高效的模拟出需要的复杂数据类型(比如集合、数组等)。Lua是一个动态弱类型语言,支持增量式垃圾收集策略。有内建的,与操作系统无关的协作式多线程(coroutine)支持。它还可以用于嵌入式硬件,不仅可以嵌入其他编程语言,而且可以嵌入微处理器中。 lua可以实现nginx.conf中复杂的逻辑处理,但是前提是nginx要安装lua-nginx-module插件,安装步骤参考https://blog.csdn.net/qq_25551295/article/details/51744815

nginx.conf结合lua编程实现逻辑处理

由于本人也是因为业务的需求才开启了nginx+lua编程的学习,所以以下内容为本人精心挑选过网友分享的知识,感谢这些网友。

  1. lua的语法学习参考菜鸟教程:http://www.runoob.com/lua/lua-tutorial.html
  2. Nginx+Lua 开发入门:http://wiki.jikexueyuan.com/project/nginx-lua/introduction.html
  3. nginx + lua实现复杂的控制:https://blog.csdn.net/huangyimo/article/details/80791816
  4. ngx映射到lua模块函数变量一览:https://blog.csdn.net/xiejunna/article/details/53465202
  5. 通过nginx_lua实现根据请求参数分发道不同后端节点: https://blog.csdn.net/yevvzi/article/details/52593490
  6. ngx_lua常用变量参数:https://blog.csdn.net/xiejunna/article/details/53444616
nginx个性化需求

nginx有几个功能,最常用的就是做负载均衡服务器和web服务器。而且因为nginx可以支撑上万的并发量,所以非常适合作为互联网公司的埋点日志服务器。 需求:根据访问参数里面的两个参数appkey和ltype动态生成日志文件。日志文件命名规则为appkey的值_ltype的值.log。同时根据请求方式的不同,get方式访问的日志才有这种需求,而post方式访问的日志命名直接用old_post命名即可。

  • 改造前的nginx.conf:
代码语言:javascript
复制
user  nginx nginx;
worker_processes  auto;
worker_cpu_affinity auto;
worker_rlimit_nofile 409600;

events {
    use epoll;
    multi_accept on;
    worker_connections  409600;
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    
    sendfile on;
    tcp_nopush     on;
    keepalive_timeout 60;
    tcp_nodelay on;
    charset utf-8;
    
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    server {
        listen       80;
        server_name  172-17-12-177;

        location / {
        root   html;
        index  index.html index.htm;
        }

    location = /favicon.ico {
        log_not_found off;
        access_log off;
        }

        location /statistics/EventAgent { 
        add_header Content-Type 'text/html; charset=utf-8';
        default_type 'application/json';
        return 200 '{"success":200}';
        }
    }
}
  • 实现需求
  1. 时间格式需要更改为2018/12/13 16:38:15,而nginx.conf默认的时间格式为:14/Dec/2018:17:40:55 +0800 。
  • 在nginx.conf中server{}上先根据
host map为
host map为

fmt_localtime参数。

  • 日志格式中[
time_local] 更改为
time_local] 更改为

fmt_localtime

  • 根据lua获取到nginx的所有参数将ngx.localtime()赋值给$fmt_localtime
代码语言:javascript
复制
 map $host $fmt_localtime {
        default '';
    }
    log_by_lua_block {
       ngx.var.fmt_localtime = ngx.localtime();
    }  
  1. 根据访问参数里面的两个参数appkey和ltype动态生成日志文件。日志文件命名规则为appkey的值_ltype的值.log.
  • 开启lua获取nginx的所有参数功能
  • 在location代码块中嵌套rewrite_by_lua_block代码块;rewrite_by_lua执行内部URL重写或者外部重定向,默认执行在rewrite处理阶段的最后。
代码语言:javascript
复制
set $log_name '';
           rewrite_by_lua_block {
                local var = ngx.var
                    local request_method = ngx.var.request_method
                    if request_method == "GET" then
                    if(ngx.var.arg_appkey ~= nil and ngx.var.arg_ltype ~= nil) then
                            ngx.var.log_name = ngx.var.arg_appkey.."_"..ngx.var.arg_ltype
                else
                ngx.var.log_name='access'
                end
                    elseif request_method == "POST" then
                            ngx.req.read_body()
                ngx.var.log_name='old_post'
                    end
            }
  1. 如果请求是post请求,需要打印出请求体。 实现这个功能需要在lua 的content代码块中写入ngx.req.read_body(),不然请求体为空。
  2. 如果嵌套了lua代码,返回值的时候不能用return 了,不然返回不了。需要嵌套content_by_lua代码块将返回值打印出来。
代码语言:javascript
复制
content_by_lua_block {
        ngx.req.read_body()
        ngx.say("{success:200}")
        }

改造后的nginx.conf配置文件如下:

代码语言:javascript
复制
user  nginx nginx;
worker_processes  auto;
worker_cpu_affinity auto;
worker_rlimit_nofile 409600;


events {
    use epoll;
    multi_accept on;
    worker_connections  409600;
}


http {
    include       mime.types;
    default_type  application/octet-stream;
    
    sendfile on;
    tcp_nopush     on;
    keepalive_timeout 60;
    tcp_nodelay on;

    charset utf-8;

    log_format  access_get  '$fmt_localtime $server_addr  $uri $args   $remote_addr  $status';
    log_format  access_post  '$fmt_localtime $server_addr  $uri $request_body   $remote_addr  $status';
    
    map $host $fmt_localtime {
        default '';
    }

    log_by_lua_block {
       ngx.var.fmt_localtime = ngx.localtime();
    }  
    
    lua_need_request_body on;
    
    server {
        listen       80;
        server_name  172-17-12-177;

        location / {
            root   html;
            index  index.html index.htm;
        }

    location = /favicon.ico {
            log_not_found off;
            access_log off;
        }

        location /statistics/EventAgent { 
    
    add_header Content-Type 'text/html; charset=utf-8';

       set $log_name '';
           rewrite_by_lua_block {
                local var = ngx.var
                    local request_method = ngx.var.request_method
                    if request_method == "GET" then
                    if(ngx.var.arg_appkey ~= nil and ngx.var.arg_ltype ~= nil) then
                            ngx.var.log_name = ngx.var.arg_appkey.."_"..ngx.var.arg_ltype
                else
                ngx.var.log_name='access'
                end
                    elseif request_method == "POST" then
                            ngx.req.read_body()
                ngx.var.log_name='old_post'
                    end
            }
 
        if ($request_method = "GET") {
        access_log  /data/log/nginx/$log_name.log  access_get ;
        }

        if ($request_method = "POST") {
        access_log  /data/log/nginx/$log_name.log  access_post ;
        }
    
         #return 200 '{"success":true,"status":1,"message":"成功"}';

        default_type 'application/json';
        
        content_by_lua_block {
        ngx.req.read_body()
        ngx.say("{success:200}")
        }
        }
    
    location /statistics/log {  
    add_header Content-Type 'text/html; charset=utf-8';
        access_log  /data/log/nginx/h5.log  access_get ;
        default_type 'application/json';
    return 200 '{"success":200}';
        }      
    location /status {
            vhost_traffic_status_display;
            vhost_traffic_status_display_format html;
        access_log off;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
    vhost_traffic_status_zone shared:vhost_traffic_status:24m;  
}

通过修改后的nginx.conf配置,nginx启动之后日志分类很完美。

分类日志.png

lua的功能还有很多,执行速度也很快,非常适合在其他组件中作为嵌套代码执行,继续学习分享中...

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018.12.14 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Lua简介
  • nginx.conf结合lua编程实现逻辑处理
  • nginx个性化需求
相关产品与服务
负载均衡
负载均衡(Cloud Load Balancer,CLB)提供安全快捷的流量分发服务,访问流量经由 CLB 可以自动分配到云中的多台后端服务器上,扩展系统的服务能力并消除单点故障。负载均衡支持亿级连接和千万级并发,可轻松应对大流量访问,满足业务需求。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档