小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

nginx的client

 waitingnothing 2017-08-04

前言

之前看磊君寫的wiki:Nginx配置中l(wèi)arge_client_header_buffers的問題排查 ,其中提到:

large_client_header_buffers 雖然也可以在server{}內(nèi)生效,但是只有 低于 nginx主配置中的值才有意義。
否則,那些有巨大header的請(qǐng)求,依然會(huì)受到主配置中 large_client_header_buffers 的限制。

對(duì)這個(gè)結(jié)論,心存疑慮,總覺得這種設(shè)計(jì)很奇怪,于是自己做了個(gè)測(cè)試,希望能了解的更深入一些。

測(cè)試方法

  • nginx主配置中加入配置項(xiàng):(<span style='color:red;'>在主配置中將header大小控制在1k</span>)
http { include mime.types; default_type application/octet-stream; large_client_header_buffers 4 1k; ...... }
  • 刪除所有干擾vhost,僅留下一個(gè):
server { listen 80 ; server_name www.; large_client_header_buffers 4 1m; ...... }
  • 構(gòu)造請(qǐng)求的shell:(<span style='color:red;'>構(gòu)造header超過1k的請(qǐng)求</span>)
#!/bin/bash url='http://www./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

第一次測(cè)試結(jié)果

測(cè)試得到的結(jié)果和磊君的結(jié)果不同,該長(zhǎng)url請(qǐng)求成功被nginx處理。

什么情況???和磊君的結(jié)論完全不同。于是查看和磊君環(huán)境上的不同,發(fā)現(xiàn)很重要的一點(diǎn):<span style='color:red;'>我只有這一個(gè)vhost。</span>

于是添加了另外一個(gè)vhost,添加vhost配置如下:(<span style='color:red;'>沒有設(shè)置 large_client_header_buffers</span>)

server { listen 80; server_name db.; ...... }

第二次測(cè)試結(jié)果

測(cè)試發(fā)現(xiàn),nginx依舊可以處理該長(zhǎng)url請(qǐng)求。

再次思考不同點(diǎn),想到:這些vhost是被主配置中include進(jìn)來的,是否會(huì)和讀取順序有關(guān)呢?

于是再次調(diào)整配置,將兩個(gè)vhost放到了一個(gè)conf文件中,配置如下:

server { listen 80; server_name db.; ...... } server { listen 80 ; server_name www.; large_client_header_buffers 4 1m; ...... }

第三次測(cè)試結(jié)果

得到和磊君相同的結(jié)果,nginx返回414 Request-URI Too Large

帶著好奇心,我顛倒了下兩個(gè)vhost的順序,如下:

server { listen 80 ; server_name www.; large_client_header_buffers 4 1m; ...... } server { listen 80; server_name db.; ...... }

第四次測(cè)試結(jié)果

nginx成功處理該長(zhǎng)url請(qǐng)求。

初步結(jié)論

通過上面的現(xiàn)象,我得到一個(gè)初步結(jié)論:<span style='color:blue;'>在第一個(gè)vhost中配置的large_client_header_buffers參數(shù)會(huì)起作用。</span>

好奇怪的現(xiàn)象啊,我對(duì)自己得出的結(jié)論也是心存疑惑,于是決定從手冊(cè)中好好讀下控制header_buffer相關(guān)的指令。

從手冊(cè)上理解nginx有關(guān)header_buffer配置指令

從手冊(cè)上找到有兩個(gè)指令和header_buffer有關(guān):
對(duì)nginx處理header時(shí)的方法,學(xué)習(xí)后理解如下:
  1. 先處理請(qǐng)求的request_line,之后才是request_header。
  2. 這兩者的buffer分配策略相同。
  3. 先根據(jù)client_header_buffer_size配置的值分配一個(gè)buffer,如果分配的buffer無法容納 request_line/request_header,那么就會(huì)再次根據(jù)large_client_header_buffers配置的參數(shù)分配large_buffer,如果large_buffer還是無法容納,那么就會(huì)返回414(處理request_line)/400(處理request_header)錯(cuò)誤。
根據(jù)對(duì)手冊(cè)的理解,我理解這兩個(gè)指令在配置header_buffer時(shí)的使用場(chǎng)景是不同的,個(gè)人理解如下:
  1. 如果你的請(qǐng)求中的header都很大,那么應(yīng)該使用client_header_buffer_size,這樣能減少一次內(nèi)存分配。
  2. 如果你的請(qǐng)求中只有少量請(qǐng)求header很大,那么應(yīng)該使用large_client_header_buffers,因?yàn)檫@樣就僅需在處理大header時(shí)才會(huì)分配更多的空間,從而減少無謂的內(nèi)存空間浪費(fèi)。

