V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
drymonfidelia
V2EX  ›  程序员

Python aiohttp 异步 需要同时请求同域名下 8000 个 URL(对方网站无并发限制)把结果拼接返回,要求总耗时最短, 8000 个同时发还是先发 1000 个,不等待结果,间隔 0.1 秒再发下一批快?

  •  1
     
  •   drymonfidelia · 283 天前 · 2723 次点击
    这是一个创建于 283 天前的主题,其中的信息可能已经有所发展或是发生改变。
    爬虫,所有同行爬的都比我们快,不知道为什么
    别人 1 秒更新,我们上了 10 台服务器还是慢别人 3 秒
    43 条回复    2024-02-22 17:45:51 +08:00
    so1n
        1
    so1n  
       283 天前
    一个请求一个 task 不就异步了?可以并发 n 个
    drymonfidelia
        2
    drymonfidelia  
    OP
       283 天前
    @so1n 并发 8000 个要 3 秒多的话才能全爬完一组 8000 个,但是单请求一个耗时只有 0.15 秒
    业务实时更新接近 9 万个 URL 的数据,同行不知道怎么做到的延迟不到一秒,我们用了 10 台服务器都做不到
    drymonfidelia
        3
    drymonfidelia  
    OP
       283 天前
    爬的是国外的站,对方的站套了 cdn 不知道是什么机房,已经选了测试出来的耗时最短的云买服务器爬了
    drymonfidelia
        4
    drymonfidelia  
    OP
       283 天前
    对方套的是 akamai 的 cdn ,测试出来 azure 耗时最短
    locoz
        5
    locoz  
       283 天前 via Android
    什么使用场景会需要实时更新近 9W 个 URL 的数据,还有同行以秒级差距进行竞争,并且同行的时效性还能被看到…你确定你这情况不是 XY 问题导致的吗…
    drymonfidelia
        6
    drymonfidelia  
    OP
       283 天前
    @locoz 具体场景不方便公开,但差不多就是库存监控,有 90000 个商品,上货时间没办法提前知道,我们永远比同行慢 3 秒
    drymonfidelia
        7
    drymonfidelia  
    OP
       283 天前
    上货=>补货
    drymonfidelia
        8
    drymonfidelia  
    OP
       283 天前
    没有 API 能一次性查多个商品库存
    GeekGao
        9
    GeekGao  
       283 天前
    不知道你们具体的实现,但是多台机器也需要调度过程的。例如 10 台机器,每台 1000 并发。但是还是要根据机器配置来设置,得测。

    CPU 、内存和网络带宽。CPU 的处理能力、内存的大小以及网络的带宽和延迟都会影响并发性能的。
    phrack
        10
    phrack  
       283 天前
    单个请求 0.15 秒是并发为 1 的情况下计算的吧?
    8000 个并发的时候,假设你说的 3 秒,这应该是从你程序代码里计算的吧,还得细化,
    1. 从程序调了 API 发出这个包到这个包从内核发出去的时间差
    2. 从内核上包发出去之后,接收到对方服务器返回包的时间差
    3. 从内核接收到包,到程序解析完这个包的时间差

    还有几个可能需要细化的地方,思路就是得判断这 3 秒到底花在哪里了,3 秒相对 0.15 秒长太多了,为什么并发 8000 的时候多出来了这么多。

    现在的计算机这么牛逼处理 8000 并发我感觉轻轻松松(我瞎估计的哈),如果是这样呢那就是对方 CDN ,WAF 之类的给 IP 限速了,虽然你说了没有限制但我感觉不太可能呢。
    drymonfidelia
        11
    drymonfidelia  
    OP
       283 天前
    @GeekGao 纯发请求消耗不了多少 CPU 和内存吧, azure 带宽至少 1Gbps, 看起来是足够了
    @phrack 确实是在代码里通过全部请求收到返回-首个请求发送前时间, 精确到毫秒计算的. 从内核发出的时间要怎么看, 在服务器上抓包么?
    phrack
        12
    phrack  
       283 天前   ❤️ 1
    @drymonfidelia 那你这样算还有一个地方得细化,你得计算每个请求花的时间而不是从所有请求完成后减去第一个请求发送时间,然后先看一下这 8000 个请求花的时间的总体统计分布,基于时间的统计分布(有个问题是先发出去的包是有可能后到对方服务器的,这个还得考虑进去,有办法可以做到先发的先到,也可以做到 8000 个请求几乎同时到,具体搜索 last-byte-sync, single-packet-attack )

    反正你就是得先判断这 3 秒里面到底发生了什么,不然就是瞎猫抓耗子,碰巧某个解决方案成功了你还是不知道到底怎么回事。
    phrack
        13
    phrack  
       283 天前
    @drymonfidelia 要在服务器上抓包,怕影响性能也可以上级路由器镜像流量在另一台服务器抓,不过我感觉影响不大。
    drymonfidelia
        14
    drymonfidelia  
    OP
       283 天前
    其实是某拍卖平台的自动出价系统, 需要实时监控价格有没有被超过, 高峰期最多有 9 万条链接接近截止时间, 延迟 3 秒体验影响很大的, 同行能做到实时
    平台本身推送但是延迟还不止 3 秒
    @locoz
    lesismal
        15
    lesismal  
       283 天前   ❤️ 2
    暂时想到几点,OP 可以参考下:
    1. 多用一些出口 IP ,对方没有限制并发可能是不直接报错但对单 IP 高频可能也有频率限制
    2. 是每个请求一个短链接吗?还是 keepalive 的复用长连接?如果是 keepalive 复用长连接,http 1.x 很多不支持 pipeline 的所以要请求-响应然后才发下一个这就比较慢了,如果是 http2.0 又有 4 层线头阻塞的问题、并发量大了也是慢的很,所以也确认清楚这个
    3. py 的实现是怎样的,for 循环发送 8000 个? 10 台机器每个节点 for 循环 800 个?这个 for 循环调用所有请求一共多久?请求回来再处理、虽然是异步的但是处理响应的代码是 py 的吧?有没有把这部分也统计上?
    4. 对比下其他语言的实现?比如 go ,如果姿势 http 请求也是比较容易的
    5. 会不会有订阅机制、竞品订阅了实时收到通知?

    实在不行加上抓包分析下网络吧
    lesismal
        16
    lesismal  
       283 天前
    再不济,加钱请技术咨询来协助定位、开发
    lovelylain
        17
    lovelylain  
       283 天前 via Android
    @drymonfidelia 补货时间没法提前知道,于是你们不停访问页面判断有没有补货,中间不带 sleep ?这算 ddos 了吧,有 sleep 的话没办法保证你 sleep 的那间隙没补货啊。
    Hopetree
        18
    Hopetree  
       283 天前
    我觉得你可以先 100 ,然后 1000,2000...8000 试探,看看到底是从多少并发开始变慢的
    opengps
        19
    opengps  
       283 天前
    有没有可能,对方已经压测到极限了,你才过来加上你的压力。注意压崩了要负责的
    shuax
        20
    shuax  
       283 天前
    有没有可能加上缓存,带上 etag 什么的,没变化就快速返回,或者 GET 之前先 HEAD 一下,看看有没有变动。根据我的经验,并发过多以后反而会变慢,可能竞争加大了,我习惯开 128 个并发。
    cat
        21
    cat  
       283 天前
    90000 个商品,秒级更新,意思是你们每秒都去抓取对方 90000 个页面???
    6IbA2bj5ip3tK49j
        22
    6IbA2bj5ip3tK49j  
       283 天前
    为什么要 8000 个结果拼接之后再返回?
    8000 个单独返回不是更合理吗?
    warcraft1236
        23
    warcraft1236  
       283 天前
    uvloop 用了吗
    iorilu
        24
    iorilu  
       283 天前
    什么业务需要拼接 8000 个页面呢
    alexsz
        25
    alexsz  
       283 天前
    有没有可能 对手是拍卖平台的合作伙伴-根本不用爬的?
    lingeo
        26
    lingeo  
       283 天前
    多进程+aio ,cpu 和带宽都没跑满那就单纯是响应慢了,然后自己统计排查哪个接口慢。
    lingeo
        27
    lingeo  
       283 天前
    反正你是最后拿到结果才拼接,又不涉及到内存竞争,都拿到返回了处理以下就好了。
    lingeo
        28
    lingeo  
       283 天前
    #26 CPU 和带宽都跑慢了那就是单纯的响应慢。
    gorira
        29
    gorira  
       283 天前
    一千毫秒内 90k url 还要返回完整处理结果,经济形势不好,搞高频交易的失业出来写爬虫了?
    lambdaq
        30
    lambdaq  
       283 天前
    对方不一定是直接趴页面

    好多年前我也趴微博,TWTR ,写了一套自以为巨 NB 的系统,效率比市面上的都高,可以同时趴 XXXXXX 个账号的页面,当然也耗费了很多 IP

    后来发现自己就是纯纯的傻。。更巧妙的方法是直接 follow XXXXXX 个 账号,每次趴 1 个页面就行。。。
    lvlongxiang199
        31
    lvlongxiang199  
       283 天前
    你为啥实际试试呢 ?
    IvanLi127
        32
    IvanLi127  
       283 天前
    有没有可能你请求的 host 有并行处理请求的上限?你开多点机子测呢?上代理 ip 池呢?
    xivcm
        33
    xivcm  
       283 天前
    别人也许同机房有节点 路径比你短的多 你的最短耗时并不意味着真的是最短耗时 而且算下来你爬你对手的 比直接爬数据源要快
    drymonfidelia
        34
    drymonfidelia  
    OP
       283 天前
    @cat 是这样,同行据说也是这么做的
    @lambdaq 平台推送延迟不止 3 秒
    @lovelylain 一批爬完马上爬下一批,没有 sleep
    GeekGao
        35
    GeekGao  
       283 天前
    @drymonfidelia cpu 主频决定了内核调度速度
    lazywen
        36
    lazywen  
       283 天前 via Android
    看你回帖你已经排除了服务端限制,那你先着手在长链接优化和并行逻辑优化上,还是没有效果的话换 golang 吧,因为没多少优化空间了(无限堆机器的话另说),你使用了 aiohttp ,python 中的协程还是单核 cpu 调度的,你并发太多,会在某一瞬时峰值达到观测不到的瓶颈,而 golang 的强项就在协程并发
    markgor
        37
    markgor  
       283 天前
    做个日志吧....
    看看分配到 10 台机,每次请求返回的时长是多少,整体完成时间是多少......
    先找出耗时的点。
    另外确定下是不是对方根据 IP 限速,这部分可以根据上面的测试结果判断,如果每台机实际 QPS 都是 100 ,那可能对方是根据 IP 限制了 QPS ,这个时候上代理池。
    1 、测试对方是否限制 QPS ;
    2 、测试对方根据什么限制 QPS ?[IP/token/cookies....]
    3 、如果能 100%确定对方是没限制 QPS 的话,看看时间消耗在哪里了,这个根据服务器监控和埋点的日志基本可以分析出来。
    4 、如果确定对方限制 QPS ,根据限制策略进行调整,如限制单 IP 的 QPS 为 100 ,那[每 100 个地址,就用一个代理 IP] = 1 次任务。

    不过说真的,并发 8000 ,不止你们去爬,这访问量挺恐怖的...
    有没有一种可能,同行爬取的方式和你们不同,即对方可能一次请求返回所有,而你们没发现只能一个个爬呢?
    yuyue001
        38
    yuyue001  
       283 天前
    对比一下 akamai CDN 更新数据时间,和竞争对手的数据时间。会不会对手家有别的渠道?

    以及资源的 CDN 的路径是有规则的吗?也就是这 8000 个 URL 地址是怎么获取的?会不会是发现地址慢了?而不是请求资源满了。
    drymonfidelia
        39
    drymonfidelia  
    OP
       283 天前
    @yuyue001 8000 个 URL 是用户提交的,在我们数据库里
    akamai CDN 的数据是实时的
    drymonfidelia
        40
    drymonfidelia  
    OP
       283 天前
    @markgor 平台上拍卖机器人泛滥,官方没管过,基本上是默许了 是有一次请求多个的列表 API ,但列表 API 有缓存延迟不止 3 秒,用不了
    drymonfidelia
        41
    drymonfidelia  
    OP
       282 天前
    @lesismal 任务随机下发到一个节点,在同一个 aiohttp session 里面发,每个 URL 拿到结果马上发同 URL 的下一个请求,没有关注是 http 1.x 还是 2.0
    有订阅机制,但是订阅延迟不止 3 秒,用不了
    laminux29
        42
    laminux29  
       282 天前
    笑死了,

    不方便告诉你们到底是什么网站;

    不方便告诉你们到底怎么去爬;

    反正你们一定要浪费你们的时间,去不断地猜测,直到解决我的问题;

    什么 NTR 问题。
    drymonfidelia
        43
    drymonfidelia  
    OP
       282 天前
    @laminux29 全告诉了 是你自己不翻回帖
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2695 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 07:27 · PVG 15:27 · LAX 23:27 · JFK 02:27
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.