nginx共享内存

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Nginx共享内存

 

 

 

 



 


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1.       介绍

1.1.   介绍

nginx共享内存是利用mmap将内容存储在内存中以及自旋锁。当master启动的时候,根据相应的指令去初始化共享内存。利用共享内存实现一个轻量级的k/v系统。

 

 

 

 

2.       结构

2.1.   全局变量

 

ngx_cycle_s结构:

struct ngx_cycle_s {

   void                 ****conf_ctx;  //配置上下文数组(含所有模块)

   ngx_pool_t              *pool;      //内存池

   ngx_log_t               *log;       //日志

    ngx_log_t                 new_log;

   ngx_connection_t       **files;     //连接文件

   ngx_connection_t        *free_connections;  //空闲连接

   ngx_uint_t               free_connection_n; //空闲连接个数

   ngx_queue_t              reusable_connections_queue;  //再利用连接队列

   ngx_array_t              listening;     //监听数组

   ngx_array_t               pathes;        //路径数组

   ngx_list_t               open_files;    //打开文件链表

   ngx_list_t               shared_memory; //共享内存链表

   ngx_uint_t               connection_n;  //连接个数

   ngx_uint_t               files_n;       //打开文件个数

    ngx_connection_t         *connections;   //连接

   ngx_event_t             *read_events;   //读事件

   ngx_event_t             *write_events;  //写事件

   ngx_cycle_t             *old_cycle;     //old cycle指针

   ngx_str_t                conf_file;     //配置文件

    ngx_str_t                 conf_param;    //配置参数

   ngx_str_t                conf_prefix;   //配置前缀

   ngx_str_t                prefix;        //前缀

   ngx_str_t                lock_file;     //锁文件

   ngx_str_t                hostname;      //主机名

};

2.2.   共享内存结构

ngx_zone_s结构:

struct ngx_shm_zone_s {

void *data; //指向自定义数据结构,一般用来初始化时使用,可能指向本地地址

ngx_shm_t shm; //真正的共享内存

ngx_shm_zone_init_pt init; //初始化函数

void *tag; //标记

};

 

ngx_shm_t结构:

typedef struct { 

    u_char   *addr;   // 共享内存首地址 

    size_t   size;    // 共享内存大小 

    ngx_str_t  name;  // 共享内存名称 

    ngx_log_t  *      // 日志 

    ngx_uint_t  exists;

} ngx_shm_t

 

回收共享内存:

void

ngx_shm_free(ngx_shm_t *shm)

{

    if(munmap((void *) shm->addr, shm->size) == -1) {

        ngx_log_error(NGX_LOG_ALERT,shm->log, ngx_errno,

                     "munmap(%p, %uz) failed", shm->addr, shm->size);

    }

}

 

 

分配共享内存:

ngx_int_t

ngx_shm_alloc(ngx_shm_t *shm)

{

    shm->addr =(u_char *) mmap(NULL, shm->size,

                               PROT_READ|PROT_WRITE,

                               MAP_ANON|MAP_SHARED, -1, 0);

 

    if(shm->addr == MAP_FAILED) {

       ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,

                     "mmap(MAP_ANON|MAP_SHARED, %uz) failed", shm->size);

        returnNGX_ERROR;

    }

 

    return NGX_OK;

}

 

 

ngx_shm_zone_t * ngx_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, size_t size, void*tag)

{

   ngx_uint_t        i;

   ngx_shm_zone_t   *shm_zone;

   ngx_list_part_t  *part;

 

    part =&cf->cycle->shared_memory.part;

   shm_zone = part->elts;

//先查找所有已经存在的共享内存,看看要创建的共享内存是否存在于这里面,如果存在的话就直接返回,否则

//创建一个新的共享内存结构体再返回

for (i = 0; /* void */ ; i++) {

 

        if(i >= part->nelts) {

           if (part->next == NULL) {

               break;

           }

           part = part->next;

           shm_zone = part->elts;

           i = 0;

        }

 

        if(name->len != shm_zone[i].shm.name.len) {

           continue;

        }

 

        if(ngx_strncmp(name->data, shm_zone[i].shm.name.data, name->len)

           != 0)

        {

           continue;

        }

 

        if(size && size != shm_zone[i].shm.size) {

           ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,

                            "the size %uz of shared memory zone\"%V\" "

                            "conflictswith already declared size %uz",

                            size,&shm_zone[i].shm.name, shm_zone[i].shm.size);

           return NULL;

        }

 

        if(tag != shm_zone[i].tag) {

           ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,

                            "the sharedmemory zone \"%V\" is "

                            "alreadydeclared for a different use",

                           &shm_zone[i].shm.name);

           return NULL;

        }

//此共享内存已经存在,直接返回

       return &shm_zone[i];

    }

//插入一个新的共享内存结构体结点

   shm_zone = ngx_list_push(&cf->cycle->shared_memory);

 

    if(shm_zone == NULL) {

       return NULL;

    }

 

   shm_zone->data = NULL;

   shm_zone->shm.log = cf->cycle->log;

   shm_zone->shm.size = size;

   shm_zone->shm.name = *name;

   shm_zone->shm.exists = 0;

   shm_zone->init = NULL;

   shm_zone->tag = tag;

 

    returnshm_zone;

}

 

