由火币k线爬虫引出的-- http长链接问题

0X00 背景

在一次恰巧查看vps时,发现vps存在大量的TIME_WAIT状态的连接(几百个吧也不是很大量),发现是某Python进程引起,甚觉奇怪。当时VPS上只跑有SSR和一个火币K线爬虫。当然我第一反应是怀疑到SSR,但转念一想,如果是SSR,我的梯子估计早就塌了,故怀疑到爬虫。以至后来引出了一些关于http keep-alive,tcp长连接和python requests的一些思考。

0X01 起因

问题的原因在于,火币在github上提供的Python SDK中,直接使用requests.get()和requests.post()。导致每次请求都会不断建/拆连接,作为主动关闭方,频繁的建/拆tcp连接,必定导致大量的TIME_WAIT。

了解到起因后修改了一下火币的SDK,利用request.session来保持长链接。效果很棒,不但减少了TIME_WAIT的产生,还提升了请求速度。

修改之前:
use 1.104477 seconds

修改之后:
use 0.385232 seconds

0X02 反问

找到了问题原因,还修改了火币SDK分享给了群里的韭菜们。开开心心的扭头跟叶老师分享我的成果。但叶老师反问了一个很专业的问题,你说的长链接,是说的那个keep-alive么?

长连接?keep-alive? 恩,我也不知道是哪种,不过可以抓包看一下。但抓包之前要先抛出假设。经过我和叶老师激烈的讨(si)论(bi)我做了如下假设:

1、http不带有keep-alive的话,服务器再完成请求后会主动断开连接
2、requests.get() 发起的http请求不带有keep-alive,所以请求完成后,服务器会把连接接断开。
3、session.get() 发起的http请求带有keep-alive,请求完成后服务器非意外情况不会断开连接,由客户端控制连接长短

下面就是抓包
第一个场景:调用requests.get(),观察http是否带有keep-alive,服务器 or 客户端 主动断开连接

源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import time
import requests

HEADERS = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:44.0) Gecko/20100101 Firefox/44.0',
}

url = "http://www.163.com"
r = requests.get(url)
#r = self.session.get(url)
print r

while True:
time.sleep(5)

这是我访问www.163.com的包。可以看到requests.get()里面其实是带有keep-alive的。跟我预想的不太一样。

avatar

再看一下连接断开的包,其实也是客户端主动断开的。

avatar

恩,看来有keep-alive的时候确实服务器不会主动断开链接。

那我们尝试一下把keep-alive干掉,服务器会不会主动断开连接?
因为用的是requests库,而且keep-alive是默认加上的,只能去库里面把代码注释掉了。

注释位置如下:requests/utils.py :741

avatar

注释掉代码后,再次发起请求看一下,确实没有了keep-alive

avatar

但是好像还是客户端断开的连接。为什么呢?后来查了查可能跟nginx的特性有关,这个后续再专门来研究吧。

avatar

总之到此为止,前两个假设都已经错误了。不过倒是可以确定一点。request.get会自己断开连接,确实是短连接,哈哈。



版权声明:本文为原创,欢迎转载,转载请注明出处,勿用于商业用途!