`
风过无声
  • 浏览: 92090 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Nginx 配置指令的执行顺序(四)access_by_lua & 性能比较 (转载)

 
阅读更多

转载自 http://blog.sina.com.cn/openresty

 

ngx_lua 模块提供了配置指令 access_by_lua,用于在 access 请求处理阶段插入用户 Lua 代码。这条指令运行于 access 阶段的末尾,因此总是在 allow 和 deny 这样的指令之后运行,虽然它们同属 access 阶段。一般我们通过 access_by_lua 在 ngx_access 这样的模块检查过客户端 IP 地址之后,再通过 Lua 代码执行一系列更为复杂的请求验证操作,比如实时查询数据库或者其他后端服务,以验证当前用户的身份或权限。

 

    我们来看一个简单的例子,利用 access_by_lua 来实现 ngx_access 模块的 IP 地址过滤功能:

    location /hello {

        access_by_lua '

            if ngx.var.remote_addr == "127.0.0.1" then

                return

            end

 

            ngx.exit(403)

        ';

 

        echo "hello world";

    }

这里在 Lua 代码中通过引用 Nginx 标准的内建变量 $remote_addr 来获取字符串形式的客户端 IP 地址,然后用 Lua 的 if 语句判断是否为本机地址,即是否等于 127.0.0.1. 如果是本机地址,则直接利用 Lua 的 return 语句返回,让 Nginx 继续执行后续的请求处理阶段(包括 echo 指令所处的 content 阶段);而如果不是本机地址,则通过 ngx_lua 模块提供的 Lua 函数 ngx.exit 中断当前的整个请求处理流程,直接返回 403 错误页给客户端。

 

    这个例子在功能上完全等价于先前在 (三) 中介绍过的那个使用 ngx_access 模块的例子:

    location /hello {

        allow 127.0.0.1;

        deny all;

 

        echo "hello world";

    }

虽然这两个例子在功能上完全相同,但在性能上还是有区别的,毕竟 ngx_access 是用纯 C 实现的专门化的 Nginx 模块。

 

    下面我们不妨来实际测量一下这两个例子的性能差别。因为我们使用 Nginx 就是为了追求性能,而量化的性能比较,在工程上具有很大的现实意义,所以我们顺便介绍一下重要的测量技术。由于无论是 ngx_access 还是 ngx_lua 在进行 IP 地址验证方面的性能都非常之高,所以为了减少测量误差,我们希望能对 access 阶段的用时进行直接测量。为了做到这一点,传统的做法一般会涉及到修改 Nginx 源码,自己插入专门的计时代码和统计输出代码,抑或是重新编译 Nginx 以启用像 GNU gprof 这样专门的性能监测工具。

 

    幸运的是,在新一点的 Solaris, Mac OS X, 以及 FreeBSD 等系统上存在一个叫做 dtrace 的工具,可以对任意的用户程序进行微观性能分析(以及行为分析),而无须对用户程序的源码进行修改或者对用户程序进行重新编译。因为 Mac OS X 10.5 以后就自带了 dtrace,所以为方便起见,下面在我的 MacBook Air 笔记本上演示一下这里的测量过程。

 

    首先,在 Mac OS X 系统中打开一个命令行终端,在某一个文件目录下面创建一个名为 nginx-access-time.d 的文件,并编辑内容如下:

    #!/usr/bin/env dtrace -s

 

    pid$1::ngx_http_handler:entry

    {

        elapsed = 0;

    }

 

    pid$1::ngx_http_core_access_phase:entry

    {

        begin = timestamp;

    }

 

    pid$1::ngx_http_core_access_phase:return

    /begin > 0/

    {

        elapsed += timestamp - begin;

        begin = 0;

    }

 

    pid$1::ngx_http_finalize_request:return

    /elapsed > 0/

    {

        @elapsed = avg(elapsed);

        elapsed = 0;

    }

保存好此文件后,再赋予它可执行权限:

    $ chmod +x ./nginx-access-time.d

这个 .d 文件中的代码是用 dtrace 工具自己提供的 D 语言来编写的(注意,这里的 D 语言并不同于 Walter Bright 作为另一种“更好的 C++”而设计的 D 语言)。由于本系列教程并不打算介绍如何编写 dtrace 的 D 脚本,同时理解这个脚本需要不少有关 Nginx 内部源码实现的细节,所以这里我们不展开介绍。大家只需要知道这个脚本的功能是:统计指定的 Nginx worker 进程在处理每个请求时,平均花费在 access 阶段上的时间。

 

    现在来演示一下这个 D 脚本的运行方法。这个脚本接受一个命令行参数用于指定监视的 Nginx worker 进程的进程号(pid)。由于 Nginx 支持多 worker 进程,所以我们测试时发起的 HTTP 请求可能由其中任意一个 worker 进程服务。为了确保所有测试请求都为固定的 worker 进程处理,不妨在 nginx.conf 配置文件中指定只启用一个 worker 进程:

    worker_processes 1;

重启 Nginx 服务器之后,可以利用 ps 命令得到当前 worker 进程的进程号:

    $ ps ax|grep nginx|grep worker|grep -v grep

在我机器上的一次典型输出是

    10975   ??  S      0:34.28 nginx: worker process

其中第一列的数值便是我的 nginx worker 进程的进程号,10975。如果你得到的输出不止一行,则通常意味着你的系统中同时运行着多个 Nginx 服务器实例,或者当前 Nginx 实例启用了多个 worker 进程。

 

    接下来使用刚刚得到的 worker 进程号以及 root 身份来运行 nginx-access-time.d 脚本:

    $ sudo ./nginx-access-time.d 10975

如果一切正常,则会看到这样一行输出:

    dtrace: script './nginx-access-time.d' matched 4 probes

这行输出是说,我们的 D 脚本已成功向目标进程动态植入了 4 个 dtrace “探针”(probe)。紧接着这个脚本就挂起了,表明 dtrace 工具正在对进程 10975 进行持续监视。

 

    然后我们再打开一个新终端,在那里使用 curl 这样的工具多次请求我们正在监视的接口

    $ curl 'http://localhost:8080/hello'

    hello world

 

    $ curl 'http://localhost:8080/hello'

    hello world

最后我们回到原先那个一直在运行 D 脚本的终端,按下 Ctrl-C 组合键中止 dtrace 的运行。而该脚本在退出时会向终端打印出最终统计结果。例如我的终端此时是这个样子的:

    $ sudo ./nginx-access-time.d 10975

    dtrace: script './nginx-access-time.d' matched 4 probes

    ^C

           19219

最后一行输出 19219 便是那几次 curl 请求在 access 阶段的平均用时(以纳秒,即 10 的负 9 次方秒为单位)。

 

    通过上面介绍的步骤,可以通过 nginx-access-time.d 脚本分别统计出各种不同的 Nginx 配置下 access 阶段的平均用时。针对我们感兴趣的三种情况可以进行三组平行试验,即使用 ngx_access 过滤 IP 地址的情况,使用 access_by_lua 过滤 IP 地址的情况,以及不在 access 阶段使用任何配置指令的情况。最后一种情况属于“空白对照组”,用于校正测试过程中因 dtrace 探针等其他因素而引入的“系统误差”。另外,为了最小化各种不可控的“随机误差”,可以用 ab 这样的批量测试工具来取代 curl 发起连续十万次以上的请求,例如

    $ ab -k -c1 -n100000 'http://127.0.0.1:8080/hello'

这样我们的 D 脚本统计出来的平均值将更加接近“真实值”。

 

    在我的苹果系统上,一次典型的测试结果如下:

    ngx_access 组               18146

    access_by_lua 组            35011

    空白对照组                   15887

把前两组的结果分别减去“空白对照组”的结果可以得到

    ngx_access 组               2259

    access_by_lua 组           19124

可以看到,ngx_access 组比 access_by_lua 组快了大约一个数量级,这正是我们所预期的。不过其绝对时间差是极小的,对于我的 Intel Core2Duo 1.86 GHz 的 CPU 而言,也只有区区十几微秒,或者说是在十万分之一秒的量级。

 

    当然,上面使用 access_by_lua 的例子还可以通过换用 $binary_remote_addr 内建变量进行优化,因为 $binary_remote_addr 读出的是二进制形式的 IP 地址,而 $remote_addr 则返回更长一些的字符串形式的地址。更短的地址意味着用 Lua 进行字符串比较时通常可以更快。

 

    值得注意的是,如果按 (一) 中介绍的方法为 Nginx 开启了“调试日志”的话,上面统计出来的时间会显著增加,因为“调试日志”自身的开销是很大的。

    

分享到:
评论

相关推荐

    lua-nginx-module-0.10.13

    Lua-Nginx-Module,简称lua-nginx-module,是Nginx服务器的一个重要扩展模块,它将强大的Lua脚本语言集成到Nginx中,允许用户在Nginx配置文件中直接编写Lua代码,极大地增强了Nginx的功能性和灵活性。版本0.10.13是...

    Nginx的error_log和Access_log分析.docx

    access_log 指令可以在 Nginx 配置文件的多个级别中配置,包括主配置文件、服务器配置文件和_location_ 配置文件。 Nginx 中的日志系统非常复杂,需要深入了解 Nginx 的配置机制和日志机制。Nginx 的日志系统可以...

    nginx_upload_module 加lua 实现上传

    1. 安装和配置Nginx:首先确保Nginx已经安装,并且添加了`nginx_upload_module`和`ngx_lua`模块。这通常涉及到编译Nginx源码并添加模块选项。 2. 配置`nginx.conf`:在Nginx配置文件中,定义一个location块来处理...

    lua-upstream-nginx-module, Nginx C 模块将Lua向ngx_lua公开,用于 Nginx upstreams.zip

    lua-upstream-nginx-module, Nginx C 模块将Lua向ngx_lua公开,用于 Nginx upstreams 电子邮件名称ngx_http_lua_upstream - Nginx MODULE,用于向 Nginx upstreams公开Lua到 ngx_lua目录NAME状态概要说明函数get_...

    lua+nginx动态更新配置.zip

    在nginx初始化中使用init_worker_by_lua_file 指令创建一个循环定时器,每次超时的时候去判断配置文件是否更新了。如果更新了重新加载。 通过在工作线程中使用rewrite_by_lua_block指令,获取任意时刻的配置情况测试...

    nginx_limit_access_module.zip

    nginx_limit_access_module - 可通过指定的 HTTP POST 接口中的值来拒绝请求。 示例配置: http { limit_access_zone zone=one:5m bucket_number=10007 type=ip; server { listen 80; server_name ...

    nginx流媒体安装包(nginx_mod_h264_streaming,yamdi)

    Nginx,作为一个高性能的Web服务器和反向代理服务器,因其高效的并发处理能力和轻量级的特性,常被用于搭建流媒体服务器。而Yamdi(Yet Another MP4 Demuxer)则是一个辅助工具,用于处理H.264编码的MP4视频,使其能...

    Nginx-ngx_lua模块原理和内置函数.docx

    - **rewrite_by_lua / rewrite_by_lua_file / access_by_lua / access_by_lua_file / header_filter_by_lua / header_filter_by_lua_file / body_filter_by_lua / body_filter_by_lua_file:** - 这些指令用于处理...

    跟我学Nginx+Lua开发_nginxlua原理_nginx_

    《跟我学Nginx+Lua开发》这本书主要探讨了如何利用Nginx与Lua进行高效、灵活的Web服务开发。Nginx以其高性能、反向代理和负载均衡能力而闻名,而Lua则是一种轻量级的脚本语言,两者结合可以实现强大的服务器端功能。...

    Nginx安装+nginx_upstream_check_module后端健康检查

    ### Nginx安装与后端健康检查模块配置详解 #### 一、Nginx环境搭建与核心组件安装 **1.1 基础环境准备** - **操作系统**: CentOS 6.5 - **基本服务器配置**: 在安装过程中选择了“基本服务器”配置。 **1.2 安装...

    lua-nginx-module完全指南.docx

    此外,`init_by_lua*`系列指令在Nginx工作进程启动时执行,常用于全局变量的初始化和配置。`init_worker_by_lua*`则在每个工作进程启动时运行,适合做进程级的初始化操作,确保每个工作进程都有独立的初始化环境。 ...

    lua-nginx-module-0.10.9rc7

    例如,使用`lua_code_cache on|off`来控制Lua代码缓存策略,用`set_by_lua_file`或`access_by_lua_file`等指令执行Lua脚本。 4. **测试与启动**:在修改配置后,务必先运行`nginx -t`测试配置文件的正确性,无误后...

    ngx_lua_module-windows-1.1.2.0

    ngx_lua_module是一款强大的扩展模块,专为Nginx服务器设计,允许在Nginx配置文件中直接嵌入Lua脚本,极大地增强了Nginx的功能和灵活性。这个"ngx_lua_module-windows-1.1.2.0"是该模块的一个Windows版本,适应于...

    Nginx配置文件详细说明

    在此记录下Nginx服务器nginx.conf的配置文件说明, 部分注释收集与网络. #运行用户 user www-data; #启动进程,通常设置成和cpu的数量相等 worker_processes 1; #全局错误日志及PID文件 error_log /var/log/...

    nginx-accesskey

    Nginx 和 Tengine 作为广泛应用的高性能 Web 服务器,提供了丰富的模块来扩展其功能,其中 ngx_http_accesskey_module 是一个用于实现下载文件防盗链的第三方模块。这个模块可以通过在请求头中设置特定的 access key...

    ngx_lua_waf-master.zip_lua_nearly11h_nginx_ngx_lua_waf

    ngx_lua_waf是一个基于Nginx的Web应用防火墙,其核心是利用了Nginx的ngx_lua模块,通过Lua脚本实现灵活且强大的安全防护功能。ngx_lua_waf项目名称中的“master”通常指的是该项目的主分支或最新版本。"nearly11h...

    nginx配置lua所需组件

    此外,`lua_shared_dict`可以用来在Nginx实例间共享数据,`lua休息`用于设置定时任务,`log_by_lua`允许在日志记录中使用Lua,而`rewrite_by_lua`则可以在重写规则中执行Lua代码。 为了调试和优化Lua脚本,还可以...

    nginx实战-基于lua语言

    1. **Nginx配置中的Lua**:在Nginx配置文件中,使用`location`块定义 Lua 脚本的入口点,例如`content_by_lua_file`指令指定Lua脚本文件。 2. ** ngx_lua API**:Nginx提供了一系列的Lua API接口,如`ngx.req.get_...

    lua-nginx插件

    在Nginx配置文件中,使用`lua_code_cache`指令来决定是否缓存Lua代码,以及`set_by_lua*`、`access_by_lua*`、`content_by_lua*`等指令将Lua脚本插入到不同的请求阶段。通过这种方式,开发者可以直接在Nginx配置...

Global site tag (gtag.js) - Google Analytics