2013-12-27 08:49:01
来 源
IT技术网
Nginx
本文介绍Nginx_lua-openapi项目笔记,希望对于初学Nginx服务器相关的朋友有帮助,更多Nginx安装、配置、报错处理等资源请本站内搜索。。

最近用nginx的开源项目openresty做了一个api网关的项目,代码就不方便开源了,其中踩了一些坑,做下笔记。

1、lua的os.time()返回时间戳,单位是秒而不是毫秒。对于这方面貌似要么使用第三方库才能解决,不过一般秒也够用了。

2、lua的模块是以文件为单位,所有的模块需要定义模块名和上下文,下面就是一个通用的模块供require的。一开始我没注意,在nginx配置文件中写入  lua_code_cache = off 时,就算不定义module也一样正常运行,可是当我切换到 lua_code_cache = on 时就出现了无法找到变量的错误了。

local "pln"> Res_Class "pln"> = "pln"> require "pln"> "resclass" "pun">["Res_Class" "pun">]    "pun">--引用Res_Class "pun">类

注意,在 init_by_lua 中require的lua包会定义为全局变量,在之后content_by_lua等里放心使用

3、nginx事件主要发生3段,依次是 rewrite 阶段、access 阶段以及 content 阶段,这次我算是对这3个阶段有了彻底的理解,之前看文档还有点模模糊糊。这3个阶段就算你在代码中return,也还是会依次触发的。比如我在rewrite阶段执行了ngx.say()响应了一个东西,同时return,access和content阶段你注入的lua代码还是会依次执行的,除非你在中间显示的进行了跳转

4、HTTP method constants,比如:ngx.HTTP_GET 或 ngx.HTTP_POST,返回的不是字符串"GET"或"POST",而是数字,而 ngx.req.get_method() 返回的却是字符串,这点文档上是有说明,需要注意

5、nginx lua的db库,比如我这次用到的mysql和redis库都带有连接池,需要善加利用,在close的时候请使用相对应的归还连接到连接池方法代替,这样我们的数据库连接就能够复用了,减少重复建立和销毁连接的损耗

6、lua是很脆弱的,比如将一个nil对象丢入string.lower()函数里就将导致抛出异常,所以一定要像写强类型语言那样检测变量的类型,而不是像node那样讲一个null随便丢入都不会报错。

7、lua的函数可以返回多个值,比如 

return "pln"> false "pun">,err

所以如下的代码很常见:

local "pln"> ok, "pln"> res_json = "pln"> pcall( "kwd">function() "pln"> return "pln"> --异常捕获,当用户提交不是 "pln">json "pun">格式

"pln">             "pln">cjson. "pln">decode( "kwd">self. "pln">_body_data "pun">)

"pln">       "kwd">end)

要习惯及善于使用函数多返回值的特性

8、nginx默认是不解析json格式的post提交的,好像有第三方库可以支持,但是我还是根据req头部手动写了一个支持json作为body的post提交支持,当然在使用 cjson.decode() 时可能抛出一个异常,所以在 cjson.decode() 或者 cjson.encode() 时要使用pcall来捕获可能发生的错误。

9、ngx.shared.DICT 是全局单进程共享的一个变量,可以往 ngx.shared.DICT 内存入key = value 的东西,当然value只能是字符串,不能存储lua的table等。所以我在项目中就是往 ngx.shared.DICT 存入了json字符串来了表示table缓存一些table格式的数据,这样就做到了一些table变量的进程共享内存。

10、善加利用 ngx.location.capture() 方法,他可以做到内部的跳转,而对客户端uri不变,还可以在跳转时动态修改参数以及一些其他东西。比如我们有:

1、获取用户头像接口A

2、获取用户信息接口B

3、获取用户好友接口C

4、获取用户最近帖子D

我们可以轻松的封装一个接口,获取用户的最新状态E,而对于E来说就是接口A,B,C,D的查询结果的总和,所以就可以利用这个方法轻松实现这类功能,而不用多写很多代码。

11、尽量减少 很多的字符串拼接,多利用table.concat,效率更高,lua中大字符串很常见,所以不用担心。

12、每次用户请求都是独立的一个上下文,所有的变量都会被自动GC,不用担心内存泄露,其实是你想泄露都没地方泄露。

13、resty.http这个库如果你想利用request的返回值,需要自定义body_callback函数,而且这个body_callback函数会执行多次,每次回将chunk作为参数返回,所以这里你就需要自己保存和拼接这些chunk了,不然默认body_callback 就是直接ngx.say(chunk),这不是我们想要的。

14、还是那个库,local ok, code, headers, status, body = self.http_client:proxy_pass 方法如果ok为false,则第二个参数code返回的不是number类型,所以我们得这样处理:

ngx "pun">.status  "pun">= tonumber "pun">(code "pun">)  "kwd">or 

15、nginx_lua的业务压测结果:

测试机:

"pln">cpu: "pln">E5620 @ "pln"> 2.40GHz "pln"> ( "pun">个)

"pln">men: "lit">8G

"pln">ab - "pln">n  "pln"> - "pln">c  "pln"> - "pln">T  "str">'application/json' "pln"> - "pln">p / "pln">tmp/ "pln">open_api_test. "pln">json http: "com">//192.168.28.5/test/

"com">qps:8715.41

"pln">cpu:% "pln"> ( "pln">avg "pun">)

"pln">mem: "lit">22MB  "pun">(avg "pun">)

CPU消耗还是蛮大的,最多的时候几乎跑到了80%,内存消耗非常小,这也和nginx单线程模型密不可分,业务主要包括redis库的多次访问,以及用户请求数据以及签名的md5是否合法等,这样的成绩单机性能已经完全可以应付我们公司的业务了。

就想到这么多,有机会再补充吧

声明: 此文观点不代表本站立场;转载须要保留原文链接;版权疑问请联系我们。