前文:

     最近在搞全网的CDN刷新系统,在性能调优时遇到了requests长连接的一个问题,以前关注过长连接太多造成浪费的问题,但因为系统都是分布式扩展的,针对这种各别问题就懒得改动了。 现在开发的缓存刷新系统,对于性能还是有些敏感的,我后面会给出最优的http长连接池构建方式。


该文章写的有些乱,欢迎来喷 ! 另外文章后续不断更新中,请到原文地址查看更新.    http://xiaorui.cc/?p=4437


老生常谈:

    python下的httpclient库哪个最好用? 我想大多数人还是会选择requests库的。原因么?也就是简单,易用! 


如何蛋疼的构建reqeusts的短连接请求:

python requests库默认就是长连接的 (http 1.1, Connection: keep alive),如果单纯在requests头部去掉Connection是不靠谱的,还需要借助httplib来配合.

正确发起 http 1.0的请求姿势是:

服务端接收的http包体内容:

所谓短连接就是发送 HTTP 1.0 协议,这样web服务端当然会在send完数据后,触发close(),也就是传递 \0 字符串,达到关闭连接 !  这里还是要吐槽一下,好多人天天说系统优化,连个基本的网络io都不优化,你还想干嘛。。。下面我们依次聊requests长连接的各种问题及性能优化。


那么requests长连接如何实现? 

requests给我们提供了一个Session的长连接类,他不仅仅能实现最基本的长连接保持,还会附带服务端返回的cookie数据。 在底层是如何实现的? 把HTTP 1.0 改成 HTTP 1.1 就可以了, 如果你标明了是HTTP 1.1 ,那么有没有 Connection: keep-alive 都无所谓的。  如果 HTTP 1.0加上Connection: keep-alive ,那么server会认为你是长连接。 就这么简单 !

Session的长连接支持多个主机么? 也就是我在一个服务里先后访问 a.com, b.com, c.com 那么requests session能否帮我保持连接 ?

答案很明显,当然是可以的! 

但也仅仅是可以一用,但他的实现有很多的槽点。比如xiaorui.cc的主机上还有多个虚拟主机,那么会出现什么情况么? 会不停的创建新连接,因为reqeusts的urllib3连接池管理是基于host的,这个host可能是域名,也可能ip地址,具体是什么,要看你的输入。 

又比如你可能都是访问同一个域名,但是子域名不一样,例子 a.xiaorui.cc, b.xiaorui.cc, c.xiaorui.cc, xxxx.xiaorui.cc,那么会造成什么问题?  哪怕IP地址是一样的,因为域名不一样,那么requests session还是会帮你实例化长连接。


如果是同一个二级域名,不同的url会发生呢? 是我们要的结果,只需要一个连接就可以了。

我们可以看到该进程只实例化了一个长连接。 

那么requests还有一个不是问题的性能问题。。。 requests session是可以保持长连接的,但他能保持多少个长连接? 10个长连接!  session内置一个连接池,requests库默认值为10个长连接。requests.adapters.HTTPAdapter(pool_connections=100, pool_maxsize=100)    一般来说,单个session保持10个长连接是绝对够用了,但如果你是那种social爬虫呢?这么多域名只共用10个长连接肯定不够的。 

让我们看看requests的连接池是如何实现的?  通过代码很容易得出Session()默认的连接数及连接池是如何构建的? 下面是requests的长连接实现源码片段。如需要再详细的实现细节,那就自己分析吧 

Python requests连接池是借用urllib3.poolmanager来实现的。每一个独立的(scheme, host, port)元祖使用同一个Connection, (scheme, host, port)是从请求的URL中解析分拆出来的。 from .packages.urllib3.poolmanager import PoolManager, proxy_from_url 。  下面是 urllib3的一些精简源码, 可以看出他的连接池实现也是简单粗暴的。

这里为止,Python requests关于session连接类实现,说的算明白了。 但就requests和urllib3的连接池实现来说,还是有一些提升空间的。 但问题来了,单单靠着域名和端口会造成一些问题,至于造成什么样子的问题,我在上面已经有详细的描述了。  那么如何解决? 我们可以用 scheme + 主domain +  host_ip + port 来实现长连接池的管理。 其实大多数的场景是无需这么细致的实现连接池的,但根据我们的测试的结果来看,在服务初期性能提升还是不小的。这样既解决了域名ip轮询带来的连接重置问题,也解决了多级域名下不能共用连接的问题。 

END.



对Python及运维开发感兴趣的朋友可以加QQ群 : 478476595 !!!
{ 2000人qq大群内有各厂大牛,常组织线上分享及沙龙,对高性能及分布式场景感兴趣同学欢迎加入该QQ群 }

另外如果大家觉得文章对你有些作用!   帮忙点击广告. 一来能刺激我写博客的欲望,二来好维护云主机的费用.
如果想赏钱,可以用微信扫描下面的二维码. 另外再次标注博客原地址  xiaorui.cc  ……   感谢!
暂无相关产品

评论已关闭。