极客时间已完结课程限时免费阅读

03 | 揪出隐藏在背后的那些子项目

03 | 揪出隐藏在背后的那些子项目-极客时间

03 | 揪出隐藏在背后的那些子项目

讲述:温铭

时长15:31大小14.17M

你好,我是温铭。
我们先来揭晓上一节最后留下的思考题,如何把 Lua 代码从 nginx.conf 里面抽取出来,保持代码的可读性和可维护性呢?
操作其实很简单。
我们先在 geektime 的工作目录下,创建一个名为 lua 的目录,专门用来存放代码:
$ mkdir lua
$ cat lua/hello.lua
ngx.say("hello, world")
然后修改 nginx.conf 的配置,把 content_by_lua_block 改为 content_by_lua_file:
pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
server {
listen 8080;
location / {
content_by_lua_file lua/hello.lua;
}
}
}
最后,重启 OpenResty 的服务就可以了:
$ sudo kill -HUP `cat logs/nginx.pid`
你可以使用 curl ,验证是否返回了预期的结果。至于后面 Lua 代码的变更,你就可以直接修改 hello.lua 这个文件,而不是 nginx.conf 了。
其实,在上面这个小例子里面,也有几个有趣的地方:
content_by_lua_file lua/hello.lua; 里面写的是相对路径,那么 OpenResty 是如何找到这个 Lua 文件的?
Lua 代码内容的变更,需要重启 OpenResty 服务才会生效,这样显然不方便调试,那么有没有什么即时生效的方法呢?
如何把 lua 代码所在的文件夹,加入到 OpenResty 的查找路径中呢?
这几个问题,我鼓励你先自己思考一下,它们都可以在官方文档里面找到答案。这也是为什么,我一直强调文档的重要性。
接下来我们一起来解答。先看第一个问题。如果原本给出的是相对路径,那么 OpenResty 在启动时,会把 OpenResty 启动的命令行参数中的 -p PATH 作为前缀,将相对路径拼接为绝对路径。这样,自然就可以顺利找到 Lua 文件。
再来看第二个问题。Lua 代码在第一个请求时会被加载,并默认缓存起来。所以在你每次修改 Lua 源文件后,都必须重新加载 OpenResty 才会生效。其实,在 nginx.conf 中关闭 lua_code_cache 就能避免重新加载,这一点你可以自己试试看。不过,特别需要注意的是,这种方法只能临时用于开发和调试,如果是线上部署,一定要记得打开缓存,否则会非常影响性能。
最后一个问题,OpenResty 提供了 lua_package_path 指令,可以设置 Lua 模块的查找路径。针对上面的例子,我们可以把 lua_package_path 设置为 $prefix/lua/?.lua;;,其中,
$prefix就是启动参数中的 -p PATH;
/lua/?.lua表示 lua 目录下所有以 .lua 作为后缀的文件;
最后的两个分号,则代表内置的代码搜索路径。

OpenResty 安装后的目录结构

