我目前正在使用api为我自己的处理收集数据而不是。目前我每秒做100个http.Get,我想知道每秒1000个并发http.Gets的最佳方法是什么。
这就是我现在所拥有的:
waitTime := time.Second
var lastID uint64 = 1234567890
for {
for i := 0; i < 100; i++ {
var tmpID uint64 = lastID
lastID++
go func(ID uint64) {
err = scrape(ID) // this does the http.Get and saves the
// resulting json into postgresql
if err != nil {
errStr := strings.TrimSpace(err.Error())
if strings.HasSuffix(errStr, "Too Many request to server") {
log.Println("hit a real 429")
panic(err)
}
}
}(tmpID)
}
time.Sleep(waitTime - time.Now().Sub(now)) // this is here to
// ensure I dont go over the limit
}
我打的api速率限制在1000 req / s。
我的go func(ID)
的原因是,我可以逐步增加我的ID,而不必担心使用锁访问&#34;下一个ID是什么&#34;。
我觉得我做错了。一般来说,我也很陌生。
我还假设我必须将我的ubuntu服务器上的ulimit
提升到1000以上,以处理所有这些打开的连接。
非常感谢任何提示或建议!
答案 0 :(得分:-1)
您的http客户端是否缓存连接?默认为。
默认情况下,Transport会缓存连接以供将来重复使用。访问许多主机时,这可能会留下许多开放的连接。可以使用Transport的CloseIdleConnections方法和MaxIdleConnsPerHost和DisableKeepAlives字段来管理此行为。
为什么你在一个循环中产生goroutine而不是在里面产生一些带有循环的gouroutines,如果你达到了它可以退回一下的限制。
原始示例(我没有测试它。可能包含拼写错误。)
numWorkers := 1000
var delay time.Duration = 0.01 //10 ms (iirc) =)
var maxDelay time.Duration = 0.1 //100 ms (i guess)
quit := make(chan struct{})
for i := 0; i < numWorkers ; i++ {
go func(ID, shift uint){
var iter := 0
var curDelay time.Duration = delay
for {
select {
case <-quit:
return
default:
//0th worker: lastID + 0 + 0, lastID + 100 + 0, lastID + 200 + 0, ...
//1st worker: lastID + 0 + 1, lastID + 100 + 1, lastID + 200 + 2, ...
//...
//99th worker: lastID + 0 + 99, lastID + 100 + 99, lastID + 100 + 299, ...
curID := ID + iter * numWorkers + shift
err = scrape(curID) // this does the http.Get and saves the
// resulting json into postgresql
if err != nil {
errStr := strings.TrimSpace(err.Error())
if strings.HasSuffix(errStr, "Too Many request to server") { log.Println("hit a real 429")
if curDelay > maxDelay {
return //or panic, whatever you want
}
time.Sleep(curDelay)
curdelay = curdelay * 2 //exponential delay: 10ms, 20ms, 40ms, 80ms, return/panic
continue //no increment on iter
}
}
//increment on success
iter++
time.Sleep(1) // 1000 workers, each make request and sleep for 1 sec, sounds like 1000 rpm
}
}
}(lastID, i)
}
ID永远不会重叠,但可能会有漏洞。但你不能避免没有同步(互斥是好的),并且可能你可以在1000rpm这样做,但性能将受到更大数量的工人的影响。
close(quit)
当你想要停止时。