golang实现高效定时速率限制功能插件库go-rate的使用

go-rate - Golang高效定时速率限制功能插件库

go-rate是一个专为多种使用场景设计的速率限制器,包括服务器端垃圾信息防护和防止API调用过载等。

使用说明

导入github.com/beefsack/go-rate并使用rate.New(limit int, interval time.Duration)函数创建一个新的速率限制器。

速率限制器提供Wait()Try() (bool, time.Duration)方法,分别用于阻塞和非阻塞功能。

示例代码

阻塞式速率限制

这个示例演示如何将输出速率限制为每秒3次。

package main

import (
	"fmt"
	"time"

	"github.com/beefsack/go-rate"
)

func main() {
	rl := rate.New(3, time.Second) // 3 times per second
	begin := time.Now()
	for i := 1; i <= 10; i++ {
		rl.Wait()
		fmt.Printf("%d started at %s\n", i, time.Now().Sub(begin))
	}
	// Output:
	// 1 started at 12.584us
	// 2 started at 40.13us
	// 3 started at 44.92us
	// 4 started at 1.000125362s
	// 5 started at 1.000143066s
	// 6 started at 1.000144707s
	// 7 started at 2.000224641s
	// 8 started at 2.000240751s
	// 9 started at 2.00024244s
	// 10 started at 3.000314332s
}

多限制器组合的阻塞式速率限制

这个示例演示如何组合两个速率限制器,一个限制每秒1次,另一个限制每3秒2次。

package main

import (
	"fmt"
	"time"

	"github.com/beefsack/go-rate"
)

func main() {
	begin := time.Now()
	rl1 := rate.New(1, time.Second)   // Once per second
	rl2 := rate.New(2, time.Second*3) // 2 times per 3 seconds
	for i := 1; i <= 10; i++ {
		rl1.Wait()
		rl2.Wait()
		fmt.Printf("%d started at %s\n", i, time.Now().Sub(begin))
	}
	// Output:
	// 1 started at 11.197us
	// 2 started at 1.00011941s
	// 3 started at 3.000105858s
	// 4 started at 4.000210639s
	// 5 started at 6.000189578s
	// 6 started at 7.000289992s
	// 7 started at 9.000289942s
	// 8 started at 10.00038286s
	// 9 started at 12.000386821s
	// 10 started at 13.000465465s
}

非阻塞式速率限制

这个示例演示非阻塞速率限制,例如可用于限制聊天客户端中的垃圾信息。

package main

import (
	"fmt"
	"time"

	"github.com/beefsack/go-rate"
)

var rl = rate.New(3, time.Second) // 3 times per second

func say(message string) {
	if ok, remaining := rl.Try(); ok {
		fmt.Printf("You said: %s\n", message)
	} else {
		fmt.Printf("Spam filter triggered, please wait %s\n", remaining)
	}
}

func main() {
	for i := 1; i <= 5; i++ {
		say(fmt.Sprintf("Message %d", i))
	}
	time.Sleep(time.Second / 2)
	say("I waited half a second, is that enough?")
	time.Sleep(time.Second / 2)
	say("Okay, I waited a second.")
	// Output:
	// You said: Message 1
	// You said: Message 2
	// You said: Message 3
	// Spam filter triggered, please wait 999.980816ms
	// Spam filter triggered, please wait 999.976704ms
	// Spam filter triggered, please wait 499.844795ms
	// You said: Okay, I waited a second.
}

作者

  • Michael Alexander
  • Geert-Johan Riemer
  • Matt T. Proud

更多关于golang实现高效定时速率限制功能插件库go-rate的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang实现高效定时速率限制功能插件库go-rate的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang高效定时速率限制库go-rate使用指南

go-rate是一个高效的Golang速率限制库,它提供了灵活的速率限制功能,可以帮助开发者控制API调用、数据库访问等操作的频率。

安装

go get github.com/beefsack/go-rate

基本使用

1. 简单的速率限制

package main

import (
	"fmt"
	"time"
	
	"github.com/beefsack/go-rate"
)

