Nginx的client_header_buffer_size和large_client_header_buffers学习
之前看到有人写的一篇关于nginx配置中large_client_header_buffers的问题排查的文章,其中提到:
large_client_header_buffers 虽然也可以在server{}内生效,但是只有 低于 nginx主配置中的值才有意义。
对这个结论,我心存疑虑,总觉得这种设计很奇怪,于是自己做了个测试,希望能了解的更深入一些。
测试方法
nginx主配置中加入配置项:(在主配置中将header大小控制在1k)
http {
include mime.types;
default_type application/octet-stream;
large_client_header_buffers 4 1k;
......
}
删除所有干扰vhost,仅留下一个:
server {
listen 80;
server_name www.job360.com;
large_client_header_buffers 4 1m;
......
}
构造请求的shell:(构造header超过1k的请求)
#!/bin/bash
url="http://www.job360.com/test.html?debug=1"
for i in {0..1000}
do
var="v$i"
url="${url}&$var=$i"
done
curl $url -x 127.0.0.1:80 -v
第一次测试结果
测试得到的结果和之前看到的文章的结果不同,该长url请求成功被nginx处理。
什么情况啊?于是查看和文章中环境上的不同,发现很重要的一点:我只有这一个vhost。
于是添加了另外一个vhost,添加vhost配置如下:(没有设置 large_client_header_buffers)
server {
listen 80;
server_name db.job360.com;
......}
第二次测试结果
测试发现,nginx依旧可以处理该长url请求。
再次思考不同点,想到:这些vhost是被主配置中include进来的,是否会和读取顺序有关呢?
于是再次调整配置,将两个vhost放到了一个conf文件中,配置如下:
server {
listen 80;
server_name db.job360.com;
......
}
server {
listen 80;
server_name www.job360.com;
large_client_header_buffers 4 1m;
......
}
第三次测试结果
得到和文章中相同的结果,nginx返回414 Request-URI Too Large
。
带着好奇心,我颠倒了下两个vhost的顺序,如下:
server {
listen 80;
server_name www.job360.com;
large_client_header_buffers 4 1m;
......
}
server {
listen 80;
server_name db.job360.com;
......
}
第四次测试结果
nginx成功处理该长url请求。
初步结论
通过上面的现象,我得到一个初步结论:在第一个vhost中配置的large_client_header_buffers参数会起作用。
好奇怪的现象啊,我对自己得出的结论也是心存疑惑,于是决定从手册中好好读下控制header_buffer相关的指令。
从手册上理解nginx有关header_buffer配置指令
从手册上找到有两个指令和header_buffer有关:
对nginx处理header时的方法,学习后理解如下:
- 先处理请求的request_line,之后才是request_header。
- 这两者的buffer分配策略相同。
- 先根据client_header_buffer_size配置的值分配一个buffer,如果分配的buffer无法容纳 request_line/request_header,那么就会再次根据large_client_header_buffers配置的参数分配large_buffer,如果large_buffer还是无法容纳,那么就会返回414(处理request_line)/400(处理request_header)错误。
根据对手册的理解,我理解这两个指令在配置header_buffer时的使用场景是不同的,个人理解如下:
- 如果你的请求中的header都很大,那么应该使用client_header_buffer_size,这样能减少一次内存分配。
- 如果你的请求中只有少量请求header很大,那么应该使用large_client_header_buffers,因为这样就仅需在处理大header时才会分配更多的空间,从而减少无谓的内存空间浪费。
为了印证自己对两个配置指令的理解,我把large_client_header_buffer换成client_header_buffer_size,重新跑上面的多种测试,得到了和之前各种场景相同的结论。
手册上也只是说明了这两个指令的使用场景,没有说更多的东西了,之前的疑惑还是没有得到解答,那么只有最后一招了,也是绝招:从源码中寻找答案!
源码学习
这里从client_header_buffer_size指令入手,先查看这个指令的定义部分:
{ ngx_string("client_header_buffer_size"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, //可以定义在http{}或server{}中,需要携带一个参数
ngx_conf_set_size_slot, //参数意义为size,使用nginx预定义的解析size参数方法解析
NGX_HTTP_SRV_CONF_OFFSET, //将参数值放到srv级别的conf中
offsetof(ngx_http_core_srv_conf_t, client_header_buffer_size), //解析后放到ngx_http_core_srv_conf_t结构体的client_header_buffer_size中
NULL },
src/http/ngx_http_core_module.c
由定义看到,我们在server{}中解析到的值会和http{}中的值做一次merge,作为该server{}下的最终值。查看merge相关的逻辑:
ngx_conf_merge_size_value(conf->client_header_buffer_size, //conf代表server{},prev代表http{}
prev->client_header_buffer_size, 1024);
src/http/ngx_http_core_module.c
#define ngx_conf_merge_size_value(conf, prev, default) \
if (conf == NGX_CONF_UNSET_SIZE) { \
conf = (prev == NGX_CONF_UNSET_SIZE) ? default : prev; \
}
src/core/ngx_conf_file.h
从这段逻辑中得到结论:如果我们在server{}中配置了client_header_buffer_size,那么针对这个server{}块的最终值应该就是我们配置的值。
为了印证我的结论,我重新写了vhost配置,并在代码中加入调试信息,把最终结果打印出来:
http {
include mime.types;
default_type application/octet-stream;
large_client_header_buffers 4 1k;
......
server {
listen <span class="hljs-number">80</span>;
server_name db.job360.com;
......
}
server {
listen <span class="hljs-number">80</span>;
server_name www.job360.com;
large_client_header_buffers <span class="hljs-number">4</span> <span class="hljs-number">1</span>m;
......
}
}
调试代码:
printf("buffer before merge:\nchild: %lu\nparent: %lu\n\n", conf->client_header_buffer_size, prev->client_header_buffer_size);
......
ngx_conf_merge_size_value(conf->client_header_buffer_size,
prev->client_header_buffer_size, 1024);
......
printf("buffer after merge:\nchild: %lu\nparent: %lu\n\n", conf->client_header_buffer_size, prev->client_header_buffer_size);
src/http/ngx_http_core_module.c
重新编译nginx,测试每个server{}中client_header_buffer_size的最终值为:
buffer before merge:
child: 18446744073709551615 //由于第一个server{}中没有配置,所以这个是-1(NGX_CONF_UNSET_SIZE)的unsigned long int表示
parent: 1024 //http{}中配置为1k
buffer after merge:
child: 1024
parent: 1024
buffer before merge:
child: 1048576 //第二个server{}中配置为1m
parent: 1024
buffer after merge:
child: 1048576
parent: 1024
从值的最终结果看,的确是之前设置的1m,但是请求时却返回了414。
由于将两个server{}的位置颠倒后可以正常处理请求,所以在颠倒的情况下又测试了下最终值,输出如下:
buffer before merge:
child: 1048576
parent: 1024
buffer after merge:
child: 1048576
parent: 1024
buffer before merge:
child: 18446744073709551615
parent: 1024
buffer after merge:
child: 1024
parent: 1024
最终值的输出还是1m,但是这次就可以正常处理请求了。
看来nginx在实际处理请求的过程中,一定还有之前不知道的一套逻辑,用来判断client_header_buffer_size的最终值。
nginx处理请求时的相关代码如下:
ngx_http_core_srv_conf_t *cscf;
......
/* the default server configuration for the address:port */
cscf = addr_conf->default_server;
......
if (c->buffer == NULL) {
c->buffer = ngx_create_temp_buf(c->pool,
cscf->client_header_buffer_size);
src/http/ngx_http_request.c
这里真相大白:
原来client_header_buffer_size的最终值,是nginx在解析conf后,default_server中经过merge的最终值。
而default_server在nginx中的定义为:在listen指令中定义:
The default_server parameter, if present, will cause the server to become the default server for the specified address:port pair. If none of the directives have the default_server parameter then the first server with the address:port pair will be the default server for this pair.
为了验证这一点,我修改vhost配置为:
server {
listen 80;
server_name db.job360.com;
......
}
server {
listen 80 default;
server_name www.job360.com;
large_client_header_buffers <span class="hljs-number">1</span>m;
......
}
重启nginx观察merge结果:
buffer before merge:
child: 18446744073709551615
parent: 1024
buffer after merge:
child: 1024
parent: 1024
buffer before merge:
child: 1048576
parent: 1024
buffer after merge:
child: 1048576
parent: 1024
merge结果没有不同。测试请求,这次nginx成功处理该请求,和预期的效果一致。
结束语
笔者又测试了large_client_header_buffers,得到和client_header_buffer_size同样的结果。可以得出结论:nginx在处理header时实际分配的buffer大小,是解析conf后,default_server中的最终值。
个人水平有限,上面的测试方法和理解如有不当的地方,还望大家指正,谢谢!
</div>
</div>
Nginx的client_header_buffer_size和large_client_header_buffers学习的更多相关文章
- Nginx code 常用状态码学习小结
最近了解下Nginx的Code状态码,在此简单总结下.一个http请求处理流程: 一个普通的http请求处理流程,如上图所示:A -> client端发起请求给nginxB -> ngin ...
- Nginx支持WebSocket反向代理-学习小结
WebSocket是目前比较成熟的技术了,WebSocket协议为创建客户端和服务器端需要实时双向通讯的webapp提供了一个选择.其为HTML5的一部分,WebSocket相较于原来开发这类app的 ...
- 《基于Nginx的中间件架构》学习笔记---4.nginx编译参数详细介绍
通过nginx -V查看编译时参数: 在nginx安装目录下,通过./configure --help,查看对应版本ngnix编译时支持的所有参数: Nginx编译参数详细介绍: --help 显示本 ...
- 《基于Nginx的中间件架构》学习笔记---3.nginx的目录分析
一.目录分析 用yum的方式进行安装实质上装的都是一个个的rpm包,对于linux系统rpm包管理器,我们使用命令rpm -ql 服务名称 就可以列出我们已经安装的服务所对应安装的每一个文件所在的目 ...
- 《基于Nginx的中间件架构》学习笔记---2.nginx的优点以及nginx的安装
[优势] 优势1:IO多路复用和epoll模型(详见总结知识) 优势2:轻量级(1.功能模块少:只保留了一些核心代码 2.代码模块化) 优势3:CPU亲和 这里的CPU亲和指的是:是一种把cp ...
- Nginx反代服务器进阶学习最佳配置实践指南
转载自:https://www.bilibili.com/read/cv16150010?spm_id_from=333.999.0.0 0x00 编译实践 描述:在企业线上生产环境中推荐进行Ngin ...
- 《基于Nginx的中间件架构》学习笔记---1.环境配置
一.环境调试确认 (四项确认) 1.确认系统网络 ping www.baidu.com 2.确认yum可用 yum list|grep gcc 3.确认关闭iptables规则 iptables -L ...
- Get请求携带数据量的各种限制及解决办法、Post请求说明
1. Get请求携带数据量的各种限制及解决办法 Http Get方法提交的数据大小长度并没有限制,HTTP协议规范没有对URL长度进行限制.这个限制是特定的浏览器及服务器对它的限制. 到新公司处理 ...
- Nginx基础学习
参考博客: http://www.2cto.com/os/201212/176520.html http://os.51cto.com/art/201111/304611.htm http://www ...
随机推荐
- 初步学习pg_control文件之十
接前文 初步学习pg_control文件之九 看下面这个 XLogRecPtr checkPoint; /* last check point record ptr */ 看看这个pointer究竟保 ...
- RTL8195AM开发板使用
1. 本次使用RTL8195AM测试一下,原厂资源地址:https://os.mbed.com/platforms/Realtek-RTL8195AM/ 2. 由于板子支持mbed,所以把CON2连接 ...
- Bug是一种财富-------研发同学的错题集、测试同学的遗漏用例集
此文已由作者王晓明授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 各位看官,可能看到标题的你一定认为这是一篇涉嫌"炒作"的文章,亦或是为了吸引眼球而起的标 ...
- abtest-system后台系统设计与搭建
本文来自网易云社区 作者:刘颂 1 项目背景: 2017年5月:客户端提出增加https&dns以及双cdn业务功能 后台配合实现使用disconf配置 针对不同的域名或者请求配置不同的htt ...
- 【vim环境配置】解决ubuntu上 由YouCompleteMe插件配置不当引起的 自动补全失效的问题
背景: 由于不可抗拒的原因,学习环境由之前centos的一台机器上,变成了ubuntu的一台机器上.因此,需要在新的ubuntu的机器上再配置一次vim环境.算起来这已经是第三次配置vim环境了(ma ...
- 洛谷P1378油滴扩展
题目描述 在一个长方形框子里,最多有N(0≤N≤6)个相异的点,在其中任何一个点上放一个很小的油滴,那么这个油滴会一直扩展,直到接触到其他油滴或者框子的边界. 必须等一个油滴扩展完毕才能放置下一个油滴 ...
- tensorflow的几种优化器
最近自己用CNN跑了下MINIST,准确率很低(迭代过程中),跑了几个epoch,我就直接stop了,感觉哪有问题,随即排查了下,同时查阅了网上其他人的blog,并没有发现什么问题 之后copy了一篇 ...
- day-12 python实现简单线性回归和多元线性回归算法
1.问题引入 在统计学中,线性回归是利用称为线性回归方程的最小二乘函数对一个或多个自变量和因变量之间关系进行建模的一种回归分析.这种函数是一个或多个称为回归系数的模型参数的线性组合.一个带有一个自变 ...
- git 创建分支并提交到服务器对应的新分支
1.切换到源分支 git checkout test 2.在源分支的基础上创建新分支 git branch test1 3.提交到远程分支 git pull 会自动提示下面的命令 git pull - ...
- HDU 4431 Mahjong(枚举+模拟)(2012 Asia Tianjin Regional Contest)
Problem Description Japanese Mahjong is a four-player game. The game needs four people to sit around ...