nginx upstream header过大是啥情况
公司一项目采用LNMP架构,最近老是报502,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,其中u->buffer为Nginx和后端Upstream交互的缓冲区,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个请求,则占用1000*16K的内存,所以不宜设的过大,这也是Nginx保存内存的一种办法。
- python3 邮箱相关邮箱的服务
- 谈一谈Python中str()和repr()的区别
- TensorFlow从0到1 - 15 - 重新思考神经网络初始化
- python2.7搬运--->TensorFlow - 深度学习破解验证码
- 来学习几个简单的Hive函数啦
- 推荐系统实战-基于用户的协同过滤
- 素数的筛法
- 听说GAN很高大上,其实就这么简单
- python3 解码base64遇到的问题与解决
- TensorFlow从0到1 - 16 - L2正则化对抗“过拟合”
- 使用虚拟环境,搭建python3+scrapy
- Matplotlib基础全攻略
- Python 小爬虫 - 爬取今日头条街拍美女图
- python3使用zookeeper和私钥解密及编码转化配置信息
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 献给每一位母亲
- JUC学习之生产者和消费者
- 在 WSL 2 中基于 Docker 编排 LNMP 运行环境
- PHP 魔术方法、序列化与对象复制
- PHP 静态属性和静态方法
- 通过 Trait 水平扩展 PHP 类功能
- 通过对象组合水平扩展 PHP 类功能
- DO,DTO,VO,POJO 你知道吗?
- Python 爬虫进阶必备 | AES-CBC 的 Pyhon 实现要怎么写?给代码就完事了
- Babel:下一代Javascript语法编译器
- 如何定位及优化SQL语句的性能问题
- Java线程安全如何进行原子操作,一致性的最佳实践
- 冒泡排序
- 现有CDP-DC集群启用Auto-TLS
- 打卡001/这是一篇软文