`

nginx hash源码分析

阅读更多
HASH是NGINX核心数据结构之一.见几个链接.分析的很详细
1.http://www.linuxidc.com/Linux/2012-08/67040.htm
2.http://www.oschina.net/question/234345_42065
3.http://blog.csdn.net/lifeibo/article/details/5897126
4.http://code.google.com/p/nginxsrp/wiki/NginxCodeReview

//ngx_hash_key_t中的key即为ngx_hash_elt中的name(name余下的部分跟在name[1]后),  +2是加上len的大小,然后据*value对齐
#define NGX_HASH_ELT_SIZE(name)                                               \
    (sizeof(void *) + ngx_align((name)->key.len + 2, sizeof(void *)))

ngx_int_t
ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts)
{
    u_char          *elts;
    size_t           len;
    u_short         *test;
    ngx_uint_t       i, n, key, size, start, bucket_size;
    ngx_hash_elt_t  *elt, **buckets;
    for (n = 0; n < nelts; n++) {
//一个桶至少容得下一个ngx_hash_elt, +sizeof(void *)是因为一个桶(bucket)是以void *标识结尾的.
        if (hinit->bucket_size < NGX_HASH_ELT_SIZE(&names[n]) + sizeof(void *))
        {
            ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0,
                          "could not build the %s, you should "
                          "increase %s_bucket_size: %i",
                          hinit->name, hinit->name, hinit->bucket_size);
            return NGX_ERROR;
        }
    }

//test是用来测试冲突是否频繁,至于为什么乘以sizeof(u_short),见下面的 test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n]));
//即一个bucket至多为u_short大,拟max_size * sizeof(u_short)即可容纳max_size个bucket,不会内存不够
//test中的每个元素只是存储一个bucket占多大内存,而不是分配这么多内存.test只是用来测试的
    test = ngx_alloc(hinit->max_size * sizeof(u_short), hinit->pool->log);
    if (test == NULL) {
        return NGX_ERROR;
    }

    bucket_size = hinit->bucket_size - sizeof(void *);//减去bucket最后标识结尾的void*

    start = nelts / (bucket_size / (2 * sizeof(void *)));//(2 * sizeof(void *))是ngx_hash_elt的最小内存占用. 即len 和name 加起来最多是4字节,和*value对齐
    start = start ? start : 1;

//这段没看懂
    if (hinit->max_size > 10000 && nelts && hinit->max_size / nelts < 100) {
        start = hinit->max_size - 1000;
    }

    for (size = start; size < hinit->max_size; size++) {

        ngx_memzero(test, size * sizeof(u_short));//注意这里每次都重置前面填充的内存

        for (n = 0; n < nelts; n++) {
            if (names[n].key.data == NULL) {
                continue;
            }

//计算是否能容下所有ngx_hash_elt
            key = names[n].key_hash % size;//当size==1时,key 一直是0
            test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n]));

#if 0
            ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
                          "%ui: %ui %ui \"%V\"",
                          size, key, test[key], &names[n].key);
#endif

            if (test[key] > (u_short) bucket_size) {
                goto next;
            }
        }

        goto found;

    next:

        continue;
    }

    ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0,
                  "could not build the %s, you should increase "
                  "either %s_max_size: %i or %s_bucket_size: %i",
                  hinit->name, hinit->name, hinit->max_size,
                  hinit->name, hinit->bucket_size);

    ngx_free(test);

    return NGX_ERROR;

found:

//重置test,注意这里初始化为一个void*的大小,正好是一个bucket的结尾void*
    for (i = 0; i < size; i++) {
        test[i] = sizeof(void *);
    }

    for (n = 0; n < nelts; n++) {
        if (names[n].key.data == NULL) {
            continue;
        }

        key = names[n].key_hash % size;
        test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n]));
    }

    len = 0;

//以ngx_cacheline_size对齐,并计算所有元素总大小
ngx_cacheline_size = 32;
    for (i = 0; i < size; i++) {
        if (test[i] == sizeof(void *)) {
            continue;
        }

        test[i] = (u_short) (ngx_align(test[i], ngx_cacheline_size));

        len += test[i];
    }

    if (hinit->hash == NULL) {//如果没有初始化过hash
//初始化hash结构会申请ngx_hash_wildcard_t的空间(看hash结构图)
        hinit->hash = ngx_pcalloc(hinit->pool, sizeof(ngx_hash_wildcard_t)
                                             + size * sizeof(ngx_hash_elt_t *));
        if (hinit->hash == NULL) {
            ngx_free(test);
            return NGX_ERROR;
        }

        buckets = (ngx_hash_elt_t **)
                      ((u_char *) hinit->hash + sizeof(ngx_hash_wildcard_t));

    } else {
        buckets = ngx_pcalloc(hinit->pool, size * sizeof(ngx_hash_elt_t *));
        if (buckets == NULL) {
            ngx_free(test);
            return NGX_ERROR;
        }
    }

    elts = ngx_palloc(hinit->pool, len + ngx_cacheline_size);
    if (elts == NULL) {
        ngx_free(test);
        return NGX_ERROR;
    }

    elts = ngx_align_ptr(elts, ngx_cacheline_size);

//计算每个bucket的起始位置
    for (i = 0; i < size; i++) {
        if (test[i] == sizeof(void *)) {
            continue;
        }

        buckets[i] = (ngx_hash_elt_t *) elts;
        elts += test[i];
    }

    for (i = 0; i < size; i++) {
        test[i] = 0;
    }

    for (n = 0; n < nelts; n++) {
        if (names[n].key.data == NULL) {
            continue;
        }

        key = names[n].key_hash % size;
        elt = (ngx_hash_elt_t *) ((u_char *) buckets[key] + test[key]);
        elt->value = names[n].value;
        elt->len = (u_short) names[n].key.len;

        ngx_strlow(elt->name, names[n].key.data, names[n].key.len);

        test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n]));
    }

    for (i = 0; i < size; i++) {
        if (buckets[i] == NULL) {
            continue;
        }

        elt = (ngx_hash_elt_t *) ((u_char *) buckets[i] + test[i]);

        elt->value = NULL;
    }

    ngx_free(test);

    hinit->hash->buckets = buckets;
    hinit->hash->size = size;

#if 0

    for (i = 0; i < size; i++) {
        ngx_str_t   val;
        ngx_uint_t  key;

        elt = buckets[i];

        if (elt == NULL) {
            ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
                          "%ui: NULL", i);
            continue;
        }

        while (elt->value) {
            val.len = elt->len;
            val.data = &elt->name[0];

            key = hinit->key(val.data, val.len);

            ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
                          "%ui: %p \"%V\" %ui", i, elt, &val, key);

            elt = (ngx_hash_elt_t *) ngx_align_ptr(&elt->name[0] + elt->len,
                                                   sizeof(void *));
        }
    }

#endif

    return NGX_OK;
}
  • 大小: 91.3 KB
分享到:
评论

相关推荐

    Nginx源码剖析

    ### Nginx源码剖析:进程模型、内存管理与请求处理 #### 1.1 Nginx 的进程模型 Nginx 是一款广泛使用的高性能 Web 和反向代理服务器,其核心设计之一是高效的进程模型。Nginx 采用的是 Master-Worker 模型,其中...

    解析nginx负载均衡

    - **源码分析**:通用Hash和一致性Hash的相关实现通常在第三方模块中完成。 #### 四、结论 通过对nginx负载均衡策略的深入解析,我们可以看出nginx不仅具备强大的功能,而且能够根据实际需求灵活配置各种负载均衡...

    nginx-1.20.2源码包

    **Nginx 1.20.2 源码包详解** Nginx 是一款高性能的 HTTP 和反向代理服务器,广泛应用于互联网行业,以其轻量级、高并发、低内存消耗等特性受到赞誉。Nginx 1.20.2 是 Nginx 的一个稳定版本,提供了一系列增强和...

    nginx-1.11.11.tar.gz

    9. **日志记录**:Nginx可以自定义日志格式,便于分析和监控服务器运行状态。 在解压"nginx-1.11.11.tar.gz"之后,我们通常会得到一个名为"nginx-1.11.11"的目录,其中包含源代码、配置文件、文档、示例配置等。接...

    Nginx 应用技术指南

    Nginx通常通过源码编译的方式进行安装,这样可以根据具体需求定制所需的模块。 **2.3 Nginx配置文件测试** 为了确保配置文件无误,在每次修改配置文件之后都应该进行测试。 **2.4 Nginx启动** 启动Nginx服务,可以...

    nginx-1.16.0:学习nginx架构设计与实现,翻译nginx的源码,写nginx的测试代码,在问题中记录nginx的精妙设计及其常见问题https

    nginx-1.16.0源码分析及其注释-记录心路历程,有问题随时沟通交流,一起学习 调试练习ngx_pool.c的代码 调试练习ngx_hash.c的代码 调试练习ngx_list.c的代码 调试练习ngx_md5.c的代码,ngx_sha1.c亦如此 调试练习ngx...

    用nginx代理weblobic.pdf

    通过以上的分析与解释,我们可以了解到Nginx代理weblogic.pdf文件的配置方法,同时也对Nginx的基本配置、安装以及代理功能有了全面的认识。正确地配置和使用Nginx对于提升Web应用性能和管理都有着至关重要的作用。

    Nginx负载均衡Tomcat简单配置

    为了确保负载均衡效果,你可以使用Nginx的访问日志(access.log)进行分析,或者结合第三方工具(如Nginx Plus、Prometheus、Grafana)进行实时监控和性能优化。 总结,配置Nginx进行Tomcat负载均衡是一项重要的...

    nginx-1.16.0.zip

    总之,"nginx-1.16.0.zip"这个压缩包包含了一个完整的Nginx 1.16.0安装源码,使用者可以通过编译安装,自定义配置来搭建符合自身需求的Web服务器环境。无论是用于静态文件服务、反向代理,还是负载均衡,Nginx都能...

    nginx负载均衡加FastDfs

    1. **Nginx安装与配置**:下载Nginx的源码包,编译并安装。配置文件中,你需要开启反向代理功能,通过`http`模块的`upstream`指令定义一组服务器,以实现负载均衡策略,如轮询(round-robin)、最少连接(least ...

    nginx反向代理配置及优化.doc

    3. **安装Nginx**:下载源码并进行编译安装,同时添加特定的编译选项以优化性能。 ``` wget http://sysoev.ru/nginx/nginx-0.7.58.tar.gz tar zxvf nginx-0.7.58.tar.gz cd nginx-0.7.58/ ./configure --user=...

    nginx配置负载

    分析这个配置文件能帮助我们理解如何在实际环境中设置Nginx的负载均衡功能。 现在,让我们深入探讨Nginx配置负载均衡的关键知识点: 1. **上游服务器(Upstream)**:在Nginx配置中,我们首先需要定义一个上游...

    nginx-1.20.1.tar.zip

    Nginx的负载均衡策略有多种,包括轮询(Round Robin)、权重轮询(Weighted Round Robin)、最少连接数(Least Connections)和IP哈希(IP Hash)。轮询是默认策略,每个请求按顺序分配给后端服务器;权重轮询允许...

    nginx配置参考

    3. **日志分析**:通过`access.log`和`error.log`分析性能瓶颈和错误。 4. **错误页定制**:自定义404、50x等错误页面,提升用户体验。 通过以上讲解,我们可以看到Nginx配置涉及多方面的知识,包括基础架构、指令...

    手把手教你负载均衡-tomcat1.7+nginx+memcached

    例如,你可以使用`round-robin`策略实现简单的轮询分配请求,或者利用`ip_hash`让相同IP地址的请求始终落在同一台服务器上。 Memcached则用于缓存部分数据,减轻数据库的压力。在Java应用中,可以使用诸如...

    有图有真相。windows环境下配置tomat+redis+nginx集群共享session

    - 根据系统需求选择合适的策略,通过`upstream`块中的`hash`或`round_robin`等指令设置。 7. **安全与性能优化**: - 为保证安全性,需要在Nginx中启用SSL/TLS,配置证书和密钥。 - 对Redis进行安全配置,限制...

Global site tag (gtag.js) - Google Analytics