V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
Cy86
V2EX  ›  Python

Python 爬虫并发极限是多少呢?

  •  
  •   Cy86 · 2020-03-14 04:24:44 +08:00 · 2245 次点击
    这是一个创建于 1497 天前的主题,其中的信息可能已经有所发展或是发生改变。

    模块介绍: 爬取网上很多公开的代理 IP 网址, HTTP HTTPS Sock5 , 去重后, 访问自己域名(返回 Json, 小于 300 字节), 用来测试匿名程度后保存

      不使用代理,仅本地网络测试
      设备:  联通光纤宽带(我一个人用) 下行 300M 上行 30    CPU: I7 7700HQ 4 核 8 逻辑处理器 内存: 16G 
      国内的服务器: 阿里云  1 核 2 内  1M
    

      单进程 + 异步: 
          URL 500 个
          asyncio.Semaphore(500)   
          aiohttp 设置超时时间为 1 秒
    
      结果: 并发 500 的成功率为 97%左右(偶尔抽风)
          每秒并发个数: 485
    
      多进程 + 异步:
          URL 500 个
          5 个进程 (每个进程平均 100 个 URL)
          asyncio.Semaphore(100)   
          aiohttp 设置超时时间为 1 秒
    
      结果:并发 500 的成功率为 99%左右(偶尔抽风)
          每秒并发个数: 495
    
      多进程 + 异步:
          URL 1600 个
          8 个进程 (每个进程平均 200 个 URL)
          asyncio.Semaphore(200)   
          aiohttp 设置超时时间为 1 秒
    
      结果:并发 1600 的成功率为 4% ~ 75%左右(大概率低于 30%)
          每秒并发个数: 64 ~ 1200
    

    当前遇到的问题: 超过 500 并发后极其不稳定

      目前猜测之所以 500 是临界点, 可能联通限制连接数 1000 导致 或是  Windows 平台 select 限制
    

    当前策略每三秒对所有 代理 IP 访问自己服务器进行测试 测试代理 IP 超时时间为 3 秒 通过超时次数,和响应时间(使用) 对每个 IP 分配权重来筛选,排序, 所以要很大程度上减少自身网络或程序的错误, 才尽可能保证代理 IP 的准确性于可用性, 毕竟能用的 IP 太少, 误封就太可惜了

      电脑性能和上行带宽没跑满, 多加几个服务器太浪费了
    

    请问各位, 有什么方式能提高并发量, 或容错(误封可用 IP)的策略呢,

    25 条回复    2020-03-17 01:34:29 +08:00
    chizuo
        1
    chizuo  
       2020-03-14 08:28:17 +08:00
    你这个明显少了。我之前写了个爬虫 b 站排行榜的,多进程+异步 async+代理池,放到学校服务器上( 20c+48G),每秒并发可以轻松上千。不过持续不了多久,因为代理池太弱了,就会被封。
    测试本地网页的话,应该能上万。
    ClericPy
        2
    ClericPy  
       2020-03-14 09:16:40 +08:00
    并发极限没测过, 反正协程自己跑就挺快了, requests + 多线程大概比 httpx 协程慢个 10%, gevent 不测

    Test without uvloop, 12 logical CPUs.
    Windows-10-10.0.18362-SP0
    3.7.1 (v3.7.1:260ec2c36a, Oct 20 2018, 14:57:15) [MSC v.1915 64 bit (AMD64)]
    ================================================================================
    test_aiohttp(3.6.2) : 2000 / 2000 = 100.0%, cost 1.158s, 1727 qps, 100.0% standard.
    test_httpx(0.11.1) : 2000 / 2000 = 100.0%, cost 3.927s, 509 qps, 29.47% standard.

    Test with uvloop, 1 logical CPUs.
    Linux-4.15.0-13-generic-x86_64-with-Ubuntu-18.04-bionic
    3.7.3 (default, Apr 3 2019, 19:16:38)
    [GCC 8.0.1 20180414 (experimental) [trunk revision 259383]]
    ================================================================================
    test_aiohttp(3.6.2) : 2000 / 2000 = 100.0%, cost 0.698s, 2866 qps, 100.0% standard.
    test_httpx(0.11.1) : 2000 / 2000 = 100.0%, cost 2.337s, 856 qps, 29.87% standard.

    以前随手测的, 请求本地 golang 只带 net/http 的 server
    lc7029
        3
    lc7029  
       2020-03-14 11:52:52 +08:00
    具体说是看你配置和网络
    家用宽带可能有运营商的限制连接数或者 QOS
    black11black
        4
    black11black  
       2020-03-14 19:37:29 +08:00
    很明显是你用 select 锁 512fd 的问题吧
    lithbitren
        5
    lithbitren  
       2020-03-14 21:40:56 +08:00 via iPhone
    @black11black 大佬,select 锁怎么解啊?我最近试了试一个挺火的 py 新框架 fastAPI,据说 qps 能上万,结果本地拿并发爬虫一打就死了,win10 上开服务并发量不能超 510,一超就爆 select 错直接垮了,stackoverflow 和 github 都没找到解答。。
    ericbize
        6
    ericbize  
       2020-03-14 21:53:05 +08:00 via iPhone
    之前单位安全大佬写的 py 脚本 , 在 kvm 的 ubuntu 上面打了 12w 条连接,直接把单位的网卡死了。 背景,电信专线,固定 ip,100M
    rockjike
        7
    rockjike  
       2020-03-14 22:04:23 +08:00 via Android
    一般网站,爬虫并发多大会挂掉
    opengps
        8
    opengps  
       2020-03-14 22:29:46 +08:00
    @ericbize 你们单位的网络设备支撑的在线连接数可能用满了,所以没有连接可用,表现成网络卡死。我当初 gps 系统上云是因为 5 万多买的硬件思科防火墙只能支撑 25 万 tcp 长连接
    johnsona
        9
    johnsona  
       2020-03-14 23:23:31 +08:00 via iPhone
    你先把反爬虫绕过去再说
    qsnow6
        10
    qsnow6  
       2020-03-14 23:33:32 +08:00
    提供一个数据,python 爬虫框架的扛把子,scrapy,每秒并发可以达到 1800 request /s
    binux
        11
    binux  
       2020-03-15 03:56:57 +08:00 via Android
    @qsnow6 #10 开 HTTPS 开 gzip 就卡死了
    RicardoY
        12
    RicardoY  
       2020-03-15 10:22:03 +08:00
    @qsnow6 这是怎么测出来的,scrapy bench 只能跑到 2400min/s 左右
    qsnow6
        13
    qsnow6  
       2020-03-15 18:56:26 +08:00
    @RicardoY #12 不好意思,敲错了,单位是 min
    lithbitren
        14
    lithbitren  
       2020-03-15 20:21:30 +08:00
    我用 grequests 单线程最快每秒可以发 500-700 个 request,还没算上多进程,一次性可以同时建立数万的个协程请求,尤其找到一些复杂点的 API,没有保护的话必崩,同事里的个人几乎都被干崩过。
    不过最近遇到一次严重的内存泄漏也是因为 grequests 的 gevent 给搞得,开了 20 万个协程,等了几分钟,直接爆了个 memory error,然后可能是 c 扩展里面的内存没有释放,程序炸了,idle 关了,内存占用率都还在 95%以上,开流氓工具清内存都清不掉,最后只能重启。
    Cy86
        15
    Cy86  
    OP
       2020-03-15 21:13:16 +08:00
    @qsnow6 好吧... 我用协成单进程 9410min/s
    Cy86
        16
    Cy86  
    OP
       2020-03-15 21:28:18 +08:00
    @lithbitren 目前用 grequests 能达到 13377min/s 但 timeout 的几率有点大, 很难控制在百分之 98 以下, 我再研究研究
    Cy86
        17
    Cy86  
    OP
       2020-03-15 21:37:48 +08:00
    目前猜测是运营商的限制, 偶尔能突破 500 限制, 但阿里云和国外 VPS 测试依旧并发不满意, 服务器端可能是网络抖动的原因
    目前:
    国外: VPS 测试代理 IP 端口是否开放,过滤一波虚假的
    家里: 单线程 异步 每秒 400 并发来使用, 3 秒能测试 1200 个代理 IP(GET 国内匿名测试服务器), 准确率达到百分之 98+%
    lithbitren
        18
    lithbitren  
       2020-03-15 21:46:54 +08:00
    @Cy86 外网 grequests 我这边最多也就射出秒均 200-300 这样,任何做过保护的网站都会秒封 IP,只要设了 timeout 怎么都会被短暂阻塞,我测的是自己搭的本地服务框架,算上回收处理时间是 500-700,其实应该算成服务器秒内处理请求数。单纯的看发射的话,本地的秒均单进程应该可以达到 900 多,刚刚测了 1000 个请求,服务器日志的的请求间隔是 1.1 秒这样。其实对于小服务器来说,做好保护的话最多是带宽资源占用导致其他人无法正常使用服务,但也不是这么好崩的。
    black11black
        19
    black11black  
       2020-03-16 19:24:14 +08:00
    @lithbitren 建议补习基础知识....想异步爬虫就好好原生异步,不要猴子补丁....select 机能限制就这么高性能啊,我猜测 select 限制是因为 select 默认 512fd,正好符合了你说的超 500 不稳定,有问题上 epoll 啊,我又不知道你代码怎么写的,纯粹瞎猜。py 原生异步切换携程的时间消耗是微秒级的,合理配置后可以到纳秒级,十万并发不好说,网络状况合适的条件下单线程一万肯定能达到,你这么低性能都出问题明显是网络问题或者代码写的有问题。。
    v2eeeeee
        20
    v2eeeeee  
       2020-03-16 19:48:47 +08:00
    并发的时候会考虑 linux 系统设置的 ulimit (max user processes)吗?
    还是说网络流的并发都是一个进程 (单线程理解为一个进程) 维护的?
    lithbitren
        21
    lithbitren  
       2020-03-16 20:49:34 +08:00 via iPhone
    @black11black 没懂,grequests 用的 gevent 应该和之后的官方协程算另一套体系吧。。
    lithbitren
        22
    lithbitren  
       2020-03-16 20:55:53 +08:00 via iPhone
    @black11black grequests 的问题应该是解析数据占用了线程资源导致的效率瓶颈吧
    black11black
        23
    black11black  
       2020-03-17 00:11:22 +08:00
    @lithbitren 我一直不支持用猴子补丁,我不知道 grequests 的具体实现方式。但是你应该知道多线程是多线程,IO 复用是 IO 复用,你用线程的思考方式考虑 IO 复用是风马牛不相及的两码事。windows 下线程切换的默认时间片是十毫秒还是多少记不住了,linux 应该是几十微秒,基于线程模型理所当然是浪费大部分 IO 性能的,无所谓什么解析数据占用线程资源,就像 select 有监控上限,他不是 py 的并发极限,只是单纯你用了错误的方式而已
    lithbitren
        24
    lithbitren  
       2020-03-17 01:17:10 +08:00
    @black11black 不是,不推荐归不推荐,grequests 就是单纯的 gevent+request 的封装,并发爬虫几行写完了就是图个方便,协程是原理,但用 grequests 根本不需要懂协程,而且印象中是 3.5 之前就有了。单独 request 发送回收数据是需要解析时间解析的,从数据返回到数据解析成 request 对象也是需要时间的,是需要占用 GIL 资源的,切协程这个时间在解析数据这里是可以忽略不计的,但最后接收数据的时候阻塞的,如果任意一个请求的响应变慢或超时,整体的统计时间也会大幅增加。
    我这里 win10 开线程的应该是不到 1ms 左右,协程应该也是几十微妙。
    grequests 的核心代码就是一行 grequests.map(request_list),计时函数只能放在这行代码的前后,实质统计到的是所有请求完整生命周期的时间。
    lithbitren
        25
    lithbitren  
       2020-03-17 01:34:29 +08:00
    @black11black 不过我之前说的确实也不对,grequests 的发送时间统计里包括了所有 request 对象的构建,request 发送接受,对返回内容解析几个过程,并不算是实质从第一个对象发出到最后一个对象发出的时间。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1442 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 35ms · UTC 23:56 · PVG 07:56 · LAX 16:56 · JFK 19:56
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.