nginx upstream一致性哈希的實現


地址:http://wiki.nginx.org/HttpUpstreamConsistentHash

 

首先聲明一個命令:

static ngx_command_t  ngx_http_upstream_consistent_hash_commands[] = {

    {   ngx_string("consistent_hash"),
        NGX_HTTP_UPS_CONF|NGX_CONF_TAKE1,
        ngx_http_upstream_consistent_hash,
        0,
        0,
        NULL },

    ngx_null_command
};

 

看下命令的處理函數:ngx_http_upstream_consistent_hash

 

 

 ngx_str_t                                    *value;
    ngx_http_script_compile_t                     sc;
    ngx_http_upstream_srv_conf_t                 *uscf;
    ngx_http_upstream_consistent_hash_srv_conf_t *uchscf;

    value = cf->args->elts;

    uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module);
    uchscf = ngx_http_conf_upstream_srv_conf(uscf,
                                          ngx_http_upstream_consistent_hash_module);

    ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

    sc.cf = cf;
    sc.source = &value[1];
    sc.lengths = &uchscf->lengths;
    sc.values = &uchscf->values;
    sc.complete_lengths = 1;
    sc.complete_values = 1;

    if (ngx_http_script_compile(&sc) != NGX_OK) {
        return NGX_CONF_ERROR;
    }

    uscf->peer.init_upstream = ngx_http_upstream_init_consistent_hash;

    uscf->flags = NGX_HTTP_UPSTREAM_CREATE
        |NGX_HTTP_UPSTREAM_WEIGHT;

 

這個模塊獲取upstream模塊的配置,設置了peer.init_upstream為函數ngx_http_upstream_init_consistent_hash,這個函數用來初始化upstream的,ngx_http_upstream_init_consistent_hash(ngx_conf_t *cf,
函數會根據服務器的IP和端口號進行一致性哈希計算,

ngx_int_t
ngx_http_upstream_init_consistent_hash(ngx_conf_t *cf,
        ngx_http_upstream_srv_conf_t *us)
{

……

us->peer.init = ngx_http_upstream_init_consistent_hash_peer;

……

for (i = 0; i < us->servers->nelts; i++) {
        for (j = 0; j < server[i].naddrs; j++) {
            for (k = 0; k < ((MMC_CONSISTENT_POINTS * server[i].weight) / server[i].naddrs); k++) {
                ngx_snprintf(hash_data, HASH_DATA_LENGTH, "%V-%ui%Z", &server[i].addrs[j].name, k);
                continuum->nodes[continuum->nnodes].sockaddr = server[i].addrs[j].sockaddr;
                continuum->nodes[continuum->nnodes].socklen = server[i].addrs[j].socklen;
                continuum->nodes[continuum->nnodes].name = server[i].addrs[j].name;
                continuum->nodes[continuum->nnodes].name.data[server[i].addrs[j].name.len] = 0;
                continuum->nodes[continuum->nnodes].point = ngx_crc32_long(hash_data, ngx_strlen(hash_data));
                continuum->nnodes++;
            }
        }
    }

  //排序
    qsort(continuum->nodes, continuum->nnodes,
            sizeof(ngx_http_upstream_consistent_hash_node),
            (const void*) ngx_http_upstream_consistent_hash_compare_continuum_nodes);

……

}

 

可以看到,是根據服務器的IP和端口號及索引做ngx_crc32_long計算;

這里也指定了ngx_http_upstream_init_consistent_hash_peer函數為peer的init函數,這個在每次連接的時候都會執行,作用是根據key來查找服務器,

 

static ngx_int_t
ngx_http_upstream_init_consistent_hash_peer(ngx_http_request_t *r,
        ngx_http_upstream_srv_conf_t *us)
{

……

 uchscf = ngx_http_conf_upstream_srv_conf(us,
                                          ngx_http_upstream_consistent_hash_module);

    uchpd = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_consistent_hash_peer_data_t));

    r->upstream->peer.data = uchpd->peers;
    uchpd->peers = us->peer.data;
  //編譯變量
    if (ngx_http_script_run(r, &evaluated_key_to_hash,
                uchscf->lengths->elts, 0, uchscf->values->elts) == NULL)
    {
        return NGX_ERROR;
    }
 //根據key計算hash值
    uchpd->point =
        ngx_crc32_long(evaluated_key_to_hash.data, evaluated_key_to_hash.len);

    r->upstream->peer.free = ngx_http_upstream_free_consistent_hash_peer;

    //獲取哪個服務器作計算節點
    r->upstream->peer.get = ngx_http_upstream_get_consistent_hash_peer;

……

}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM