生产环境中 Ngx_lua 使用技巧和应用的范例

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介:

Lua的性能超牛的,这个不需要再啰嗦了。。。


Nginx_lua的适用场景


  1. 网络I/O 阻塞时间远高于CPU 计算占用时间、同时上游资源非瓶颈(可伸缩)的网络应用,如高性能网络中间层、HTTP REST 接口服务等;

  2. 期望简化系统架构,让服务向Nginx 同质化的Web 站点;




优势:

  • 同步非阻塞I/O 形式直观易懂,并发服务能力强

  • CPU、内存运行开销低

  • 同Nginx 结合度高,可方便粘合现有Nginx 模块功能

劣势:

  • 属于新技术方案,Lua 相比于PHP、Ruby 等广泛使用的开发

  • 语言,周边附属设施尚不够健全,需要时间积累




安装就简单过一遍,其实大家用openresty就行啦。。。  作者已经做了很多的调优。。。

还是推荐大家用 openresty。。。 最少在测试环境下用这个,可以省去很多找模块,折腾模块的时间。。。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
1 .下载nginx
wget http: //nginx.org/download/nginx-1.2.2.tar.gz
2 .安装gcc
sudo apt- get  install gcc
3 .下载LuaJIT
wget http: //luajit.org/download/LuaJIT-2.0.0-beta10.tar.gz
4 . 安装LuaJIT
tar -xzvf  LuaJIT- 2.0 . 0 -beta10.tar.gz
cd LuaJIT- 2.0 . 0 -beta10
make && sudo make install
5 .下载 ngx_devel_kit(在这个页面找:https: //github.com/simpl/ngx_devel_kit/tags)
wget https: //github.com/simpl/ngx_devel_kit/tarball/master -O simpl-ngx_devel_kit.tar.gz
6 .下载最新的 lua-nginx-module(在这个页面找:https: //github.com/chaoslawful/lua-nginx-module/tags)
  wget https: //github.com/chaoslawful/lua-nginx-module/tarball/master -O lua-nginx-module.tar.gz
7 .下载pcre
wget ftp: //ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.31.tar.gz
tar -xzvf pcre- 8.31 .tar.gz
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
  ./configure && make(如果报“compile: unrecognized option `-DHAVE_CONFIG_H'”,请安装sudo apt- get  install build-essential)
sudo make install
8 .下载echo模块
wget https: //github.com/agentzh/echo-nginx-module/tarball/master -O echo-nginx-module.tar.gz
  tar -xzvf echo-nginx-module.tar.gz
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
7 . 解压nginx,ngx_devel_kit, lua-nginx-module
tar -xzvf nginx- 1.2 . 2 .tar.gz
tar -xzvf simpl-ngx_devel_kit.tar.gz
  tar -xzvf lua-nginx-module.tar.gz
8 .安装
sudo apt- get  install openssl libssl-dev
sudo apt- get  install libtool
cd  nginx- 1.2 . 2
export LUAJIT_LIB=/usr/local/lib/
export LUAJIT_INC=/usr/local/ include /luajit- 2.0
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
./configure --user=www-data --group=www-data -- with -debug -- with -http_gzip_static_module -- with -http_ssl_module  -- with -http_stub_status_module -- with -http_realip_module \
--prefix=/usr/local/nginx \
     --add-module=../simpl-ngx_devel_kit-4192ba6/ \
   --add-module=../chaoslawful-lua-nginx-module-b771a2e/\
     --add-module=../agentzh-echo-nginx-module-8042c62/
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
make -j2
sudo make install




一定要注意他的执行顺序

  1. Rewrite phase.

  2. Access phase.

  3. Content phase.


详细的步骤:


1
2
3
4
5
6
7
8
1 .init_by_lua  上下文http  ngx启动时执行
2 . set_by_lua  上下文 server, server  if , location, location  if
3 .rewrite_by_lua 上下文  http, server, location, location  if
4 .access_by_lua 上下文 http, server, location, location  if
5 .content_by_lua 上下文   location, location  if
6 .header_filter_by_lua 上下文   http, server, location, location  if
7 .body_filter_by_lua 上下文 http, server, location, location  if
8 .log_by_lua 上下文 http, server, location, location  if




咱们再过滤post、get请求或者是触发了某个access、rewrite,如果发现恶意和违规的侵入的话,可以发邮件报警,好让我们第一时间收到邮件的信息。。。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
location  =  / smtp {
         default_type  "text/plain" ;
         content_by_lua '
             local smtp  =  require( "socket.smtp" )
             local  from  =  "<ruifengyunceshi@163.com>"
             local  rcpt  =  {"",}
             local   mesgt  =  {
             headers  =  {
             to  =  "",  - -  收件人
             subject  =  "This is Mail Title"
             },
         body  =  "This is  Mail Content."
     }
      local  r, e  =  smtp.send{
         server = "smtp.163.com" ,
         user = "",
         password = "",
         from  =  from ,
         rcpt  =  rcpt,
         source  =  smtp.message(mesgt)
       }
     if  not  r then
         ngx.say(e)
     else
         ngx.say( "send ok!" )
     end
     ';
     }


lua这东西挺怪的,他的双引号和单引号是有很大区别的,我到现在也没搞明白,啥区别,反正用双引号就对了。。。有事error.log报错的话,改成单引号试试。。

好点的方法是  先在lua的环境中跑一边,ok后,在放到ngx_lua里面。


Lua有丰富的接口的方案,不只是给别人提供的接口,还有他自己访问别的接口所用的模块。


如果你的同事那边已经有个高性能的socket接口,那你就别麻烦他改成rest模式了。。。 毕竟socket对socket速度很快的。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
location /cosocket {
         default_type  "text/plain" ;
         content_by_lua '
         local sock = ngx.socket.tcp()
         sock:settimeout( 1000 )
         local ok, err = sock:connect( "127.0.0.1" 12000 )
         if  not ok then
             ngx.say( "failed to connect: " , err)
             return
         end
         local bytes, err = sock:send( "flush_all" )
         ngx.say(bytes,err)
         if  not bytes then
             ngx.say( "failed to send query: " , err)
             return
         end
        local line, err = sock:receive()
         if  not line then
             ngx.say( "failed to receive a line: " , err)
             return
         end
         ngx.say( "result: " , line)
         ';
       }
                                                                                                                                                                                                                                                                                                                                                                                       
     }
}



对于给别人的mysql查询,给账号密码不合适,和一个小权限的账号密码也不合适。

这种情况,我们要是求高性能的话,可以用lua配置cjson做成rest接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
location /select2 {
content_by_lua '
local mysql = require  "resty.mysql"
local db,err = mysql: new ()
if  not db then
ngx.say( "failed to instantiate mysql: " ,err)
return
end
db:set_timeout( 1000 )
local ok,err,errno,sqlstate = db:connect{
host =  "127.0.0.1" ,
port =  3306 ,
database =  "niubi" ,
user =  "ruifengyun" ,
password =  "" ,
max_package_size =  1024
}
if  not ok then
ngx.say( "failed to connect: " , err,  ": " , errno,  " " , sqlstate)
return
end
ngx.say( "connected to mysql." )
res,err,errno,sqlstate = db:query( "select username,password from users where id=" ..ngx. var .arg_id)
if  not res then
ngx.say( "bad result: " , err,  ": " , errno,  ": " , sqlstate,  "." )
return
end
local cjson = require  "cjson"
ngx.say("result: “,cjson.encode(res))
';
}

113443887.jpg




咱们既然知道了 lua的强大之处, 可以从lua里面搞负载均衡。

往redis里面 扔两个key   比如 web1 8.8.8.111  web2 8.8.8.222

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
server {
   listen  80 ;
   server_name _;
   server_name_in_redirect off;
   port_in_redirect off;
   root /root/html;
   location / {
     set  $upstream  "" ;
     rewrite_by_lua '
       local routes = _G.routes
       -- setup routes cache  if  empty
       if  routes == nil then
         routes = {}
         ngx.log(ngx.ALERT,  "Route cache is empty." )
       end
       --  try  cached route first      local route = routes[ngx. var .http_host]
       if  route == nil then
         local redis  = require  "redis"
         local client = redis.connect( "localhost" 6379 )
         route        = client: get (ngx. var .http_host)
       end
       if  route ~= nil then
         ngx. var .upstream = route
         routes[ngx. var .http_host] = route
         _G.routes = routes
       else
         ngx.exit(ngx.HTTP_NOT_FOUND)
       end
     ';
     proxy_buffering             off;
     proxy_set_header            Host $host;
     proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;
     proxy_redirect              off;
     proxy_connect_timeout        10 ;
     proxy_send_timeout           30 ;
     proxy_read_timeout           30 ;
     proxy_pass                  http: //$upstream;
   }
}


用lua 对cookie的控制


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
header_filter_by_lua '
         t = {}
         if  ngx. var .http_cookie then
             s = ngx. var .http_cookie
             for  k, v  in  string.gmatch(s,  "(%w+)=([%w%/%.=_-]+)" do
                 t[k] = v
             end
         end
                                                   
         p = ngx.req.get_uri_args()
                                                   
         if  not t.uid and p.uid then
             expires = ngx.cookie_time( 4523969511 )
             ngx.header[ "Set-Cookie" ] = { "uid="  .. p.uid .. "; expires="  .. expires .. ";
         end
                                                   
';




 本文转自 rfyiamcool 51CTO博客,原文链接:http://blog.51cto.com/rfyiamcool/1252501,如需转载请自行联系原作者

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
测试技术 C语言
wrk(2)- Lua 脚本的使用
wrk(2)- Lua 脚本的使用
785 0
wrk(2)- Lua 脚本的使用
|
5月前
|
应用服务中间件 nginx
nginx中handle模块的编写小案例
nginx中handle模块的编写小案例
nginx中handle模块的编写小案例
配置Lua环境
配置Lua环境
119 0
|
JavaScript PHP
PHP从零开始--错误处理&&函数
PHP从零开始--错误处理&&函数
PHP从零开始--错误处理&&函数
|
存储 Java C语言
Lua 基础
Lua 基础语法及示例
568 0
Lua 基础
|
测试技术 C#
Lua基本语法-lua脚本与C#的交互(相当简单详细的例子)
lua脚本 与 C#的交互 本文提供全流程,中文翻译。Chinar坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 —— 高分辨率用户请根据需求调整网页缩放比例) ...
1381 0
|
NoSQL Linux 测试技术
Redis进阶实践之八Lua的Cjson在Linux下安装、使用和用C#调用Lua脚本
原文:Redis进阶实践之八Lua的Cjson在Linux下安装、使用和用C#调用Lua脚本 一、引言         学习Redis也有一段时间了,感触还是颇多的,但是自己很清楚,路还很长,还要继续。
2723 0
|
应用服务中间件 nginx 索引

热门文章

最新文章