equalizer

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Mar 14, 2024 License: MIT Imports: 10 Imported by: 1

README

equalizer

The equalizer package provides a set of simple and easy-to-use rate limiters for Go. These rate limiters can be used to limit the rate of requests to any resource, such as a database, API, or file.

The package includes the following rate limiters:

Equalizer

Equalizer is a rate limiter that adjusts the rate of requests based on the outcomes of previous requests. If previous attempts have failed, Equalizer will slow down the rate of requests to avoid overloading the system. Conversely, if previous attempts have been successful, Equalizer will accelerate the rate of requests to make the most of the available capacity.

Usage Example

// a random offset manager 
offset := equalizer.NewRandomOffset(96)
// an Equalizer with a bitmap size of 96, 16 reserved positive bits, and the random offset manager
eq := equalizer.NewEqualizer(96, 16, offset)
// non-blocking quota request
haveQuota := eq.TryAcquire()
// update on the successful request
eq.Success(1)

Benchmarks

BenchmarkEqualizer_ShortTryAcquireStep-16       31538967                38.33 ns/op            0 B/op          0 allocs/op
BenchmarkEqualizer_ShortTryAcquireRandom-16     37563639                31.66 ns/op            0 B/op          0 allocs/op
BenchmarkEqualizer_ShortNotify-16               29519719                40.43 ns/op            0 B/op          0 allocs/op
BenchmarkEqualizer_LongTryAcquireStep-16        32084402                38.36 ns/op            0 B/op          0 allocs/op
BenchmarkEqualizer_LongTryAcquireRandom-16      39996501                30.37 ns/op            0 B/op          0 allocs/op
BenchmarkEqualizer_LongNotify-16                29648655                40.46 ns/op            0 B/op          0 allocs/op

Slider

Slider tracks the number of requests that have been processed in a recent time window. If the number of requests exceeds the limit, the rate limiter will block new requests until the window has moved forward. Implements the equalizer.Limiter interface.

Usage Example

// a Slider with a one-second window size, a 100-millisecond sliding interval,
// and a capacity of 32
slider := equalizer.NewSlider(time.Second, 100*time.Millisecond, 32)
// non-blocking quota request
haveQuota := slider.TryAcquire()
// blocking call
slider.Acquire(context.Background())

Benchmarks

BenchmarkSlider_TryAcquire-16                   293645348                4.033 ns/op           0 B/op          0 allocs/op
BenchmarkRateLimiter_Allow-16                     9362382              127.4 ns/op             0 B/op          0 allocs/op

* Compared to rate.Limiter from the golang.org/x/time package.

Token Bucket

TokenBucket maintains a fixed number of tokens. Each token represents a request that can be processed. When a request is made, the rate limiter checks to see if there are any available tokens. If there are, the request is processed and one token is removed from the bucket. If there are no available tokens, the request is blocked until a token becomes available. Implements the equalizer.Limiter interface.

Usage Example

// a TokenBucket with the capacity of 32 and a 100-millisecond refill interval
tokenBucket := equalizer.NewTokenBucket(32, 100*time.Millisecond)
// non-blocking quota request
haveQuota := tokenBucket.TryAcquire()
// blocking call
tokenBucket.Acquire(context.Background())

Benchmarks

BenchmarkTokenBucket_TryAcquire-16              304653043                3.909 ns/op           0 B/op          0 allocs/op
BenchmarkRateLimiter_Allow-16                     9362382              127.4 ns/op             0 B/op          0 allocs/op

* Compared to rate.Limiter from the golang.org/x/time package.

License

Licensed under the MIT License.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Equalizer

type Equalizer struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

An Equalizer represents an adaptive rate limiter based on a bit array.

The Equalizer uses a round-robin bit array with a moving head to manage quotas. The quota management algorithm is simple and works in the following way. To request a permit in a non-blocking manner use the TryAcquire method. The Equalizer will locate the appropriate position on the tape using the offset manager and return the value, denoting whether the request is allowed or not. To update the tape state, a notification method (Success or Failure) should be invoked based on the operation status. The Reset and Purge methods allow for immediate transition of the limiter state to whether permissive or restrictive.

An Equalizer is safe for use by multiple goroutines simultaneously.

func NewEqualizer

func NewEqualizer(size, reserved int, offset Offset) (*Equalizer, error)

NewEqualizer instantiates and returns a new Equalizer rate limiter, where size is the length of the bit array, reserved is the number of reserved positive bits and offset is an instance of the equalizer.Offset strategy.

func (*Equalizer) Failure

func (eq *Equalizer) Failure(n int)

Failure notifies the equalizer with n failed operations.

func (*Equalizer) Purge

