上接 深入理解nginx一致性哈希负载均衡模块[上]
nginx的一致性哈希功能是通过ngx_http_upstream_hash_module来提供的,下面来整体通过ngx_http_upstream_hash_module来学习一下一致性哈希算法的实现原理。
要启用Nginx的一致性哈希负载均衡算法,你需要使用ngx_http_upstream_hash_module
模块。下面是一些配置指令的详细说明:
upstream指令用于定义一个负载均衡的后端服务器组。
语法: upstream group_name { ... }
示例:
upstream backend_servers {
server backend1.example.com;
server backend2.example.com;
...
}
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,另外一个就是设置负载均衡算法配置初始化的回调函数,虽然本模块同时实现了普通哈希和一致性哈希两种负载均衡算法,由于本文的重点是一致性哈希算法,所以普通哈希负载均衡算法略过不讲了。
&esmp; 在3.1节中的配置指令解析完成后,如果开启了consistent负载均衡功能,那么就会将uscf->peer.init_upstream设置为ngx_http_upstream_init_chash。当nginx完成配置解析工作以后,因为已经加载到了upstrem中的所有server,后续还需要用这些server对启用的负载均衡算法进行初始化准备工作。
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;
peers = us->peer.data;
npoints =<