OpenResty使用Lua笔记

07-17 1234阅读

文章目录

  • 一、基础
    • 1、常用
    • 2、使用局部变量
    • 3、模块化
    • 二、性能提升
      • 1、使用fft调用shell
      • 2、不要在循环中拼接字符串
      • 3、不要频繁修改table
      • 4、不要在table中用nil
      • 5、做好异常处理
      • 6、ngx.var 的性能提升
      • 三、拓展
        • 1、加载字符串为动态方法
        • 一、基础

          1、常用

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

          OpenResty使用Lua笔记
          (图片来源网络,侵删)

          包管理: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()'
          

VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]