func (eq *Equalizer) Purge()

Purge blanks out the tape to the positive bitmask state.

func (*Equalizer) Reset

func (eq *Equalizer) Reset()

Reset resets the tape to its initial state.

func (*Equalizer) Success

func (eq *Equalizer) Success(n int)

Success notifies the equalizer with n successful operations.

func (*Equalizer) TryAcquire

func (eq *Equalizer) TryAcquire() bool

TryAcquire moves the tape head to the next index and returns the value.

type Limiter

type Limiter interface {
	// Acquire blocks the calling goroutine until a token is acquired, the Context
	// is canceled, or the wait time exceeds the Context's Deadline.
	Acquire(ctx context.Context) error
	// TryAcquire attempts to acquire a token without blocking.
	// Returns true if a token was acquired, false if no tokens are available.
	TryAcquire() bool
}

Limiter represents a rate limiter.

Rate limiters control the rate at which requests are processed by allocating a certain number of tokens. Each token represents the ability to process a single request. When a request is made, the limiter checks if there are any available tokens. If there are, it deducts one token and allows the request to proceed. If there are no tokens available, the request is blocked until a token becomes available.

By controlling the number of tokens available, rate limiters can ensure that requests are processed at a controlled rate, preventing overloading and ensuring fair access to resources.

type Offset

type Offset interface {
	NextIndex() int
}

The Offset component is responsible for advancing the head position of the Equalizer tape after each request. Implementations of Offset must be thread-safe.

type RandomOffset

type RandomOffset struct {
	Len int
}

RandomOffset is an offset manager that uses a random-based offset approach.

func NewRandomOffset

func NewRandomOffset(len int) *RandomOffset

NewRandomOffset returns a new RandomOffset, where len is the bitmap tape length.

func (*RandomOffset) NextIndex

func (ro *RandomOffset) NextIndex() int

NextIndex returns the next random index within a tape.

type Slider

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

A Slider represents a rate limiter which is based on a sliding window with a specified quota capacity. Implements the equalizer.Limiter interface.

A Slider is safe for use by multiple goroutines simultaneously.

The underlying slider instance ensures that the background goroutine does not keep the main Slider object from being garbage collected. When it is garbage collected, the finalizer stops the background goroutine, after which the underlying slider can be collected.

func NewSlider

func NewSlider(window, slidingInterval time.Duration, capacity int) (*Slider, error)

NewSlider allocates and returns a new Slider rate limiter, where window is the fixed duration of the sliding window, slidingInterval controls how frequently a new sliding window is started and capacity is the quota limit for the window.

func (*Slider) Acquire

func (s *Slider) Acquire(ctx context.Context) error

Acquire blocks the calling goroutine until a token is acquired, the Context is canceled, or the wait time exceeds the Context's Deadline.

func (*Slider) TryAcquire

func (s *Slider) TryAcquire() bool

TryAcquire attempts to acquire a token without blocking. returns true if a token was acquired, false if no tokens are available.

type StepOffset

type StepOffset struct {
	Len  int
	Step int64
	// contains filtered or unexported fields
}

StepOffset is an offset manager that uses a fixed step approach.

func NewStepOffset

func NewStepOffset(len, step int) *StepOffset

NewStepOffset allocates and returns a new StepOffset, where len is the length of the bitmap tape and step is the offset to be taken from the previous position.

func (*StepOffset) NextIndex

func (so *StepOffset) NextIndex() int

NextIndex returns the next index in a round-robin fashion, utilizing the specified step value to advance along the tape.

type TokenBucket

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

A TokenBucket represents a rate limiter based on a custom implementation of the token bucket algorithm with a refill interval. Implements the equalizer.Limiter interface.

A TokenBucket is safe for use by multiple goroutines simultaneously.

The underlying tokenBucket instance ensures that the background goroutine does not keep the main TokenBucket object from being garbage collected. When it is garbage collected, the finalizer stops the background goroutine, after which the underlying tokenBucket can be collected.

func NewTokenBucket

func NewTokenBucket(capacity int, refillInterval time.Duration) (*TokenBucket, error)

NewTokenBucket allocates and returns a new TokenBucket rate limiter, where capacity is the capacity of the token bucket and refillInterval is the token bucket refill interval.

func (*TokenBucket) Acquire

func (tb *TokenBucket) Acquire(ctx context.Context) error

Acquire blocks the calling goroutine until a token is acquired, the Context is canceled, or the wait time exceeds the Context's Deadline.

func (*TokenBucket) TryAcquire

func (tb *TokenBucket) TryAcquire() bool

TryAcquire attempts to acquire a token without blocking. Returns true if a token was acquired, false if no tokens are available.

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

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