1.场景描述
现有基础数据 13w 条,需循环通过第三方 HTTP 接口获取历史数据进行分析统计,意味着要发生 13w 次 HTTP 请求。接口请求速度还比较慢,平均每次请求需要 1s,如果在单线程的情况下至少需要 36 个小时,目前我设计的是使用多线程每 3w 条作为一个任务进行请求,目前的消耗时间大概能减少到 16 小时左右,但效率还是太低了,有没有大佬有更好的解决方案的?求 Help!!
2.部署环境
系统:CentOS7
配置:单 CPU 双核
1
gaius 2019-04-19 11:04:25 +08:00
1s 是网络问题还是对方处理的比较慢?
|
4
2kCS5c0b0ITXE5k2 2019-04-19 11:16:59 +08:00 via iPhone
@EdwardLee 感觉没啥办法。。1s 太慢了
|
5
peyppicp 2019-04-19 11:18:47 +08:00
ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor(100, 200,
10, TimeUnit.MINUTES, new ArrayBlockingQueue<>(100), new NamedThreadFactory("trade-thread-", true), new ThreadPoolExecutor.CallerRunsPolicy()); 然后你主线程 for 循环提交 runnable 或者 callable 任务就完事了。200 条线程应该可以了 |
7
orangeade 2019-04-19 11:23:58 +08:00 via Android 1
换 golang 然后无脑开 goroutine ?
|
8
EdwardLee OP @peyppicp 200 个线程会不会出问题啊?我试试。多线程不太会用,我是参照网上说的 IO 密集型任务应设置线程数为核心数的两倍,HTTP 请求应该属于网络 IO 吧。
|
10
xuwenping 2019-04-19 11:33:05 +08:00 via Android
对方能不能也使用多线程?
|
11
HuHui 2019-04-19 11:33:25 +08:00 via Android
让对方提供批量查询接口
|
12
peyppicp 2019-04-19 11:42:04 +08:00 1
|
14
honeycomb 2019-04-19 11:47:23 +08:00 via Android
@EdwardLee 楼主遇到的情况是每个线程大部分时间在等回复,这个意义上再多开一些(三五百个)也成。
|
15
gz911122 2019-04-19 11:52:58 +08:00
用 netty 异步回调
这种性能主要是卡在网络 io 的情况下用异步再合适不过了 |
17
feiyuanqiu 2019-04-19 11:56:36 +08:00 via Android
对方一个请求都能处理一秒,开几百个线程的不一下把人家服务器打死?
问问看能不能提供批量查询接口吧,估计没戏 |
18
az422 2019-04-19 12:13:45 +08:00 via Android
异步 httpclient,如 Apache 那个 httpasync 或者 vertx.client (多个实例),并设置 keepalive (双方)
当然还是批量接口靠谱 |
19
EdwardLee OP |
21
rrfeng 2019-04-19 12:30:11 +08:00 via Android
你算一下对方最多能提供每秒几个
然后就写自己的并发量 取决于对方而不是自己 |
24
lhx2008 2019-04-19 12:51:03 +08:00 via Android
异步可以一下打 13 万条请求出去,对方回数据,操作系统会自动保存,然后程序可以慢慢拿返回结果。但是对方的服务器是妥妥的挂了。。
所以先压测一下,看看同时打多少条出去 |
25
MoHen9 2019-04-19 13:00:05 +08:00 via Android
数据量有多大,返回怎么那么慢?还有为什么不能自定义获取条数?
|
26
CoSpLi 2019-04-19 13:12:37 +08:00 via iPhone
对接的蛋疼事儿,并发量只能看对方接口了。。之前也碰到过,并发请求多了被对方拉黑了。。。
|
27
az422 2019-04-19 13:18:33 +08:00
@EdwardLee 是取决于对方承受能力,但跟多线程本质不同,多线程本质会阻塞的,异步不会,在对方承受能力下能增大你这边的吞吐量。
`我设计的是使用多线程每 3w 条作为一个任务进行请求,目前的消耗时间大概能减少到 16 小时左右` 像你这样设计,在对方 1s 内没有返回内你的线程是被阻塞不能干其他事的,完全浪费了性能。130000/(16*3600)约 2.25 ,相当于你 1s 才 3 个请求?要是对方能力真这样当我没说。。。 假设对方最大 qps=10000, 你可以开 10000 线程, (但是你单 CPU 双核 = =), 这种情况下还是用异步 IO 能压榨对方性能 |
28
misaka19000 2019-04-19 13:22:45 +08:00 via Android
异步操作
|
29
33and66 2019-04-19 13:58:08 +08:00
这种数据 建议生成 txt 文件 然后通过文件内容建议直接做
方法很土 但是很实用 我们现在和银行每天上千万的数据对账就是这么干 |
30
liujan 2019-04-19 15:37:55 +08:00
如果是对方数据加工处理比较慢的话,是不是可以先让他每天 定时离线处理好了数据,然后你再过去拉处理后的数据?
|
31
whp1473 2019-04-19 15:51:58 +08:00
每天根据你的数据定时获取对方数据,将获取的数据保存起来,用户查询时查自己库,然后缓存起来。
|
32
mritd 2019-04-19 15:57:14 +08:00 via iPhone
可能这个回答不对路,但是如果这种需要大并发处理的我真的会上 golang 写,因为这样基本不需要带脑子....
|
33
xdlucky 2019-04-19 15:57:40 +08:00
联系对方直接买数据
|
34
xzg 2019-04-19 17:44:51 +08:00
看你响应结果是否需要,不需要就搞异步多线程。如果需要响应结果那就只能等待 1s,尝试开启多线程,实在不行部署多个服务并行发
|
35
Yourshell 2019-04-19 20:39:07 +08:00
寄 U 盘吧
|
39
EdwardLee OP @az422 目前使用 30 个线程,处理时间已经减少到 3.5 小时,偶尔会有 HTTP 请求超时的情况出现。我再观察一下,感谢您的建议
|
40
EdwardLee OP @misaka19000 很多都是建议异步操作的,没怎么了解过,我试试看。感谢建议
|
41
EdwardLee OP @33and66 如果有现成的数据文件是可行,但是在第三方不改动的情况下,暂时也没有其他方式可以获取数据来源,还是得调接口请求
|
43
EdwardLee OP @whp1473 您建议的这种方式可能不太适合我这个场景,应该适合那种一次性响应数据量比较大的情况。目前接口并非因为响应数据量大而缓慢,所以即使定时获取也无法迈过多次 HTTP 请求这道坎,还是得想办法提高 IO 利用率
|
47
EdwardLee OP @xzg 业务场景是不需要实时响应的,异步应该是可行的。暂时不太了解异步,尝试了下多线程,效果还是很明显的,已经能够满足需求了。
|
48
EdwardLee OP 目前情况:
1. 单线程:耗时约 36 小时,请求稳定(效率极低) 2. 分批 3w 数据 /线程,共 5 个线程:耗时约 16 小时,请求较稳定 (效率略低) 3. 固定 30 个线程:耗时约 3.5 小时,偶有 HTTP 请求超时(效率已经能够满足,需解决部分超时异常) 4. 固定 100 个线程:测试过程因请求超时案例过多,暂不予考虑,所以未计耗时 总结: 我的业务场景属于网络 IO 密集型任务,时间基本都消耗在等待 HTTP 请求的响应,所以多线程请求还是效果很明显的,至于固定多少线程效率最高我无法确定,纯手工尝试😂,有科学测量方式的小伙伴麻烦指教一下。30 线程数已经能够满足业务需求,暂以项目交付为先,关于各位 V 友的建议比如异步请求之类的有空的时候再尝试。 在此感谢各位 V 友的不吝赐教 |