golang實現限制每秒多少次的限頻操作

前言

一些函數的執行可能會限制頻率,比如某個api接口要求每秒最大請求30次。下面記錄了自己寫的限頻和官方的限頻

代碼

// 加鎖限頻,輸出次數大概率小於最大值
func ExecLimit(lastExecTime *time.Time, l *sync.RWMutex ,maxTimes int, perDuration time.Duration, f func()) {
    l.Lock()
    defer l.Unlock()
	// per times cost time(s)
	SecondsPerTimes := float64(perDuration) / float64(time.Second) / float64(maxTimes)

	now := time.Now()
	interval := now.Sub(*lastExecTime).Seconds()
	if interval < SecondsPerTimes {
		time.Sleep(time.Duration(int64((SecondsPerTimes-interval)*1000000000)) * time.Nanosecond)
	}
	f()
	*lastExecTime = time.Now()
}

// 官方的,需要引用	"golang.org/x/time/rate"
// 基本上可以達到滿值,比自己寫的更優
func ExecLimit2(l *rate.Limiter, f func()) {
	go func() {
		l.Wait(context.Background())
		f()
	}()
}

使用

func TestExecLimit(t *testing.T) {
	runtime.GOMAXPROCS(runtime.NumCPU())
	go func() {
		var lastExecTime time.Time
		var l sync.RWMutex
		for {
			ExecLimit(&lastExecTime, &l, 10, time.Second, func() {
				fmt.Println("do")
			})
		}
	}()

	select {
	case <-time.After(1 * time.Second):
		fmt.Println("1秒到時")
	}
}

func TestExecLimit2(t *testing.T) {
	runtime.GOMAXPROCS(runtime.NumCPU())

	l := rate.NewLimiter(1, 30)

	go func() {
		for {
            ExecLimit2(l, func() {
				fmt.Println("do")
			})
		}
	}()

	select {
	case <-time.After(1 * time.Second):
		fmt.Println("1秒到時")
	}
}

輸出:

一秒內輸出了<=10次 "do"

如何在多節點服務中限制頻

上述使用,定義在某個服務節點的全局變量lastExecTime僅僅會對該服務的函數f()操作限頻,如果在負載均衡後,多個相同服務的節點,對第三方的接口累計限頻,比如三個服務共同拉取第三方接口,合計限頻爲30次/s.
則,必須將lastExecTime的獲取,從redis等共享中間件中獲取,而不應該從任何一個單點服務獲取。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章