用lua让nginx成为应用服务器


相遇是件难得的事情,在一起更不简单,但是nginx和lua就是成功的结合起来。文本将以演进式方式与大家一起分享lua的威力和nginx的优秀架构。

1、从猩猩那个年代说起
从互联网进入人类生活开始,用户和服务器就扮演着你来我往的角色,从技术角度描绘就是一直存在着request/response(请求/响应)的架构。如今随着网络设施的加强,人们对网站内容的需求也更多样化,从简单的html到现在丰富的媒介内容。横空出世的开源服务器软件也承担着更多的功能。但是再怎么复杂变化,总是只有静态和动态两种类型。静态即静态资源如html、css、js等这种文件式的内容,动态即根据请求信息处理的如.php这种常见的内容。在静态方面,现在已经有足够成熟的架构方案,反倒动态的处理方案非常之多。

2、站在巨人的肩上
可以说提到web服务器,人们自然会想到apache,这个在技术发展史上不能被忽略的优秀软件,如今依然有着60%(保守估计)的使用量。nginx是个极致的东西,优势的架构让它迅速征服了很大一批工程师,这同样适合国内的情况。nginx做了两件事:处理静态请求和动态请求。完全符合我们上面说的,在静态方面,nginx的性能表现非常突出,默认使用sendfile传输内容,还可以设置缓存(针对file fd)。在动态方面,nginx可以集成很多的应用软件,其实从这角度讲它只是个代理,但是nginx能做的不仅仅是代理,这就是本文存在的价值。

3、nginx+php-fpm vs apache+mod_php
php是世界上最好的语言,这已经成为一个段子,我本身非常喜欢这个语言。这里以php为例解释下nginx的动态处理方式。
首先它们都是为了处理动态请求。php是脚本语言解释器,不做处理网络请求和响应的事(虽然它可以)。nginx, apache, php-fpm 这3个都是网络服务器,处理请求和响应。mod_php是个c解释php的模块库。

client >---http-request--- apache(mod_php)
client <---http-response-- apache(mod_php)

client >---http-request--- nginx >---fastcgi-request--- php-fpm(c解释php)
client <---http-response-- nginx <---fastcgi-response-- php-fpm(c解释php)

为统一,我们把处理http的服务器称为web服务器,处理动态请求的称为应用服务器。所以apache是应用服务器,nginx是web服务器,它通过代理(fastcgi协议)转发给应用服务器php-fpm。服务器的设计原则是永远不能阻塞,但规则往往因为被打破而简化了问题。注意nginx与php-fpm的交互是异步的,mod_php, php-fpm里c解释php阻塞的。(不用纠结这两个词)

4、让nginx成为应用服务器。
nginx本身有个模块ssi,全称是server side includes,它是个极小解释器,可以让响应内容有小动态的功能。 30秒明白ssi使用和原理
以下这行是test.html的文件内容,很像脚本语言吧,从这角度讲nginx已经是应用服务器。
hello: < !--# echo var="request_url" -->

脚本动态语言如此之多,php, perl, python, ruby, js, lua, blala 语法各异,粉丝从多,据说上帝为了不让巴别塔造成才搞了这么多不一样的东西,虽然他们目标是做同一件事,让事情变得更简单。实现应用服务器的方案也不在少数,都非常优秀。在上面我们清楚,现在的应用服务器干了两件,处理网络服务和执行业务脚本。网络服务本身是基于协议的,比如http,这个只要保证稳定性,高性能和健壮性即可。在执行业务脚本方面就区别大了。但大体有两种方法,网络处理和业务脚本是同个语言,比如nodejs, go等。这其实是有好处的,业务脚本可以获取网络服务的上下文。还有一种是分开的,根据语言有不同的系统,比如c+dsl系列的nginx + lua。那么问题来了,选择哪一个呢?稳定性,高性能和健壮。nginx本身在网络方面已经具备这3个要素了,这是我们选择它的原因。至于为什么选择lua,是因为这语言本身设计是为了让c写起来更轻松。所以我们选择一个东西时,它的出发点是什么很有参考价值。正如php为web而生一样。所以现在剩下的问题就是nginx如何执行lua。

5、我们不仅关注优秀的openresty,还有更多
openresty的作者可能是目前世界上在nginx的第三方模块的贡献者,除了openresty这个开源产品,还有其它优秀的模块。 openresty是一个在nginx上扩展lua的应用服务器。它的官网和github上的资料非常完善,但文本的价值在于探讨如何让nginx具备应用能力。所以你不用担心是否懂openresty。我们探讨明白lua是如何被加到nginx的。

6、lua与nginx的架构设计
nginx架构图(来源 http://www.aosabook.org/en/nginx.html)

lua是个脚本语言,有着简洁的语法,虽然我不觉得非常易用。官方定义了语言规则和源码实现,目前稳定版是5.3。
还有个luajit,这是非官方的实现,支持5.1的语法(openresty是用luajit的)。本文基于官方lua5.3版本。

              ---- worker ----
nginx     ---- worker ----
                                                            ---- process request (lua_newthread) ----
              ---- worker (lua_newstate)    ---- process request ----
                                                            ---- process request ----
               ---- worker ----

nginx有多个工作进程,每个worker process启动时会加载一个lua_State,然后等待请求进来,多个请求是允许同时存在的,比如有的忙着去请求远程服务,这时就异步挂着休息。当有请求过来需要处理时,nginx为每个请求创建一个lua_newthread,这个lua_newthread将加载文件、解释执行等操作。

因此你要做的就是
在init:
conf->L = lua_newstate(); // L是lua_State结构体

在handler:
L = conf->L;
NL = lua_newthread(L); // NL也是lua_State结构体
r->ctx->NL = NL;
luaL_loadfile(NL);

你可能猜到了吧,lua_newstate是个虚拟机,专门给nginx进程的,每个进程一个。lua_newthread是给请求的,每个请求也有一个,他们都具备运行lua文件的能力。但由于请求是变化的,上下文不一样,所以才需要为每个请求创建一个lua_State结构体。我们将分析lua的内部,让你更明白这个架构。

未完待续,写到这发现可以探讨的空间很大,lua的协程、虚拟机、全局变量和闭包(绝对有料,比如lua没有全局变量,那是为什么呢)、nginx调用了lua的哪些功能、为什么openresty写道lua的全局变量不能使用,c与lua的协作,如何让lua去调其它服务(memcache, redis, mongodb, mysql)。有关注才有动力^-^

推荐阅读:
nginx ssi使用和原理
nginx源码分析之stream设计

转载于:https://my.oschina.net/fqing/blog/422450

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值