教你用nginx与lua打造更高并发应用

教你用nginx与<a href='/tag/lua.html'>lua</a>打造更高并发应用

在web应用开发中,我们用的比较多事的php、java,后端容器一般是apache、tomcat,前端采用nginx实现高并发,其实还一种组合的性能比他们还要高,那就是nginx+lua组合。

一、lua是什么?

Lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。

Lua 特性

轻量级: 它用标准C语言编写并以源代码形式开放,编译后仅仅一百余K,可以很方便的嵌入别的程序里。
可扩展: Lua提供了非常易于使用的扩展接口和机制:由宿主语言(通常是C或C++)提供这些功能,Lua可以使用它们,就像是本来就内置的功能一样。

二、nginx+lua 对比nginx+php

nginx+php虽然是市面上非常常用的一对组合,但他们也是两个不同的软件,需要进程间的通信,但openresty(也就是nginx+lua)是将lua作为一个模块集成进了nginx自身(这里区别apache的mod_php模型),此时,nginx+Lua是一个软件了,不需要进程间的通信,这在根上就决定了这个组合的速度的天然优势要比ngxin+php快。

但因为lua的文档比较少,函数库少等等因素,语法比较独特,导致现在用nginx+lua作为解决方案的比nginx+php的少的多。

由于nginx+lua的性能优势,结合redis,可以实现更多高并发的应用。

三、使用场景

(1)异步缓存更新:前端http查询一些数据,直接在nginx中通过lua访问redis拿到,直接返回到前端,减少服务器的压力;redis中数据通过服务器进行主动更新

(2)数据统计:点击次数和页面打开次数分析:在点击和页面打开之间,加上了请求到达nginx的统计,当请求到达nginx时,通过lua将访问的页面次数写入redis中,然后通过点击次数、nginx获得的请求次数、页面打开次数进行具体业务的分析

四、nginx+lua+redis示例

1、下载OpenResty的lua访问redis的插件:https://github.com/openresty/lua-resty-redis

下载后,导入对应的插件:

lua_package_path "/opt/openresty/lualib/kafka/?.lua;;";
lua_need_request_body on;

2、使用lua访问redis:

server {
location /test {
content_by_lua_block {
local redis = require "resty.redis"
local red = redis:new()

red:set_timeout(1000) -- 1 sec

-- or connect to a unix domain socket file listened
-- by a redis server:
-- local ok, err = red:connect("unix:/path/to/redis.sock")

local ok, err = red:connect("127.0.0.1", 6379)
if not ok then
ngx.say("failed to connect: ", err)
return
end

ok, err = red:set("dog", "an animal")
if not ok then
ngx.say("failed to set dog: ", err)
return
end

ngx.say("set result: ", ok)

local res, err = red:get("dog")
if not res then
ngx.say("failed to get dog: ", err)
return
end

if res == ngx.null then
ngx.say("dog not found.")
return
end

ngx.say("dog: ", res)

red:init_pipeline()
red:set("cat", "Marry")
red:set("horse", "Bob")
red:get("cat")
red:get("horse")
local results, err = red:commit_pipeline()
if not results then
ngx.say("failed to commit the pipelined requests: ", err)
return
end

for i, res in ipairs(results) do
if type(res) == "table" then
if res[1] == false then
ngx.say("failed to run command ", i, ": ", res[2])
else
-- process the table value
end
else
-- process the scalar value
end
end

-- put it into the connection pool of size 100,
-- with 10 seconds max idle time
local ok, err = red:set_keepalive(10000, 100)
if not ok then
ngx.say("failed to set keepalive: ", err)
return
end

-- or just close the connection right away:
-- local ok, err = red:close()
-- if not ok then
-- ngx.say("failed to close: ", err)
-- return
-- end
}
}
}


3、使用redis连接池

local ok, err = red:set_keepalive(60000, 20)


4、需要密码的redis的访问:使用 auth 方法

local ok, err = red.connect(red, "127.0.0.1", "6379")
if not ok then
return
end

local res, err = red:auth("password")
if not res then
return
end

5、redis的操作,不需要单独封装方法,lua-resty-redis 支持自动生成对应的lua方法

具体配置方法是:redis.lua 中,common_cmds 的array,在这里添加需要使用的方法

例如:需要使用redis hsah的hincrby,那么就在 common_cmds 添加 hincrby,在lua中直接使用就可以,red:hincrby(key, field, 1)

参考:https://cloud.tencent.com/developer/article/1482358

{{collectdata}}

网友评论0