微信公众号:
关注可了解更多的Nginx知识。任何问题或建议,请公众号留言;关注公众号,有趣有内涵的文章第一时间送达!
简介
本篇文章主要是分析配置文件解析完毕之后对location的进一步优化。这一部分主要完成了静态树的构建,一切的目的就是为了更快捷的找到对应的location,提高http响应的速度。
代码分析
在ngx_http_block()
中有下面的一部分代码,如下:
1 /* create location trees */ 2 for (s = 0; s < cmcf->servers.nelts; s++) { 3 // 当前server的ctx的loc_conf[ngx_http_core_module.ctx_index] 4 clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index]; 5 6 if (ngx_http_init_locations(cf, cscfp[s], clcf) != NGX_OK) { 7 return NGX_CONF_ERROR; 8 } 9 10 if (ngx_http_init_static_location_trees(cf, clcf) != NGX_OK) { 11 return NGX_CONF_ERROR; 12 } 13 } 复制代码
上面的cmcf
是ngx_http_core_module
在http
级别的ctx
的main_conf数组
中对应的配置结构体,类型为ngx_http_core_main_conf_t
类型。经过前面分析,我们知道它的servers
字段是一个动态数组,保存了当前配置文件中的所有server
指令块对应的配置结构体。上面的代码就是遍历这个server
数组,然后对每个server下面的location进行处理。下面我们看一下处理的过程:
ngx_http_init_locations
代码如下:
1static ngx_int_t 2ngx_http_init_locations(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, 3 ngx_http_core_loc_conf_t *pclcf) 4{ 5 ngx_uint_t n; 6 ngx_queue_t *q, *locations, *named, tail; 7 ngx_http_core_loc_conf_t *clcf; 8 ngx_http_location_queue_t *lq; 9 ngx_http_core_loc_conf_t **clcfp; 10#if (NGX_PCRE) 11 ngx_uint_t r; 12 ngx_queue_t *regex; 13#endif 14 15 locations = pclcf->locations; 16 17 if (locations == NULL) { 18 return NGX_OK; 19 } 20 21 ngx_queue_sort(locations, ngx_http_cmp_locations); 22 23 named = NULL; 24 n = 0; 25#if (NGX_PCRE) 26 regex = NULL; 27 r = 0; 28#endif 29 30 for (q = ngx_queue_head(locations); 31 q != ngx_queue_sentinel(locations); 32 q = ngx_queue_next(q)) 33 { 34 lq = (ngx_http_location_queue_t *) q; 35 36 clcf = lq->exact ? lq->exact : lq->inclusive; 37 38 if (ngx_http_init_locations(cf, NULL, clcf) != NGX_OK) { 39 return NGX_ERROR; 40 } 41 42#if (NGX_PCRE) 43 44 if (clcf->regex) { 45 r++; 46 47 if (regex == NULL) { 48 regex = q; 49 } 50 51 continue; 52 } 53 54#endif 55 56 if (clcf->named) { 57 n++; 58 59 if (named == NULL) { 60 named = q; 61 } 62 63 continue; 64 } 65 66 if (clcf->noname) { 67 break; 68 } 69 } 70 71 if (q != ngx_queue_sentinel(locations)) { 72 ngx_queue_split(locations, q, &tail); 73 } 74 75 if (named) { 76 clcfp = ngx_palloc(cf->pool, 77 (n + 1) * sizeof(ngx_http_core_loc_conf_t *)); 78 if (clcfp == NULL) { 79 return NGX_ERROR; 80 } 81 82 cscf->named_locations = clcfp; 83 84 for (q = named; 85 q != ngx_queue_sentinel(locations); 86 q = ngx_queue_next(q)) 87 { 88 lq = (ngx_http_location_queue_t *) q; 89 90 *(clcfp++) = lq->exact; 91 } 92 93 *clcfp = NULL; 94 95 ngx_queue_split(locations, named, &tail); 96 } 97 98#if (NGX_PCRE) 99 100 if (regex) { 101 102 clcfp = ngx_palloc(cf->pool, 103 (r + 1) * sizeof(ngx_http_core_loc_conf_t *)); 104 if (clcfp == NULL) { 105 return NGX_ERROR; 106 } 107 108 pclcf->regex_locations = clcfp; 109 110 for (q = regex; 111 q != ngx_queue_sentinel(locations); 112 q = ngx_queue_next(q)) 113 { 114 lq = (ngx_http_location_queue_t *) q; 115 116 *(clcfp++) = lq->exact; 117 } 118 119 *clcfp = NULL; 120 121 ngx_queue_split(locations, regex, &tail); 122 } 123 124#endif 125 126 return NGX_OK; 127} 复制代码
上面的代码首先调用ngx_queue_sort()
函数对所有的location进行排序,排序之后的结果他如下:
- 两个比较location中的未命名location(即noname为1,rewrite_module中if指令产生的location)排到后面;
- 如果比较的两个location都为未命名location,则维持原次序:用户在配置文件里书写的先后顺序;
- 两个比较location中的命名location(即named为1,@前缀)排到后面;
- 如果比较的两个location都为命名location,则按字符串大小排序,名称字符序大的排到后面;
- 两个比较location中的正则匹配location(即regex字段不为空)排到后面;
- 如果比较的两个location都为正则匹配location,则维持原次序:用户在配置文件里书写的先后顺序;
- 其他情况,按字符串大小排序。但对于两个location名称相同的情况,如果存在绝对匹配location,则把它放在前
紧接着将所有属于正则表达式和named的location分别放置到不同的地方,对于我们的例子,如下:
ngx_http_init_static_location_trees
这个函数主要是为了构建静态的location三叉树,由于我们的config文件中的location数量太少,这里没有办法进行仔细的讲解,所以具体的构建过程这里不详细的介绍,后面文章会仔细介绍这个过程,我们这里仅仅展示构建的最终结果:
由于我们的配置文件只有一个location,所以形成的树结构只有一个节点,后面我们会分析多个location的时候如何构建这棵树。
喜欢本文的朋友们,欢迎长按下图关注订阅号郑尔多斯,更多精彩内容第一时间送达