最佳方法〜每秒1000 http.Get

时间:2016-06-02 17:31:07

标签: http go concurrency

我目前正在使用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以上,以处理所有这些打开的连接。

非常感谢任何提示或建议!

1 个答案:

答案 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)当你想要停止时。