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

推荐 Java http 发包框架

  •  
  •   loyan666 · 2023-09-05 22:55:49 +08:00 · 3639 次点击
    这是一个创建于 426 天前的主题,其中的信息可能已经有所发展或是发生改变。
    佬,java 有没有符合以下需求的 http 发包框架,
    1 不要有连接池管理(不要用线程池发包,直接用调用线程发包)。
    [有这个需求原因,是因为:爬虫每一个请求都要单独设置一个 Socks5 代理,目前用的 okhttp ,设置了共享连接池和最大 dispatch ,任然有很奇怪的问题,哪怕是小小 300 并发请求,都会出现大量超时、connect reset 、以及其他奇奇怪怪错误,导致成功发包率很低,300 包基本只有 50%能发出去,其他都是各种原因失败]
    2 支持 http2.0 。
    3 可以设置 socks5 、http 代理。
    39 条回复    2023-09-08 22:06:04 +08:00
    cnhongwei
        1
    cnhongwei  
       2023-09-05 23:36:42 +08:00
    用 spring boot 3.0 自带的 WebClient 试试,这个是 reactive 的,理论上吞吐量应比连接池好一些。
    loyan666
        2
    loyan666  
    OP
       2023-09-05 23:40:48 +08:00
    @cnhongwei 感谢大佬深夜指点~~
    刚了解了下,WebClient 依然内嵌线程池,不太适合爬虫需求......
    爬虫是一个请求一个代理,他的线程池和通道复用,只是累赘......
    Huelse
        3
    Huelse  
       2023-09-05 23:51:19 +08:00
    iseki
        4
    iseki  
       2023-09-05 23:52:37 +08:00
    socks 代理和线程池有什么关系
    iseki
        5
    iseki  
       2023-09-05 23:52:53 +08:00
    哦,连接池啊
    selca
        6
    selca  
       2023-09-06 00:14:23 +08:00
    netty 或者 async-http-client
    这俩应该都支持这些
    loyan666
        7
    loyan666  
    OP
       2023-09-06 00:20:49 +08:00
    @Huelse 非常感谢佬佬推荐。
    大概了解了下,这东西似乎是完全异步方式,
    因为要暴露接口供其他应用调用,得使用同步 http 框架,响应式不太满足需求...........
    loyan666
        8
    loyan666  
    OP
       2023-09-06 00:21:14 +08:00
    @iseki 是滴是滴,我表述有问题........
    loyan666
        9
    loyan666  
    OP
       2023-09-06 00:22:56 +08:00
    @selca netty 底层支持灵活是灵活,就是有点难用,啊哈哈。
    感谢佬佬推荐,netty 作为最后底线方案..........
    kuituosi
        10
    kuituosi  
       2023-09-06 00:25:47 +08:00
    自己写一个完全没有难度啊·,op 如果出得起价格资深架构师可以提供优质服务
    loyan666
        11
    loyan666  
    OP
       2023-09-06 00:28:09 +08:00
    @kuituosi 对于我有难度.......嘤嘤嘤..........还是找现成轮子好些
    selca
        12
    selca  
       2023-09-06 00:43:47 +08:00
    @loyan666 #9 实际上也没那么难用,eventloop 一启动,开 channel 就完事
    bringyou
        13
    bringyou  
       2023-09-06 03:19:09 +08:00
    可以试试 Java11 自带的全新 HttpClient
    timethinker
        14
    timethinker  
       2023-09-06 04:45:53 +08:00   ❤️ 1
    你每一次请求都是创建一个新的 TCP 链接,链接之间也不是复用的,哪里来的“连接池”的说法呢,使用线程池只是为了减少频繁创建/销毁产生开销,所以使用线程池没有冲突呀。

    这里也不存在某一个链接绑定到某一个线程环境(比如你说的 socks5 代理),下一个链接用这个线程就会有问题的说法吧,这里的 socks5 应该是绑定到每一个请求上面去的,而不是线程上面。
    chendy
        15
    chendy  
       2023-09-06 07:44:56 +08:00
    http 客户端哪来的连接池,最多 keep alive 一下吧
    其他包不熟悉,http client 的请求完事之后可以 close 掉,按说是直接关闭连接了
    其他包应该也有相关的配置
    letitbesqzr
        16
    letitbesqzr  
       2023-09-06 08:26:56 +08:00
    @chendy #15 okhttp 默认配置下,的确会使用连接池
    fzdwx
        17
    fzdwx  
       2023-09-06 08:53:12 +08:00
    `哪怕是小小 300 并发请求,都会出现大量超时、connect reset 、以及其他奇奇怪怪错误,导致成功发包率很低`

    那你这有没有想过是对方服务器的问题?
    monkeyWie
        18
    monkeyWie  
       2023-09-06 09:04:41 +08:00
    建议直接用 go
    kingfalse
        19
    kingfalse  
       2023-09-06 09:15:12 +08:00 via Android
    jsoup ,请求解析一条龙,我也是爬虫。
    Goooooos
        20
    Goooooos  
       2023-09-06 09:21:21 +08:00
    第一个问题没看出来跟连接池有什么关系
    joyhub2140
        21
    joyhub2140  
       2023-09-06 09:47:31 +08:00
    @Goooooos 楼主的情况反而更需要连接池控制并发,连接池是为了合理利用系统的线程资源,避免巨量的并发请求而设计的,不要连接池无节制地发起请求,服务器那段处理不过来反而更容易出现连接超时,连接 reset 这种问题。
    kanepan19
        22
    kanepan19  
       2023-09-06 10:29:06 +08:00
    apache HttpClient 你可以不用那个池, 用了那个池就会,就可能会走长连接,如果是同一个 client 就会公用 cookie 确实会出现楼主说的奇怪的问题。
    babyrjw
        23
    babyrjw  
       2023-09-06 10:35:21 +08:00
    楼主请求经过 IP 池代理之后到达目标网站,请求大量失败可能其实是 1 、IP 池的质量问题,本身就有部分 IP 是不可用的; 2 、IP 池服务商并发数限制,300/s 的并发怕是要加不少钱才会给你开这么大
    直接用隧道 IP 呗,每个请求出口自动切换 IP
    lysS
        24
    lysS  
       2023-09-06 10:44:02 +08:00
    估计是你的爬虫的代理 IP 有问题,任何语言都能轻易地处理 300 个普通连接
    loyan666
        25
    loyan666  
    OP
       2023-09-06 11:03:18 +08:00 via Android
    @fzdwx 可能有原因,但是自己这肯定有更大原因。
    因为进行过如下测试,都是 100 并发测试,
    使用 3 家 ip 代理测试并发,都会出现 rest 、peer terminal 、ssl incorrect 这类错误,频率很高。
    然后又切换那种完全买流量的机场 vpn(也就是无设备数、流量限制),然后 v2ray 开启 s5 端口,依然会有类似问题。
    loyan666
        26
    loyan666  
    OP
       2023-09-06 11:06:33 +08:00 via Android
    @monkeyWie 切不了了.....整个项目迁移成本无法承受,只能以后项目用 go 了....
    loyan666
        27
    loyan666  
    OP
       2023-09-06 11:08:11 +08:00 via Android
    @joyhub2140 实际上不最好不用连接池,因为用的短效 ip ,一个请求就是一个新 ip ,旧的链接通道根本不会用,不快速断开释放,只会增加拥堵.......
    loyan666
        28
    loyan666  
    OP
       2023-09-06 11:09:06 +08:00 via Android
    @lysS ip 有一定的锅,但是自己程序问题更大.......
    loyan666
        29
    loyan666  
    OP
       2023-09-06 11:11:45 +08:00 via Android
    @kanepan19 正在尝试 apache httpclient5 ,似乎大概也许满足需求......就是有点奇怪的是,他 httpclients 不能设置 http2 ,httpAsyncClient 默认就是 http ,但是 httpAsyncClient 又默认使用线程池发包........
    还在研究中.....
    loyan666
        30
    loyan666  
    OP
       2023-09-06 11:13:48 +08:00 via Android
    @babyrjw 确实如佬所说,ip 质量层次不起有一定原因,
    但是用 vpn 开启本地 s5(那种耗流量的机场,不限制台数流量的)去做 100 并发请求,尽然也会出现不少错误。
    程序本身还是有问题需要优化优化
    kanepan19
        31
    kanepan19  
       2023-09-06 11:42:51 +08:00
    @loyan666
    我们之前的业务高度依赖 httpclient ,功能和稳定应该是最强的。 只不过没 okhttp 方便好用。
    loyan666
        32
    loyan666  
    OP
       2023-09-06 12:05:07 +08:00
    @kanepan19 方便都是次要的,最主要还是稳定可靠.............毕竟谁不想早点睡,舒服摸鱼.........
    aqua02
        33
    aqua02  
       2023-09-06 14:22:50 +08:00 via Android
    即便复用了 http 连接也要注意线程池的线程数量,
    因为 http 都是在框架的线程池的基础上进行请求,所以并发的本质就是控制线程数,设置在 6w 的线程数就好,这样可控,避免意外


    连接池其实并不是特别需要,可以关掉某些框架的连接池限制。就是缓存同一个 host 的 http1.1 连接的那个东东。
    oldshensheep
        34
    oldshensheep  
       2023-09-06 18:39:43 +08:00
    > 因为进行过如下测试,都是 100 并发测试,
    使用 3 家 ip 代理测试并发,都会出现 rest 、peer terminal 、ssl incorrect 这类错误,频率很高。
    然后又切换那种完全买流量的机场 vpn(也就是无设备数、流量限制),然后 v2ray 开启 s5 端口,依然会有类似问题。

    连接失败为什么是工具的问题?建议你用 Go 或者 Python 写一个类似的逻辑再来测试,肯定不是 Java 的问题。
    才 100 并发就处处报错,是代码的问题别人早就发现了。
    xinJang
        35
    xinJang  
       2023-09-06 19:21:07 +08:00
    我用 okhttp 爬的 并發還可以
    ikas
        36
    ikas  
       2023-09-06 20:40:17 +08:00
    直接用最新的 jdk,然后使用内置的 httpclient,配置一个虚拟线程池,就可以了
    ikas
        37
    ikas  
       2023-09-06 20:51:22 +08:00
    var client = HttpClient.newBuilder()
    .version(HttpClient.Version.HTTP_2)
    .followRedirects(HttpClient.Redirect.NORMAL)
    .connectTimeout(Duration.ofSeconds(5))
    .proxy(ProxySelector.of(new InetSocketAddress("127.0.0.1", 10800)))
    .executor(Executors.newVirtualThreadPerTaskExecutor())
    .build();

    var request = HttpRequest.newBuilder()
    .uri(URI.create("https://www.baidu.com/"))
    .timeout(Duration.ofMinutes(2))
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{}"))
    .build();

    client.sendAsync(request, HttpResponse.BodyHandlers.ofString()).thenAccept(System.out::println);
    loyan666
        38
    loyan666  
    OP
       2023-09-08 22:00:17 +08:00
    @ikas 感谢佬佬精心案例
    loyan666
        39
    loyan666  
    OP
       2023-09-08 22:06:04 +08:00
    @oldshensheep 现在又回退 okhttp 了,折腾一圈下来还是 okhttp 比较全面好用....................确实昨天也用 C#写了个对照,报错率差不多,
    是 ip 、vpn ( vpn 本地代理)有问题.....................
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4599 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 05:35 · PVG 13:35 · LAX 21:35 · JFK 00:35
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.