OpenResty从入门到实战
温铭
OpenResty软件基金会主席,《OpenResty 最佳实践》作者
立即订阅
4333 人已学习
课程目录
已完结 52 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | OpenResty,为你打开高性能开发的大门
免费
入门篇 (14讲)
01 | 初探OpenResty的三大特性
02 | 如何写出你的“hello world”?
03 | 揪出隐藏在背后的那些子项目
04 | 如何管理第三方包?从包管理工具luarocks和opm说起
05 | [视频]opm项目导读
06 | OpenResty 中用到的 NGINX 知识
07 | 带你快速上手 Lua
08 | LuaJIT分支和标准Lua有什么不同?
09 | 为什么 lua-resty-core 性能更高一些?
10 | JIT编译器的死穴:为什么要避免使用 NYI ?
11 | 剖析Lua唯一的数据结构table和metatable特性
12 | 高手秘诀:识别Lua的独有概念和坑
13 | [视频]实战:基于FFI实现的lua-resty-lrucache
14 | 答疑(一):Lua 规则和 NGINX 配置文件产生冲突怎么办?
API篇 (11讲)
15 | OpenResty 和别的开发平台有什么不同?
16 | 秒杀大多数开发问题的两个利器:文档和测试案例
17 | 为什么能成为更好的Web服务器?动态处理请求和响应是关键
18 | worker间的通信法宝:最重要的数据结构之shared dict
19 | OpenResty 的核心和精髓:cosocket
20 | 超越 Web 服务器:特权进程和定时任务
21 | 带你玩转时间、正则表达式等常用API
22 | [视频]从一个安全漏洞说起,探寻API性能和安全的平衡
23 | [视频]导读lua-resty-requests:优秀的lua-resty-*是如何编写的?
24 | 实战:处理四层流量,实现Memcached Server
25 | 答疑(二):特权进程的权限到底是什么?
测试篇 (5讲)
26 | 代码贡献者的拦路虎:test::nginx 简介
27 | test::nginx 包罗万象的测试方法
28 | test::nginx 还可以这样用?
29 | 最容易失准的性能测试?你需要压测工具界的“悍马”wrk
30 | 答疑(三)如何搭建测试的网络结构?
性能优化篇 (16讲)
31 | 性能下降10倍的真凶:阻塞函数
32 | 让人又恨又爱的字符串操作
33 | 性能提升10倍的秘诀:必须用好 table
34 | 特别放送:OpenResty编码指南
35 | [视频]实际项目中的性能优化:ingress-nginx中的几个PR解读
36 | 盘点OpenResty的各种调试手段
37 | systemtap-toolkit和stapxx:如何用数据搞定“疑难杂症”?
38 | [视频]巧用wrk和火焰图,科学定位性能瓶颈
39 | 高性能的关键:shared dict 缓存和 lru 缓存
40 | 缓存与风暴并存,谁说缓存风暴不可避免?
41 | lua-resty-* 封装,让你远离多级缓存之痛
42 | 如何应对突发流量:漏桶和令牌桶的概念
43 | 灵活实现动态限流限速,其实没有那么难
44 | OpenResty 的杀手锏:动态
45 | 不得不提的能力外延:OpenResty常用的第三方库
46 | 答疑(四):共享字典的缓存是必须的吗?
API网关篇 (4讲)
47 | 微服务API网关搭建三步曲(一)
48 | 微服务API网关搭建三步曲(二)
49 | 微服务API网关搭建三步曲(三)
50 | 答疑(五):如何在工作中引入 OpenResty?
结束语 (1讲)
结束语 | 行百里者半九十
OpenResty从入门到实战
登录|注册

07 | 带你快速上手 Lua

