<服务>集成常用nginx模块的nginx——openresty

时间:May 14, 2017 分类:

目录:

我选用openresty是因为需要给nginx添加nginx_lua的模块,首先openresty可以理解为已经添加了lua相关模块的nginx。

官方介绍

openresty汇聚了精良的Nginx模块,从而将Nginx有效的变为一个强大的web应用平台,使用lua脚本语言调动Nginx支持的各种C和Lua模块

openresty官方文档

https://openresty.org/cn/

安装openresty

下载

[root@why program]# wget https://openresty.org/download/openresty-1.11.2.3.tar.gz --no-check-certificate
 --prefix=/usr/local/openresty

1.11.2.3版本是截止到17年5月13日,如果距离这天久远可以去官网下载最新的版本

安装依赖

[root@why program]# yum install readline-devel pcre-devel openssl-devel gcc

安装

[root@why program]# tar xf openresty-1.11.2.3.tar.gz 
[root@why program]# cd openresty-1.11.2.3
[root@why openresty-1.11.2.3]# ./configure --prefix=/opt/openresty             --with-luajit             --without-http_redis2_module              --with-http_iconv_module
[root@why openresty-1.11.2.3]# gmake
[root@why openresty-1.11.2.3]# gmake install

这样就安装完成了,和nginx编译类似,--with是添加模块,--without是不添加模块

可以看到安装了luajit和nginx

[root@why openresty-1.11.2.3]# cd /opt/openresty/
[root@why openresty]# ll
total 232
drwxr-xr-x  2 root root   4096 May 13 20:26 bin
drwxr-xr-x  6 root root   4096 May 13 20:26 luajit
drwxr-xr-x  6 root root   4096 May 13 20:26 lualib
drwxr-xr-x  6 root root   4096 May 13 20:26 nginx
drwxr-xr-x 43 root root   4096 May 13 20:26 pod
-rw-r--r--  1 root root 210365 May 13 20:26 resty.index
drwxr-xr-x  5 root root   4096 May 13 20:26 site

nginx+lua

文档案例均来自https://github.com/openresty/lua-nginx-module#status,如果愿意摸索可以去直接去github自行实践。

nginx+lua的hello world

添加测试目录

测试目录是为了不修改原有的openresty,也可以直接修改openresty中nginx的配置文件

[root@why openresty]# mkdir test test/logs test/conf
[root@why openresty]# tree test/
test/
├── conf
└── logs

2 directories, 0 files

配置文件

[root@why openresty]# cd test/conf/
[root@why conf]# vi nginx.conf
worker_processes  1;        #nginx worker 数量
error_log logs/error.log;   #指定错误日志文件路径
events {
    worker_connections 1024;
}

http {
    server {
        #监听端口,若你的端口已经被占用,则需要修改
        listen 82;
        location / {
            default_type text/html;
            content_by_lua_block {
                ngx.say("HelloWorld")
            }
        }
    }
}

ngx.say是打印输出的意思

启动服务

[root@why conf]# /opt/openresty/nginx/sbin/nginx -p /opt/openresty/test/
[root@why conf]# ss -nlpt | grep 82
LISTEN     0      128                       *:82                       *:*      users:(("nginx",17192,6),("nginx",17193,6))

通过浏览器访问

通过curl访问

[root@why conf]# curl 121.42.37.139:82
HelloWorld
[root@why conf]# curl 121.42.37.139:82 -i
HTTP/1.1 200 OK
Server: openresty/1.11.2.3
Date: Sat, 13 May 2017 13:09:14 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive

HelloWorld

获取url变量

