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从入门到实战
登录|注册

41 | lua-resty-* 封装,让你远离多级缓存之痛

温铭 2019-08-28
你好,我是温铭。
前面两节课中,我们已经学习了 OpenResty 中的缓存,以及容易出错的缓存风暴问题,这些都是属于偏基础的一些知识。在实际的项目开发中,开发者自然更希望有一个已经把各种细节处理好并隐藏起来的开箱即用的库,可以拿来直接开发业务代码。
这其实就是分工的一个好处,基础组件的开发者,重心在于架构灵活、性能极致、代码稳定,并不需要关心上层业务逻辑;而应用层的工程师,更关心的是业务实现和快速迭代,并不希望被底层的各种技术细节分心。这中间的鸿沟,就需要有一些封装库来填平了。
OpenResty 中的缓存,也面临一样的问题。共享字典和 lru 缓存足够稳定和高效,但需要处理太多的细节。如果没有一些好用的封装,那么到达应用开发工程师的“最后一公里”,就会变得比较痛苦。这个时候,就要体现社区的重要性了。一个活跃的社区,会主动去发现鸿沟,并迅速地填平。

lua-resty-memcached-shdict

让我们回到缓存的封装上来。lua-resty-memcached-shdict 是 OpenResty 官方的一个项目,它使用 shared dict 为 memcached 做了一层封装,处理了缓存风暴和过期数据等细节。如果你的缓存数据正好存储在后端的 memcached 中,那么你可以尝试使用这个库。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《OpenResty从入门到实战》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(6)

  • manatee
    想请问下老师多次提到的timer数量限制,这个限制具体是多少呢,从哪里可以查到相关资料呢

    作者回复: lua_max_pending_timers 和 lua_max_running_timers 这两个指令来做控制

    2019-08-28
    2
    4
  • Shliesce
    接着我上面的这个观点,最近在设计“联动注册发现中心 动态更新 upstream 并缓存在进程内”的插件时,目前仅做了shared dict这一层的缓存,从初步的压测结果来看,单机 32C 的 cpu 平均使用率 30%可以达到 8w 的 qps,也不知道是不是错觉,性能比我们用 upsync 时还要好。。。
    重点是在后续增加 lrucache 时,因为考虑到这种场景不存在key expired 的问题,主要是 value 变更比较频繁,且需要保证尽可能的数据一致性,像 mlcache 这种被动更新的逻辑就不太好实现,而且还要考虑到每次 reload 时的lrucache 全量 miss 的场景,最终评估下来我决定采用主动更新缓存的方案。同时因为 nginx 每次 reload 时都会加载 init_by_lua*阶段,所以我打算把主动更新的逻辑做到 init 阶段,借助 master fork worker 时继承内存空间的逻辑提前预热缓存;另外就是每次更新 shared dict 时同步更新 lrucache。暂时还不确定这个方案有没有什么坑,老师能帮忙提几条建议吗?

    作者回复: 没有明白为什么把主动更新的逻辑放在 init 阶段呢?
    你可以在 init 阶段获取全量数据,通过长连接监听事件通知,去获取增量的数据。
    这时候其实你可以只用 lru 缓存,去掉共享字典这个 L2 缓存。
    APISIX(https://github.com/iresty/apisix)也是这么实现的,它的数据源在 etcd,通过 etcd 的 watch 来获取上游的变更。

    2019-09-01
    2
  • Shliesce
    在实际的生产应用中,我认为 shared dict 这一层缓存是必须的,貌似大家都只记得lrucache的好,数据格式没限制,不需要反序列化,不需要根据 k/v 体积算内存空间,worker 间独立不相互争抢,没有读写锁,性能高云云,但是却忘记了它最致命的一个弱点就是 lrucache 的生命周期是跟着 worker 走的,每当nginx reload 时,这部分缓存会全部丢失,这时候如果没有 shared dict,那 L3 的数据源分分钟被打挂,当然这是并发比较高的情况下,但是既然用到了缓存,说明业务体量肯定不会小。。不知道我的这个观点对吗?

    作者回复: 大部分情况下确实如你所说,共享字典在 reload 的时候不会丢失。也有一种特例,如果在 init 阶段或者init_worker阶段就能从 L3 主动获取到所有数据,那么只有 L1 其实也是可以接受的。

    2019-09-01
    2
  • 许童童
    共享字典这一层缓存不是必须的,但有这一层性能会高很多,因为lrucache 只能在单个worker中共享,而共享字典可以在整个server中共享,所以当一个worker中命中不了时,此时数据可能在另一个worker中存在,如果有server层的缓存,那命中率将大大提高。
    2019-08-28
    2
  • 言身寸飞
    我觉得shared dict是必须的。如果只有L1的话,量级大的、缓存经常变化的应用的话work多的话后面的数据会有连接压力吧。
    2019-09-19
  • wusiration
    共享字典这一层缓存并非必须,只用lrucache同样可以满足需求。只不过多加一层L2缓存(共享字典),可以使得服务器在L1缓存未命中的情况下,通过多个worker之间的共享数据,以减少读库的次数。
    2019-08-28
收起评论
6
返回
顶部