Open vislee opened 4 years ago
在nginx做一些请求内容过滤的操作。当用户上传一个大文件时,偶然会有上传失败的情况,当关闭内容过滤时问题不再发生。 初步定位是和文件过滤有关系,在测试环境模拟了很多次都无法复现。
首先reset肯定不是一个正常的关闭连接。先排查是否nginx在某种情况下会发送reset。 查看了nginx代码,发现只要配置了reset_timedout_connection指令就会有reset连接的可能,看线上配置也没有配置该指令。
reset_timedout_connection
零窗口探测难道有超时设置,查看《tcp/ip协议详解》几乎说所有的实现都没有超时,零窗口会一直探测。
猜测是源站读请求内容超时,导致源站关闭连接,发送fin包。 分析了nginx核心循环的代码,nginx在主循环里优先处理网络事件,因此可能是包过滤调用了hypherscan导致nginx进程陷入。 而源站关闭连接后,nginx也要关闭和客户端的连接,而此时接收窗口还有数据没有接收。网络层就发送rst包reset掉和客户端的连接了。 以下python代码可以复现reset包。
# -*- coding: utf-8 -*- import socket import sys import time sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_address = ('127.0.0.1', 10001) sock.bind(server_address) sock.listen(1) while True: connection, client_address = sock.accept() time.sleep(1) connection.recv(1) connection.close() print("close")
根据业务逻辑,修改了代码减少了包过滤的内容,上线观察了一段时间后问题解决。
概述:
在nginx做一些请求内容过滤的操作。当用户上传一个大文件时,偶然会有上传失败的情况,当关闭内容过滤时问题不再发生。 初步定位是和文件过滤有关系,在测试环境模拟了很多次都无法复现。
问题追踪
首先reset肯定不是一个正常的关闭连接。先排查是否nginx在某种情况下会发送reset。 查看了nginx代码,发现只要配置了
reset_timedout_connection
指令就会有reset连接的可能,看线上配置也没有配置该指令。零窗口探测难道有超时设置,查看《tcp/ip协议详解》几乎说所有的实现都没有超时,零窗口会一直探测。
猜测是源站读请求内容超时,导致源站关闭连接,发送fin包。 分析了nginx核心循环的代码,nginx在主循环里优先处理网络事件,因此可能是包过滤调用了hypherscan导致nginx进程陷入。 而源站关闭连接后,nginx也要关闭和客户端的连接,而此时接收窗口还有数据没有接收。网络层就发送rst包reset掉和客户端的连接了。 以下python代码可以复现reset包。
根据业务逻辑,修改了代码减少了包过滤的内容,上线观察了一段时间后问题解决。
总结