问题回顾
近日,我们一个版本的分支上了预发,一个订单查询接口总是报错,后端服务器日志大概如下
ClientAbortException Caused by: java.net.SocketException: Connection reset by peer: socket write error
一开始排查问题的方向肯定是后端出错了,但是看这个完整的异常栈,出错报在框架层,和业务代码无关,怀疑的方向就是后端数据量太大
然后通过抓包,发现每次前端报错的时候,那个http返回报文中body里的json被截断了,只有一部分,这时候就有点怀疑nginx了,毕竟这个请求是nginx代理请求的,极有可能nginx哪里配置出错了
那么就进服务器看nginx error日志,看到了如下日志
[crit] 17201#0: *58771 open() "/usr/local/nginx//proxy_temp/8/65/0000000658" failed (13: Permission denied) while reading upstream, client: 10.111.42.228, server: ys.test.
51juban.cn, request: "GET /order/index?verson=20170925 HTTP/1.1", upstream: "[http://10.111.12.42:9102/order/index?verson=20170925](http://10.111.12.42:9102/order/index?verson=20170925)", host: "ys.test02.51juban.cn", referrer: "[http://ys.test02.51juban.cn/frame/](http://ys.test02.51juban.cn/frame/)"
把/usr/local/nginx目录的权限设置为nginx,让nginx进程能够访问就行了,返回报文被截断的情况就再也没发生了,疯狂吐槽的App开发哥们终于能够测试了。
这个问题阻碍测试接近1天,调查问题进度也没上面写的那么顺风顺水,我觉得遇到问题首先要合理分析出问题出在哪里,问题的初期其实我经过百度,其实和运维提过排查下nginx日志
这个虽然加错了,凡是方向对了,如果看了nginx日志,应该能立刻解决问题,但是没有看,我也没那台服务器权限
第二天,我们抓包了,发现返回被截断,我更加怀疑nginx的问题
嗯,这次对了
一个小小的点,阻碍了这么多时间,这么多人力,可见细节决定成败,以及经验的重要性
所以以后遇到问题
- 合理分析问题原因
- 看日志,看日志,看日志
- 团队合作
出现这个问题的原因就是nginx对它的缓冲区目录没有权限,下面我们就来学习下这个缓冲区
缓冲区的作用
缓冲区的作用,就是为了协调客户端到nginx以及nginx到服务器的速度不同。如果这两条链路都非常快,那么没有缓冲区的事了。
如果客户端到nginx速度快,nginx到服务器速度慢,没有缓冲区,一点点数据量就直接发到客户端,十分浪费性能。有了缓冲区,积累到一定量,再传输到客户端,减少了Tcp请求。
相反,客户端到nginx速度慢,nginx到服务器速度快,没有缓冲区,nginx到服务器的连接就会一直保持在那边,直到客户端接受完毕。有了缓冲区,返回内容放到缓冲区后,nginx到服务器的连接就能断开了,客户端从缓冲区拉取即可。
缓冲区这个概念在很多地方都用到,你想到了那些地方?IO?MQ?
nginx缓冲区配置
nginx缓冲区的配置主要在location模块下面,主要配置参数如下
proxy_buffer_size
后端服务器的相应头会放到proxy_buffer_size当中,这个大小默认等于proxy_buffers当中的设置单个缓冲区的大小。 proxy_buffer_size只是响应头的缓冲区,没有必要也跟着设置太大。 proxy_buffer_size最好单独设置,一般设置个4k就够了。
proxy_buffers
proxy_buffers的缓冲区大小一般会设置的比较大,以应付大网页。 proxy_buffers当中单个缓冲区的大小是由系统的内存页面大小决定的,Linux系统中一般为4k。 proxy_buffers由缓冲区数量和缓冲区大小组成的。总的大小为number*size。
若某些请求的响应过大,则超过_buffers的部分将被缓冲到硬盘(缓冲目录由_temp_path指令指定), 当然这将会使读取响应的速度减慢, 影响用户体验. 可以使用proxy_max_temp_file_size指令关闭磁盘缓冲.
proxy_busy_buffers_size
proxy_busy_buffers_size不是独立的空间,他是proxy_buffers和proxy_buffer_size的一部分。nginx会在没有完全读完后端响应的时候就开始向客户端传送数据,所以它会划出一部分缓冲区来专门向客户端传送数据(这部分的大小是由proxy_busy_buffers_size来控制的,建议为proxy_buffers中单个缓冲区大小的2倍),然后它继续从后端取数据,缓冲区满了之后就写到磁盘的临时文件中。
proxy_max_temp_file_size和proxy_temp_file_write_size
临时文件由proxy_max_temp_file_size和proxy_temp_file_write_size这两个指令决定。 proxy_temp_file_write_size是一次访问能写入的临时文件的大小,默认是proxy_buffer_size和proxy_buffers中设置的缓冲区大小的2倍,Linux下一般是8k。
proxy_max_temp_file_size指定当响应内容大于proxy_buffers指定的缓冲区时, 写入硬盘的临时文件的大小. 如果超过了这个值, Nginx将与Proxy服务器同步的传递内容, 而不再缓冲到硬盘. 设置为0时, 则直接关闭硬盘缓冲.
缓冲区分为内存和文件两部分,不可能所有Response都在内存中缓冲,毕竟需要用内存去建立更多连接,所以超过一定的量会刷到磁盘,我们出现的问题就是刷到磁盘这一步被权限阻碍了,导致客户端拿到的部分报文是内存中的
但是我们的Response并不是全部被截断,百分之60的Response是正常的,我猜测要么是这些Response没有超过缓冲区大小,要么写的缓冲目录部分存在权限
注意下上面的默认配置,缓冲区是默认开启的
nginx缓冲区使用
默认的配置应该够用,也可以根据应用平均的Response大小做优化,毕竟直接走内存肯定要比走IO快
参考的文章
https://www.cnblogs.com/me115/p/5698787.html
https://www.cnblogs.com/bethal/p/5606062.html
https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_temp_file_write_size