公司一项目采取LNMP架构,最近总是报500,Nginx缺点日志如下:
[error] 7649#0: 60873458 upstream sent too big header while reading response header from upstream, client: XXX, server: XXX, request: "GET /xx HTTP/1.1",
由于涉及到一些敏感信息,以是一些关键信息去除了,但这不影响问题的剖析。
从字面理解该当是upstream返回的header头超出限定了 ,这里大概脑补下FastCgi协议,Nginx和PhpFpm是通过这个协议进行数据传输的,个中Nginx和后端所有Upstream交互都是分两步的,第一步是处理头,第二步是处理body,每个协议实现自己的部分。
FastCgi协议这里不详述,在本案例中,头部分干系于后端写回的http头太大了,详细是哪部分大,一样平常来说是Cookiem的内容过长。
百度了一下,说要调度缓冲区大小,
fastcgi_buffer_size 16k; fastcgi_buffers 8 128k;
个中fastcgi_buffer_size默认是4K,在这个案例中,由于后端返回的Cookie和其它Http头信息超出4K了,以是报错,这里调度为16K,问题办理。
详细可以看下Nginx源码中处理FastCgi头的函数ngx_http_upstream_process_header:
if (rc == NGX_AGAIN) { if (u->buffer.last == u->buffer.end) { ngx_log_error(NGX_LOG_ERR, c->log, 0, "upstream sent too big header"); ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_INVALID_HEADER); return; } continue; }
这里会判断last是否即是end,Nginx针对缓冲是通过ngx_buf构造来描述的:
struct ngx_buf_s { u_char pos; u_char last; off_t file_pos; off_t file_last; u_char start; / start of buffer / u_char end; / end of buffer / ngx_buf_tag_t tag; ngx_file_t file; ngx_buf_t shadow; ……
个中start是缓冲的开始部分,end是结束部分,这是系统分配下来的,实际用的时候是将数据读到缓冲区里,并增加last部分,还有个pos表示运用场置的部分。
打个比方,我申请了1000的内存,开始地址为 1000,结束为1999(当然实际地址不可能这么小,这些是留给OS的,这里只是便于解释问题),那刚开始start为1000,end为1999,pos和last都为1000;这个时候运用读取后端upstream的头部分,读取了500字节,那last指向1500,post指向0,然后解析upstream的头,转换为内部一些构造,则pos也推进了。
回到上面的情形, 这里判断了last是否指向了end,这种情形下表示这个缓冲区已经用完了,在案例中,由于配的是4K,即表示从upstream中读取的头超出了4K,以是报错。
这个配置是针对每个Upstream的,即如果同时有1000个要求,则占用100016K的内存,以是不宜设的过大,这也是Nginx保存内存的一种办法。