大佬们,用 go 同时发起几万个 get 请求,怎么优化请求函数呢? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
biuyixia
V2EX    程序员

大佬们,用 go 同时发起几万个 get 请求,怎么优化请求函数呢?

  •  1
     
  •   biuyixia 2022-09-22 09:41:27 +08:00 5535 次点击
    这是一个创建于 1119 天前的主题,其中的信息可能已经有所发展或是发生改变。

    代码如下:

    func check_url(url string) { client := &http.Client{ Timeout: time.Second * 5, } req, _ := http.NewRequest("GET", url, nil) req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.82 Safari/537.36") resp, err := client.Do(req) if err == nil { defer resp.Body.Close() status := resp.Status if strings.Contains(status, "200") { fmt.Println(url,"===请求成功===") } } } 

    小弟刚学 go ,我需要同时并发几万个 url 请求,调用 check_url 函数,发现有时候明明可以访问的端口,却报 context deadline exceeded (Client.Timeout exceeded while awaiting headers) 错误,怎么优化这个 check_url 函数呢?

    37 条回复    2022-10-08 15:25:27 +08:00
    hxysnail
        1
    hxysnail  
       2022-09-22 09:44:17 +08:00
    你的 Client 设置了 5 秒钟超时,把时间调长一点呗
    biuyixia
        2
    biuyixia  
    OP
       2022-09-22 09:52:26 +08:00
    内网请求,大佬。不需要那么长的超时时间
    biuyixia
        3
    biuyixia  
    OP
       2022-09-22 09:54:52 +08:00
    @hxysnail

    需要对内网进行扫描,单个请求的时候如 8888 ,可以正常请求到判断为 200 状态,当对这个 ip 并发全端口进行扫描的时候,通过打印 resp, err := client.Do(req)的 err 可知:
    Get "...192.168.100.126:8888": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
    biuyixia
        5
    biuyixia  
    OP
       2022-09-22 10:04:52 +08:00
    @licoycn 看样子还是需要调整下函数的超时时间,,服务端没法控制。不知道还没有更优解。。
    morri
        6
    morri  
       2022-09-22 10:10:21 +08:00
    https://github.com/go-resty/resty
    试试用这个 http 工具呢?
    Nazz
        7
    Nazz  
       2022-09-22 10:15:24 +08:00   1
    需要限制并发协程数量
    biuyixia
        8
    biuyixia  
    OP
       2022-09-22 10:15:41 +08:00
    @morri 谢谢大佬。我试试哈
    coderxy
        9
    coderxy  
       2022-09-22 10:16:16 +08:00
    go 的 http client 默认有连接池限制的, 先把那个限制调大一点再试试
    d29107d
        10
    d29107d  
       2022-09-22 10:18:12 +08:00 via Android
    也有可能被请求端承受不了啊
    biuyixia
        11
    biuyixia  
    OP
       2022-09-22 10:18:46 +08:00
    @Nazz 我是通过 Ants github.com/panjf2000/ants ,因为用的同一个函数,通过 NewPoolWithFunc 创建了一个 20000 的协程池。
    seers
        12
    seers  
       2022-09-22 10:27:53 +08:00 via Android
    系统的 open file 数没打开吧,连接满了后面的 tcp 连接没发出去所以超时了,ulimit 确认下
    seers
        13
    seers  
       2022-09-22 10:31:03 +08:00 via Android
    你最后 err 打印下看看错误是啥,不要是 nil 后就不管了
    dcalsky
        14
    dcalsky  
       2022-09-22 10:34:54 +08:00
    optimize your http client transport, increase the number of idle connection for each host in the connection pool.
    runningman
        15
    runningman  
       2022-09-22 10:48:40 +08:00
    go routine
    fyooo
        16
    fyooo  
       2022-09-22 11:24:48 +08:00
    @Nazz +1 大概率是服务器扛不住了,内网服务扛不住那么大并发的。
    shawndev
        17
    shawndev  
       2022-09-22 11:29:08 +08:00
    堪比 ddos
    sadfQED2
        18
    sadfQED2  
       2022-09-22 11:42:14 +08:00   1
    ```
    var client *http.Client = &http.Client{
    Timeout: time.Second * 5,
    }

    func check_url(url string) {

    go func() {
    req, _ := http.NewRequest("GET", url, nil)
    req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.82 Safari/537.36")
    resp, err := client.Do(req)
    if err == nil {
    defer resp.Body.Close()

    status := resp.Status
    if strings.Contains(status, "200") {
    fmt.Println(url, "===请求成功===")
    }
    }
    }()

    }

    ```


    试试这个?你每次都 new 一个 httpclient 我记得好像是不能用上 keepalive 的,使用同一个 client ,保证 keepalive 。然后开协程疯狂请求就完事了。

    但是你确定服务器扛得住?
    aino
        19
    aino  
       2022-09-22 11:50:22 +08:00
    go 同时发起几万个 get 请求并发这么猛的吗,请教下 java 能做到吗,具体怎么做呢
    biuyixia
        20
    biuyixia  
    OP/div>
       2022-09-22 12:26:03 +08:00
    @shawndev 太真实了,哈哈。看来得另想他法了。。。
    biuyixia
        21
    biuyixia  
    OP
       2022-09-22 12:38:52 +08:00
    @sadfQED2 谢大佬。那就 client 共用。
    wheeler
        22
    wheeler  
       2022-09-22 13:08:33 +08:00 via iPhone
    @sadfQED2 #18 keepalive 不是 transport 维护的吗?不指定 transport 都是复用默认的 transport 吧?
    wheeler
        23
    wheeler  
       2022-09-22 13:10:43 +08:00 via iPhone
    @wheeler #22

    // Transport specifies the mechanism by which individual
    HTTP requests are made.
    If nil, DefaultTransport is used.

    https://pkg.go.dev/net/http
    a132811
        24
    a132811  
       2022-09-22 13:34:42 +08:00
    Client.Timeout exceeded while awaiting headers
    可能服务端超时、或者带宽不够吧。
    1. 确认你的网络有没有瓶颈
    2. 确认你的服务真实并发:用 ab/vegeta/gowrk 等工具压测一下
    monkeyWie
        25
    monkeyWie  
       2022-09-22 13:37:04 +08:00
    @aino #19 能啊,上 nio 、或者直接 netty
    p23XnFNH1Wq953rV
        26
    p23XnFNH1Wq953rV  
       2022-09-22 13:47:36 +08:00
    也可能是目标服务器瓶颈, 或者 seers 说的问题
    biuyixia
        27
    biuyixia  
    OP
       2022-09-22 14:02:17 +08:00
    @derrick1 好的大佬。估计就是了
    zbatman
        28
    zbatman  
       2022-09-22 15:26:27 +08:00
    刑啊
    sadfQED2
        29
    sadfQED2  
       2022-09-22 15:30:09 +08:00 via Android
    @wheeler 额,确实是。是我记错了
    lysS
        30
    lysS  
       2022-09-22 15:34:09 +08:00
    接口扫描是吧?不用 GET 、用 HEAD ,更好的方法其实还是用 tcp 请求
    lysS
        31
    lysS  
       2022-09-22 15:37:38 +08:00
    还有啊,扫描不同的地址,连接池是没用的
    iceiceice
        32
    iceiceice  
       2022-09-22 15:39:22 +08:00
    用 fasthttp
    aladdinding
        33
    aladdinding  
       2022-09-22 16:03:43 +08:00
    用同一个 client transport 调节大点
    bthulu
        34
    bthulu  
       2022-09-22 16:40:31 +08:00
    带宽打满了吧, 后面的请求只能排队了, 然后就超时了
    biuyixia
        35
    biuyixia  
    OP
       2022-09-30 09:10:11 +08:00
    @seers 大佬,我想问问你说的 open file 数是什么?还有 ulimit ,跟 http 请求有关系吗,小弟刚学。请指教

    你说的第二个,最后 err 打印下,那个异常端口就是报的 context deadline exceeded (Client.Timeout exceeded while awaiting headers)
    seers
        36
    seers  
       2022-09-30 14:29:04 +08:00
    @biuyixia 不严谨简单的说,在 Linux 里面发起一个 HTTP 请求等同于打开一个文件(一切皆文件,Unix 哲学),系统打开文件数是有上限的,由 ulimit 查看修改,如果限制数太低,后面发起的连接就会进入队列,然后进入队列的请求会超时报错,当然这只是猜测,还需要你多分析。
    biuyixia
        37
    biuyixia  
    OP
       2022-10-08 15:25:27 +08:00
    @seers 谢谢大佬。我这个 windows
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5446 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 40ms UTC 07:57 PVG 15:57 LAX 00:57 JFK 03:57
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86