func main() {
	// 创建一个限制器:每秒最多5次操作
	rl := rate.New(5, time.Second)
	
	for i := 0; i < 10; i++ {
		// Try()尝试获取令牌,返回是否成功和需要等待的时间
		ok, remaining := rl.Try()
		if !ok {
			fmt.Printf("请求 %d 被限流,需要等待 %v\n", i, remaining)
			time.Sleep(remaining)
			continue
		}
		fmt.Printf("请求 %d 通过\n", i)
	}
}

2. 使用Wait()方法

func main() {
	rl := rate.New(2, time.Second) // 每秒2次
	
	for i := 0; i < 5; i++ {
		// Wait()会阻塞直到可以执行
		rl.Wait()
		fmt.Printf("执行操作 %d 在 %v\n", i, time.Now().Format("15:04:05.000"))
	}
}

高级功能

1. 突发限制

func main() {
	// 允许突发3个请求,然后限制为每秒1个
	rl := rate.New(1, time.Second)
	rl.SetBurst(3)
	
	for i := 0; i < 5; i++ {
		ok, _ := rl.Try()
		if ok {
			fmt.Printf("请求 %d 通过\n", i)
		} else {
			fmt.Printf("请求 %d 被限流\n", i)
			time.Sleep(time.Second)
		}
	}
}

2. 动态调整速率

func main() {
	rl := rate.New(10, time.Minute) // 每分钟10次
	
	// 动态调整速率
	rl.SetRate(20, time.Minute) // 调整为每分钟20次
	
	// 检查当前速率
	rate, interval := rl.Rate()
	fmt.Printf("当前速率: %d 次每 %v\n", rate, interval)
}

实际应用示例

API调用限流

package main

import (
	"fmt"
	"net/http"
	"time"
	
	"github.com/beefsack/go-rate"
)

var apiRateLimiter = rate.New(100, time.Minute) // 每分钟100次API调用

func makeAPICall(url string) (*http.Response, error) {
	// 等待直到可以执行
	apiRateLimiter.Wait()
	
	resp, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	
	return resp, nil
}

func main() {
	urls := []string{
		"https://api.example.com/endpoint1",
		"https://api.example.com/endpoint2",
		// 更多URL...
	}
	
	for _, url := range urls {
		resp, err := makeAPICall(url)
		if err != nil {
			fmt.Printf("调用 %s 失败: %v\n", url, err)
			continue
		}
		fmt.Printf("调用 %s 成功,状态码: %d\n", url, resp.StatusCode)
		resp.Body.Close()
	}
}

数据库操作限流

package main

import (
	"database/sql"
	"fmt"
	"time"
	
	_ "github.com/lib/pq"
	"github.com/beefsack/go-rate"
)

var dbRateLimiter = rate.New(50, time.Second) // 每秒最多50次数据库操作

func queryDB(db *sql.DB, query string) (*sql.Rows, error) {
	dbRateLimiter.Wait()
	return db.Query(query)
}

func main() {
	db, err := sql.Open("postgres", "user=postgres dbname=test sslmode=disable")
	if err != nil {
		panic(err)
	}
	defer db.Close()
	
	queries := []string{
		"SELECT * FROM users",
		"SELECT * FROM orders",
		// 更多查询...
	}
	
	for _, q := range queries {
		rows, err := queryDB(db, q)
		if err != nil {
			fmt.Printf("查询失败: %v\n", err)
			continue
		}
		defer rows.Close()
		fmt.Printf("查询成功: %s\n", q)
	}
}

性能考虑

go-rate在设计上考虑了高性能:

  1. 使用原子操作而非锁,减少竞争
  2. 内存占用小
  3. 无外部依赖

对于大多数应用场景,go-rate的性能开销可以忽略不计。

与其他库的比较

相比golang.org/x/time/rate:

  • go-rate API更简单
  • 提供了Try()方法可以立即知道是否被限流
  • 支持动态调整速率

相比uber-go/ratelimit:

  • go-rate支持更灵活的速率设置
  • 提供了突发限制功能

go-rate是一个轻量级但功能完整的速率限制库,适合大多数Golang应用的限流需求。

回到顶部