Your SlideShare is downloading. ×
Perl在nginx里的应用
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Introducing the official SlideShare app

Stunning, full-screen experience for iPhone and Android

Text the download link to your phone

Standard text messaging rates apply

Perl在nginx里的应用

2,529
views

Published on

简述了脚本语言(主要是perl)在nginx中的应用,介绍了nginx_perl项目。

简述了脚本语言(主要是perl)在nginx中的应用,介绍了nginx_perl项目。

Published in: Technology

0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
2,529
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
11
Comments
0
Likes
1
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. Perl 与 Nginx 应用 —— jeff
  • 2. 题目的由来
    • perl 是 OPSer 最熟悉的 script language
    • nginx 是 OPSer 最喜欢的 web server
    • 相信我的 perl 和 nginx 水平都不是最好的,不过感谢 laird 的乱点鸳鸯谱,把它们凑在一起给我作讲题,大概或许可能仿佛应该想来我看过一些而大家没留意的吧 ^=^
  • 3. 提要
    • nginx 的主要功能
    • nginx 原生 perl 模块介绍
    • 几个简单的例子
    • nginx 第三方模块 (ngx_js/ngx_lua) 介绍
    • nginx 增强版 perl 介绍
    • 总结
  • 4. nginx 的主要功能
    • nginx 主要分成 http 和 mail 两个部分,一般来说,我们的操作都是 http 部分的(奇怪的是 nginx-src 的 configure 选项里只有 --without-http 而没有 --without-mail )
    • http 中,最常用的标准模块是静态文件发布的 core ,反向代理的 proxy ,上游集群的 upstream ,重定向的 rewrite 等 ……
    • 其他常用官方模块有: fastcgi/flv/mp4/gzip_static/limit_conn/uwsgi 等
  • 5. nginx 与动态应用
    • nginx 的标准作用是静态文件发布( proxy_cache/proxy_store 的结果也是静态文件发布,区别在目录结构而已)
    • 与动态程序结合,最通用的办法就是使用 proxy 和 upstream 模块。
    • 方便一点的,比如用 fastcgi 启动 perl/php 程序,或者支持 uwsgi 标准的 python/perl 程序等 ……
  • 6. nginx 原生 perl 模块介绍
    • 大家都知道, apache 除了 cgi 方式外,还有 mod_perl , nginx 也一样。
    • 在编译时,启用 --with-http_perl_module 选项即可。
    • 功能上,主要分两种,一种是简单的通过 perl_set 指令,返回一个 nginx.conf 的内部变量,完成后续响应;一种是通过 handler 替代一部分 serve 功能。
    • 指令的使用方法,见 nginx 的 wiki 。
  • 7. perl_set 举例
    • 通过 perl_set 完成 url 大小写的改变。注意,这并不意味着 url 大小写不重要了,只是说在实际文件统一小写的情况下,不会对有大写的 url 返回 404 了 ……
    • nginx.conf: http { perl_set $new_uri ' sub { my $r = shift; return lc($r->uri); }; '; rewrite ^.*$ $new_uri last; };
  • 8. perl 举例
    • 在文件下载服务时,根据文件大小的不同,将请求引向不同的服务器集群。进一步可以根据 ip ,根据 dir ,根据 cookie 等等 ……
    • nginx.conf: http { perl_module perl/lib; perl_require Redirect.pm; server { location / { perl Redirect::handler; }; }; };
    • Redirect.pm: package Redirect; use nginx; sub handler { my $self = shift; my $webroot = '/www/dl.gamedomain.com/' return HTTP_NOT_ALLOWED unless $self->uri =~ m!^(/.+/)[^/]+$!; my $file = $webroot . $1 . $self->filename; my @filestat = stat($file) or return HTTP_NOT_FOUND; my $filesize = $filestat[7]; if ( $filesize < 8 * 1024 * 1024 ) { return OK; } else { $self->location('http://bigfile.cdndomain.com'.$self->uri); } }; 1
  • 9. 模拟 ngx_perl 的 ngx_js
    • 除了 Igor Sysoev 提供的 ngx_perl ,在第三方模块库里还有另外一个 ngx_javascript 模块,其实现效果甚至指令命名,都模仿了 ngx_perl 的形式。
    • 感谢微博上某位我不记得的童鞋当初告诉我这个模块 …… 可惜偶不会 js ,估计会 js 又想折腾 webserver 都去玩 node 去了 = =!
  • 10. 突破 ngx_perl 的 ngx_lua
    • agentzh 目前全力以赴的 OpenResty 项目主要就是以这个 ngx_lua 为中心,粘合一系列其他 ngx_*(memd/redis/mysql...) 的 asynchronous 模块完成一个全程 asynchronous 的 webservice 。
    • agentzh 提到过两点:一是 openresty 的早期版本是 perl 的,后来因为性能废弃了;二是 ngx_perl 模块的 blocking 完全浪费了 nginx 优秀的 nonblocking 设计所以纯粹是个玩具。
  • 11. 突破 ngx_perl 的 ngx_lua
    • 在 ngx_perl 的 wiki 上,有这么两句话:一是不要试图使用 perl 来完成类似 dns 解析、 mysql 请求之类的需要长时间等待的任务,这会导致整个 worker 被阻塞;二是启用了 ngx_perl 的 server ,尽量避免使用 reload 命令,有可能会内存溢出。
    • 在 agentzh 的文档 ( 讲座 ?) 中,也曾提到, ngx_lua 模块最好用来做运算,把 IO 请求通过 subrequest 交给专门的模块来做。
  • 12. nginx 增强版 perl 介绍
    • 由上推断,可以认为如果只是单纯的运算类的事情,使用 ngx_perl 完成是完全可以的,比如之前举例的 perl_set 的情况。
    • 那么,如果想完成一个复杂功能,只能靠 ngx_lua 了么?
    • 感谢 CPAN ,我发现了 Nginx::Engine 模块 —— 前不久这个模块刚刚从 cpan 搬到 github ,名为 nginx_perl ,会在 release 后再搬回 cpan~~
  • 13. nginx 增强版 perl 介绍
    • 在 Nginx::Engine 的介绍上,写的是 an asynchronous web framework based on nginx ;在 nginx_perl 的介绍上,则是 full-featured perl support for nginx 。
    • 通过 $r->print 发送内容的方式很类似原始的 CGI.pm ,所以如果是写网页,还是用 dancer 之类的 framework 比较方便。
    • 除了一些细节上的功能,比如 perl_init_worker/perl_eval 指令之外,最重要的几个地方:
  • 14. nginx_perl 新增功能
    • 1 、 $r->main_count_inc; 每个 async 的 handler 都要 increase 主进程的计数器以便 callback ;
    • 2 、 ngx_timer $after, $repeat, sub {}; 一个定时器,在 $after 秒后 callback ,重复 $repeat 次;
    • 3 、 ngx_connector $ip, $port, $timeout, sub {}; 异步链接 $ip:$port ,超时时间 $timeout ,成功的话,建立的链接将作为 $_[0] 返回;否则返回 $! 。
  • 15. nginx_perl 新增功能
    • 4 、 ngx_reader $connection, $buf, $min, $max, $timeout, sub{}; 从 ngx_connector 返回的 $connection 中异步读取数据到 $buf ,规定 $buf 的长度在 $min 到 $max 之间。如果长度不足,返回 NGX_EOF ,也会存入 $! 中。
    • 5 、 ngx_writer $connection, $buf, $timeout, sub {}; 和 ngx_reader 相对的。
  • 16. nginx_perl 新增功能
    • ngx_ssl_handshaker $connection, sub {}; 如果启动了 ssl 加密,必须在 connection 之后使用 handshaker ,再创建 reader/writer 。
    • ngx_resolver $host, $timeout, sub {}; 返回域名解析结果 ip 列表到 @_ 中;目前这个指令还是 nginx 原生 resolver 的封装,如果要使用的话,建议在本机配备 named/dnsmasq 等 dns 缓存 …… 这里是 TODO 中列的下一步重点改进。
  • 17. nginx_perl 新增功能
    • $r->take_connection();
    • $r->give_connection(); 之前的 ngx_connector 指令,用来创建和其他 server 的链接,而这里的 takeover ,是用来获取 client 的链接,这样做 websocket 之类的就比较方便 …… 使用时同样要记得 inc ,更关键的是要使用 $r->finalize_request(NGX_DONE) 表示 EOF , return NGX_NOOP 表示 NGX_CLOSE 。
  • 18. nginx_perl 示例
    • 源码中默认有 helloworld,self_sufficient,redis 和 Nginx::Util 四个示例。不过我还是自己试着写一个类似 proxy_pass 的例子,从中也发现一些 README 没有说明的细节:
    • package HelloWorld;
    • use Nginx;
    • use strict;
    • # 用来在 nginx 启动的时候做的事情,这里单纯显示一下
    • sub init_worker {
    • warn 'nginx_perl start [OK]';
    • };
    • # 这里是 nginx 的 http 模块中调用的 handler , alexander 有计划改成 tcp 级别的
    • sub handler {
    • my $r = shift;
    • # 增加主循环的计数器
    • $r->main_count_inc;
  • 19. nginx_perl 示例
    • # 使用非阻塞的连接器连接 127.0.0.1 的 80 端口, 10 秒超时
    • ngx_connector '127.0.0.1', 80, 10, sub {
    • # 如果连接出问题,会记录在 $! 中
    • if ($!) {
    • $r->send_http_header('text/html');
    • $r->print(&quot;Connection failed, $!n&quot;);
    • $r->send_special(NGX_HTTP_LAST);
    • # 不管怎么处理这次连接,最后一定要记得用 $r->finalize_request() ,会 decrease 之前 $r->main_count_inc; 里加上的计数。
    • $r->finalize_request(NGX_OK);
    • return NGX_CLOSE;
    • };
    • # 返回 $c 是建立的连接
    • my $c = shift;
    • my $req_buf = &quot;GET /index.php HTTP/1.0x0dx0a&quot;.
    • &quot;Host: chenlinux.comx0dx0a&quot;.
    • &quot;Connection: closex0dx0a&quot;.
    • &quot;x0dx0a&quot;;
    • # 这里记住定义 buffer 的时候不要搞成 undef 了,会报段错误的,不过俄国佬回信说他修复了
    • my $res_buf = '';
  • 20. nginx_perl 示例
    • # 非阻塞写入,超时 10 秒
    • ngx_writer $c, $req_buf, 10, sub {
    • if ($!) {
    • ......
    • };
    • $req_buf = '';
    • # 之前的 buffer 测试就是这里,如果加一个 warn ,就不会报错 …… 汗
    • #warn &quot;$req_bufn$res_bufn&quot;;
    • # 写入完成后,开始调用读取
    • return NGX_READ;
    • };
  • 21. nginx_perl 示例
    • # 读取到 buffer ,最短 0 字节,最长 8000 字节,超时 10 秒
    • ngx_reader $c, $res_buf, 0, 8000, 10, sub {
    • if ($!) {
    • ......
    • }
    • $r->send_http_header('text/html');
    • $r->print($res_buf);
    • $r->send_special(NGX_HTTP_LAST);
    • $r->finalize_request(NGX_OK);
    • return NGX_CLOSE;
    • };
    • # 这个是 connector 的语句,表示连接成功后调用写入
    • return NGX_WRITE;
    • };
    • # 各个非阻塞调用完成后的返回, NGX_DONE 只能用在 http 的 handler 里,不能在 ngx_*r 里用,里面请用 NGX_CLOSE 。
    • return NGX_DONE;
    • };
    • 1;
  • 22. 总结
    • 今天主要是介绍了一下在 nginx.conf 里能够使用的几个 script ,以及用 perl 完成的两个 cdn 功能的实验。
    • 关于 asynchronous 的应用,其实我还是门外围观者,感觉单纯 perl 也好 lua 也好,主要还是多多搭配各种模块的复杂运用。