nginx如何动态修改upstream ngx_http_dyups_module


小编给大家分享一下nginx如何动态修改upstream ngx_http_dyups_module,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!nginx 动态修改upstream不reload nginx模块,ngx_http_dyups_module分析。主要围绕https://github.com/yzprofile/ngx_http_dyups_module/blob/master/ngx_http_dyups_module.c进行分析记录下来。开整……在create_main_conf的时候初始化这个数组static void * ngx_http_dyups_create_main_conf(ngx_conf_t *cf){…if (ngx_array_init(&dmcf->dy_upstreams, cf->pool, 1024, sizeof(ngx_http_dyups_srv_conf_t)) != NGX_OK){return NULL;}…}static ngx_http_module_t ngx_http_dyups_module_ctx = {ngx_http_dyups_pre_conf, /* preconfiguration */ngx_http_dyups_init, /* postconfiguration */ngx_http_dyups_create_main_conf, /* create main configuration */ngx_http_dyups_init_main_conf, /* init main configuration */ngx_http_dyups_create_srv_conf, /* create server configuration */NULL, /* merge server configuration */NULL, /* create location configuration */NULL /* merge location configuration */};在dyups init的时把upstream中的conf取出来放进去。初始化dy_upstream链以及全局ngx_http_dyups_deleted_upstream。static ngx_int_t ngx_http_dyups_init(ngx_conf_t *cf){…dmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_dyups_module);umcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_upstream_module);uscfp = umcf->upstreams.elts;for (i = 0; i upstreams.nelts; i++) {duscf = ngx_array_push(&dmcf->dy_upstreams);// 清零ngx_memzero(duscf, sizeof(ngx_http_dyups_srv_conf_t));duscf->pool = NULL;// 赋值duscf->upstream = uscfp[i];duscf->dynamic = (uscfp[i]->port == 0&& uscfp[i]->srv_conf && uscfp[i]->servers&& uscfp[i]->flags & NGX_HTTP_UPSTREAM_CREATE);duscf->deleted = 0;// 赋值indexduscf->idx = i;}…}shm初始化是在ngx_http_dyups_init_main_conf函数中实现的,同时设置了read_mesg的超时时间,并且指定了大小。static char *ngx_http_dyups_init_main_conf(ngx_conf_t *cf, void *conf){…if (dmcf->read_msg_timeout == NGX_CONF_UNSET_MSEC) {// 一秒一次dmcf->read_msg_timeout = 1000;}if (dmcf->shm_size == NGX_CONF_UNSET_UINT) {dmcf->shm_size = 2 * 1024 * 1024;}return ngx_http_dyups_init_shm(cf, conf);…}static char *ngx_http_dyups_init_shm(ngx_conf_t *cf, void *conf){…shm_zone = ngx_shared_memory_add(cf, &dmcf->shm_name, dmcf->shm_size,&ngx_http_dyups_module);shm_zone->data = cf->pool;// 加进去的这个名头的共享内存块的init函数会在初始化的时候统一调用shm_zone->init = ngx_http_dyups_init_shm_zone;…}static ngx_int_t ngx_http_dyups_init_shm_zone(ngx_shm_zone_t *shm_zone, void *data){…shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;sh = ngx_slab_alloc(shpool, sizeof(ngx_dyups_shctx_t));if (sh == NULL) {return NGX_ERROR;}// 全局变量,sh和shpoolngx_dyups_global_ctx.sh = sh;ngx_dyups_global_ctx.shpool = shpool;// 初始化msg->queuengx_queue_init(&sh->msg_queue);sh->version = 0;sh->status = NULL;…}该函数在启动进程时候调用,设定了一些定时器。初始化共享内存,判断如果是非正常退出的,那么重新加载upstream配置。static ngx_int_t ngx_http_dyups_init_process(ngx_cycle_t *cycle){…// 设定定时器来定时read msg,同步信息timer = &ngx_dyups_global_ctx.msg_timer;timer->handler = ngx_http_dyups_read_msg;ngx_add_timer(timer, dmcf->read_msg_timeout);// 拿到全局的pool和shshpool = ngx_dyups_global_ctx.shpool;sh = ngx_dyups_global_ctx.sh;ngx_shmtx_lock(&shpool->mutex);// 初始化的时候肯定是NULL,,申请对应数量进程数的内存if (sh->status == NULL) {sh->status = ngx_slab_alloc_locked(shpool,sizeof(ngx_dyups_status_t) * ccf->worker_processes);if (sh->status == NULL) {ngx_shmtx_unlock(&shpool->mutex);return NGX_ERROR;}ngx_memzero(sh->status,sizeof(ngx_dyups_status_t) * ccf->worker_processes);ngx_shmtx_unlock(&shpool->mutex);return NGX_OK;}ngx_shmtx_unlock(&shpool->mutex);// 判断version,如果不是0的话,说明version已经在同步中被++了,所以是进程挂掉再被拉起来if (sh->version != 0) {//…}最核心的是ngx_http_dyups_read_msg函数,里面的是ngx_http_dyups_read_msg_locked函数static void ngx_http_dyups_read_msg_locked(ngx_event_t *ev){…sh = ngx_dyups_global_ctx.sh;shpool = ngx_dyups_global_ctx.shpool;for (i = 0; i worker_processes; i++) {status = &sh->status[i];if (status->pid == 0 || status->pid == ngx_pid) {ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ev->log, 0,”[dyups] process %P update time %ui”,status->pid, status->time);// 遍历全部进程,将对应的pid赋值status->pid = ngx_pid;status->time = now;break;}}// 遍历消息队列for (q = ngx_queue_last(&sh->msg_queue);q != ngx_queue_sentinel(&sh->msg_queue);q = ngx_queue_prev(q)){// 如果该msg的count和进程数一致,就是大家都同步过了,把这个msg删掉if (msg->count == ccf->worker_processes) {t = ngx_queue_next(q); ngx_queue_remove(q); q = t;ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ev->log, 0, “[dyups] destroy msg %V:%V”,&msg->name, &msg->content);ngx_dyups_destroy_msg(shpool, msg);continue;}found = 0;for (i = 0; i count; i++) {ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0,”[dyups] msg pids [%P]”, msg->pid[i]);if (msg->pid[i] == ngx_pid) {found = 1;break;}}// 如果发现该进程了,就说明已经同步过了。if (found) {ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ev->log, 0, “[dyups] msg %V count %ui found”, &msg->name, msg->count);continue;}// 如果没发现的话,count++,pid更新msg->pid[i] = ngx_pid;msg->count++;ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ev->log, 0, “[dyups] msg %V count %ui”, &msg->name, msg->count);// 取出来name和contentname = msg->name;content = msg->content;// 执行同步rc = ngx_dyups_sync_cmd(pool, &name, &content, msg->flag);if (rc != NGX_OK) {ngx_log_error(NGX_LOG_ALERT, ev->log, 0, “[dyups] read msg error, may cause the ” “config inaccuracy,name:%V, content:%V”,&name, &content);}}…}static ngx_int_t ngx_dyups_sync_cmd(ngx_pool_t *pool, ngx_str_t *name, ngx_str_t *content, ngx_uint_t flag){…} else if (flag == NGX_DYUPS_ADD) {body.start = body.pos = content->data;body.end = body.last = content->data + content->len;body.temporary = 1;rc = ngx_dyups_do_update(name, &body, &rv);ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, “[dyups] sync add: %V rv: %V rc: %i”, name, &rv, rc);if (rc != NGX_HTTP_OK) {return NGX_ERROR;}return NGX_OK;}…}同步其他进程接受的信息,如果是当前进程处理的就要把信息添加到消息队列中。ngx_int_t ngx_dyups_update_upstream(ngx_str_t *name, ngx_buf_t *buf, ngx_str_t *rv){…ngx_http_dyups_read_msg_locked(timer);// 沙箱测试配置status = ngx_dyups_sandbox_update(buf, rv);if (status != NGX_HTTP_OK) {goto finish;}status = ngx_dyups_do_update(name, buf, rv);if (status == NGX_HTTP_OK) {//把操作发到队列中去if (ngx_http_dyups_send_msg(name, buf, NGX_DYUPS_ADD)) {ngx_str_set(rv, “alert: update success “”but not sync to other process”);status = NGX_HTTP_INTERNAL_SERVER_ERROR;}}…}ngx_http_dyups_send_msg函数分析static ngx_int_t ngx_http_dyups_send_msg(ngx_str_t *name, ngx_buf_t *body, ngx_uint_t flag){…// 初始化整个msg,将name和body填充进去sh->version++;ngx_queue_insert_head(&sh->msg_queue, &msg->queue);…}在update之前先find寻找对应的upstream。static ngx_http_dyups_srv_conf_t * ngx_dyups_find_upstream(ngx_str_t *name, ngx_int_t *idx){…duscfs = dumcf->dy_upstreams.elts;for (i = 0; i dy_upstreams.nelts; i++) {duscf = &duscfs[i];uscf = duscf->upstream;if (uscf->host.len != name->len|| ngx_strncasecmp(uscf->host.data, name->data, uscf->host.len)!= 0){continue;}*idx = i;return duscf;}…}如果寻找到了idx赋值。一旦发现寻找到了对应name的dy_upstream就先判断。然后调用的是ngx_dyups_mark_upstream_delete函数static void ngx_dyups_mark_upstream_delete(ngx_http_dyups_srv_conf_t *duscf){…// 获取umcf和uscfuscf = duscf->upstream;umcf = ngx_http_cycle_get_module_main_conf(n免费云主机域名gx_cycle,ngx_http_upstream_module);// us获取这个dynamic upstream下的serversus = uscf->servers->elts;for (i = 0; i servers->nelts; i++) {// 标志位置1us[i].down = 1;#if (NGX_HTTP_UPSTREAM_CHECK)if (us[i].addrs) {// 关闭peer,看宏定义主要关闭健康检查的peerngx_http_upstream_check_delete_dynamic_peer(&uscf->host,us[i].addrs);}#endif}// 将upstream对应的index的配置变成一个dummy配置uscfp[duscf->idx] = &ngx_http_dyups_deleted_upstream;#if (NGX_HTTP_UPSTREAM_RBTREE)ngx_rbtree_delete(&umcf->rbtree, &uscf->node);#endifduscf->deleted = NGX_DYUPS_DELETING;…}其中最重要的是check_delete_dynamic_peervoid ngx_http_upstream_check_delete_dynamic_peer(ngx_str_t *name,ngx_addr_t *peer_addr){…/* 一堆比较 找到choosen*/chosen = &peer[i];chosen->shm->ref–;if (chosen->shm->ref shm->delete != PEER_DELETED) {ngx_http_upstream_check_clear_dynamic_peer_shm(chosen->shm);chosen->shm->delete = PEER_DELETED;}ngx_shmtx_unlock(&chosen->shm->mutex);ngx_http_upstream_check_clear_peer(chosen);…}这样子删完一次之后,再find一次,idx大概率就变成-1了,就可以进行创建static ngx_int_t ngx_dyups_do_update(ngx_str_t *name, ngx_buf_t *buf, ngx_str_t *rv){…if (idx == -1) {duscf = ngx_array_push(&dumcf->dy_upstreams);uscfp = ngx_array_push(&umcf->upstreams);ngx_memzero(duscf, sizeof(ngx_http_dyups_srv_conf_t));// 这里为了获取在umcf中的新upstream的index值。idx = umcf->upstreams.nelts – 1;}duscf->idx = idx;rc = ngx_dyups_init_upstream(duscf, name, idx);rc = ngx_dyups_add_server(duscf, buf);…}最重要的就是init_upstream和add_server。首先是init ipstream,他的传参其实是dy_srv_conf_t。upstream的name,以及upstream链表中对应的indexstatic ngx_int_t ngx_dyups_init_upstream(ngx_http_dyups_srv_conf_t *duscf, ngx_str_t *name, ngx_uint_t index){…umcf = ngx_http_cycle_get_module_main_conf(ngx_cycle,ngx_http_upstream_module);uscfp = umcf->upstreams.elts;/*初始化uscf 也就是upstream的各个结构体*/uscfp[index] = uscf; // 赋值duscf->dynamic = 1;duscf->upstream = uscf;ctx = ngx_pcalloc(duscf->pool, sizeof(ngx_http_conf_ctx_t));// 存放ctxduscf->ctx = ctx;// insert进去uscfuscf->node.key = ngx_crc32_short(uscf->host.data, uscf->host.len);ngx_rbtree_insert(&umcf->rbtree, &uscf->node);…}static ngx_int_t ngx_dyups_add_server(ngx_http_dyups_srv_conf_t *duscf, ngx_buf_t *buf){…ngx_dyups_parse_upstream(&cf, buf)…}static char * ngx_dyups_parse_upstream(ngx_conf_t *cf, ngx_buf_t *buf){…b = *buf;ngx_memzero(&conf_file, sizeof(ngx_conf_file_t));conf_file.file.fd = NGX_INVALID_FILE;conf_file.buffer = &ampb;cf->conf_file = &conf_file;return ngx_conf_parse(cf, NULL);…}static ngx_int_t ngx_dyups_do_delete(ngx_str_t *name, ngx_str_t *rv){…duscf = ngx_dyups_find_upstream(name, &dumy);// 如果查出来的是NULL,或者是一个已经被标记删除,或者彻底删除的,就说明要删这个有异常if (duscf == NULL || duscf->deleted) {ngx_log_error(NGX_LOG_DEBUG, ngx_cycle->log, 0, “[dyups] not find upstream %V %p”, name, duscf);ngx_str_set(rv, “not found uptream”);return NGX_HTTP_NOT_FOUND;}// 没问题的话就执行正常删除ngx_dyups_mark_upstream_delete(duscf);…}find upstream做了很多事还做了一部分的删除操作。static ngx_http_dyups_srv_conf_t * ngx_dyups_find_upstream(ngx_str_t *name, ngx_int_t *idx){…dumcf = ngx_http_cycle_get_module_main_conf(ngx_cycle, ngx_http_dyups_module);duscfs = dumcf->dy_upstreams.elts;for (i = 0; i dy_upstreams.nelts; i++) {// 这里是在mark_upstream中被标记的if (duscf->deleted == NGX_DYUPS_DELETING) {// 确认可以删除,主要看这个ref的引用计数if (*(duscf->ref) == 0) {ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0, “[dyups] free dynamic upstream in find upstream” ” %ui”, duscf->idx);duscf->deleted = NGX_DYUPS_DELETED;if (duscf->pool) {ngx_destroy_pool(duscf->pool);duscf->pool = NULL;}}}// 如果是deleted或者是deleting,算是没有找到,除非遍历完没找到返回一个deleted。if (duscf->deleted == NGX_DYUPS_DELETING) {continue;}if (duscf->deleted == NGX_DYUPS_DELETED) {*idx = i;duscf_del = duscf;continue;}// 如果找到了就正常返回if (uscf->host.len != name->len|| ngx_strncasecmp(uscf->host.data, name->data, uscf->host.len)!= 0){continue;}*idx = i;return duscf;}…}dyups的peer init get和free函数。static ngx_int_t ngx_http_dyups_init_peer(ngx_http_request_t *r,ngx_http_upstream_srv_conf_t *us){…// 设置上下文ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_dyups_ctx_t));if (ctx == NULL) {return NGX_ERROR;}// scf指向对应的dscf,ctx的data指向了自己ctx->scf = dscf;ctx->data = r->upstream->peer.data;ctx->get = r->upstream->peer.get;ctx->free = r->upstream->peer.free;r->upstream->peer.data = ctx;r->upstream->peer.get = ngx_http_dyups_get_peer;r->upstream->peer.free = ngx_http_dyups_free_peer;// 与客户端的连接的这个pool注册一个销毁函数cln = ngx_pool_cleanup_add(r->pool, 0);if (cln == NULL) {return NGX_ERROR;}// 引用计数加一dscf->ref++;// 等调用这个就会将ref–。cln->handler = ngx_http_dyups_clean_request;cln->data = &dscf->ref;…}// 这个函数是在ngx_dyups_add_server初始化upstream中被赋值的uscf->peer.init = ngx_http_dyups_init_peer;// 调用的位置是在这里static void ngx_http_upstream_init_request(ngx_http_request_t *r){…if (uscf->peer.init(r, uscf) != NGX_OK) {ngx_http_upstream_finalize_request(r, u,NGX_HTTP_INTERNAL_SERVER_ERROR);return;}ngx_http_upstream_connect(r, u);…}static ngx_int_t ngx_http_dyups_get_peer(ngx_peer_connection_t *pc, void *data){ngx_http_dyups_ctx_t *ctx = data;// 就用之前的peer get来。return ctx->get(pc, ctx->data);}static void ngx_http_dyups_free_peer(ngx_peer_connection_t *pc, void *data,ngx_uint_t state){ngx_http_dyups_ctx_t *ctx = data;ngx_pool_cleanup_t *cln;/* upstream connect failed */if (pc->connection == NULL) {goto done;}if (pc->cached) {goto done;}// free的时候先给ref++,等调用handler后ref–ctx->scf->ref++;// pool设置一个销毁pool的数据结构,赋值给pool->cleanupcln = ngx_pool_cleanup_add(pc->connection->pool, 0);if (cln == NULL) {ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, “[dyups] dynamic upstream free peer may cause memleak %i”,ctx->scf->ref);goto done;}// 销毁的递归函数cln->handler = ngx_http_dyups_clean_request;cln->data = &ctx->scf->ref;done:// 结束后调用之前保存的freectx->free(pc, ctx->data, state);}static void ngx_http_dyups_clean_request(void *data){ngx_uint_t *ref = data;(*ref)–;ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, “[dyups] http clean request count %i”, *ref);}pool在被destroy的时候,会调用这个handler将引用计数减掉。void ngx_destroy_pool(ngx_pool_t *pool){ngx_pool_t *p, *n;ngx_pool_large_t *l;ngx_pool_cleanup_t *c;for (c = pool->cleanup; c; c = c->next) {if (c->handler) {ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0,”run cleanup: %p”, c);c->handler(c->data);}}…}以上是“nginx如何动态修改upstream ngx_http_dyups_module”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注云编程开发博客行业资讯频道!

相关推荐: windows看视频cpu占用过高如何解决

本篇内容介绍了“windows看视频cpu占用过高如何解决”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一般来说,视频追求高画质,所以需要CPU和显卡的解码你的…

免责声明:本站发布的图片视频文字,以转载和分享为主,文章观点不代表本站立场,本站不承担相关法律责任;如果涉及侵权请联系邮箱:360163164@qq.com举报,并提供相关证据,经查实将立刻删除涉嫌侵权内容。

Like (0)
Donate 微信扫一扫 微信扫一扫
Previous 02/02 21:16
Next 02/02 21:17