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 的时候也是一样:

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

相关推荐

  1. OpenResty使用Lua笔记

    2024-07-17 07:28:04       26 阅读
  2. OpenResty使用Lua大全(七)OpenResty使用全局缓存

    2024-07-17 07:28:04       44 阅读
  3. openresty安装并使用lua进行业务逻辑处理

    2024-07-17 07:28:04       32 阅读
  4. OpenResty 安装及lua-resty-redis

    2024-07-17 07:28:04       32 阅读
  5. openresty lua修改响应体内容

    2024-07-17 07:28:04       30 阅读
  6. Openresty+lua 定时函数 ngx.timer.every

    2024-07-17 07:28:04       23 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-17 07:28:04       70 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-17 07:28:04       74 阅读
  3. 在Django里面运行非项目文件

    2024-07-17 07:28:04       62 阅读
  4. Python语言-面向对象

    2024-07-17 07:28:04       72 阅读

热门阅读

  1. Springboot定义阿里云oss工具类

    2024-07-17 07:28:04       24 阅读
  2. 入门 git

    2024-07-17 07:28:04       22 阅读
  3. IPython 的 %history -p 命令:探索命令行历史的秘籍

    2024-07-17 07:28:04       30 阅读
  4. [NOIP2006 提高组] 作业调度方案(含代码)

    2024-07-17 07:28:04       20 阅读
  5. OpenSearch 第三方IoT设备日志分析

    2024-07-17 07:28:04       31 阅读
  6. Photoshop

    Photoshop

    2024-07-17 07:28:04      20 阅读
  7. Github07-16 Python开源项目日报 Top10

    2024-07-17 07:28:04       24 阅读
  8. 用于图像增强的学习型可控ISP

    2024-07-17 07:28:04       30 阅读