Detailed explanation of usage of Golang official current limiter
The current limiter is a very important component to improve service stability. It can be used to limit the request rate and protect the service to avoid service overload. There are many ways to implement current limiters. Common current limiting algorithms include fixed window, sliding window, leaky bucket, and token bucket. I mentioned this in my previous article"Applications of Commonly Used Current Limiting Algorithms. Scenarios and Implementation Principles" explains the characteristics and application scenarios of these current limiting methods. Among them, token buckets can also cope with certain burst traffic while limiting current. Internet applications are prone to hot spots due to It is more suitable for the characteristics of sudden traffic peaks in events.
To put it simply, the token bucket is a bucket of a fixed size. The system will put tokens into the bucket at a constant rate. If the bucket is full, it will not be put temporarily. When there are relatively few requests, the bucket can "save" some tokens first to cope with sudden traffic. If there are remaining tokens in the bucket, it can be continuously withdrawn. If there are no tokens left, you need to wait until tokens are placed in the bucket.
For a more detailed explanation about token bucket current limiting, please refer to the article: Application Scenarios and Implementation Principles of Commonly Used Current Limiting Algorithms
Some students are reading this After understanding the principle of token bucket, I really want to implement a current limiter and apply it to my own project, em... How to put it, building a wheel is indeed helpful to improve my level, but if it is applied to commercial projects In fact, there is no need to build the wheel yourself, Golang has officially built the wheel for us...~!
The extension library officially provided by Golang comes with the implementation of the current limiting algorithm, namely golang.org/x/time/rate
. This current limiter is also implemented based on Token Bucket.
The internal structure of the current limiter
time/rate
Limiter
type pair of the package The current limiter is defined. All current limiting functions are implemented based on the Limiter
type. Its internal structure is as follows:
type Limiter struct { mu sync.Mutex limit Limit burst int // 令牌桶的大小 tokens float64 last time.Time // 上次更新tokens的时间 lastEvent time.Time // 上次发生限速器事件的时间(通过或者限制都是限速器事件) }
The functions of its main fields are:
limit: limit
字段表示往桶里放Token的速率,它的类型是Limit,是int64的类型别名。设置limit
时既可以用数字指定每秒向桶中放多少个Token,也可以指定向桶中放Token的时间间隔,其实指定了每秒放Token的个数后就能计算出放每个Token的时间间隔了。burst: 令牌桶的大小。 tokens: 桶中的令牌。 last: 上次往桶中放 Token 的时间。 lastEvent:上次发生限速器事件的时间(通过或者限制都是限速器事件)
可以看到在 timer/rate
的限流器实现中,并没有单独维护一个 Timer 和队列去真的每隔一段时间向桶中放令牌,而是仅仅通过计数的方式表示桶中剩余的令牌。每次消费取 Token 之前会先根据上次更新令牌数的时间差更新桶中Token数。
大概了解了time/rate
限流器的内部实现后,下面的内容我们会集中介绍下该组件的具体使用方法:
构造限流器
我们可以使用以下方法构造一个限流器对象:
limiter := rate.NewLimiter(10, 100);
这里有两个参数:
第一个参数是 r Limit
,设置的是限流器Limiter的limit
字段,代表每秒可以向 Token 桶中产生多少 token。Limit 实际上是 float64 的别名。第二个参数是 b int
,b 代表 Token 桶的容量大小,也就是设置的限流器 Limiter 的burst
字段。
那么,对于以上例子来说,其构造出的限流器的令牌桶大小为 100, 以每秒 10 个 Token 的速率向桶中放置 Token。
除了给r Limit
参数直接指定每秒产生的 Token 个数外,还可以用 Every 方法来指定向桶中放置 Token 的间隔,例如:
limit := rate.Every(100 * time.Millisecond); limiter := rate.NewLimiter(limit, 100);
以上就表示每 100ms 往桶中放一个 Token。本质上也是一秒钟往桶里放 10 个。
使用限流器
Limiter 提供了三类方法供程序消费 Token,可以每次消费一个 Token,也可以一次性消费多个 Token。每种方法代表了当 Token 不足时,各自不同的对应手段,可以阻塞等待桶中Token补充,也可以直接返回取Token失败。
Wait/WaitN
func (lim *Limiter) Wait(ctx context.Context) (err error) func (lim *Limiter) WaitN(ctx context.Context, n int) (err error)
Wait 实际上就是 WaitN(ctx,1)
。
当使用 Wait 方法消费 Token 时,如果此时桶内 Token 数组不足 (小于 N),那么 Wait 方法将会阻塞一段时间,直至 Token 满足条件。如果充足则直接返回。
这里可以看到,Wait 方法有一个 context 参数。我们可以设置 context 的 Deadline 或者 Timeout,来决定此次 Wait 的最长时间。
// 一直等到获取到桶中的令牌 err := limiter.Wait(context.Background()) if err != nil { fmt.Println("Error: ", err) } // 设置一秒的等待超时时间 ctx, _ := context.WithTimeout(context.Background(), time.Second * 1) err := limiter.Wait(ctx) if err != nil { fmt.Println("Error: ", err) }
Allow/AllowN
func (lim *Limiter) Allow() bool func (lim *Limiter) AllowN(now time.Time, n int) bool
Allow 实际上就是对 AllowN(time.Now(),1)
进行简化的函数。
AllowN 方法表示,截止到某一时刻,目前桶中数目是否至少为 n 个,满足则返回 true,同时从桶中消费 n 个 token。反之不消费桶中的Token,返回false。
对应线上的使用场景是,如果请求速率超过限制,就直接丢弃超频后的请求。
if limiter.AllowN(time.Now(), 2) { fmt.Println("event allowed") } else { fmt.Println("event not allowed") }
Reserve/ReserveN
func (lim *Limiter) Reserve() *Reservation func (lim *Limiter) ReserveN(now time.Time, n int) *Reservation
Reserve 相当于 ReserveN(time.Now(), 1)
。
ReserveN 的用法就相对来说复杂一些,当调用完成后,无论 Token 是否充足,都会返回一个 *Reservation
对象。你可以调用该对象的Delay()
方法,该方法返回的参数类型为time.Duration
,反映了需要等待的时间,必须等到等待时间之后,才能进行接下来的工作。如果不想等待,可以调用Cancel()
方法,该方法会将 Token 归还。
举一个简单的例子,我们可以这么使用 Reserve 方法。
r := limiter.Reserve() f !r.OK() { // Not allowed to act! Did you remember to set lim.burst to be > 0 ? return } time.Sleep(r.Delay()) Act() // 执行相关逻辑
动态调整速率和桶大小
Limiter 支持创建后动态调整速率和桶大小:
SetLimit(Limit) 改变放入 Token 的速率 SetBurst(int) 改变 Token 桶大小
有了这两个方法,可以根据现有环境和条件以及我们的需求,动态地改变 Token 桶大小和速率。
总结
今天我们总结了 Golang 官方限流器的使用方法,它是一种令牌桶算实现的限流器。其中 Wait/WaitN,Allow/AllowN 这两组方法在平时用的比较多,前者是消费Token时如果桶中Token不足可以让程序等待桶中新Token的放入(最好设置上等待时长)后者则是在桶中的Token不足时选择直接丢弃请求。
In addition to the current limiter implementation officially provided by Golang, Uber's open source current limiter uber-go/ratelimit
is also a good choice. What is different from Golang's official current limiter is Uber's limiter The flow controller is implemented through the leaky bucket algorithm, but the traditional leaky bucket algorithm has been improved. Interested students can experience it on their own.
The above is the detailed content of Detailed explanation of usage of Golang official current limiter. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics



Reading and writing files safely in Go is crucial. Guidelines include: Checking file permissions Closing files using defer Validating file paths Using context timeouts Following these guidelines ensures the security of your data and the robustness of your application.

How to configure connection pooling for Go database connections? Use the DB type in the database/sql package to create a database connection; set MaxOpenConns to control the maximum number of concurrent connections; set MaxIdleConns to set the maximum number of idle connections; set ConnMaxLifetime to control the maximum life cycle of the connection.

JSON data can be saved into a MySQL database by using the gjson library or the json.Unmarshal function. The gjson library provides convenience methods to parse JSON fields, and the json.Unmarshal function requires a target type pointer to unmarshal JSON data. Both methods require preparing SQL statements and performing insert operations to persist the data into the database.

The difference between the GoLang framework and the Go framework is reflected in the internal architecture and external features. The GoLang framework is based on the Go standard library and extends its functionality, while the Go framework consists of independent libraries to achieve specific purposes. The GoLang framework is more flexible and the Go framework is easier to use. The GoLang framework has a slight advantage in performance, and the Go framework is more scalable. Case: gin-gonic (Go framework) is used to build REST API, while Echo (GoLang framework) is used to build web applications.

The FindStringSubmatch function finds the first substring matched by a regular expression: the function returns a slice containing the matching substring, with the first element being the entire matched string and subsequent elements being individual substrings. Code example: regexp.FindStringSubmatch(text,pattern) returns a slice of matching substrings. Practical case: It can be used to match the domain name in the email address, for example: email:="user@example.com", pattern:=@([^\s]+)$ to get the domain name match[1].

Backend learning path: The exploration journey from front-end to back-end As a back-end beginner who transforms from front-end development, you already have the foundation of nodejs,...

Using predefined time zones in Go includes the following steps: Import the "time" package. Load a specific time zone through the LoadLocation function. Use the loaded time zone in operations such as creating Time objects, parsing time strings, and performing date and time conversions. Compare dates using different time zones to illustrate the application of the predefined time zone feature.

Go framework development FAQ: Framework selection: Depends on application requirements and developer preferences, such as Gin (API), Echo (extensible), Beego (ORM), Iris (performance). Installation and use: Use the gomod command to install, import the framework and use it. Database interaction: Use ORM libraries, such as gorm, to establish database connections and operations. Authentication and authorization: Use session management and authentication middleware such as gin-contrib/sessions. Practical case: Use the Gin framework to build a simple blog API that provides POST, GET and other functions.
