ratelimit

package
v1.15.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 8, 2025 License: MIT Imports: 8 Imported by: 0

README

Adaptive Rate Limiting

The mechanism of adaptive rate limiting is derived from Google BBR's congestion control idea, and its essence is:

  1. If the system is healthy, don't block traffic

    • The purpose of rate limiting is not to "shave peaks" but to "protect the system."
    • If the CPU load is not high, even if there are many requests, it means the system can still handle them, and there is no need to reject requests.
    • Otherwise, it would waste resources and reduce throughput.
  2. Only perform rate limiting when the system is about to be overwhelmed

    • Requests are only dropped when the CPU exceeds the threshold and the current number of concurrent requests is greater than the safe upper limit calculated from historical data.
    • At this point, the purpose of rate limiting is to prevent a cascade failure and pull the system back from the brink of "overload → collapse."

The advantages of adaptive rate limiting are:

  • Protects system stability: Requests are only dropped when the CPU is under high load, ensuring maximum throughput.
  • High-concurrency API services: It can accept requests to the greatest extent while ensuring performance.

Note: If the stress test scenario involves I/O-bound requests (with very low CPU usage), the rate limiting will hardly trigger and may appear "ineffective."


Example of use

Gin ratelimit middleware
import (
	rl "github.com/go-dev-frame/sponge/pkg/shield/ratelimit"
)

func RateLimit(opts ...RateLimitOption) gin.HandlerFunc {
	o := defaultRatelimitOptions()
	o.apply(opts...)
	limiter := rl.NewLimiter(
		rl.WithWindow(o.window),
		rl.WithBucket(o.bucket),
		rl.WithCPUThreshold(o.cpuThreshold),
		rl.WithCPUQuota(o.cpuQuota),
	)

	return func(c *gin.Context) {
		done, err := limiter.Allow()
		if err != nil {
			response.Output(c, http.StatusTooManyRequests, err.Error())
			c.Abort()
			return
		}

		c.Next()

		done(rl.DoneInfo{Err: c.Request.Context().Err()})
	}
}

gRPC ratelimit interceptor
import (
	rl "github.com/go-dev-frame/sponge/pkg/shield/ratelimit"
)


func UnaryServerRateLimit(opts ...RatelimitOption) grpc.UnaryServerInterceptor {
	o := defaultRatelimitOptions()
	o.apply(opts...)
	limiter := rl.NewLimiter(
		rl.WithWindow(o.window),
		rl.WithBucket(o.bucket),
		rl.WithCPUThreshold(o.cpuThreshold),
		rl.WithCPUQuota(o.cpuQuota),
	)

	return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
		done, err := limiter.Allow()
		if err != nil {
			return nil, errcode.StatusLimitExceed.ToRPCErr(err.Error())
		}

		reply, err := handler(ctx, req)
		done(rl.DoneInfo{Err: err})
		return reply, err
	}
}

Documentation

Overview

Package ratelimit is an adaptive rate limit library, support for use in gin middleware and grpc interceptors.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrLimitExceed is returned when the rate limiter is
	// triggered and the request is rejected due to limit exceeded.
	ErrLimitExceed = errors.New("rate limit exceeded")
)

Functions

This section is empty.

Types

type BBR

type BBR struct {
	// contains filtered or unexported fields
}

BBR implements bbr-like limiter. It is inspired by sentinel. https://github.com/alibaba/Sentinel/wiki/%E7%B3%BB%E7%BB%9F%E8%87%AA%E9%80%82%E5%BA%94%E9%99%90%E6%B5%81

func NewLimiter

func NewLimiter(opts ...Option) *BBR

NewLimiter returns a bbr limiter

func (*BBR) Allow

func (l *BBR) Allow() (DoneFunc, error)

Allow checks all inbound traffic. Once overload is detected, it raises limit.ErrLimitExceed error.

func (*BBR) Stat

func (l *BBR) Stat() Stat

Stat tasks a snapshot of the bbr limiter.

type DoneFunc

type DoneFunc func(DoneInfo)

DoneFunc is done function.

type DoneInfo

type DoneInfo struct {
	Err error
}

DoneInfo is done info.

type Limiter

type Limiter interface {
	Allow() (DoneFunc, error)
}

Limiter is a rate limiter.

type Option

type Option func(*options)

Option function for bbr limiter

func WithBucket

func WithBucket(b int) Option

WithBucket with bucket ize.

func WithCPUQuota

func WithCPUQuota(quota float64) Option

WithCPUQuota with real cpu quota(if it can not collect from process correct);

func WithCPUThreshold

func WithCPUThreshold(threshold int64) Option

WithCPUThreshold with cpu threshold;

func WithWindow

func WithWindow(d time.Duration) Option

WithWindow with window size.

type Stat

type Stat struct {
	CPU         int64
	InFlight    int64
	MaxInFlight int64
	MinRt       int64
	MaxPass     int64
}

Stat contains the metrics snapshot of bbr.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL