专栏首页Java进阶之路nginx联合lua打造大数据日志采集系统个性化需求

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

上篇文章介绍了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:
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{}上先根据

fmt_localtime参数。

  • 日志格式中[

fmt_localtime

  • 根据lua获取到nginx的所有参数将ngx.localtime()赋值给$fmt_localtime
 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处理阶段的最后。
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代码块将返回值打印出来。
content_by_lua_block {
        ngx.req.read_body()
        ngx.say("{success:200}")
        }

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

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 程序员如何更有效得学习

    对于程序员,我们对自己以及自己从事的工作,应该给一个准确清晰的定位,至少你要清楚,你是一个程序员,在你拿着高薪工作的时候,你要为这份工作付出很多,包括时间、经历...

    神秘的寇先森
  • python工程结构

    在一个健康的开发周期中,代码风格,API设计和自动化是非常关键的。同样的,对于工程的架构 ,仓库的结构也是关键的一部分。 当一个潜在的用户和贡献者登录到您的仓...

    神秘的寇先森
  • Flink窗口触发器

    窗口的触发器定义了窗口是何时被触发并同时决定触发行为(对窗口进行清理或者计算)。触发器确定窗口(由窗口分配程序形成)何时准备由窗口函数处理。每个WindowAs...

    神秘的寇先森
  • linux每日命令(13):more命令

    more命令,功能类似 cat ,cat命令是整个文件的内容从上到下显示在屏幕上。 more会以一页一页的显示方便使用者逐页阅读,而最基本的指令就是按空白键(s...

    用户1214487
  • 外卖系统产品思考

      外卖产品下单到收货参与到的角色有用户、商家、骑手、以及平台系统;这四个角色和角色各个对应的场景活动构成了外卖产品的业务流程。

    用户2108620
  • 为什么它能成为SaaS界的新贵?

    ? 来源 :ToBeSaaS  作者:戴珂 ---- 几天前,圈里有朋友请我分析一下SaaS界的新贵Snowflake。 文章写完好几天了也没发布,因为看...

    腾讯SaaS加速器
  • JS 变量作用域导致的一个坑

    路过君
  • 打造属于自己的支持版本迭代的Asp.Net Web Api Route

        在目前的主流架构中,我们越来越多的看到web Api的存在,小巧,灵活,基于Http协议,使它在越来越多的微服务项目或者移动项目充当很好的service...

    脑洞的蜂蜜
  • javascript dom学习笔记

    http://blog.csdn.net/zhoulenihao/article/details/11099455

    bear_fish
  • 手把手教你在腾讯云上搭建hive3.1.2的方法

    所有操作开始前,先确定hadoop版本已经装好。具体可以看我的另一篇博客 搭建hadoop3.x

    砸漏

扫码关注云+社区

领取腾讯云代金券