OpenResty使用Lua笔记

文章目录

一、基础

1、常用

OpenResty 中文官网:https://openresty.org/cn/

包管理:https://opm.openresty.org/

(1)Lua 的下标从 1 开始

(2)使用 ... 来拼接字符串

2、使用局部变量

在 Lua 中,变量默认是全局的,会被放到名为 _G 的 table 中。不加 local 的变量会在全局表中查找,这是昂贵的操作。如果再加上一些变量名的拼写错误,就会造成难以定位的 bug。

建议总是使用 local 来声明变量,即使在 require module 的时候也是一样:

lua 复制代码
-- Recommended 
local xxx = require('xxx')
 
-- Avoid
require('xxx')

local ngx_re = require "ngx.re"
local ngx = require "ngx"
lua 复制代码
--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
lua 复制代码
-- 为了风格的统一,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、模块化

lua 复制代码
-- hello.lua定义一个对象,并返回
local _M = {}
 
_M.color = {
      red = 1,
      blue = 2,
      green = 3
  }
 
  return _M
lua 复制代码
location / {
    content_by_lua_block {
    	-- 引入hello,并用一个变量接收,这个变量就可以调用对象的方法和变量了
        local hello = require "hello"
        ngx.say(hello.color.green)
     }
}

二、性能提升

1、使用fft调用shell

lua 复制代码
-- 不要用阻塞的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、不要在循环中拼接字符串

lua 复制代码
-- 不要在循环中拼接字符串
$ 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

lua 复制代码
-- 预先创建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

lua 复制代码
-- 一定不要在数组中使用 nil:
--No
local t = {1, 2, nil, 3}

-- 如果一定要使用空值,请用 ngx.null 来表示:
--Yes
local t = {1, 2, ngx.null, 3}

5、做好异常处理

对于有错误信息返回的函数,我们必须对错误信息进行判断和处理:

lua 复制代码
--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!")

而如果是自己编写的函数,错误信息要作为第二个参数,用字符串的格式返回:

lua 复制代码
--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 复制代码
-- 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 的原型了。

lua 复制代码
resty -e 'local s = [[
 return function()
    ngx.say("hello world")
end
]]
local  func1 = loadstring(s)
local ret, func = pcall(func1)
func()'
相关推荐
UWA3 天前
Unreal开发痛点破解!GOT Online新功能:Lua全监控 + LLM内存可视化!
开发语言·lua·unreal
1nullptr3 天前
Lua迭代器与泛型for
lua
半夏知半秋3 天前
skynet debug_console控制台中debug指令使用
服务器·开发语言·学习·lua
h7997103 天前
redis lua脚本(go)调用教程以及debug调试
redis·golang·lua
玩转C语言和数据结构6 天前
Lua下载和安装教程(附安装包)
lua·lua下载·lua安装教程·lua下载和安装教程·lua安装包
Arva .6 天前
HTTP Client
网络协议·http·lua
爱吃小胖橘7 天前
Lua语法(2)
开发语言·unity·lua
ellis19708 天前
LuaC API知识点汇总
unity·lua
爱吃小胖橘11 天前
Lua语法
开发语言·unity·lua
东方芷兰11 天前
JavaWeb 课堂笔记 —— 20 SpringBootWeb案例 配置文件
java·开发语言·笔记·算法·log4j·intellij-idea·lua