- 浏览: 136841 次
- 性别:
- 来自: 北京
文章分类
最新评论
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;
}
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;
}
发表评论
-
C++ 一些小点
2014-01-14 15:29 717一些小的点,防止忘了再查资料 1.类的所有对象共享虚函数表。 ... -
创建动态链接是链接静态库报错
2014-01-03 14:06 978创建一个动态库时报错,如下 relocation R_X86_ ... -
c++ 虚函数 const等的一些小问题记录
2013-11-14 16:14 1140class Base{ public: void te ... -
c++ protected误区
2013-11-14 15:11 885发现以前对protected的用法一直是错误的。 prote ... -
c++动态陷阱
2013-11-14 14:35 670记录以防忘记 class base{ public: ... -
c 指针陷阱
2013-10-08 20:00 739void test(char ***s, int x, int ... -
c实现bitmap
2013-05-14 14:34 1344直接上代码. #include <stdio.h> ... -
内存对齐
2013-03-28 14:27 1163看书看到内存对齐一段时,突然想研究一下内存对齐最底层的原理.查 ... -
贪心算法与动态规划的区别
2012-11-24 21:07 31821.贪心算法和动态规划区别 贪心算法是自顶向下的,它会先做在 ... -
fgetc read缓冲机制区别
2012-11-13 22:02 1951read属于系统调用,它的缓存是基于内核的缓冲,是记在内核空间 ... -
PHP实现各种排序
2011-11-23 17:32 932<?php /** * 各种排序 * @aut ... -
PHP实现平衡二叉树(AVL树)
2011-11-20 17:20 2933<?php require 'bstOrder ... -
PHP实现克鲁斯卡尔(kruscal)算法
2011-11-05 21:18 1179<?php require 'edge.php ... -
PHP实现图的邻接矩阵及普里姆(prim算法),弗洛伊德(floyd),迪杰斯特拉(dijkstra)算法
2011-11-02 18:35 4631<?php require 'mGraph.p ... -
php实现图的邻接表,关键路径,拓朴排序
2011-11-02 18:30 1827<?php //调用 require ... -
PHP实现二叉树,线索二叉树
2011-10-26 19:56 6446<?php require 'biTree ... -
php 实现KMP算法
2011-10-23 12:32 1842<?php /** * KMP算法的P ... -
php实现单链表(静态链表)
2011-10-21 14:40 1811<?php /* * 单链表的PH ...
相关推荐
### Nginx源码剖析:进程模型、内存管理与请求处理 #### 1.1 Nginx 的进程模型 Nginx 是一款广泛使用的高性能 Web 和反向代理服务器,其核心设计之一是高效的进程模型。Nginx 采用的是 Master-Worker 模型,其中...
- **源码分析**:通用Hash和一致性Hash的相关实现通常在第三方模块中完成。 #### 四、结论 通过对nginx负载均衡策略的深入解析,我们可以看出nginx不仅具备强大的功能,而且能够根据实际需求灵活配置各种负载均衡...
**Nginx 1.20.2 源码包详解** Nginx 是一款高性能的 HTTP 和反向代理服务器,广泛应用于互联网行业,以其轻量级、高并发、低内存消耗等特性受到赞誉。Nginx 1.20.2 是 Nginx 的一个稳定版本,提供了一系列增强和...
9. **日志记录**:Nginx可以自定义日志格式,便于分析和监控服务器运行状态。 在解压"nginx-1.11.11.tar.gz"之后,我们通常会得到一个名为"nginx-1.11.11"的目录,其中包含源代码、配置文件、文档、示例配置等。接...
Nginx通常通过源码编译的方式进行安装,这样可以根据具体需求定制所需的模块。 **2.3 Nginx配置文件测试** 为了确保配置文件无误,在每次修改配置文件之后都应该进行测试。 **2.4 Nginx启动** 启动Nginx服务,可以...
nginx-1.16.0源码分析及其注释-记录心路历程,有问题随时沟通交流,一起学习 调试练习ngx_pool.c的代码 调试练习ngx_hash.c的代码 调试练习ngx_list.c的代码 调试练习ngx_md5.c的代码,ngx_sha1.c亦如此 调试练习ngx...
通过以上的分析与解释,我们可以了解到Nginx代理weblogic.pdf文件的配置方法,同时也对Nginx的基本配置、安装以及代理功能有了全面的认识。正确地配置和使用Nginx对于提升Web应用性能和管理都有着至关重要的作用。
为了确保负载均衡效果,你可以使用Nginx的访问日志(access.log)进行分析,或者结合第三方工具(如Nginx Plus、Prometheus、Grafana)进行实时监控和性能优化。 总结,配置Nginx进行Tomcat负载均衡是一项重要的...
总之,"nginx-1.16.0.zip"这个压缩包包含了一个完整的Nginx 1.16.0安装源码,使用者可以通过编译安装,自定义配置来搭建符合自身需求的Web服务器环境。无论是用于静态文件服务、反向代理,还是负载均衡,Nginx都能...
1. **Nginx安装与配置**:下载Nginx的源码包,编译并安装。配置文件中,你需要开启反向代理功能,通过`http`模块的`upstream`指令定义一组服务器,以实现负载均衡策略,如轮询(round-robin)、最少连接(least ...
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配置负载均衡的关键知识点: 1. **上游服务器(Upstream)**:在Nginx配置中,我们首先需要定义一个上游...
Nginx的负载均衡策略有多种,包括轮询(Round Robin)、权重轮询(Weighted Round Robin)、最少连接数(Least Connections)和IP哈希(IP Hash)。轮询是默认策略,每个请求按顺序分配给后端服务器;权重轮询允许...
3. **日志分析**:通过`access.log`和`error.log`分析性能瓶颈和错误。 4. **错误页定制**:自定义404、50x等错误页面,提升用户体验。 通过以上讲解,我们可以看到Nginx配置涉及多方面的知识,包括基础架构、指令...
例如,你可以使用`round-robin`策略实现简单的轮询分配请求,或者利用`ip_hash`让相同IP地址的请求始终落在同一台服务器上。 Memcached则用于缓存部分数据,减轻数据库的压力。在Java应用中,可以使用诸如...
- 根据系统需求选择合适的策略,通过`upstream`块中的`hash`或`round_robin`等指令设置。 7. **安全与性能优化**: - 为保证安全性,需要在Nginx中启用SSL/TLS,配置证书和密钥。 - 对Redis进行安全配置,限制...