2.3.   自旋锁数据结构及实现

ngx_shmtx_t数据结构:

typedef struct {

#if (NGX_HAVE_ATOMIC_OPS)

   ngx_atomic_t  *lock;  //如果支持原子锁的话,那么使用它

#if (NGX_HAVE_POSIX_SEM)

   ngx_atomic_t  *wait;

   ngx_uint_t     semaphore;

   sem_t          sem;

#endif

#else

   ngx_fd_t       fd;   //不支持原子操作的话就使用文件锁来实现

   u_char        *name;

#endif

   ngx_uint_t     spin;     //自旋锁

} ngx_shmtx_t;

 

创建锁:

ngx_int_t

ngx_shmtx_create(ngx_shmtx_t *mtx, ngx_shmtx_sh_t*addr, u_char *name)

{

   mtx->lock = &addr->lock; //其实就是直接将内存地址赋个mtx的lock域就完事了

    if(mtx->spin == (ngx_uint_t) -1) {  //如果等于-1是自旋锁

       return NGX_OK;

    }

   mtx->spin = 2048;

    returnNGX_OK;

}

 

尝试加锁(加锁失败则直接返回,不等待):

ngx_shmtx_trylock(ngx_shmtx_t *mtx){

   ngx_err_t  err;

    err =ngx_trylock_fd(mtx->fd);

    if (err== 0) {

       return 1;

    }

}

ngx_err_t

ngx_trylock_fd(ngx_fd_t fd)

{

    structflock  fl;

 

   ngx_memzero(&fl, sizeof(struct flock));

   fl.l_type = F_WRLCK;

   fl.l_whence = SEEK_SET;

 

    if(fcntl(fd, F_SETLK, &fl) == -1) {

       return ngx_errno;

    }

    return0;

}

 

解锁:

void

ngx_shmtx_unlock(ngx_shmtx_t *mtx)

{

   ngx_err_t  err;

 

    err =ngx_unlock_fd(mtx->fd);

 

    if (err== 0) {

       return;

    }

   ngx_log_abort(err, ngx_unlock_fd_n " %s failed",mtx->name);

}

ngx_err_t

ngx_unlock_fd(ngx_fd_t fd)

{

    structflock  fl;

 

   ngx_memzero(&fl, sizeof(struct flock));

   fl.l_type = F_UNLCK;

   fl.l_whence = SEEK_SET;

 

    if(fcntl(fd, F_SETLK, &fl) == -1) {

       return  ngx_errno;

    }

 

    return0;

}

 

spinlock的实现原理是?

a.      用户态尝试竞争一个共享资源. 如果竞争不到, 则不断尝试竞争. 但是不借助内核提供的mutex等变量机制. 因为涉及到内核,就意味这效率低下.

b.      要想在用户态实现竞争一个共享资源, 必须借助cpu提供的原子操作指令. 如果是SMP多cpu,还需要lock指令锁总线.

c.       为了避免在长时间竞争却一直得不到资源导致的不断尝试浪费cpu, 在每两次尝试之间间隔一段时间. 并且随着尝试次数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
nginx支持共享内存,因此可以利用共享内存实现共享变量的配置热部署。具体步骤如下: 1. 在nginx配置文件中定义共享内存区域: ``` http { ... # 定义共享内存区域,大小为1M # 可以根据实际情况调整大小 # 以下是示例,具体的key和size可以根据需要自行调整 # 注意:key相同的共享内存只能有一个 # 如果需要多个共享内存区域,可以使用不同的key # 例如:ngx.shared.myshm1和ngx.shared.myshm2 lua_shared_dict myshm 1m; ... } ``` 2. 在nginx配置文件中定义lua脚本: ``` http { ... # 定义lua脚本 # 以下是示例,具体的脚本内容可以根据需要自行编写 # 注意:必须使用init_by_lua_file指令加载脚本文件 # 如果使用其他方式加载脚本,可能会出现共享内存无法正常使用的问题 lua_shared_dict myshm; init_by_lua_file /path/to/mylua.lua; ... } ``` 3. 在lua脚本中实现共享变量的配置热部署: ``` -- 获取共享内存区域 local myshm = ngx.shared.myshm -- 从共享内存中获取配置信息 local config = myshm:get("config") -- 处理配置信息 -- ... -- 监听配置文件的变化 local function file_change_callback(event, filename) -- 重新读取配置文件 -- ... -- 将新的配置信息写入共享内存 myshm:set("config", new_config) end -- 注册文件变化事件 -- 当配置文件发生变化时,会自动调用file_change_callback函数 local ok, err = ngx.on_config_change(file_change_callback) if not ok then ngx.log(ngx.ERR, "failed to register the on_config_change callback: ", err) end ``` 4. 修改配置文件时,nginx会自动调用lua脚本中的file_change_callback函数,将新的配置信息写入共享内存。因此,可以实现共享变量的配置热部署。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值