openresty源码剖析——lua代码的加载
2017-07-28 11:45
197 查看
##Openresty是什么
OpenResty是一个基于 Nginx 与 Lua 的高性能 Web 平台,通过把lua嵌入到Nginx中,使得我们可以用轻巧的lua语言进行nginx的相关开发,处理高并发,扩展性极高的动态 Web 应用。
大家知道lua_code_cache 开关用于控制是否缓存*_by_lua_file对应的文件里的lua代码
lua_code_cache off的情况下,跟请求有关的阶段,在每次有请求来的时候,都会重新加载最新的lua文件,这样我们修改完代码之后就不用通过reload来更新代码了
而*_by_lua_block、*_by_lua和init_by_lua_file里的代码(init_by_lua阶段和具体请求无关),如果修改的内容涉及这几个,仍需要通过reload来更新代码
那openresty是如何实现这些,如何完成加载代码,和代码缓存的呢?
##Nginx配置
假设Nginx相关的配置如下所示
当来到的请求符合 ^/api/([-_a-zA-Z0-9/] 时,会在NGX_HTTP_CONTENT_PHASE HTTP请求内容阶段交给 lua/$1.lua来处理
比如
/api/addition 交给 lua/addition.lua 处理
/api/substraction 交给 lua/substraction .lua 处理
##请求的处理
content_by_lua_file对应的请求来临时,执行流程为 ngx_http_lua_content_handler -> ngx_http_lua_content_handler_file-> ngx_http_lua_content_by_chunk
配置项相关
处理函数
创建上下文结构
276行 如果关闭了lua代码缓存,那么openresty就会为每一个请求创建一个新的lua_state 并设置相关的字段,最后赋值给ctx->vm_state,
ctx->vm_state的类型如下
回调函数
##代码加载
代码加载分成3步完成
ngx_http_lua_cache_load_code 从lua_state的全局变量table中加载代码,如果全局缓存中有就返回
ngx_http_lua_clfactory_loadfile 用自定义的函数从文件中加载代码
ngx_http_lua_cache_store_code 把代码存放到lua_state的全局变量table中
尝试从全局变量table中加载代码
42-52行,相当于LUA_REGISTRYINDEX[‘ngx_http_lua_code_cache_key’][‘key’]以ngx_http_lua_code_cache_key为索引从全局注册表表中查找key对于的value
54-61行,如果value存在并且为一个函数,因为这里的函数体是 return function() … end包裹的 所以在56行需要再调用lua_pcall执行下,以获得返回的函数并将返回的函数结果放到栈顶,最终将 LUA_REGISTRYINDEX从栈中移除
如果代码缓存关闭的时候,openresty会为每一个请求创建一个新的lua_state,这样请求来临的时候在全局变量table中找不到对应的代码缓存,需要到下一步ngx_http_lua_clfactory_loadfile中读取文件加载代码
如果代码缓存打开的时候,openresty会使用ngx_http_lua_module全局的lua_state,这样只有新的lua文件,在首次加载时需要到ngx_http_lua_clfactory_loadfile中读取文件加载代码,第二次来的时候便可以在lua_state对应的全局变量table中找到了
从文件中读取代码
#define CLFACTORY_BEGIN_CODE "return function() "
#define CLFACTORY_END_CODE "\nend"
700行用自定义的ngx_http_lua_clfactory_getF函数读取lua代码
并在原有代码的开头加上了return function() 结束处加上了\nend
缓存代码
108-119行,相当于 LUA_REGISTRYINDEX[‘ngx_http_lua_code_cache_key’][‘key’] = function xxx,将代码放入全局table中
122行,将 LUA_REGISTRYINDEX从栈中弹出
125行,因为代码块是 return function() … end包裹的,所以在56行需要再调用lua_pcall执行以获得返回的函数
##总结
1、当lua_code_cache off的情况下,openresty关闭lua代码缓存,为每一个请求都创建一个新的lua_state,这样每一个请求来临的时候在新创建的lua_state中,都在全局table的代码缓存中找不到代码,需要重新读取文件加载代码,
因此可以立即动态加载新的lua脚本,而不需要reload nginx,但因为每个请求都需要分配新的lua_state,和读取文件加载代码,所以性能较差
2、当lua_code_cache on的情况下,openresty打开lua代码缓存,每一个请求使用ngx_http_lua_module全局的lua_state,新的lua文件在首次加载的时候,会去读取文件加载代码,然后存放到lua的全局变量中,
请求再次的时候 就会在lua_state全局table缓存中找到了,不需要再读取文件加载代码,因此修改完代码之后,需要reload nginx之后才可以生效
3、通过 content_by_lua_file 中使用 Nginx 变量时,可以在实现在lua_code_cache on的情况下动态加载新的 Lua 脚本,而不需要reload nginx
OpenResty是一个基于 Nginx 与 Lua 的高性能 Web 平台,通过把lua嵌入到Nginx中,使得我们可以用轻巧的lua语言进行nginx的相关开发,处理高并发,扩展性极高的动态 Web 应用。
大家知道lua_code_cache 开关用于控制是否缓存*_by_lua_file对应的文件里的lua代码
lua_code_cache off的情况下,跟请求有关的阶段,在每次有请求来的时候,都会重新加载最新的lua文件,这样我们修改完代码之后就不用通过reload来更新代码了
而*_by_lua_block、*_by_lua和init_by_lua_file里的代码(init_by_lua阶段和具体请求无关),如果修改的内容涉及这几个,仍需要通过reload来更新代码
那openresty是如何实现这些,如何完成加载代码,和代码缓存的呢?
##Nginx配置
假设Nginx相关的配置如下所示
比如
/api/addition 交给 lua/addition.lua 处理
/api/substraction 交给 lua/substraction .lua 处理
##请求的处理
content_by_lua_file对应的请求来临时,执行流程为 ngx_http_lua_content_handler -> ngx_http_lua_content_handler_file-> ngx_http_lua_content_by_chunk
配置项相关
ctx->vm_state的类型如下
ngx_http_lua_cache_load_code 从lua_state的全局变量table中加载代码,如果全局缓存中有就返回
ngx_http_lua_clfactory_loadfile 用自定义的函数从文件中加载代码
ngx_http_lua_cache_store_code 把代码存放到lua_state的全局变量table中
尝试从全局变量table中加载代码
54-61行,如果value存在并且为一个函数,因为这里的函数体是 return function() … end包裹的 所以在56行需要再调用lua_pcall执行下,以获得返回的函数并将返回的函数结果放到栈顶,最终将 LUA_REGISTRYINDEX从栈中移除
如果代码缓存关闭的时候,openresty会为每一个请求创建一个新的lua_state,这样请求来临的时候在全局变量table中找不到对应的代码缓存,需要到下一步ngx_http_lua_clfactory_loadfile中读取文件加载代码
如果代码缓存打开的时候,openresty会使用ngx_http_lua_module全局的lua_state,这样只有新的lua文件,在首次加载时需要到ngx_http_lua_clfactory_loadfile中读取文件加载代码,第二次来的时候便可以在lua_state对应的全局变量table中找到了
从文件中读取代码
#define CLFACTORY_END_CODE "\nend"
700行用自定义的ngx_http_lua_clfactory_getF函数读取lua代码
并在原有代码的开头加上了return function() 结束处加上了\nend
缓存代码
122行,将 LUA_REGISTRYINDEX从栈中弹出
125行,因为代码块是 return function() … end包裹的,所以在56行需要再调用lua_pcall执行以获得返回的函数
##总结
1、当lua_code_cache off的情况下,openresty关闭lua代码缓存,为每一个请求都创建一个新的lua_state,这样每一个请求来临的时候在新创建的lua_state中,都在全局table的代码缓存中找不到代码,需要重新读取文件加载代码,
因此可以立即动态加载新的lua脚本,而不需要reload nginx,但因为每个请求都需要分配新的lua_state,和读取文件加载代码,所以性能较差
2、当lua_code_cache on的情况下,openresty打开lua代码缓存,每一个请求使用ngx_http_lua_module全局的lua_state,新的lua文件在首次加载的时候,会去读取文件加载代码,然后存放到lua的全局变量中,
请求再次的时候 就会在lua_state全局table缓存中找到了,不需要再读取文件加载代码,因此修改完代码之后,需要reload nginx之后才可以生效
3、通过 content_by_lua_file 中使用 Nginx 变量时,可以在实现在lua_code_cache on的情况下动态加载新的 Lua 脚本,而不需要reload nginx
相关文章推荐
- openresty源码剖析——lua代码的加载
- openresty源码剖析——lua代码的加载
- openresty源码剖析——lua代码的加载
- openresty源码剖析——lua代码的执行
- cocos2d-x+lua代码热加载(Hot Swap)的研究
- vc++工程中添加lua代码调用-增加lua的源码到工程
- openresty 应用打包并使用luajit编译lua代码实现简单加密
- 手把手教你读懂源码,View的加载流程详细剖析
- Android一行代码实现网络加载GIF闪图(附源码)
- Android Picasso图片加载库源码剖析
- 从 RequireJs 源码剖析脚本加载原理
- 第014讲:Scala中Map和HashMap源码剖析及代码实践(从1000个代码案例中学习人工智能和大数据实战)
- spring源码剖析(一)下载spring3.2源代码,并编译源代码
- WorldWind源码剖析系列:星球球体的加载与渲染
- UDT源码剖析(六):UDT::socket()过程代码注释
- BaseRecyclerViewAdapterHelper开源项目之BaseQuickAdapter源码学习上拉加载的实现代码(三)
- 大数据Spark “蘑菇云”行动第79课:Spark GraphX 代码实战及源码剖析
- lua 02 源码剖析
- Android消息处理机制:源码剖析Handler、Looper,并实现图片异步加载
- wemall app商城源码中基于JAVA的Android异步加载图片管理器代码