修改配置文件

        location /nginx_var {
            default_type text/html;
            content_by_lua_block {
            ngx.say(ngx.var.arg_a)
            }

将url参数传递过来,通过ngx.var.arg_a使用传递来的参数a

检验

[root@why conf]# /opt/openresty/nginx/sbin/nginx -p /opt/openresty/test/ -s reload

[root@why conf]# curl 121.42.37.139:82/nginx_var?a=HelloWorld
HelloWorld
[root@why conf]# curl 121.42.37.139:82/nginx_var
nil

如果没有参数传递过来,就会返回nil,在lua中代表空

另一种获取方式

修改配置文件

        location ~ ^/app/([-_a-zA-Z0-9/]+) {
            set $path $1;
            content_by_lua_block {
            ngx.say(ngx.var.path)
            }
     }

检验

[root@why conf]# curl 121.42.37.139:82/app/HelloWorld
HelloWorld
[root@why conf]# curl 121.42.37.139:82/app
<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>openresty/1.11.2.3</center>
</body>
</html>

流水线处理

    location ~ ^/app/([-_a-zA-Z0-9/]+) {
        set $path $1;
        content_by_lua_block {
        ngx.exec("/apps/"..ngx.var.path)
        }
    }
    location /apps/a {
        default_type text/html;
        content_by_lua_block {
        ngx.say("HelloWorld")
        }
    }

..用于字符串连接

ngx.exec方法与下方的外部重定向使用的ngx.redirect是完全不同的,ngx.exec是纯粹的内部跳转并且没有引入任何额外http信号,第一个location处理完,交给第二个location处理。这样就可以做多层的过滤,根据各层的策略进行处理,可以用于不同的API或者下载请求。

需要注意的是,nginx的var内容需要仔细的进行过滤,否则会有很大的风险。

当然如果要执行lua脚本就使用content_by_lua_file /path/to/lua/app/root/$path.lua;

检验

[root@why conf]# /opt/openresty/nginx/sbin/nginx -p /opt/openresty/test/ -s reload
[root@why conf]# curl 121.42.37.139:82/app/a
HelloWorld
[root@why conf]# curl 121.42.37.139:82/app/b
<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>openresty/1.11.2.3</center>
</body>
</html>

lua与nginx的location配合

内部调用

内部调用会使用在例如数据库,内部公共函数的统一接口,可以把它们放在统一的location中,并且设置为internal,可以让这个内部接口相对独立不受外界干扰。

修改配置文件

location = /sum {
    internal;                       #内部调用
    content_by_lua_block {
        ngx.sleep(0.1)              #暂停0.1秒,用于下面测试
        local args = ngx.req.get_uri_args()
        ngx.print(tonumber(args.a) + tonumber(args.b))      #对两个参数求和
    }
}

location = /subduction {
    internal;
    content_by_lua_block {
        ngx.sleep(0.1)
        local args = ngx.req.get_uri_args()
        ngx.print(tonumber(args.a) - tonumber(args.b))      #对两个参数求差值
    }
}

location = /app/test_parallels {
    content_by_lua_block {
        local start_time = ngx.now()
        local res1, res2 = ngx.location.capture_multi( {
                        {"/sum", {args={a=3, b=8}}},
                        {"/subduction", {args={a=3, b=8}}}
                    })
        ngx.say("status:", res1.status, " response:", res1.body)
        ngx.say("status:", res2.status, " response:", res2.body)
        ngx.say("time used:", ngx.now() - start_time)
    }
}

location = /app/test_queue {
    content_by_lua_block {
        local start_time = ngx.now()
        local res1 = ngx.location.capture_multi( {
                        {"/sum", {args={a=3, b=8}}}
                    })
        local res2 = ngx.location.capture_multi( {
                        {"/subduction", {args={a=3, b=8}}}
                    })
        ngx.say("status:", res1.status, " response:", res1.body)
        ngx.say("status:", res2.status, " response:", res2.body)
        ngx.say("time used:", ngx.now() - start_time)
    }
}

检验

[root@why conf]# curl 121.42.37.139:82/app/test_queue
status:200 response:11
status:200 response:-5
time used:0.20099997520447
[root@why conf]# curl 121.42.37.139:82/app/test_parallels
status:200 response:11
status:200 response:-5
time used:0.099999904632568

利用ngx.location.capture_multi函数可以直接完成两个请求并行执行,当两个请求没有相互依赖的情况下,可以大幅提高查询效率。上述的案例,两个无依赖的请求,各自是0.1s,顺序执行需要0.2s,但是通过并行执行可以在0.1s内完成两个请求。参考下图。

外部重定向

修改配置文件

[root@why conf]# cp nginx.conf nginx.conf.helloworld
[root@why conf]# vi nginx.conf

                location = /foo {
                    content_by_lua_block {
                        ngx.say([[I am foo]])
                    }
                }

                location = / {
                    rewrite_by_lua_block {
                        return ngx.redirect('/foo');
                    }
                }

通过curl查看

[root@why conf]# curl 127.0.0.1:82 -i
HTTP/1.1 302 Moved Temporarily
Server: openresty/1.11.2.3
Date: Sat, 13 May 2017 16:24:44 GMT
Content-Type: text/html
Content-Length: 167
Connection: keep-alive
Location: /foo

<html>
<head><title>302 Found</title></head>
<body bgcolor="white">
<center><h1>302 Found</h1></center>
<hr><center>openresty/1.11.2.3</center>
</body>
</html>
[root@why conf]# curl 127.0.0.1:82/foo -i
HTTP/1.1 200 OK
Server: openresty/1.11.2.3
Date: Sat, 13 May 2017 16:24:49 GMT
Content-Type: text/plain
Transfer-Encoding: chunked
Connection: keep-alive

I am foo

浏览器访问

通过lua,我们实现了rewrite功能,当访问127.0.0.1:82的时候,通过302的方式rewrite到127.0.0.1:/foo。并且外部重定向,可以是跨域名的实现,在CDN场景的大量下载应用,一般分为调度和存储两个重要环节,调度的话是根据请求方的IP地址,下载的文件等信息寻找最近最快的节点,应答跳转请求。

跨域名实现

修改配置文件

                location = /foo {
                    content_by_lua_block {
                        ngx.say([[I am foo]])
                    }
                }

                location = / {
                    rewrite_by_lua_block {
                        return ngx.redirect('http://www.whysdomain.com');
                    }
                }

浏览器查看

还有一些没看懂的案例,先提供链接,留作以后查看https://moonbingbing.gitbooks.io/openresty-best-practices/content/