OpenResty使用Lua笔记
文章目录
- 一、基础
- 1、常用
- 2、使用局部变量
- 3、模块化
- 二、性能提升
- 1、使用fft调用shell
- 2、不要在循环中拼接字符串
- 3、不要频繁修改table
- 4、不要在table中用nil
- 5、做好异常处理
- 6、ngx.var 的性能提升
- 三、拓展
- 1、加载字符串为动态方法
-
一、基础
1、常用
OpenResty 中文官网:https://openresty.org/cn/
(图片来源网络,侵删)包管理:https://opm.openresty.org/
(1)Lua 的下标从 1 开始
(2)使用 … 来拼接字符串
2、使用局部变量
在 Lua 中,变量默认是全局的,会被放到名为 _G 的 table 中。不加 local 的变量会在全局表中查找,这是昂贵的操作。如果再加上一些变量名的拼写错误,就会造成难以定位的 bug。
建议总是使用 local 来声明变量,即使在 require module 的时候也是一样:
-- Recommended local xxx = require('xxx') -- Avoid require('xxx') local ngx_re = require "ngx.re" local ngx = require "ngx"
--No local function foo() local ok, err = ngx.timer.at(delay, handler) end --Yes local timer_at = ngx.timer.at local function foo() local ok, err = timer_at(delay, handler) end
-- 为了风格的统一,require 和 ngx 也需要 local 化: --No local core = require("apisix.core") local timer_at = ngx.timer.at local function foo() local ok, err = timer_at(delay, handler) end --Yes local ngx = ngx local require = require local core = require("apisix.core") local timer_at = ngx.timer.at local function foo() local ok, err = timer_at(delay, handler) end
3、模块化
-- hello.lua定义一个对象,并返回 local _M = {} _M.color = { red = 1, blue = 2, green = 3 } return _M
location / { content_by_lua_block { -- 引入hello,并用一个变量接收,这个变量就可以调用对象的方法和变量了 local hello = require "hello" ngx.say(hello.color.green) } }
二、性能提升
1、使用fft调用shell
-- 不要用阻塞的lua语法 os.execute("kill -HUP " .. pid) os.execute(" cp test.exe /tmp ") os.execute(" openssl genrsa -des3 -out private.pem 2048 ") -- 使用lua-resty-signal 这个 OpenResty 自带的库 local resty_signal = require "resty.signal" local pid = 12345 local ok, err = resty_signal.kill(pid, "KILL") -- 使用基于 ngx.pipe 的 lua-resty-shell 库 $ resty -e 'local shell = require "resty.shell" local ok, stdout, stderr, reason, status = shell.run([[echo "hello, world"]]) ngx.say(stdout) '
2、不要在循环中拼接字符串
-- 不要在循环中拼接字符串 $ resty -e 'local begin = ngx.now() local s = "" -- for 循环,使用 .. 进行字符串拼接 for i = 1, 100000 do s = s .. "a" end ngx.update_time() print(ngx.now() - begin) ' -- 用table进行优化 $ resty -e 'local begin = ngx.now() local t = {} -- for 循环,使用数组来保存字符串,自己维护数组的长度 for i = 1, 100000 do t[i] = "a" end local s = table.concat(t, "") ngx.update_time() print(ngx.now() - begin) ' -- 或者自己定义数组索引 $ resty -e 'local begin = ngx.now() local t = {} local index = 1 for i = 1, 100000 do t[index] = "a" index = index + 1 end local response = table.concat(t, "") ngx.say(response) '
3、不要频繁修改table
-- 预先创建table,然后增删改,性能是很差的,原因在于每次新增和删除数组元素的时候,都会涉及到数组的空间分配、resize 和 rehash。 local t = {} local color = {first = "red", "blue", third = "green", "yellow"} -- 如果涉及对table的频繁修改,考虑初始化table的容量,这样就不需要使用table.insert等方法,直接通过下标设置值即可 -- table.new(narray, nhash) 两个参数分别代表table里是array还是hash的 -- table.new(10, 0) 或者 table.new(0, 10) 这样的,后者是 hash 性质的 table local new_tab = require "table.new" local t = new_tab(100, 0) for i = 1, 100 do t[i] = i end -- 可以考虑对table进行重用 -- 用 table.new(narray, nhash) 生了一个长度为 100 的数组,clear 后,长度还是 100。 -- table.clear方法就是将table所有的内容设为了nil local ok, clear_tab = pcall(require, "table.clear") if not ok then clear_tab = function (tab) for k, _ in pairs(tab) do tab[k] = nil end end end
4、不要在table中用nil
-- 一定不要在数组中使用 nil: --No local t = {1, 2, nil, 3} -- 如果一定要使用空值,请用 ngx.null 来表示: --Yes local t = {1, 2, ngx.null, 3}
5、做好异常处理
对于有错误信息返回的函数,我们必须对错误信息进行判断和处理:
--No local sock = ngx.socket.tcp() local ok = sock:connect("www.baidu.com", 80) ngx.say("successfully connected to baidu!") --Yes local sock = ngx.socket.tcp() localok, err = sock:connect("www.google.com", 80) if not ok then ngx.say("failed to connect to google: ", err) return end ngx.say("successfully connected to google!")
而如果是自己编写的函数,错误信息要作为第二个参数,用字符串的格式返回:
--No local function foo() local ok, err = func() if not ok then return false end return true end --No local function foo() local ok, err = func() if not ok then return false, {msg = err} end return true end --Yes local function foo() local ok, err = func() if not ok then return false, "failed to call func(): " .. err end return true end
6、ngx.var 的性能提升
ngx.var 是一个性能损耗比较大的操作,在实际使用时,我们需要用 ngx.ctx 来做一层缓存
-- lua-var-nginx-module模块,性能比起ngx.var 提升了 5 倍。它采用的是 FFI 的方式,所以,你需要在编译 OpenResty 的时候,先加上编译选项 ./configure --prefix=/opt/openresty \ --add-module=/path/to/lua-var-nginx-module -- 然后,使用 luarocks 的方式来安装 lua 库: luarocks install lua-resty-ngxvar -- 这里调用的方法也很简单,只需要一行 fetch 函数的调用就可以了。它的效果完全等价于原有的 ngx.var.remote_addr,来获取到终端的 IP 地址: content_by_lua_block { local var = require("resty.ngxvar") ngx.say(var.fetch("remote_addr")) }
三、拓展
1、加载字符串为动态方法
可以把 s 这个包含函数的字符串,改成可以由用户指定的形式,并加上执行它的条件,这样其实就是 FaaS 的原型了。
resty -e 'local s = [[ return function() ngx.say("hello world") end ]] local func1 = loadstring(s) local ret, func = pcall(func1) func()'
文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。