為了印證自己對(duì)兩個(gè)配置指令的理解,我把large_client_header_buffer換成client_header_buffer_size,重新跑上面的多種測(cè)試,得到了和之前各種場(chǎng)景相同的結(jié)論。

手冊(cè)上也只是說明了這兩個(gè)指令的使用場(chǎng)景,沒有說更多的東西了,之前的疑惑還是沒有得到解答,那么只有最后一招了,也是絕招:<span style='color:red;'>從源碼中尋找答案!</span>

源碼學(xué)習(xí)

這里從client_header_buffer_size指令入手,先查看這個(gè)指令的定義部分:

{ ngx_string('client_header_buffer_size'), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, //可以定義在http{}或server{}中,需要攜帶一個(gè)參數(shù) ngx_conf_set_size_slot, //參數(shù)意義為size,使用nginx預(yù)定義的解析size參數(shù)方法解析 NGX_HTTP_SRV_CONF_OFFSET, //將參數(shù)值放到srv級(jí)別的conf中 offsetof(ngx_http_core_srv_conf_t, client_header_buffer_size), //解析后放到ngx_http_core_srv_conf_t結(jié)構(gòu)體的client_header_buffer_size中 NULL }

src/http/ngx_http_core_module.c

由定義看到,我們?cè)趕erver{}中解析到的值會(huì)和http{}中的值做一次merge,作為該server{}下的最終值。查看merge相關(guān)的邏輯:

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

從這段邏輯中得到結(jié)論:如果我們?cè)趕erver{}中配置了client_header_buffer_size,那么針對(duì)這個(gè)server{}塊的最終值應(yīng)該就是我們配置的值。

為了印證我的結(jié)論,我重新寫了vhost配置,并在代碼中加入調(diào)試信息,把最終結(jié)果打印出來:

<span style='color:blue;'>vhost配置:</span>

http { include mime.types; default_type application/octet-stream; client_header_buffer_size 1k; ...... } server { listen 80; server_name db.; ...... } server { listen 80 ; server_name www.; client_header_buffer_size 1m; ...... }

<span style='color:blue;'>調(diào)試代碼:</span>

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,測(cè)試每個(gè)server{}中client_header_buffer_size的最終值為:

buffer before merge: child: 18446744073709551615 //由于第一個(gè)server{}中沒有配置,所以這個(gè)是-1(NGX_CONF_UNSET_SIZE)的unsigned long int表示 parent: 1024 //http{}中配置為1k buffer after merge: child: 1024 parent: 1024 buffer before merge: child: 1048576 //第二個(gè)server{}中配置為1m parent: 1024 buffer after merge: child: 1048576 parent: 1024

從值的最終結(jié)果看,的確是之前設(shè)置的1m,但是請(qǐng)求時(shí)卻返回了414。
由于將兩個(gè)server{}的位置顛倒后可以正常處理請(qǐng)求,所以在顛倒的情況下又測(cè)試了下最終值,輸出如下:

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,但是這次就可以正常處理請(qǐng)求了。<span style='color:blue;'>看來nginx在實(shí)際處理請(qǐng)求的過程中,一定還有之前不知道的一套邏輯,用來判斷client_header_buffer_size的最終值。</span>

nginx處理請(qǐng)求時(shí)的相關(guān)代碼如下:

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

<span style='color:blue;'>這里真相大白:</span>原來client_header_buffer_size的最終值,是nginx在解析conf后,default_server中經(jīng)過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

為了驗(yàn)證這一點(diǎn),我修改vhost配置為:

server { listen 80; server_name db.; ...... } server { listen 80 default; //指定該server為default_server server_name www.; client_header_buffer_size 1m; ...... }

重啟nginx觀察merge結(jié)果:

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結(jié)果沒有不同。測(cè)試請(qǐng)求,這次nginx成功處理該請(qǐng)求,和預(yù)期的效果一致。

結(jié)束語

筆者又測(cè)試了large_client_header_buffers,得到和client_header_buffer_size同樣的結(jié)果??梢缘贸鼋Y(jié)論:nginx在處理header時(shí)實(shí)際分配的buffer大小,是解析conf后,default_server中的最終值。

個(gè)人水平有限,上面的測(cè)試方法和理解如有不當(dāng)?shù)牡胤?,還望大家指正,謝謝!

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多