vislee / leevis.com

Blog
87 stars 13 forks source link

因业务逻辑太重导致nginx延迟读引发的问题 #168

Open vislee opened 4 years ago

vislee commented 4 years ago

概述:

在nginx做一些请求内容过滤的操作。当用户上传一个大文件时,偶然会有上传失败的情况,当关闭内容过滤时问题不再发生。 初步定位是和文件过滤有关系,在测试环境模拟了很多次都无法复现。

问题追踪

首先reset肯定不是一个正常的关闭连接。先排查是否nginx在某种情况下会发送reset。 查看了nginx代码,发现只要配置了reset_timedout_connection指令就会有reset连接的可能,看线上配置也没有配置该指令。

零窗口探测难道有超时设置,查看《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")

根据业务逻辑,修改了代码减少了包过滤的内容,上线观察了一段时间后问题解决。

总结