Ставка Ограничение) — техническое средство контроля частоты доступа к определенным ресурсам. В службах с высоким уровнем параллелизма текущий механизм ограничения может эффективно предотвратить перегрузку ресурсов и сбой службы, а также обеспечить стабильность и доступность системы. Голанг Официальная стандартная библиотека golang.org/x/time/rate
Обеспечивает эффективный и простой в использовании ограничитель тока (скорость Limiter), который может помочь разработчикам легко реализовать функцию ограничения тока. В этой статье будет подробно представлено Golang Как использовать официальный ограничитель тока и принципы, лежащие в его основе.
Прежде чем более подробно рассказать об использовании, давайте поймем несколько основных понятий:
Golang Официальный ограничитель тока реализует алгоритм ведра токенов и находится по адресу golang.org/x/time/rate
В сумке. Сначала установите пакеты зависимостей:
go get golang.org/x/time/rate
использовать rate.NewLimiter
Чтобы создать ограничитель скорости, вам необходимо передать два параметра: скорость (количество токенов, генерируемых в секунду) и емкость (размер хранилища токенов).
package main
import (
"fmt"
"golang.org/x/time/rate"
"time"
)
func main() {
// В секунду генерируется 5 токенов, а емкость ведра составляет 10 токенов.
limiter := rate.NewLimiter(5, 10)
fmt.Println("Limiter created with rate 5 tokens per second and burst size of 10")
}
Создать ограничитель токаназад,может пройти Allow
、Reserve
、Wait
ждатьметодзапросить разрешение。
Allow
Метод немедленно возвращает логическое значение, указывающее, разрешен ли запрос.
if limiter.Allow() {
fmt.Println("Request allowed")
} else {
fmt.Println("Request denied")
}
Reserve
Метод возвращает Reservation
Объект, содержащий информацию о времени и доступности лицензии.
reservation := limiter.Reserve()
if reservation.OK() {
fmt.Println("Request reserved, delay:", reservation.Delay())
} else {
fmt.Println("Request cannot be reserved")
}
Wait
Метод блокирует текущую сопрограмму до тех пор, пока запрос не будет разрешен или контекст не будет отменен.
ctx := context.Background()
if err := limiter.Wait(ctx); err == nil {
fmt.Println("Request allowed after wait")
} else {
fmt.Println("Request denied:", err)
}
Предположим, у нас есть функция обработки запросов API, которую необходимо регулировать, обрабатывая до 5 запросов в секунду и разрешая пакеты по 10 запросов.
package main
import (
"fmt"
"golang.org/x/time/rate"
"net/http"
"time"
)
var limiter = rate.NewLimiter(5, 10)
func handler(w http.ResponseWriter, r *http.Request) {
if limiter.Allow() {
fmt.Fprintln(w, "Request allowed")
} else {
http.Error(w, "Too Many Requests", http.StatusTooManyRequests)
}
}
func main() {
http.HandleFunc("/", handler)
fmt.Println("Server started at :8080")
http.ListenAndServe(":8080", nil)
}
В дополнение к базовой функции ограничения тока, официальный ограничитель тока Golang также предоставляет множество расширенных функций, которые помогают разработчикам более гибко контролировать поведение ограничения тока.
может пройти SetLimit
и SetBurst
метод динамически регулирует скорость и мощность ограничителя тока.
limiter.SetLimit(10)
limiter.SetBurst(20)
Для разных типов ресурсов можно установить отдельные ограничители скорости. Например, мы можем установить разные ограничители тока для операций чтения и записи.
var readLimiter = rate.NewLimiter(10, 20)
var writeLimiter = rate.NewLimiter(5, 10)
func readHandler(w http.ResponseWriter, r *http.Request) {
if readLimiter.Allow() {
fmt.Fprintln(w, "Read request allowed")
} else {
http.Error(w, "Too Many Requests", http.StatusTooManyRequests)
}
}
func writeHandler(w http.ResponseWriter, r *http.Request) {
if writeLimiter.Allow() {
fmt.Fprintln(w, "Write request allowed")
} else {
http.Error(w, "Too Many Requests", http.StatusTooManyRequests)
}
}
func main() {
http.HandleFunc("/read", readHandler)
http.HandleFunc("/write", writeHandler)
fmt.Println("Server started at :8080")
http.ListenAndServe(":8080", nil)
}
Передавая объект контекста, можно реализовать управление или отмену тайм-аута во время текущего процесса ограничения.
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
if err := limiter.Wait(ctx); err != nil {
fmt.Println("Request denied:", err)
} else {
fmt.Println("Request allowed")
}
Reserve
метод возвращает Reservation
Объект содержит определенное время ожидания, а логику обработки можно настроить в соответствии с потребностями бизнеса.
reservation := limiter.Reserve()
if reservation.OK() {
waitTime := reservation.Delay()
time.Sleep(waitTime)
fmt.Println("Request processed after waiting:", waitTime)
} else {
fmt.Println("Request denied")
}
Можно запросить несколько токенов одновременно, что полезно при обработке пакетных операций.
if limiter.AllowN(time.Now(), 3) {
fmt.Println("Batch request allowed")
} else {
fmt.Println("Batch request denied")
}
Когда использовать ограничитель тока,Необходимо учитывать накладные расходы на производительность。rate.Limiter
легкий,Но в сценариях с высоким параллелизмом,Частые запросы и выпуски токенов могут привести к определенным затратам производительности. Вот несколько предложений по оптимизации:
Golang Официальный ограничитель тока — это мощный инструмент для эффективного ограничения тока. Он прост и удобен в использовании. API Мощные функции помогают разработчикам легко реализовывать различные стратегии ограничения тока. В этой статье подробно описаны базовый метод использования, расширенные функции и оптимизация. производительностипредположение,Надеюсь, что это может предоставить ценную информацию для читателей. в реальных проектах,Конкретную конфигурацию ограничителя тока необходимо разумно настроить в соответствии с потребностями бизнеса.,для достижения наилучших результатов.