Skip to content

Implementation of various rate limiting algorithms in Golang

Notifications You must be signed in to change notification settings

2asm/ratelimiter

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

API rate limiters in golang

Project provides implementation of sliding window, token bucket and leaky bucket algorithm

Quick start

func main() {
    // window size = 1 second (1000 milisecond)
    // events per window = 2
    limiter1 := slidingwindow.NewLimiter(2, time.Millisecond*1000)
    fmt.Printf("sliding bucket\n")
    log.Printf("%v\n", limiter1.Allow())
    log.Printf("%v\n", limiter1.Allow())
    log.Printf("%v\n", limiter1.Allow())
    log.Printf("%v\n", limiter1.Allow())
    log.Printf("%v\n", limiter1.Allow())

    // 2 events per second (frequency)
    // burst size = 5
    limiter2 := tokenbucket.NewLimiter(2, 5)
    fmt.Printf("\ntoken bucket\n")
    log.Printf("%v\n", limiter2.Allow())
    log.Printf("%v\n", limiter2.Allow())
    log.Printf("%v\n", limiter2.Allow())
    log.Printf("%v\n", limiter2.Allow())
    log.Printf("%v\n", limiter2.Allow())
    log.Printf("%v\n", limiter2.Allow())
    time.Sleep(time.Second*1)
    log.Printf("%v\n", limiter2.Allow())
    log.Printf("%v\n", limiter2.Allow())
    log.Printf("%v\n", limiter2.Allow())
    time.Sleep(time.Second*3)
    log.Printf("%v\n", limiter2.Allow())
    log.Printf("%v\n", limiter2.Allow())
    log.Printf("%v\n", limiter2.Allow())
    log.Printf("%v\n", limiter2.Allow())
    log.Printf("%v\n", limiter2.Allow())
    log.Printf("%v\n", limiter2.Allow())
    log.Printf("%v\n", limiter2.Allow())

    // 2 events per second
    // bucket size = 4 
    wg := sync.WaitGroup{}
    limiter := leakyBucket.NewLimiter(2, 4)
    fmt.Printf("\nleaky bucket\n")
    for i := 1; i < 10; i++ {
        t, ok := limiter.Allow()
        if ok {
            wg.Add(1)
            go func(i int, t time.Duration) {
                defer wg.Done()
                time.Sleep(t)
                log.Printf("Event %d completed\n", i)
            }(i, t)
        } else {
            log.Printf("ERROR: Rate limit exceeded\n")
        }
    }
    wg.Wait()
}

Output:

sliding bucket
2023/11/30 15:12:16.459216 true
2023/11/30 15:12:16.459300 true
2023/11/30 15:12:16.459304 false
2023/11/30 15:12:16.459308 false
2023/11/30 15:12:16.459311 false

token bucket
2023/11/30 15:12:16.459318 true
2023/11/30 15:12:16.459322 true
2023/11/30 15:12:16.459325 true
2023/11/30 15:12:16.459328 true
2023/11/30 15:12:16.459332 true
2023/11/30 15:12:16.459336 false
2023/11/30 15:12:17.459651 true
2023/11/30 15:12:17.459691 true
2023/11/30 15:12:17.459704 false
2023/11/30 15:12:20.460532 true
2023/11/30 15:12:20.460580 true
2023/11/30 15:12:20.460599 true
2023/11/30 15:12:20.460613 true
2023/11/30 15:12:20.460633 true
2023/11/30 15:12:20.460689 false
2023/11/30 15:12:20.460705 false

leaky bucket
2023/11/30 15:12:20.461010 ERROR: Rate limit exceeded
2023/11/30 15:12:20.461036 ERROR: Rate limit exceeded
2023/11/30 15:12:20.461054 ERROR: Rate limit exceeded
2023/11/30 15:12:20.461068 ERROR: Rate limit exceeded
2023/11/30 15:12:20.961323 Event 1 completed
2023/11/30 15:12:21.460950 Event 2 completed
2023/11/30 15:12:21.962128 Event 3 completed
2023/11/30 15:12:22.461984 Event 4 completed
2023/11/30 15:12:22.961700 Event 5 completed

[Process exited 0]

Redis based rate limiter for distributed systems

func main() {
	redis_client := redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // no password set
		DB:       0,  // use default DB
		Protocol: 3,  // specify 2 for RESP 2 or 3 for RESP 3
	})
	limiter := NewLimiter(3213, 2, 6, redis_client)
	log.Printf("%v\n", limiter.Allow())
	log.Printf("%v\n", limiter.Allow())
	log.Printf("%v\n", limiter.Allow())
	log.Printf("%v\n", limiter.Allow())
	log.Printf("%v\n", limiter.Allow())
	time.Sleep(time.Millisecond * 999)
	log.Printf("%v\n", limiter.Allow())
	log.Printf("%v\n", limiter.Allow())
	log.Printf("%v\n", limiter.Allow())
	log.Printf("%v\n", limiter.Allow())
	log.Printf("%v\n", limiter.Allow())
	time.Sleep(time.Millisecond * 999)
	log.Printf("%v\n", limiter.Allow())
	log.Printf("%v\n", limiter.Allow())
	log.Printf("%v\n", limiter.Allow())
	log.Printf("%v\n", limiter.Allow())
	time.Sleep(time.Millisecond * 1999)
	log.Printf("%v\n", limiter.Allow())
	log.Printf("%v\n", limiter.Allow())
	log.Printf("%v\n", limiter.Allow())
	log.Printf("%v\n", limiter.Allow())
	log.Printf("%v\n", limiter.Allow())
	log.Printf("%v\n", limiter.Allow())
	log.Printf("%v\n", limiter.Allow())
}

Output:

2023/12/06 16:10:19 true
2023/12/06 16:10:19 true
2023/12/06 16:10:19 true
2023/12/06 16:10:19 true
2023/12/06 16:10:19 true
2023/12/06 16:10:20 true
2023/12/06 16:10:20 true
2023/12/06 16:10:20 true
2023/12/06 16:10:20 false
2023/12/06 16:10:20 false
2023/12/06 16:10:21 true
2023/12/06 16:10:21 true
2023/12/06 16:10:21 false
2023/12/06 16:10:21 false
2023/12/06 16:10:23 true
2023/12/06 16:10:23 true
2023/12/06 16:10:23 true
2023/12/06 16:10:23 true
2023/12/06 16:10:23 false
2023/12/06 16:10:23 false
2023/12/06 16:10:23 false

[Process exited 0]

About

Implementation of various rate limiting algorithms in Golang

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages