Rate Limiting

This Go code demonstrates the use of rate limiting with time. Tick and channels to control the frequency of requests.

Let's go through it with inline comments:

package main

import (
	"fmt"
	"time"
)

func main() {
	// Creating a buffered channel 'requests' for sending requests
	requests := make(chan int, 5)

	// Sending 5 requests to the 'requests' channel
	for i := 1; i <= 5; i++ {
		requests <- i
	}
	close(requests)

	// Creating a rate limiter with a tick of 200 milliseconds
	limiter := time.Tick(200 * time.Millisecond)

	// Processing requests with the rate limiter
	for req := range requests {
		<-limiter
		fmt.Println("request", req, time.Now())
	}

	// Creating a buffered channel 'burstyLimiter' with a capacity of 3
	burstyLimiter := make(chan time.Time, 3)

	// Initializing 'burstyLimiter' with three time values
	for i := 0; i < 3; i++ {
		burstyLimiter <- time.Now()
	}

	// Launching a goroutine to refill 'burstyLimiter' every 200 milliseconds
	go func() {
		for t := range time.Tick(200 * time.Millisecond) {
			burstyLimiter <- t
		}
	}()

	// Creating a buffered channel 'burstyRequests' for sending bursty requests
	burstyRequests := make(chan int, 5)

	// Sending 5 bursty requests to 'burstyRequests' channel
	for i := 1; i <= 5; i++ {
		burstyRequests <- i
	}
	close(burstyRequests)

	// Processing bursty requests with the bursty rate limiter
	for req := range burstyRequests {
		<-burstyLimiter
		fmt.Println("request", req, time.Now())
	}
}

Output

request 1 2024-01-23 19:12:37.8840836 +0530 IST m=+0.210007101
request 2 2024-01-23 19:12:38.0886902 +0530 IST m=+0.414613701
request 3 2024-01-23 19:12:38.2896166 +0530 IST m=+0.615540101
request 4 2024-01-23 19:12:38.4904667 +0530 IST m=+0.816390201
request 5 2024-01-23 19:12:38.6761374 +0530 IST m=+1.002060901
request 1 2024-01-23 19:12:38.6763013 +0530 IST m=+1.002224801
request 2 2024-01-23 19:12:38.6768092 +0530 IST m=+1.002732701
request 3 2024-01-23 19:12:38.6768092 +0530 IST m=+1.002732701
request 4 2024-01-23 19:12:38.8792461 +0530 IST m=+1.205169601
request 5 2024-01-23 19:12:39.0807175 +0530 IST m=+1.406641001

Explanation:

  1. package main: Indicates that this Go file belongs to the main executable package.

  2. import (...): Imports necessary packages, including "fmt" for formatting and printing, and "time" for handling time-related operations.

  3. requests := make(chan int, 5): Creates a buffered channel 'requests' for sending requests with a capacity of 5.

  4. Sending 5 requests to the 'requests' channel, and then closing the channel to indicate that no more requests will be sent.

  5. limiter := time.Tick(200 * time.Millisecond): Creates a rate limiter using time.Tick with a tick interval of 200 milliseconds.

  6. Processing requests with the rate limiter. Each request waits for the limiter to allow it before being processed.

  7. Creating a buffered channel 'burstyLimiter' with a capacity of 3.

  8. Initializing 'burstyLimiter' with three time values to allow for an initial burst of requests.

  9. Launching a goroutine to refill 'burstyLimiter' every 200 milliseconds, creating a bursty rate limiter.

  10. burstyRequests := make(chan int, 5): Creates a buffered channel 'burstyRequests' for sending bursty requests with a capacity of 5.

  11. Sending 5 bursty requests to 'burstyRequests' channel and then closing the channel.

  12. Processing bursty requests with the bursty rate limiter. The initial burst is allowed due to the buffered channel 'burstyLimiter'.

In summary, this code demonstrates two scenarios of rate limiting using channels and time.Tick. The first scenario demonstrates regular rate limiting, while the second scenario introduces a bursty rate limiter allowing an initial burst of requests before settling into a regular rate.

Further Explanation

Rate limiting is a technique used to control the rate at which events, such as requests or operations, are allowed to occur. It helps prevent resource exhaustion, manage traffic, and maintain system stability. In the provided Go code, two examples of rate limiting are demonstrated: regular rate limiting and bursty rate limiting.

  1. Regular Rate Limiting:

    • The first part of the code uses a simple rate limiter created with time.Tick(200 * time.Millisecond). This creates a channel that ticks every 200 milliseconds. Each request is processed only when it receives a tick from this channel.

    • This ensures that requests are processed at a regular interval, limiting the rate at which they can occur. If a request arrives before the next tick, it will wait for the next tick to proceed.

    • This is useful to ensure a steady flow of requests and prevent a sudden surge that could overload the system.

  2. Bursty Rate Limiting:

    • The second part of the code introduces a bursty rate limiter, allowing an initial burst of requests to be processed more rapidly.

    • The burstyLimiter channel is buffered with a capacity of 3, allowing three requests to be processed without waiting for the tick.

    • The channel is initially filled with three time values, allowing an immediate burst of requests.

    • A goroutine is launched to continuously refill the channel with time values every 200 milliseconds, creating a regular tick for subsequent requests.

    • This allows for a burst of requests initially, followed by a regular rate of requests, combining the benefits of burstiness and regular rate limiting.

In both scenarios, rate limiting is achieved by using channels and time.Tick. The rate limiter allows a controlled number of events to occur within a specified time interval, preventing a flood of requests and ensuring a more controlled and predictable behavior for the system. It's a common technique used in systems to prevent abuse, manage resources, and maintain overall stability.

Last updated