OpenResty之 lua_shared_dict 指令
1. lua_shared_dict 指令介绍
原文: lua_shared_dict
syntax:lua_shared_dict <name> <size>
default: no
context: http
phase: depends on usage
声明一个共享内存区域 name,以充当基于 Lua 字典 ngx.shared.<name> 的共享存储。
共享内存总是被当前 Nginx 服务器实例中所有的 Nginx worker 进程所共享。
size 参数接受大小单位,如 k,m:
http {
lua_shared_dict dogs 10m;
...
}
详细参见: ngx.shared.DICT
2. 源码分析
lua_shared_dict 指令位于 ngx_http_lua_module.c 文件中:
static ngx_command_t ngx_http_lua_cmds[] = {
...
{ ngx_string("lua_shared_dict"),
NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE2,
ngx_http_lua_shared_dict,
0,
0,
NULL },
...
}
2.1 ngx_http_lua_shared_dict
char *
ngx_http_lua_shared_dict(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_lua_main_conf_t *lmcf = conf;
ngx_str_t *value, name;
ngx_shm_zone_t *zone;
ngx_shm_zone_t **zp;
ngx_http_lua_shdict_ctx_t *ctx;
ssize_t size;
if (lmcf->shdict_zones == NULL) {
lmcf->shdict_zones = ngx_palloc(cf->pool, sizeof(ngx_array_t));
if (lmcf->shdict_zones == NULL) {
return NGX_CONF_ERROR;
}
if (ngx_array_init(lmcf->shdict_zones, cf->pool, 2,
sizeof(ngx_shm_zone_t *))
!= NGX_OK)
{
return NGX_CONF_ERROR;
}
}
value = cf->args->elts;
ctx = NULL;
if (value[1].len == 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid lua shared dict name \"%V"\"", &value[1]);
return NGX_CONF_ERROR;
}
/* 共享内存的名称 */
name = value[1];
/* 解析需要分配的共享内存大小 */
size = ngx_parse_size(&value[2]);
if (size <= 8191) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid lua shared dict size \"%V\"", &value[2]);
return NGX_CONF_ERROR;
}
ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_lua_shdict_ctx_t));
if (ctx == NULL) {
return NGX_CONF_ERROR;
}
ctx->name = name;
ctx->main_conf = lmcf;
ctx->log = &cf->cycle->new_log;
zone = ngx_http_lua_shared_memory_add(cf, &name, (size_t) size,
&ngx_http_lua_module);
if (zone == NULL) {
return NGX_CONF_ERROR;
}
if (zone->data) {
ctx = zone->data;
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"lua_shared_dict "\%V\" is already defined as "
"\%V\"", &name, &ctx->name);
return NGX_CONF_ERROR;
}
zone->init = ngx_http_lua_shdict_init_zone;
zone->data = ctx;
zp = ngx_array_push(lmcf->shdict_zones);
if (zp == NULL) {
return NGX_CONF_ERROR;
}
*zp = zone;
lmcf->requires_shm = 1;
return NGX_CONF_OK;
}
2.2 ngx_http_lua_shared_memory_add
ngx_shm_zone_t *
ngx_http_lua_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, size_t size,
void *tag)
{
ngx_http_lua_main_conf_t *lmcf;
ngx_shm_zone_t **zp;
ngx_shm_zone_t *zone;
ngx_http_lua_shm_zone_ctx_t *ctx;
ngx_int_t n;
lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module);
if (lmcf == NULL) {
return NULL;
}
if (lmcf->shm_zones == NULL) {
lmcf->shm_zones = ngx_palloc(cf->pool, sizeof(ngx_array_t));
if (lmcf->shm_zones == NULL) {
return NULL;
}
if (ngx_array_init(lmcf->shm_zones, cf->pool, 2,
sizeof(ngx_shm_zone_t *))
!= NGX_OK)
{
return NULL;
}
}
/* 分配一个代表共享内存的结构体 ngx_shm_zone_t,并将其插入到
* cf->cycle->shared_memory 链表中 */
zone = ngx_shared_memory_add(cf, name, (size_t) size, tag);
if (zone == NULL) {
return NULL;
}
if (zone->data) {
ctx = (ngx_http_lua_shm_zone_ctx_t *) zone->data;
return &ctx->zone;
}
n = sizeof(ngx_http_lua_shm_zone_ctx_t);
ctx = ngx_pcalloc(cf->pool, n);
if (ctx == NULL) {
return NULL;
}
ctx->lmcf = lmcf;
ctx->log = &cf->cycle->new_log;
ctx->cycle = cf->cycle;
ngx_memcpy(&ctx->zone, zone, sizeof(ngx_shm_zone_t));
zp = ngx_array_push(lmcf->shm_zones);
if (zp == NULL) {
return NULL;
}
*zp = zone;
/* 设置在 init_cycle 中真正创建共享内存时调用的初始化函数,
* 该 init 函数是各个共享内存所特定的,根据使用方的自身需求不同
* 而不同 */
/* set zone init */
zone->init = ngx_http_lua_shared_memory_init;
zone->data = ctx;
lmcf->requires_shm = 1;
return &ctx->zone;
}
在 init_cycle 函数中:
{
...
/* create shared memory */
part = &cycle->shared_memory.part;
shm_zone = part->elts;
for (i = 0; /* void */ ; i++) {
...
if (ngx_shm_alloc(&shm_zone[i].shm) != NGX_OK) {
goto failed;
}
if (ngx_init_zone_pool(cycle, &shm_zone[i]) != NGX_OK) {
goto failed;
}
/* 指向每个模块所创建的共享内存所特有的 init 函数 */
if (shm_zone[i].init(&shm_zone[i], NULL) != NGX_OK) {
goto failed;
}
}
...
}
对于 ngx_http_lua_module 模块的 lua_shared_dict 指令所创建的共享内存的 init 函数为 ngx_http_lua_shared_memory_init。
2.3 ngx_http_lua_shared_memory_init
static ngx_int_t
ngx_http_lua_shared_memory_init(ngx_shm_zone_t *shm_zone, void *data)
{
ngx_http_lua_shm_zone_ctx_t *octx = data;
ngx_shm_zone_t *ozone;
void *odata;
ngx_int_t rc;
volatile ngx_cycle_t *saved_cycle;
ngx_http_lua_main_conf_t *lmcf;
ngx_http_lua_shm_zone_ctx_t *ctx;
ngx_shm_zone_t *zone;
ctx = (ngx_http_lua_shm_zone_ctx_t *) shm_zone->data;
zone = &ctx->zone;
odata = NULL;
if (octx) {
ozone = &octx->zone;
odata = ozone->data;
}
zone->shm = shm_zone->shm;
#if defined(nginx_version) && nginx_version >= 1009000
zone->noreuse = shm_zone->noreuse;
#endif
/* 指向 ngx_http_lua_shdict_init_zone 函数 */
if (zone->init(zone, odata) != NGX_OK) {
return NGX_ERROR;
}
dd("get lmcf");
lmcf = ctx->lmcf;
if (lmcf == NULL) {
return NGX_ERROR;
}
dd("lmcf->lua: %p", lmcf->lua);
lmcf->shm_zones_inited++;
if (lmcf->shm_zones_inited == lmcf->shm_zones->nelts
&& lmcf->init_handler)
{
saved_cycle = ngx_cycle;
ngx_cycle = ctx->cycle;
rc = lmcf->init_handler(ctx->log, lmcf, lmcf->lua);
ngx_cycle = saved_cycle;
if (rc != NGX_OK) {
/* an error happened */
return NGX_ERROR;
}
}
return NGX_OK;
}
2.4 ngx_http_lua_shdict_init_zone
ngx_int_t
ngx_http_lua_shdict_init_zone(ngx_shm_zone_t *shm_zone, void *data)
{
ngx_http_lua_shdict_ctx_t *octx = data;
size_t len;
ngx_http_lua_shdict_ctx_t *ctx;
dd("init zone");
ctx = shm_zone->data;
if (octx) {
ctx->sh = octx->sh;
ctx->shpool = octx->shpool;
return NGX_OK;
}
ctx->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
if (shm_zone->shm.exists) {
ctx->sh = ctx->shpool->data;
return NGX_OK;
}
ctx->sh = ngx_slab_alloc(ctx->shpool, sizeof(ngx_http_lua_shdict_shctx_t));
if (ctx->sh == NULL) {
return NGX_ERROR;
}
ctx->shpool->data = ctx->sh;
ngx_rbtree_init(&ctx->sh->rbtree, &ctx->sh->sentinel,
ngx_http_lua_shdict_rbtree_insert_value);
ngx_queue_init(&ctx->sh->lru_queue);
len = sizeof(" in lua_shared_dict zone \"\"") + shm_zone->shm.name.len;
ctx->shpool->log_ctx = ngx_slab_alloc(ctx->shpool, len);
if (ctx->shpool->log_ctx == NULL) {
return NGX_ERROR;
}
ngx_sprintf(ctx->shpool->log_ctx, " in lua_shared_dict zone \"%V\"%Z",
&shm_zone->shm.name);
#if defined(nginx_version) && nginx_version >= 1005013
ctx->shpool->log_nomem = 0;
#endif
return NGX_OK;
}
OpenResty之 lua_shared_dict 指令的更多相关文章
- 《用OpenResty搭建高性能服务端》笔记
概要 <用OpenResty搭建高性能服务端>是OpenResty系列课程中的入门课程,主讲人:温铭老师.课程分为10个章节,侧重于OpenResty的基本概念和主要特点的介绍,包括它的指 ...
- OpenResty学习指南(一)
我的博客: https://www.luozhiyun.com/archives/217 想要学好 OpenResty,你必须理解下面 8 个重点: 同步非阻塞的编程模式: 不同阶段的作用: LuaJ ...
- OpenResty和Resis一些基本的性能配置
Basics: 1. Ensure that you have not disabled Lua code cache: https://github.com/openresty/lua-nginx- ...
- openresty域名动态解析
工作中使用openresty,使用第三方服务API通过域名访问.但是,域名通过DNS解析出来之后,在openresty是有 配置解析阶段 很多时候我们会在 Nginx 配置文件里配置上一些域名,比如配 ...
- 【技术干货】听阿里云CDN安防技术专家金九讲tengine+lua开发
一.介绍 二.安装 三.运行 四.开发 1.介绍 Tengine:轻量级.高性能.高并发.配置化.模块化.可扩展.可移植的Web和反向代理 服务器,Tengine是nginx超集,但做了很多优化,包含 ...
- Redis与DB的数据一致性解决方案(史上最全)
文章很长,而且持续更新,建议收藏起来,慢慢读! 高并发 发烧友社群:疯狂创客圈(总入口) 奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : 极致经典 + 社群大片好评 < Java 高并发 三 ...
- 高并发 Nginx+Lua OpenResty系列(3)——模块指令
Nginx Lua 模块指令 Nginx共11个处理阶段,而相应的处理阶段是可以做插入式处理,即可插拔式架构:另外指令可以在http.server.server if.location.locatio ...
- OpenResty之指令与常用API
1. 指令 通过 Lua 编写 Nginx 脚本的基本构建块是指令.指令常用于指定 Lua 代码是几时执行的以及如何使用运行的结果.下图展示了指令执行的顺序. lua_capture_error_lo ...
- 用Nginx+Lua(OpenResty)开发高性能Web应用
在互联网公司,Nginx可以说是标配组件,但是主要场景还是负载均衡.反向代理.代理缓存.限流等场景:而把Nginx作为一个Web容器使用的还不是那么广泛.Nginx的高性能是大家公认的,而Nginx开 ...
随机推荐
- swiper按钮点击无效及控制器无效问题
点击箭头图片切换的同时,下面小图标也会随着切换,同理下面小图标切换时,上面也随着滚动. 示例代码如下: <!-- Swiper --> <div class="swiper ...
- jvm系列(十):如何优化Java GC「
转自:https://www.cnblogs.com/ityouknow/p/7653129.html 本文由CrowHawk翻译,地址:如何优化Java GC「译」,是Java GC调优的经典佳作. ...
- vscode 使用ESLint 自动检查,保存时自动格式化
1:全局安装eslint `npm install -g eslint`2: 打开vscode 点击 “文件”----->“首选项”---->“设置”,在右侧“用户设置/settings. ...
- zabbix-设置邮箱预警
设置预警系统 机器是被监控上了,但是出了问题怎么通知呢?之前学过监控软件的都知道可以使用报警机制啊,如果监控平台zabbix server发现某个机器异常了,可以给运维管理员发邮件啊,通过邮件通知管理 ...
- mysql使用GTID跳过事务
GTID跳过有两种方法,一种是普通的跳过一个事务的方法,另外一个是在基于主库搭建新的slave的时候.一.普通跳过一个事务的方法.通过show slave status\G找到冲突的GTID号.然后执 ...
- php curl请求接口并获取数据
当我们在做php开发的时候,很多时候需要对接口进行测试,或者更方便的调用一些已有模块的接口,取到结果并进行后续操作,我们可以通过curl进行模拟提交post和get请求,来去实现这些功能. 下面是对c ...
- Ubuntu系统---C++之Eclipse IDE 编译器安装
Ubuntu系统---C++之Eclipse IDE 编译器安装 Eclipse是一个基于Java的.开放源码的.可扩展的应用开发平台,它为编程人员提供了一流的Java集成开发环境(Integrate ...
- Why Go? – Key advantages you may have overlooked
Why Go? – Key advantages you may have overlooked yourbasic.org/golang Go makes it easier (than Java ...
- 由浅入深剖析 go channel
原文:https://www.jianshu.com/p/24ede9e90490 ---------------------------------- 由浅入深剖析 go channel chann ...
- TCP的三次握手与四次挥手的理解
本文经过借鉴书籍资料.他人博客总结出的知识点,欢迎提问 序列号seq:占4个字节,用来标记数据段的顺序,TCP把连接中发送的所有数据字节都编上一个序号,第一个字节的编号由本地随机产生:给字节编上 ...