上接 深入理解nginx一致性哈希负载均衡模块[上]
3. 源码分析
nginx的一致性哈希功能是通过ngx_http_upstream_hash_module来提供的,下面来整体通过ngx_http_upstream_hash_module来学习一下一致性哈希算法的实现原理。
3.1 配置指令分析
要启用Nginx的一致性哈希负载均衡算法,你需要使用ngx_http_upstream_hash_module
模块。下面是一些配置指令的详细说明:
- upstream指令:
upstream指令用于定义一个负载均衡的后端服务器组。
语法: upstream group_name { ... }示例:upstream backend_servers {server backend1.example.com;server backend2.example.com;...}
- hash指令:
hash指令用于启用一致性哈希负载均衡算法。
语法: hash key [consistent] [method=xx]key: 指定用于计算哈希值的关键字,可以是变量或固定值。
consistent (可选): 使用一致性哈希算法。
method (可选): 指定哈希算法的方法,可选值为crc32, md5, sha1,默认为crc32。示例:upstream backend_servers {hash $request_uri consistent;server backend1.example.com;server backend2.example.com;...}
在以上示例中开启了以reqeust_uri作为key的一致性哈希负载均衡算法。
接下去看一下指令分析的源码,首先本模块定义了一个配置指令,如下:
static ngx_command_t ngx_http_upstream_hash_commands[] = {{ ngx_string("hash"),NGX_HTTP_UPS_CONF|NGX_CONF_TAKE12,ngx_http_upstream_hash,NGX_HTTP_SRV_CONF_OFFSET,0,NULL },ngx_null_command
};
在nginx解析到upstream块中的hash指令的时候就回调ngx_http_upstream_hash进行指令解析,源码如下:
static char *
ngx_http_upstream_hash(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{ngx_http_upstream_hash_srv_conf_t *hcf = conf;ngx_str_t *value;ngx_http_upstream_srv_conf_t *uscf;ngx_http_compile_complex_value_t ccv;value = cf->args->elts;/* 第一个参数是包含动态变量的哈希key,通过ngx_http_compile_complex_value进行解析 */ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));ccv.cf = cf;ccv.value = &value[1];ccv.complex_value = &hcf->key;if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {return NGX_CONF_ERROR;}/* 获取ngx_http_upstream_module的配置信息 */uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module);/* init_upstream如果已经设置,表示其他负载均衡算法已经设置过了 */if (uscf->peer.init_upstream) {ngx_conf_log_error(NGX_LOG_WARN, cf, 0,"load balancing method redefined");}/* 这里设置的flags中缺少了NGX_HTTP_UPSTREAM_BACKUP,所以如果开启hash负载均衡算法,那么nginx就不能支持主备服务器模式了*/uscf->flags = NGX_HTTP_UPSTREAM_CREATE|NGX_HTTP_UPSTREAM_WEIGHT|NGX_HTTP_UPSTREAM_MAX_CONNS|NGX_HTTP_UPSTREAM_MAX_FAILS|NGX_HTTP_UPSTREAM_FAIL_TIMEOUT|NGX_HTTP_UPSTREAM_DOWN;if (cf->args->nelts == 2) {/* 如果没有第三个参数consistent,则为普通的hash负载均衡算法 */uscf->peer.init_upstream = ngx_http_upstream_init_hash;} else if (ngx_strcmp(value[2].data, "consistent") == 0) {/* 设置一致性哈希算法配置初始化的回调函数 */uscf->peer.init_upstream = ngx_http_upstream_init_chash;} else {ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"invalid parameter \"%V\"", &value[2]);return NGX_CONF_ERROR;}return NGX_CONF_OK;
}
上述代码最重要的步骤就是2个,一个是设置hash key,另外一个就是设置负载均衡算法配置初始化的回调函数,虽然本模块同时实现了普通哈希和一致性哈希两种负载均衡算法,由于本文的重点是一致性哈希算法,所以普通哈希负载均衡算法略过不讲了。
3.2 负载均衡配置初始化函数的实现
&esmp; 在3.1节中的配置指令解析完成后,如果开启了consistent负载均衡功能,那么就会将uscf->peer.init_upstream设置为ngx_http_upstream_init_chash。当nginx完成配置解析工作以后,因为已经加载到了upstrem中的所有server,后续还需要用这些server对启用的负载均衡算法进行初始化准备工作。
- 第一步是加载peer链:
if (ngx_http_upstream_init_round_robin(cf, us) != NGX_OK) {return NGX_ERROR;}
以上这段代码是用round-robin模块的ngx_http_upstream_init_round_robin函数加载server到peer链中,具体可以参考深入理解nginx负载均衡round-robin算法。
- 第二步是设置负载均衡算法的上下文初始化回调函数
us->peer.init = ngx_http_upstream_init_chash_peer;
- 第三步是获取用ngx_http_upstream_init_round_robin加载到的peers链:
peers = us->peer.data;
- 第四步是分配一致性哈希算法的虚拟节点:
npoints =<