OpenResty从入门到实战
温铭
OpenResty软件基金会主席,《OpenResty 最佳实践》作者
立即订阅
4332 人已学习
课程目录
已完结 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从入门到实战
登录|注册

33 | 性能提升10倍的秘诀:必须用好 table

温铭 2019-08-09
你好,我是温铭。
在 OpenResty 中,除了字符串经常出现性能问题外,table 也是性能的拦路虎。在之前的章节中,我们零零散散地介绍过 table 相关的函数,但并没有专门提到它对性能方面的提升。今天,我就带你专门来聊聊,table 操作对性能的影响。
不同于对字符串的熟悉,开发者对于 table 相关的性能优化知之甚少,这主要有两个方面的原因。
其一,OpenResty 中使用的是 Lua ,是自己的 LuaJIT 分支,不是标准的 LuaJIT,也不是标准的 Lua。而大部分开发者并不知道它们之间的区别,倾向于使用标准 Lua 的 table 库来写 OpenResty 代码。
其二,在标准 LuaJIT 和 OpenResty 自己的 LuaJIT 分支中,table 操作相关的文档都藏得非常深,开发者很难找到;而且文档中也没有示例代码,需要开发者自己去开源项目中寻找示例。
这就形成了比较高的认知壁垒,导致了两极分化的结果——资深的 OpenResty 开发者能够写出很高性能的代码,而刚入门的则会怀疑 OpenResty 的高性能是不是一个泡沫。当然,等你学习完这节课的内容,你就可以轻松地戳破这层窗户纸,让性能提升 10 倍不是梦。
在详细介绍 table 优化之前,我想先强调的一点是,table 相关的优化,有一个自己的简单原则:
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《OpenResty从入门到实战》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(12)

  • wusiration
    尝试了以下性能测试:
    (1)预先生成数组
    resty -e '
    local begin = ngx.now()
    local t = {}
    for i = 1,100000000 do
      table.insert(t, i)
    end
    ngx.update_time()
    print(ngx.now()-begin)
    '
    用时:21.62700009346
    resty -e '
    local new_tab = require "table.new"
    local begin = ngx.now()
    local t = new_tab(100000000, 0)
    for i = 1,100000000 do
      table.insert(t, i)
    end
    ngx.update_time()
    print(ngx.now()-begin)
    '
    用时:7.595999956131

    (2)自己计算table下标
    --使用insert函数
    resty -e '
    local new_tab = require "table.new"
    local begin = ngx.now()
    local t = new_tab(100000000, 0)
    for i = 1,100000000 do
      table.insert(t, i)
    end
    ngx.update_time()
    print(ngx.now()-begin)
    '
    用时:7.6459999084473
    --自己计算下标
    resty -e '
    local new_tab = require "table.new"
    local begin = ngx.now()
    local t = new_tab(100000000, 0)
    for i = 1,100000000 do
      t[i] = i
    end
    ngx.update_time()
    print(ngx.now()-begin)
    '
    用时:0.33599996566772

    (3)循环使用单个table
    --分别建立两个table
    resty -e '
    local new_tab = require "table.new"
    local begin = ngx.now()
    local t1 = new_tab(100000000, 0)
    for i = 1,100000000 do
      t1[i] = i
    end
    local t2 = new_tab(100000000, 0)
    for i = 1,100000000 do
      t2[i] = i
    end
    ngx.update_time()
    print(ngx.now()-begin)
    '
    用时:0.66700005531311

    --复用table
    resty -e '
    local new_tab = require "table.new"
    local begin = ngx.now()
    local t = new_tab(100000000, 0)
    for i = 1,100000000 do
      t[i] = i
    end
    for i = 1,100000000 do
      t[i] = i
    end
    ngx.update_time()
    print(ngx.now()-begin)
    '
    用时:0.40800023078918

    作者回复: 👍

    2019-08-11
    2
  • 回家
    OpenResty是从哪个版本开始完全绑定LuaJIT的呢?

    作者回复: 我记得是 1.15 这个版本开始就只支持自己的 LuaJIT 了。lua 和官方的 luajit 都不再支持了

    2019-08-25
    1
  • 回家
    table. clean函数的实现是循环遍历每一个元素,然后置空,相比重新创建一个table来说效率更高。这个是和table的大小无关的是吧,table的重利用的效率总是高于新建一个表格。
    这样也有一个要求,重利用的table的大小需要满足多重情况。APISIX中的表格变量都没有使用table. new 来创建,是因为大小不确定吗?

    作者回复: APISIX 里面是做了一层封装:core.table.new(),其实底层还是 table.new

    2019-08-25
  • 回家
    老师,APISIX中的load函数少个end.

    作者回复: 多谢

    2019-08-25
  • 回家
    老师,文中有这样一段话:
    也就是说,你用 table.new(narray, nhash) 生了一个长度为 100 的数组,clear 后,长度还是 100。
    哈哈,生了一个数组

    作者回复: 好眼神:)

    2019-08-25
  • 回家
    老师好,文章中提到table. new 函数属于LuaJIT的扩展,是OpenResty维护的LuaJIT分支的扩展还是就是LuaJIT的扩展?

    作者回复: 这个函数是 LuaJIT 的扩展

    2019-08-25
  • 回家
    老师,数组以空间换时间创建时,应该是没有resize 和rehash 操作的,而不是这些操作一次完成的是吧?

    作者回复: 是的,如果不超过 table.new 的预设大小,是没有这些操作的。

    2019-08-25
  • 见习勇者
    问老师,您好,我有个疑问,您举例的table复用的阶段是在init_worker阶段,这个阶段只会在初始化worker的时候调用一次,并不会影响实际的请求,有必要进行这样的优化么?对后续的请求处理有提升么?

    作者回复: 算是一个习惯了,如果是 init worker 阶段确实优化不了多少

    2019-08-13
  • helloworld
    老师,lua最大支持的数是2的53次方,那如何处理ipv6地址相关的需求呢,就是128位大数的加减乘除,比较等运算,目前lua好像都不支持,对于这种情况怎么处理比较好呢
    2019-08-11
  • dingjiayi
    温老师,有没有比较优雅的方式去切割 access.log 和 error.log
    现在我看到网上介绍的方案都是 lograte 或者crontab 启动定时任务去切割
    想请问nginx 有自带切割日志的功能吗?或者有比crontab 更优雅的方案吗

    作者回复: 你可以使用 OpenResty 的特权进程来做日志文件的切割,等于自己用 timer.every 来实现了crontab的功能。

    2019-08-10
  • 许童童
    table优化总结:
    预先定义大小:空间换时间
    table池:对象复用
    计算下标:改进算法

    作者回复: 是的,很多优化都是抠出来的

    2019-08-09
  • 阳光梦
    您好,使用标准nginx和luajit,有没有您说的这样优化方法?谢谢

    作者回复: 这里面讲的优化方法,是适用于 LuaJIT 的

    2019-08-09
    1
收起评论
12
返回
顶部