温铭 2019-06-10
你好,我是温铭。
在大概了解 NGINX 的基础知识后,接下来,我们就要来进一步学习 Lua 了。它是 OpenResty 中使用的编程语言,掌握它的基本语法还是很有必要的。
Lua 是一个小巧精妙的脚本语言,诞生于巴西的大学实验室,这个名字在葡萄牙语里的含义是“美丽的月亮”。从作者所在的国家来看,NGINX 诞生于俄罗斯,Lua 诞生于巴西,OpenResty 诞生于中国,这三门同样精巧的开源技术都出自金砖国家,而不是欧美,也是挺有趣的一件事。
回到 Lua 语言上。事实上,Lua 在设计之初,就把自己定位为一个简单、轻量、可嵌入的胶水语言,没有走大而全的路线。虽然你平常工作中可能没有直接编写 Lua 代码,但 Lua 的使用其实非常广泛。很多的网游,比如魔兽世界,都会采用 Lua 来编写插件;而键值数据库 Redis 则是内置了 Lua 来控制逻辑。
另一方面,虽然 Lua 自身的库比较简单,但它可以方便地调用 C 库,大量成熟的 C 代码都可以为其所用。比如在 OpenResty 中,很多时候都需要你调用 NGINX 和 OpenSSL 的 C 函数,而这都得益于 Lua 和 LuaJIT 这种方便调用 C 库的能力。
下面,我带你来快速熟悉下 Lua 的数据类型和语法,以便你后面更顺畅地学习 OpenResty。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《OpenResty从入门到实战》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(21)

  • 回家
    网上有种设置随机数种子的方法:
    math.randomseed(tostring(os.time()):reverse():sub(1, 6))
    即将时间值转换为字符串,然后将字符串倒序,然后取其前六位作为种子。之所以这样做的原因是因为当时间变化很小的时候,产生随机数的序列很相似。所以通过这种方法使得即使时间变化很小,由于reverse操作,时间的高位变成低位,低位变成高位,随机数种子的值变化会很大。

    关于这种做法有以下两个问题:
    1.当前执行os.time()打印的时间是1560251897,总共十位。认为函数中使用sub(1, 6)这里取前6位的中的6并不是一个固定的值,而且并没有什么意义,直接使用math.randomseed(tostring(os.time()):reverse())就能达到想要的效果。难道有其他我没有想到的原因?

    2.这样的做法并不能阻止在同一秒内产生相同的随机数序列,如执行以下代码:
    math.randomseed(tostring(os.time()):reverse():sub(1, 6))
    print(math.random())
    print(math.random())
    math.randomseed(tostring(os.time()):reverse():sub(1, 6))
    print(math.random())
    print(math.random())
    输出结果是:
    0.49256881466135
    0.0046852543018758
    0.49256881466135
    0.0046852543018758

    另一种说法是对计算机的一些操作,如键盘、鼠标操作,会产生一些随机数,这些随机数叫熵。用户可以通过读取/dev/random和/dev/urandom文件来获取这些随机数。只不过读取/dev/random时,如果文件里的熵不足时会阻塞。读取/dev/urandom时,不会阻塞,但不能保证是合适的数据(熵不足时怎么处理未测试)。关于熵的还有其他相关知识,如通过操作鼠标、键盘等可以产生熵,通过cat /proc/sys/kernel/random/entropy_avail操作可以查看有多少熵可以用等。
    这样的话,通过读取/dev/urandom设置随机数种子,是一种方法,但觉得这种文件读取操作,效率太低。

    另外看留言里有人说通过系统调用,利用芯片电磁噪声来生成随机数。没有搜到是哪个系统调用。

    作者回复: 很详细了。如果有加密的需求,从 /dev/random 和 /dev/urandom 读取会更安全,毕竟只是 init 的时候读取一次。

    2019-06-11
    1
    9
  • 回家
    返回三个变量,前两个变量重复使用同一个虚变量的例子:
    resty -e 'local function sum(a, b) return a, b, a + b end local _, _, result = sum(1, 2) print(result)'

    os.time返回当前时间的秒数,如果在同一秒内设置当前时间秒数为种子,然后执行随机数生成函数,产生的随机数序列是一样的。如:
    resty -e 'math.randomseed(os.time()) print(math.random()) print(math.random()) math.randomseed(os.time()) print(math.random()) print(math.random())'
    输出结果是:
    0.71251659032569
    0.36755092546457
    0.71251659032569
    0.36755092546457
    可以看到两次产生的随机数序列相同。

    作者回复: 👍

    2019-06-11
    3
  • Rye
    机器名+进程ID+线程ID+毫秒时间戳做种子
    2019-06-11
    2
  • John
    请问一下老师,如果我在init_by_lua 中引入某个模块,不加local,作为全局变量,是不是说这个模块就可以在以后rewrite,access 等阶段直接拿来使用?这样做相比较于在各个阶段自己引入模块,是否减少了require的次数,提高了性能?

    作者回复: 不会提高性能,模块在单个 worker 中只会加载一次,和是否加了 local 无关。设置为全局变量,很容易出错,比如重名什么的。在OpenResty 中建议所有变量都 local。

    2019-06-11
    1
  • 一步
    明白了, os.time 是秒级别的,如果短时间运行多次会出现相同的随机数

    作者回复: 是的,没错

    2019-06-10
    1
  • 叫我图图就可以了
    种子会出现相同的,简单的做法可以用GUID或者UUID之类的做种子吧.

    作者回复: uuid 本身也是先有种子,然后通过随机数生成的。

    2019-06-10
    1
  • nicknick
    所谓的虚变量就是一个普通的变量,没有任何特殊之处,只不过是不用它的值而已,单独拿出来做一个概念是否有必要
    2019-11-29
  • void
    老师,有个问题请教一下。我的代码大概是这样的。
    ```
    ngx.req.read_body() -- 解析 body 参数之前一定要先读取 body
    local arg = ngx.req.get_post_args()
    --ngx.say(type(arg))
    ngx.print(arg)
    ```
    然后ngx.say的时候arg是table类型。ngx.print我看文档是说支持打印table的https://github.com/openresty/lua-nginx-module#ngxprint。但是我 ngx.print(arg)就会报错。
    error-log是这样的。
    ```
    2019/10/06 10:57:27 [error] 42634#1017147: *50 lua entry thread aborted: runtime error: /Users/fang/Code/lua_test/lua_script/params.lua:9: bad argument #1 to 'print' (non-array table found)
    stack traceback:
    coroutine 0:
    [C]: in function 'print'
    /Users/fang/Code/lua_test/lua_script/params.lua:9: in main chunk, client: 127.0.0.1, server: localhost, request: "POST /print_params HTTP/1.1", host: "localhost"
    ```
    提示参数出错 no array or table found 。 那么这个 arg 到底是不是一个table
    2019-10-06
  • 岁月如歌
    思考题:使用系统时间戳作为种子 在分布式环境中机器的时间不一致 导致可能产生的种子是一样的 进而可能导致随机数不再随机。 解决的防止可以使用统一的时间机器 而非 各自机器的时间。 这个问题跟生产唯一性分布式ID有点关联
    2019-07-13
  • 夏天的风
    请问一下windows上怎么运行resty,我看用luajit a.lua是可以成功的,用luajit -e 'print("hello")' 会报错,用resty -e 'print("hello")' 也会报同样的错误。
    D:\lua>luajit -e 'print("hello")'
    luajit: (command line):1: unexpected symbol near ''print(hello)''
     
    D:\lua>luajit a.lua
    hello world

    作者回复: 推荐在 Linux 环境运行专栏的代码,Windows 上OpenResty 自己也是功能受限的。

    2019-07-03
  • wusiration
    秒级的os.time在短时间调用中,random函数会以相同的随机种子产生相同的随机数
    2019-06-18
  • 小飞哥 ‍超級會員
    localhost: /usr/local/opt/openresty> ll /usr/local/Cellar/openresty/1.15.8.1/luajit/bin/luajit
    lrwxr-xr-x 1 yuesf admin 18 6 12 07:04 /usr/local/Cellar/openresty/1.15.8.1/luajit/bin/luajit -> luajit-2.1.0-beta3
    localhost: /usr/local/opt/openresty> luajit -v
    -bash: luajit: command not found

    luajit 是不是存在, 为什么 执行luajit 命令说不存在
    2019-06-16
  • 小飞哥 ‍超級會員
    为什么我这里没有luajit?
    localhost: ~> whicht luajit
    -bash: whicht: command not found
    localhost: ~> which luajit
    localhost: ~> luajit -v
    -bash: luajit: command not found
    localhost: ~>

    是否我安装有问题
    localhost: /usr/local/opt/openresty> pwd
    /usr/local/opt/openresty
    localhost: /usr/local/opt/openresty> openresty -v
    nginx version: openresty/1.15.8.1
    localhost: /usr/local/opt/openresty>

    作者回复: luajit 在 /usr/local/openresty/luajit/ 目录中,避免污染系统的 luajit

    2019-06-16
  • chengzise
    1. 用当前时间戳作为种子的,是通用做法没有什么大问题。这种方式利用的是随机数生成函数,随机数重复周期很长而已,不能算是完全随机。 大多数使用环境没什么问题。
    2. 在要求严格随机数环境中,例如:加解密算法。可以使用系统提供的随机数接口,这种方式利用的是芯片电磁噪声来生成随机数。由于需要经过系统调用,理论上速度没有第一种方式快。
    可以根据需要选择哪种方式。

    作者回复: 就是要有足够的熵

    2019-06-10
  • cylim
    brew install luajit 安装luajit。 opm没有-v参数,可是是可以用的。
    2019-06-10
  • 旺旺
    luajit -v 和 opm -v 都提示命令找不到, 这肯定是PATH的设置不对。
    lua 中pairs 和 ipairs区别可以参考下面的文章:
    https://blog.csdn.net/witch_soya/article/details/7556595
    2019-06-10
  • moshufenmo
    代表key 没有实际意义
    2019-06-10
  • 一步
    执行 resty -e 'print(math.random())'
    执行多次,为什么每次生成的随机数都一样呢?
    2019-06-10
    1
  • WL
    请问一下老师在for _, v in ipairs({4,5,6}) do ... 这段代码中的虚变量表示的是什么含义, 有点没太看懂.

    作者回复: 代表的就是下标,也就是 key

    2019-06-10
  • WL
    请问一下老师我这边luajit -v 和 opm -v 都提示命令找不到, openresty的版本是openresty/1.15.8.1, 想问下这种请情况是啥原因, 应该咋解决
    2019-06-10
收起评论
21
返回
顶部