OpenResty使用Lua笔记

avatar
作者
筋斗云
阅读量:0

文章目录

一、基础

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()' 

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!