如何设计goroutines程序来处理API限制错误

huangapple go评论106阅读模式
英文:

How to design goroutines program to handle api limit error

问题

刚开始学习关于goroutines的强大之处。

我有大约100个账户和10个地区,通过循环遍历它们,使用golang创建大约1000个goroutines来增加读取速度。它运行得太快了,以至于达到了每秒20次的API返回限制。

我该如何确保所有的goroutines都能以最大的调用速率(20/s)维持?我不确定哪种golang并发方法最适合一起处理错误。

例如:

  1. func readInstance(acc string, region string, wg *sync.WaitGroup) {
  2. defer wg.Done()
  3. response, err := client.DescribeInstances(acc, region)
  4. if err != nil {
  5. log.Println(err) // API limit exceeding 20
  6. return
  7. }
  8. .
  9. .
  10. .
  11. .
  12. }
  13. func main() {
  14. accounts := []string{"g", "h", "i", ...}
  15. regions := []string{"g", "h", "i", ...}
  16. for _, region := range regions {
  17. for i := 0; i < len(accounts); i++ {
  18. wg.Add(1)
  19. go readInstance(accounts[i], region, &wg)
  20. }
  21. }
  22. wg.Wait()
  23. }
英文:

Just started learning about the power of goroutines.

I have ~100 accounts and ~10 regions, looping through them to create ~ 1000 goroutines with golang to increase the reading speed. It worked too fast that it hit the API return limit of 20/ sec.

How do I ensure that all the goroutines can maintain at the maximum call rate of (20/s)? Im unsure of which golang concurrency methods works best together to handle the error.

eg:

  1. func readInstance(acc string, region string, wg *sync.WaitGroup) {
  2. defer wg.Done()
  3. response, err := client.DescribeInstances(acc, region)
  4. if err != nil {
  5. log.Println(err) // API limit exceeding 20
  6. return
  7. }
  8. .
  9. .
  10. .
  11. .
  12. }
  13. func main() {
  14. accounts := []string{&quot;g&quot;, &quot;h&quot;, &quot;i&quot;, ...}
  15. regions := []string{&quot;g&quot;, &quot;h&quot;, &quot;i&quot;, ...}
  16. for _, region := range regions {
  17. for i := 0; i &lt; len(accounts); i++ {
  18. wg.Add(1)
  19. go readInstance(accounts[i], region, &amp;wg)
  20. }
  21. }
  22. wg.Wait()
  23. }

答案1

得分: 3

如果您对在特定实际时间内可以进行的请求数量有一个固定的上限,您可以使用time.NewTicker()来间隔请求。

  1. c := time.NewTicker(50 * time.Millisecond)
  2. defer c.Stop()

现在,当您想要进行服务器请求时,只需在实际请求之前插入

  1. <- c.C

即可。

英文:

If you have a fixed upper limit on how many requests you can do in a particular amount of real time, you can use a time.NewTicker() to space things out.

  1. c := time.NewTicker(50 * time.Millisecond)
  2. defer c.Stop()

Now, when you want to make a server request, just insert

  1. &lt;- c.C

prior to the actual request.

答案2

得分: 0

我认为你可以尝试使用这个:https://github.com/uber-go/ratelimit

根据文档,它是并发安全的。

  1. import (
  2. "fmt"
  3. "time"
  4. "go.uber.org/ratelimit"
  5. )
  6. func main() {
  7. rl := ratelimit.New(100) // 每秒限制100个请求
  8. prev := time.Now()
  9. for i := 0; i < 10; i++ {
  10. now := rl.Take()
  11. fmt.Println(i, now.Sub(prev))
  12. prev = now
  13. }
  14. // 输出:
  15. // 0 0
  16. // 1 10ms
  17. // 2 10ms
  18. // 3 10ms
  19. // 4 10ms
  20. // 5 10ms
  21. // 6 10ms
  22. // 7 10ms
  23. // 8 10ms
  24. // 9 10ms
  25. }
英文:

i think you can try this: https://github.com/uber-go/ratelimit

According to the documentation, it is concurrency safe.

  1. import (
  2. &quot;fmt&quot;
  3. &quot;time&quot;
  4. &quot;go.uber.org/ratelimit&quot;
  5. )
  6. func main() {
  7. rl := ratelimit.New(100) // per second
  8. prev := time.Now()
  9. for i := 0; i &lt; 10; i++ {
  10. now := rl.Take()
  11. fmt.Println(i, now.Sub(prev))
  12. prev = now
  13. }
  14. // Output:
  15. // 0 0
  16. // 1 10ms
  17. // 2 10ms
  18. // 3 10ms
  19. // 4 10ms
  20. // 5 10ms
  21. // 6 10ms
  22. // 7 10ms
  23. // 8 10ms
  24. // 9 10ms
  25. }

huangapple
  • 本文由 发表于 2021年10月11日 12:34:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/69521082.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定