了解完第一个 hello world 程序后,我们继续追根究底,来看下 OpenResty 自身安装完成后,它的目录结构是怎样的,以及里面包含哪些文件。
我们先通过 -V 选项,查看 OpenResty 安装到了哪一个目录。下面的这个结果,我省略了很多模块的编译参数,这些我们稍后再来补上:
$ openresty -V
nginx version: openresty/1.13.6.2
built by clang 10.0.0 (clang-1000.10.44.4)
built with OpenSSL 1.1.0h 27 Mar 2018
TLS SNI support enabled
configure arguments: --prefix=/usr/local/Cellar/openresty/1.13.6.2/nginx ...
我本地是通过 brew 安装的,所以目录是/usr/local/Cellar/openresty/1.13.6.2/nginx ,和你的本地环境很可能不同。这其中主要包含了 bin、luajit、lualib、nginx、pod 这几个子目录。理解这几个文件夹的含义很重要,可以帮我们更好地学习 OpenResty。接下来,我们逐个来看一下。
首先是最重要的 bin 目录:
$ ll /usr/local/Cellar/openresty/1.13.6.2/bin
total 320
-r-xr-xr-x 1 ming admin 19K 3 27 12:54 md2pod.pl
-r-xr-xr-x 1 ming admin 15K 3 27 12:54 nginx-xml2pod
lrwxr-xr-x 1 ming admin 19B 3 27 12:54 openresty -> ../nginx/sbin/nginx
-r-xr-xr-x 1 ming admin 62K 3 27 12:54 opm
-r-xr-xr-x 1 ming admin 29K 3 27 12:54 resty
-r-xr-xr-x 1 ming admin 15K 3 27 12:54 restydoc
-r-xr-xr-x 1 ming admin 8.3K 3 27 12:54 restydoc-index
这里面既有我们上一节中提到的 OpenResty CLI resty,也有最核心的可执行文件 openresty,它其实是 nginx 的一个软链接。至于目录里面其他的一些工具,没有任何悬念,它们和 resty 一样,都是 Perl 脚本。
在这其中,opm 是包管理工具,可以通过它来管理各类第三方包,后面会有一节内容专门来讲;而 restydoc,则是我们第一节提到过的“老朋友”了,它是 OpenResty 提供的文档查看工具,你可以通过它来查看 OpenResty 和 NGINX 的使用文档:
$ restydoc -s ngx.say
$ restydoc -s proxy_pass
这段代码中的两个例子,分别查询了 OpenResty 的 API 和 NGINX 的指令。restydoc 这个工具,对服务端工程师的专注开发有很大帮助。
浏览完了 bin 目录,我们接着看下 pod 目录。先强调一点,这里的“pod”,和 k8s 里“pod”的概念完全没有关系。pod 是 Perl 里面的一种标记语言,用于给 Perl 的模块编写文档。pod 目录中存放的就是 OpenResty、 NGINX、lua-resty-*、LuaJIT 的文档, 这些就和刚才提到的 restydoc 联系在一起了。
接下来是熟悉的 nginx 和 luajit 这两个目录。这两个很好理解,主要存放 NGINX 和 LuaJIT 的可执行文件和依赖,是 OpenResty 的基石。很多人说 OpenResty 基于 Lua,这个说法其实并不准确,从上面我们可以看出, OpenResty 其实是基于 LuaJIT 的。
事实上,早期的 OpenResty 同时带有 Lua 和 LuaJIT,你可以通过编译选项,来决定使用 Lua 还是 LuaJIT。不过到了现在,Lua 逐渐被淘汰,就只支持更高性能的 LuaJIT 了。
最后,我们看下 lualib 目录。它里面存放的是 OpenResty 中使用到的 Lua 库,主要分为 ngx 和 resty 两个子目录。
前者存放的是 lua-resty-core 这个官方项目中的 Lua 代码,里面都是基于 FFI 重新实现的 OpenResty API,后面我会用专门的文章来解释为什么要重新实现,这里你有个大概印象即可,不必深究。
而 resty 目录中存放的则是各种 lua-resty-* 项目包含的 Lua 代码,接下来我们会接触到。
按照我讲课的惯例,到这一步我会给出这些目录源头的出处。这也是开源项目的乐趣之一,如果你喜欢打破砂锅问到底,那你总发现更多好玩的东西。
下面是 OpenResty 在 CentOS 中的打包脚本,里面包含了上面提到的所有目录,你可以自己了解一下。
%files
%defattr(-,root,root,-)
/etc/init.d/%{name}
/usr/bin/%{name}
%{orprefix}/bin/openresty
%{orprefix}/site/lualib/
%{orprefix}/luajit/*
%{orprefix}/lualib/*
%{orprefix}/nginx/html/*
%{orprefix}/nginx/logs/
%{orprefix}/nginx/sbin/*
%{orprefix}/nginx/tapset/*
%config(noreplace) %{orprefix}/nginx/conf/*
%{orprefix}/COPYRIGHT

OpenResty 项目概览

提到 OpenResty,你应该会想到 lua-nginx-module。没错,这个 NGINX 的 C 模块确实是 OpenResty 的核心,但它并不等价于 OpenResty。很多工程师都会把 OpenResty 叫做 ngx lua,有不少技术大会的分享和出版的书籍中也是用的这个叫法,这其实是不严谨的,也是 OpenResty 社区不提倡的。
下面我来讲讲为什么,以及 OpenResty 中除了 lua-nginx-module ,还有哪些其他的关联项目。
打开 OpenResty 在 GitHub 的 项目主页,你可以看到 OpenResty 包含了 68 个公开的项目,大概分为以下 7 类, 下面我来分别简单介绍下,让你有个初步的印象,这样你后面学习起来也轻松一些。

NGINX C 模块

OpenResty 的项目命名都是有规范的,以 *-nginx-module命名的就是 NGINX 的 C 模块。
OpenResty 中一共包含了 20 多个 C 模块,我们在本节最开始使用的 openresty -V 中,也可以看到这些 C 模块:
$ openresty -V
nginx version: openresty/1.13.6.2
built by clang 10.0.0 (clang-1000.10.44.4)
built with OpenSSL 1.1.0h 27 Mar 2018
TLS SNI support enabled
configure arguments: --prefix=/usr/local/Cellar/openresty/1.13.6.2/nginx --with-cc-opt='-O2 -I/usr/local/include -I/usr/local/opt/pcre/include -I/usr/local/opt/openresty-openssl/include' --add-module=../ngx_devel_kit-0.3.0 --add-module=../echo-nginx-module-0.61 --add-module=../xss-nginx-module-0.06 --add-module=../ngx_coolkit-0.2rc3 --add-module=../set-misc-nginx-module-0.32 --add-module=../form-input-nginx-module-0.12 --add-module=../encrypted-session-nginx-module-0.08 --add-module=../srcache-nginx-module-0.31 --add-module=../ngx_lua-0.10.13 --add-module=../ngx_lua_upstream-0.07 --add-module=../headers-more-nginx-module-0.33 --add-module=../array-var-nginx-module-0.05 --add-module=../memc-nginx-module-0.19 --add-module=../redis2-nginx-module-0.15 --add-module=../redis-nginx-module-0.3.7 --add-module=../ngx_stream_lua-0.0.5 --with-ld-opt='-Wl,-rpath,/usr/local/Cellar/openresty/1.13.6.2/luajit/lib -L/usr/local/lib -L/usr/local/opt/pcre/lib -L/usr/local/opt/openresty-openssl/lib' --pid-path=/usr/local/var/run/openresty.pid --lock-path=/usr/local/var/run/openresty.lock --conf-path=/usr/local/etc/openresty/nginx.conf --http-log-path=/usr/local/var/log/nginx/access.log --error-log-path=/usr/local/var/log/nginx/error.log --with-pcre-jit --with-ipv6 --with-stream --with-stream_ssl_module --with-stream_ssl_preread_module --with-http_v2_module --without-mail_pop3_module --without-mail_imap_module --without-mail_smtp_module --with-http_stub_status_module --with-http_realip_module --with-http_addition_module --with-http_auth_request_module --with-http_secure_link_module --with-http_random_index_module --with-http_geoip_module --with-http_gzip_static_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-threads --with-dtrace-probes --with-stream --with-stream_ssl_module --with-http_ssl_module
这里--add-module=后面跟着的,就是 OpenResty 的 C 模块。其中,最核心的就是 lua-nginx-module 和 stream-lua-nginx-module,前者用来处理七层流量,后者用来处理四层流量。
这些 C 模块中,有些是需要特别注意的,虽然默认编译进入了 OpenResty,但并不推荐使用。 比如 redis2-nginx-module、redis-nginx-module 和 memc-nginx-module,它们是用来和 redis 以及 memcached 交互使用的。这些 C 库是 OpenResty 早期推荐使用的,但在 cosocket 功能加入之后,它们都已经被 lua-resty-redis 和 lua-resty-memcached 替代,处于疏于维护的状态。
OpenResty 后面也不会开发更多的 NGINX C 库,而是专注在基于 cosocket 的 Lua 库上,后者才是未来。

lua-resty- 周边库

OpenResty 官方仓库中包含 18 个 lua-resty-* 库,涵盖 Redis、MySQL、memcached、websocket、dns、流量控制、字符串处理、进程内缓存等常用库。除了官方自带的之外,还有更多的第三方库。它们非常重要,所以下一章节,我们会花更多的篇幅来专门介绍这些周边库。

自己维护的 LuaJIT 分支

OpenResty 除了维护自己的 OpenSSL patch 外,还维护了自己的 LuaJIT 分支。在 2015 年,LuaJIT 的作者 Mike Pall 宣布退休,寻找新的 LuaJIT 维护者,但 Mike 并没有找到合适的维护者,他现在主要是做 bugfix 的维护工作,新功能的开发也已经暂停,所以 OpenResty 维护着自己的 LuaJIT 分支。
相对于 Lua,LuaJIT 增加了不少独有的函数,这些函数非常重要,但知道的工程师并不多,算是 _ 半隐藏技能 _,后面我也会专门介绍。

测试框架

OpenResty 的测试框架是test-nginx,同样也是用 Perl 语言来开发的,从名字上就能看出来,它是专门用来测试 NGINX 相关的项目。OpenResty 官方的所有 C 模块和 lua-resty 库的测试案例,都是由 test-nginx 驱动的。
这个框架和常见的基于断言的框架不同,是一套更强大和独立的系统,我们后面会花几节课来专门学习。
事实上,有些 OpenResty 的代码贡献者也没有搞清楚这个测试框架,有时候提交的 PR 中包含了不少复杂的 C 和 Lua 代码,但对编写对应的测试案例一事,还是经常发怵。所以,如果你已经查看过一些 OpenResty 项目中/t目录里面的测试案例,却仍然一头雾水,先别急着怀疑自己,大部分人都是一样的。
除了 test-nginx 之外,mockeagain 这个项目可以模拟慢速的网络,让程序每次只读写一个字节。对于 web 服务器来说,这是一个很有用的工具。

调试工具链

OpenResty 项目在如何科学和动态地调试代码上,花费了大量的精力,可以说是达到了极致。OpenResty 的作者章亦春专门写了一篇文章,来介绍动态追踪技术。我强烈推荐给你,看完也有助于理解对应的工具链。
openresty-systemtap-toolkitstapxx 这两个 OpenResty 的项目,都基于 systemtap 这个动态调试和追踪工具。使用 systemtap 最大的优势,便是实现活体分析,同时对目标程序完全无侵入。
打个比方,systemtap,就像是我们去医院照了个 CT,无痛无感知。更棒的是,systemtap 可以生成直观的火焰图来做性能分析,后面我也会专门介绍,这里先放一个火焰图,让你直观上有个感性的认识:

打包相关

OpenResty 在不同发行操作系统(比如 CentOS、Ubuntu、MacOS 等)版本中的打包脚本,出于更细可控力度的目的,都是手工编写的。我们在介绍安装后目录结构的时候,就已经涉及到了这些打包相关的项目:openresty-packaginghome-brew。如果你对此有兴趣,可以自行学习,这里我就不再赘述了。

工程化工具

除了上面这些比较大块儿的项目之外,OpenResty 还有一些负责工程化的工具,大都也是“深藏闺中”。
比如 openresty-devel-utils 就是开发 OpenResty 和 NGINX 的工具集。它们也都使用 Perl 开发,其中大部分的工具都是没有文档的。但对于 OpenResty 的开发者来说,这些工具又是非常有用的。
这里我先挑几个简单介绍一下。
lj-releng 是一个简单有效的 LuaJIT 代码检测工具,类似 luacheck,可以找出全局变量等潜在的问题。
reindex 从名字来看是重建索引的意思,它其实是格式化 test-nginx 测试案例的工具,可以重新排列测试案例的编号,以及去除多余的空白符。reindex 可以说是 OpenResty 开发者每天都会用到的工具之一。
opsboy 也是一个深藏不露的项目,主要用于自动化部署。OpenResty 每次发布版本前,都会在 AWS EC2 集群上做完整的回归测试,详细的文档你可以参考官方文档,而这个回归测试正是由 opsboy 来部署和驱动的。
opsboy 是一个用 Perl 实现的 DSL(领域特定语言)。实际上, OpenResty 的作者非常喜欢创造各种不同的 DSL 来解决问题。

写在最后

今天,我们主要学习了 OpenResty 安装后的目录结构,以及背后的一些子项目。希望你学完今天的内容后,能够了解更多 OpenResty 的项目。OpenResty 已经远远超出了 NGINX 负载均衡和反向代理的范畴,实现了自己的生态,下一次我们会详细聊聊这方面。
对于今天的内容,你有哪些疑惑和问题吗?欢迎留言和我分享,也欢迎你把这篇文章转发给你的同事、朋友,一起学习高效开发。
分享给需要的人,Ta购买本课程,你将得18
生成海报并分享

赞 16

提建议

上一篇
02 | 如何写出你的“hello world”?
下一篇
04 | 如何管理第三方包?从包管理工具luarocks和opm说起
unpreview
 写留言

精选留言(36)

  • oatlmy
    2019-06-01
    看了温大15年底的文章《OpenResty的现状、趋势、使用及学习方法》,对比在三年半后的这几篇文章中讲到的特性模块,真是太优秀了!

    作者回复: 加油:)

    8
  • KevinGao
    2021-04-12
    CentOS 下 OpenResty 安装后需要手动安装 resty,doc 和 opm 1,安装 openresty-resty ``` yum install openresty-resty ``` 2,安装 opm ``` yum install openresty-opm ``` 3,安装 restydoc (其实安装 OPM 时会自动安装 doc) ``` yum install openresty-doc ``` 4,列出可用的 openresty 包 ``` yum --disablerepo="*" --enablerepo="openresty" list available ```
    展开
    5
  • 红鲤鱼与绿鲤鱼与驴ba...
    2019-05-31
    sudo kill -HUP cat logs/nginx.pid 代码 应该是 sudo kill -HUP `cat logs/nginx.pid` 吧

    作者回复: 是的,多谢指正

    5
  • 业余草
    2019-06-05
    这是第3张了。但是我看到现在我还没有看懂这个名字的来历。就是现在有人问的话,我也是一脸懵逼啊。

    作者回复: OpenResty 的名字来历? OpenResty 最早是雅虎中国的一个公司项目,起步于 2007 年 10 月。当时兴起了 OpenAPI 的热潮,于是春哥想做一个类似的东西,可以支持各种 Web Service 的需求。 Open 取自 OpenAPI, Resty 取自 rest API。

    4
  • 石仔
    2019-05-31
    之前项目需要做个nginx为基础的api网关,我用了nginx + lua-nginx-module模块 模拟kong的编码结构做了一个半吊子的实践。当时的文档和生态都没有现在丰富,都是摸着石头过河,现在终于找到宝了,能让我系统化的窥探这架构了,非常感谢作者

    作者回复: 专栏最后也会搭建一个 api 网关:)

    4
  • 写点啥呢
    2019-08-29
    请问老师,lua_package_path似乎配置的是lua依赖的搜索路径,对于content_by_lua_file, 我试验发现它只在prefix下去根据指令提供的文件相对路径去搜索,而不会到lua_package_path下搜索,不知道我的理解对不对?

    作者回复: 是的,你的理解是对的

    共 2 条评论
    3
  • K1
    2019-05-31
    需要出一本书,OpenResty开发权威指南
    3
  • 莫得办法
    2019-12-27
    为什么centos7安装的没有restydoc,/usr/local/openresty/bin中只有一个openresty的软连接,一个CLI resty,再没有其他了
    共 1 条评论
    2
  • 大裤衩子
    2019-06-05
    Openresty可执行文件是nginx的一个软连接?这样的话为什么不直接基于本地已经装好的nginx呢?

    作者回复: 因为这里的 nginx 并不等同于官方的 nginx,而是把很多 c 模块打包重新生成的。 所以,为了和你本地已经安装好的 nginx 做区分,就做了一个软链接,名字是 OpenResty

    2
  • 2019-06-01
    老师你好,我发现在geektime文件中有很多以_temp结尾的文件夹,这些文件夹有什么作用吗?
    2
  • 向阳
    2020-08-16
    centos7 使用wget https://openresty.org/package/centos/openresty.repo及yum install -y openresty-resty安装之后默认没有安装resty-doc帮助工具咋办
    共 1 条评论
    1
  • ZeroIce
    2019-08-03
    初学者对于这些模块有什么作用,听起来一脸懵

    作者回复: 慢慢来,现有一个印象。用到的话才能理解深入

    1
  • 2019-06-19
    [root@localhost geektime]# sudo kill -HUP `cat logs/nginx.pid` [root@localhost geektime]# curl -i 127.0.0.1:8080 HTTP/1.1 404 Not Found Server: openresty/1.15.8.1 Date: Wed, 19 Jun 2019 14:41:34 GMT Content-Type: text/html Content-Length: 159 Connection: keep-alive <html> <head><title>404 Not Found</title></head> <body> <center><h1>404 Not Found</h1></center> <hr><center>openresty/1.15.8.1</center> </body> </html> [root@localhost geektime]# 为什么我运行出来是404??
    展开

    作者回复: 看看 error.log 的信息,是不是 lua 代码没有被找到?

    共 9 条评论
    1
  • 小飞哥 ‍超級會員
    2019-06-14
    为什么我openresty -v之后只有一条,我没有后面几行?

    作者回复: 大写的 V

    1
  • 初音未来
    2019-06-05
    老师你好,lua_code_cache 打开之后怎么解决lua代码更新及时生效的问题呢

    作者回复: 后面会讲到代码热更新

    1
  • 王金全
    2019-06-03
    指定pid就可以了,02节例子中没有指定pid

    作者回复: 是的,指定 pid 就行

    1
  • howei
    2019-06-02
    配置文件有个权限问题,如果不指定user 用户默认是nobody 无法执行lua 文件就会报错[error] 31322#31322: *1 failed to load external Lua file "/root/geektime/lua/hello.lua": cannot open /root/geektime/lua/hello.lua: Permission denied, client: 127.0.0.1, server: ,

    作者回复: 可以更换个目录来存放 lua 代码,或者指定 user

    共 2 条评论
    1
  • Panda
    2019-06-01
    分析项目结构 如庖丁解牛
    1
  • 王金全
    2019-06-01
    我在macOS下,按照官方文档安装,按照例子执行,logs/nginx.pid找不到,能找到/usr/local/var/run/openresty.pid文件,不知道是不是有问题?

    作者回复: nginx.conf 中是否有 pid 的设置呢?

    1
  • 2019-06-01
    老师,我打开geektime文件夹后,多出了很多不是自己创建的文件夹,都是以_temp结尾的,这些文件夹有什么作用吗?

    作者回复: 这些没有什么用的

    1