Repository files navigation

Distributed Rate-Limiting Library Using Redis

Overview

This library is designed to implement distributed rate limiting in a simple, no-nonsense way. Similar to how an ID generator works, the client retrieves data from Redis in batches (essentially just values). As long as these values aren't consumed, the rate limit is not exceeded.

Key Advantages

  • Minimal dependencies—only Redis is required, no additional services
  • Utilizes Redis' internal clock, so clients don't need synchronized clocks
  • Thread- and coroutine-safe
  • Low overhead on the system and minimal pressure on Redis

Important Notes

Different limiter types use different Redis key data structures, so they cannot share the same Redis key name.

Example:

127.0.0.1:6379> type key:leaky
string
127.0.0.1:6379> type key:token
hash
127.0.0.1:6379> hgetall key:token
"token_count"
"0"
"updateTime"
"1613805726567122"
127.0.0.1:6379> get key:leaky
"1613807035353864"

Installation

go get github.com/arpan491/API-RateLimiter

Usage

1. Create a Redis client

Using the "github.com/go-redis/redis" package, the library supports both master-slave and cluster Redis modes.

client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "xxx", // no password
DB: 0, // default DB
})

Or, for Redis cluster mode:

client := redis.NewClusterClient(&redis.ClusterOptions{
Addrs: []string{"127.0.0.1:6379"},
Password: "xxxx",
})

2. Create a RateLimiter

For a token bucket rate limiter that allows 200 operations per second:

limiter, err := ratelimit.NewTokenBucketRateLimiter(ctx, client, "push", time.Second, 200, 20, 5)

For 200 operations per minute:

limiter, err := ratelimit.NewTokenBucketRateLimiter(ctx, client, "push", time.Minute, 200, 20, 5)

2.1 Counter Algorithm

func NewCounterRateLimiter(ctx context.Context, client redis.Cmdable, key string, duration time.Duration,
throughput int, batchSize int) (Limiter, error)
ParameterDescription
keyRedis key name
durationTime interval for the allowed operation throughput
throughputAllowed number of operations within the given time interval
batchSizeNumber of operations retrieved from Redis in one batch

2.2 Token Bucket Algorithm

func NewTokenBucketRateLimiter(ctx context.Context, client redis.Cmdable, key string, duration time.Duration,
throughput int, maxCapacity int, batchSize int) (Limiter, error)
ParameterDescription
keyRedis key name
durationTime interval for the allowed operation throughput
throughputNumber of operations allowed within the given time interval
maxCapacityMaximum tokens that can be stored in the token bucket
batchSizeNumber of operations retrieved from Redis in one batch

2.3 Leaky Bucket Algorithm

func NewLeakyBucketLimiter(ctx context.Context, client redis.Cmdable, key string, duration time.Duration,
throughput int) (Limiter, error)
ParameterDescription
keyRedis key name
durationTime interval for the allowed operation throughput
throughputNumber of operations allowed within the given time interval

2.4 Sliding Time Window

NewSlideTimeWindowLimiter(throughput int, duration time.Duration, windowBuckets int) (Limiter, error)
ParameterDescription
durationTime interval for the allowed operation throughput
throughputNumber of operations allowed within the given time interval
windowBucketsNumber of buckets representing a segment of the time window (duration/windowBuckets)

Note: The sliding window limiter operates in-memory and doesn't use Redis, making it unsuitable for distributed rate-limiting scenarios.

Example

More examples

package main
import (
"context""fmt""github.com/go-redis/redis/v8""github.com/arpan491/API-RateLimiter"
slog "github.com/vearne/simplelog""sync""time"
)
funcconsume(r ratelimit.Limiter, group*sync.WaitGroup, c*ratelimit.Counter, targetCountint) {
defergroup.Done()
varokboolfor {
ok=trueerr:=r.Wait(context.Background())
slog.Debug("r.Wait:%v", err)
iferr!=nil {
ok=falseslog.Error("error:%v", err)
}
ifok {
value:=c.Incr()
slog.Debug("---value--:%v", value)
ifvalue>=targetCount {
break
}
}
}
}
funcmain() {
client:=redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "xxeQl*@nFE", // passwordDB: 0, // use default DB
})
limiter, err:=ratelimit.NewTokenBucketRateLimiter(
context.Background(),
client,
"key:token",
time.Second,
10,
5,
2,
)
iferr!=nil {
fmt.Println("error", err)
return
}
varwg sync.WaitGrouptotal:=50counter:=ratelimit.NewCounter()
start:=time.Now()
fori:=0; i<10; i++ {
wg.Add(1)
goconsume(limiter, &wg, counter, total)
}
wg.Wait()
cost:=time.Since(start)
fmt.Println("cost", cost, "rate", float64(total)/cost.Seconds())
}

Dependency

go-redis/redis

About

A Go-based distributed rate-limiting library using Redis, supporting Token Bucket, Leaky Bucket, Sliding Window, and Counter algorithms. It's lightweight, scalable, and thread-safe, ideal for API throttling with minimal overhead.

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

Distributed Rate-Limiting Library Using Redis

Overview

This library is designed to implement distributed rate limiting in a simple, no-nonsense way. Similar to how an ID generator works, the client retrieves data from Redis in batches (essentially just values). As long as these values aren't consumed, the rate limit is not exceeded.

Key Advantages

  • Minimal dependencies—only Redis is required, no additional services
  • Utilizes Redis' internal clock, so clients don't need synchronized clocks
  • Thread- and coroutine-safe
  • Low overhead on the system and minimal pressure on Redis

Important Notes

Different limiter types use different Redis key data structures, so they cannot share the same Redis key name.

Example:

127.0.0.1:6379> type key:leaky
string
127.0.0.1:6379> type key:token
hash
127.0.0.1:6379> hgetall key:token
"token_count"
"0"
"updateTime"
"1613805726567122"
127.0.0.1:6379> get key:leaky
"1613807035353864"

Installation

go get github.com/arpan491/API-RateLimiter

Usage

1. Create a Redis client

Using the "github.com/go-redis/redis" package, the library supports both master-slave and cluster Redis modes.

client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "xxx", // no password
DB: 0, // default DB
})

Or, for Redis cluster mode:

client := redis.NewClusterClient(&redis.ClusterOptions{
Addrs: []string{"127.0.0.1:6379"},
Password: "xxxx",
})

2. Create a RateLimiter

For a token bucket rate limiter that allows 200 operations per second:

limiter, err := ratelimit.NewTokenBucketRateLimiter(ctx, client, "push", time.Second, 200, 20, 5)

For 200 operations per minute:

limiter, err := ratelimit.NewTokenBucketRateLimiter(ctx, client, "push", time.Minute, 200, 20, 5)

2.1 Counter Algorithm

func NewCounterRateLimiter(ctx context.Context, client redis.Cmdable, key string, duration time.Duration,
throughput int, batchSize int) (Limiter, error)
ParameterDescription
keyRedis key name
durationTime interval for the allowed operation throughput
throughputAllowed number of operations within the given time interval
batchSizeNumber of operations retrieved from Redis in one batch

2.2 Token Bucket Algorithm

func NewTokenBucketRateLimiter(ctx context.Context, client redis.Cmdable, key string, duration time.Duration,
throughput int, maxCapacity int, batchSize int) (Limiter, error)
ParameterDescription
keyRedis key name
durationTime interval for the allowed operation throughput
throughputNumber of operations allowed within the given time interval
maxCapacityMaximum tokens that can be stored in the token bucket
batchSizeNumber of operations retrieved from Redis in one batch

2.3 Leaky Bucket Algorithm

func NewLeakyBucketLimiter(ctx context.Context, client redis.Cmdable, key string, duration time.Duration,
throughput int) (Limiter, error)
ParameterDescription
keyRedis key name
durationTime interval for the allowed operation throughput
throughputNumber of operations allowed within the given time interval

2.4 Sliding Time Window

NewSlideTimeWindowLimiter(throughput int, duration time.Duration, windowBuckets int) (Limiter, error)
ParameterDescription
durationTime interval for the allowed operation throughput
throughputNumber of operations allowed within the given time interval
windowBucketsNumber of buckets representing a segment of the time window (duration/windowBuckets)

Note: The sliding window limiter operates in-memory and doesn't use Redis, making it unsuitable for distributed rate-limiting scenarios.

Example

More examples

package main
import (
"context""fmt""github.com/go-redis/redis/v8""github.com/arpan491/API-RateLimiter"
slog "github.com/vearne/simplelog""sync""time"
)
funcconsume(r ratelimit.Limiter, group*sync.WaitGroup, c*ratelimit.Counter, targetCountint) {
defergroup.Done()
varokboolfor {
ok=trueerr:=r.Wait(context.Background())
slog.Debug("r.Wait:%v", err)
iferr!=nil {
ok=falseslog.Error("error:%v", err)
}
ifok {
value:=c.Incr()
slog.Debug("---value--:%v", value)
ifvalue>=targetCount {
break
}
}
}
}
funcmain() {
client:=redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "xxeQl*@nFE", // passwordDB: 0, // use default DB
})
limiter, err:=ratelimit.NewTokenBucketRateLimiter(
context.Background(),
client,
"key:token",
time.Second,
10,
5,
2,
)
iferr!=nil {
fmt.Println("error", err)
return
}
varwg sync.WaitGrouptotal:=50counter:=ratelimit.NewCounter()
start:=time.Now()
fori:=0; i<10; i++ {
wg.Add(1)
goconsume(limiter, &wg, counter, total)
}
wg.Wait()
cost:=time.Since(start)
fmt.Println("cost", cost, "rate", float64(total)/cost.Seconds())
}

Dependency

go-redis/redis

About

A Go-based distributed rate-limiting library using Redis, supporting Token Bucket, Leaky Bucket, Sliding Window, and Counter algorithms. It's lightweight, scalable, and thread-safe, ideal for API throttling with minimal overhead.

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Distributed Rate-Limiting Library Using Redis

Overview

This library is designed to implement distributed rate limiting in a simple, no-nonsense way. Similar to how an ID generator works, the client retrieves data from Redis in batches (essentially just values). As long as these values aren't consumed, the rate limit is not exceeded.

Key Advantages

  • Minimal dependencies—only Redis is required, no additional services
  • Utilizes Redis' internal clock, so clients don't need synchronized clocks
  • Thread- and coroutine-safe
  • Low overhead on the system and minimal pressure on Redis

Important Notes

Different limiter types use different Redis key data structures, so they cannot share the same Redis key name.

Example:

127.0.0.1:6379> type key:leaky
string
127.0.0.1:6379> type key:token
hash
127.0.0.1:6379> hgetall key:token
"token_count"
"0"
"updateTime"
"1613805726567122"
127.0.0.1:6379> get key:leaky
"1613807035353864"

Installation

go get github.com/arpan491/API-RateLimiter

Usage

1. Create a Redis client

Using the "github.com/go-redis/redis" package, the library supports both master-slave and cluster Redis modes.

client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "xxx", // no password
DB: 0, // default DB
})

Or, for Redis cluster mode:

client := redis.NewClusterClient(&redis.ClusterOptions{
Addrs: []string{"127.0.0.1:6379"},
Password: "xxxx",
})

2. Create a RateLimiter

For a token bucket rate limiter that allows 200 operations per second:

limiter, err := ratelimit.NewTokenBucketRateLimiter(ctx, client, "push", time.Second, 200, 20, 5)

For 200 operations per minute:

limiter, err := ratelimit.NewTokenBucketRateLimiter(ctx, client, "push", time.Minute, 200, 20, 5)

2.1 Counter Algorithm

func NewCounterRateLimiter(ctx context.Context, client redis.Cmdable, key string, duration time.Duration,
throughput int, batchSize int) (Limiter, error)
ParameterDescription
keyRedis key name
durationTime interval for the allowed operation throughput
throughputAllowed number of operations within the given time interval
batchSizeNumber of operations retrieved from Redis in one batch

2.2 Token Bucket Algorithm

func NewTokenBucketRateLimiter(ctx context.Context, client redis.Cmdable, key string, duration time.Duration,
throughput int, maxCapacity int, batchSize int) (Limiter, error)
ParameterDescription
keyRedis key name
durationTime interval for the allowed operation throughput
throughputNumber of operations allowed within the given time interval
maxCapacityMaximum tokens that can be stored in the token bucket
batchSizeNumber of operations retrieved from Redis in one batch

2.3 Leaky Bucket Algorithm

func NewLeakyBucketLimiter(ctx context.Context, client redis.Cmdable, key string, duration time.Duration,
throughput int) (Limiter, error)
ParameterDescription
keyRedis key name
durationTime interval for the allowed operation throughput
throughputNumber of operations allowed within the given time interval

2.4 Sliding Time Window

NewSlideTimeWindowLimiter(throughput int, duration time.Duration, windowBuckets int) (Limiter, error)
ParameterDescription
durationTime interval for the allowed operation throughput
throughputNumber of operations allowed within the given time interval
windowBucketsNumber of buckets representing a segment of the time window (duration/windowBuckets)

Note: The sliding window limiter operates in-memory and doesn't use Redis, making it unsuitable for distributed rate-limiting scenarios.

Example

More examples

package main
import (
"context""fmt""github.com/go-redis/redis/v8""github.com/arpan491/API-RateLimiter"
slog "github.com/vearne/simplelog""sync""time"
)
funcconsume(r ratelimit.Limiter, group*sync.WaitGroup, c*ratelimit.Counter, targetCountint) {
defergroup.Done()
varokboolfor {
ok=trueerr:=r.Wait(context.Background())
slog.Debug("r.Wait:%v", err)
iferr!=nil {
ok=falseslog.Error("error:%v", err)
}
ifok {
value:=c.Incr()
slog.Debug("---value--:%v", value)
ifvalue>=targetCount {
break
}
}
}
}
funcmain() {
client:=redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "xxeQl*@nFE", // passwordDB: 0, // use default DB
})
limiter, err:=ratelimit.NewTokenBucketRateLimiter(
context.Background(),
client,
"key:token",
time.Second,
10,
5,
2,
)
iferr!=nil {
fmt.Println("error", err)
return
}
varwg sync.WaitGrouptotal:=50counter:=ratelimit.NewCounter()
start:=time.Now()
fori:=0; i<10; i++ {
wg.Add(1)
goconsume(limiter, &wg, counter, total)
}
wg.Wait()
cost:=time.Since(start)
fmt.Println("cost", cost, "rate", float64(total)/cost.Seconds())
}

Dependency

go-redis/redis

About

A Go-based distributed rate-limiting library using Redis, supporting Token Bucket, Leaky Bucket, Sliding Window, and Counter algorithms. It's lightweight, scalable, and thread-safe, ideal for API throttling with minimal overhead.

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Distributed Rate-Limiting Library Using Redis

Overview

This library is designed to implement distributed rate limiting in a simple, no-nonsense way. Similar to how an ID generator works, the client retrieves data from Redis in batches (essentially just values). As long as these values aren't consumed, the rate limit is not exceeded.

Key Advantages

  • Minimal dependencies—only Redis is required, no additional services
  • Utilizes Redis' internal clock, so clients don't need synchronized clocks
  • Thread- and coroutine-safe
  • Low overhead on the system and minimal pressure on Redis

Important Notes

Different limiter types use different Redis key data structures, so they cannot share the same Redis key name.

Example:

127.0.0.1:6379> type key:leaky
string
127.0.0.1:6379> type key:token
hash
127.0.0.1:6379> hgetall key:token
"token_count"
"0"
"updateTime"
"1613805726567122"
127.0.0.1:6379> get key:leaky
"1613807035353864"

Installation

go get github.com/arpan491/API-RateLimiter

Usage

1. Create a Redis client

Using the "github.com/go-redis/redis" package, the library supports both master-slave and cluster Redis modes.

client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "xxx", // no password
DB: 0, // default DB
})

Or, for Redis cluster mode:

client := redis.NewClusterClient(&redis.ClusterOptions{
Addrs: []string{"127.0.0.1:6379"},
Password: "xxxx",
})

2. Create a RateLimiter

For a token bucket rate limiter that allows 200 operations per second:

limiter, err := ratelimit.NewTokenBucketRateLimiter(ctx, client, "push", time.Second, 200, 20, 5)

For 200 operations per minute:

limiter, err := ratelimit.NewTokenBucketRateLimiter(ctx, client, "push", time.Minute, 200, 20, 5)

2.1 Counter Algorithm

func NewCounterRateLimiter(ctx context.Context, client redis.Cmdable, key string, duration time.Duration,
throughput int, batchSize int) (Limiter, error)
ParameterDescription
keyRedis key name
durationTime interval for the allowed operation throughput
throughputAllowed number of operations within the given time interval
batchSizeNumber of operations retrieved from Redis in one batch

2.2 Token Bucket Algorithm

func NewTokenBucketRateLimiter(ctx context.Context, client redis.Cmdable, key string, duration time.Duration,
throughput int, maxCapacity int, batchSize int) (Limiter, error)
ParameterDescription
keyRedis key name
durationTime interval for the allowed operation throughput
throughputNumber of operations allowed within the given time interval
maxCapacityMaximum tokens that can be stored in the token bucket
batchSizeNumber of operations retrieved from Redis in one batch

2.3 Leaky Bucket Algorithm

func NewLeakyBucketLimiter(ctx context.Context, client redis.Cmdable, key string, duration time.Duration,
throughput int) (Limiter, error)
ParameterDescription
keyRedis key name
durationTime interval for the allowed operation throughput
throughputNumber of operations allowed within the given time interval

2.4 Sliding Time Window

NewSlideTimeWindowLimiter(throughput int, duration time.Duration, windowBuckets int) (Limiter, error)
ParameterDescription
durationTime interval for the allowed operation throughput
throughputNumber of operations allowed within the given time interval
windowBucketsNumber of buckets representing a segment of the time window (duration/windowBuckets)

Note: The sliding window limiter operates in-memory and doesn't use Redis, making it unsuitable for distributed rate-limiting scenarios.

Example

More examples

package main
import (
"context""fmt""github.com/go-redis/redis/v8""github.com/arpan491/API-RateLimiter"
slog "github.com/vearne/simplelog""sync""time"
)
funcconsume(r ratelimit.Limiter, group*sync.WaitGroup, c*ratelimit.Counter, targetCountint) {
defergroup.Done()
varokboolfor {
ok=trueerr:=r.Wait(context.Background())
slog.Debug("r.Wait:%v", err)
iferr!=nil {
ok=falseslog.Error("error:%v", err)
}
ifok {
value:=c.Incr()
slog.Debug("---value--:%v", value)
ifvalue>=targetCount {
break
}
}
}
}
funcmain() {
client:=redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "xxeQl*@nFE", // passwordDB: 0, // use default DB
})
limiter, err:=ratelimit.NewTokenBucketRateLimiter(
context.Background(),
client,
"key:token",
time.Second,
10,
5,
2,
)
iferr!=nil {
fmt.Println("error", err)
return
}
varwg sync.WaitGrouptotal:=50counter:=ratelimit.NewCounter()
start:=time.Now()
fori:=0; i<10; i++ {
wg.Add(1)
goconsume(limiter, &wg, counter, total)
}
wg.Wait()
cost:=time.Since(start)
fmt.Println("cost", cost, "rate", float64(total)/cost.Seconds())
}

Dependency

go-redis/redis

About

A Go-based distributed rate-limiting library using Redis, supporting Token Bucket, Leaky Bucket, Sliding Window, and Counter algorithms. It's lightweight, scalable, and thread-safe, ideal for API throttling with minimal overhead.

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

Distributed Rate-Limiting Library Using Redis

Overview

This library is designed to implement distributed rate limiting in a simple, no-nonsense way. Similar to how an ID generator works, the client retrieves data from Redis in batches (essentially just values). As long as these values aren't consumed, the rate limit is not exceeded.

Key Advantages

  • Minimal dependencies—only Redis is required, no additional services
  • Utilizes Redis' internal clock, so clients don't need synchronized clocks
  • Thread- and coroutine-safe
  • Low overhead on the system and minimal pressure on Redis

Important Notes

Different limiter types use different Redis key data structures, so they cannot share the same Redis key name.

Example:

127.0.0.1:6379> type key:leaky
string
127.0.0.1:6379> type key:token
hash
127.0.0.1:6379> hgetall key:token
"token_count"
"0"
"updateTime"
"1613805726567122"
127.0.0.1:6379> get key:leaky
"1613807035353864"

Installation

go get github.com/arpan491/API-RateLimiter

Usage

1. Create a Redis client

Using the "github.com/go-redis/redis" package, the library supports both master-slave and cluster Redis modes.

client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "xxx", // no password
DB: 0, // default DB
})

Or, for Redis cluster mode:

client := redis.NewClusterClient(&redis.ClusterOptions{
Addrs: []string{"127.0.0.1:6379"},
Password: "xxxx",
})

2. Create a RateLimiter

For a token bucket rate limiter that allows 200 operations per second:

limiter, err := ratelimit.NewTokenBucketRateLimiter(ctx, client, "push", time.Second, 200, 20, 5)

For 200 operations per minute:

limiter, err := ratelimit.NewTokenBucketRateLimiter(ctx, client, "push", time.Minute, 200, 20, 5)

2.1 Counter Algorithm

func NewCounterRateLimiter(ctx context.Context, client redis.Cmdable, key string, duration time.Duration,
throughput int, batchSize int) (Limiter, error)
ParameterDescription
keyRedis key name
durationTime interval for the allowed operation throughput
throughputAllowed number of operations within the given time interval
batchSizeNumber of operations retrieved from Redis in one batch

2.2 Token Bucket Algorithm

func NewTokenBucketRateLimiter(ctx context.Context, client redis.Cmdable, key string, duration time.Duration,
throughput int, maxCapacity int, batchSize int) (Limiter, error)
ParameterDescription
keyRedis key name
durationTime interval for the allowed operation throughput
throughputNumber of operations allowed within the given time interval
maxCapacityMaximum tokens that can be stored in the token bucket
batchSizeNumber of operations retrieved from Redis in one batch

2.3 Leaky Bucket Algorithm

func NewLeakyBucketLimiter(ctx context.Context, client redis.Cmdable, key string, duration time.Duration,
throughput int) (Limiter, error)
ParameterDescription
keyRedis key name
durationTime interval for the allowed operation throughput
throughputNumber of operations allowed within the given time interval

2.4 Sliding Time Window

NewSlideTimeWindowLimiter(throughput int, duration time.Duration, windowBuckets int) (Limiter, error)
ParameterDescription
durationTime interval for the allowed operation throughput
throughputNumber of operations allowed within the given time interval
windowBucketsNumber of buckets representing a segment of the time window (duration/windowBuckets)

Note: The sliding window limiter operates in-memory and doesn't use Redis, making it unsuitable for distributed rate-limiting scenarios.

Example

More examples

package main
import (
"context""fmt""github.com/go-redis/redis/v8""github.com/arpan491/API-RateLimiter"
slog "github.com/vearne/simplelog""sync""time"
)
funcconsume(r ratelimit.Limiter, group*sync.WaitGroup, c*ratelimit.Counter, targetCountint) {
defergroup.Done()
varokboolfor {
ok=trueerr:=r.Wait(context.Background())
slog.Debug("r.Wait:%v", err)
iferr!=nil {
ok=falseslog.Error("error:%v", err)
}
ifok {
value:=c.Incr()
slog.Debug("---value--:%v", value)
ifvalue>=targetCount {
break
}
}
}
}
funcmain() {
client:=redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "xxeQl*@nFE", // passwordDB: 0, // use default DB
})
limiter, err:=ratelimit.NewTokenBucketRateLimiter(
context.Background(),
client,
"key:token",
time.Second,
10,
5,
2,
)
iferr!=nil {
fmt.Println("error", err)
return
}
varwg sync.WaitGrouptotal:=50counter:=ratelimit.NewCounter()
start:=time.Now()
fori:=0; i<10; i++ {
wg.Add(1)
goconsume(limiter, &wg, counter, total)
}
wg.Wait()
cost:=time.Since(start)
fmt.Println("cost", cost, "rate", float64(total)/cost.Seconds())
}

Dependency

go-redis/redis

About

A Go-based distributed rate-limiting library using Redis, supporting Token Bucket, Leaky Bucket, Sliding Window, and Counter algorithms. It's lightweight, scalable, and thread-safe, ideal for API throttling with minimal overhead.

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Distributed Rate-Limiting Library Using Redis

Overview

This library is designed to implement distributed rate limiting in a simple, no-nonsense way. Similar to how an ID generator works, the client retrieves data from Redis in batches (essentially just values). As long as these values aren't consumed, the rate limit is not exceeded.

Key Advantages

  • Minimal dependencies—only Redis is required, no additional services
  • Utilizes Redis' internal clock, so clients don't need synchronized clocks
  • Thread- and coroutine-safe
  • Low overhead on the system and minimal pressure on Redis

Important Notes

Different limiter types use different Redis key data structures, so they cannot share the same Redis key name.

Example:

127.0.0.1:6379> type key:leaky
string
127.0.0.1:6379> type key:token
hash
127.0.0.1:6379> hgetall key:token
"token_count"
"0"
"updateTime"
"1613805726567122"
127.0.0.1:6379> get key:leaky
"1613807035353864"

Installation

go get github.com/arpan491/API-RateLimiter

Usage

1. Create a Redis client

Using the "github.com/go-redis/redis" package, the library supports both master-slave and cluster Redis modes.

client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "xxx", // no password
DB: 0, // default DB
})

Or, for Redis cluster mode:

client := redis.NewClusterClient(&redis.ClusterOptions{
Addrs: []string{"127.0.0.1:6379"},
Password: "xxxx",
})

2. Create a RateLimiter

For a token bucket rate limiter that allows 200 operations per second:

limiter, err := ratelimit.NewTokenBucketRateLimiter(ctx, client, "push", time.Second, 200, 20, 5)

For 200 operations per minute:

limiter, err := ratelimit.NewTokenBucketRateLimiter(ctx, client, "push", time.Minute, 200, 20, 5)

2.1 Counter Algorithm

func NewCounterRateLimiter(ctx context.Context, client redis.Cmdable, key string, duration time.Duration,
throughput int, batchSize int) (Limiter, error)
ParameterDescription
keyRedis key name
durationTime interval for the allowed operation throughput
throughputAllowed number of operations within the given time interval
batchSizeNumber of operations retrieved from Redis in one batch

2.2 Token Bucket Algorithm

func NewTokenBucketRateLimiter(ctx context.Context, client redis.Cmdable, key string, duration time.Duration,
throughput int, maxCapacity int, batchSize int) (Limiter, error)
ParameterDescription
keyRedis key name
durationTime interval for the allowed operation throughput
throughputNumber of operations allowed within the given time interval
maxCapacityMaximum tokens that can be stored in the token bucket
batchSizeNumber of operations retrieved from Redis in one batch

2.3 Leaky Bucket Algorithm

func NewLeakyBucketLimiter(ctx context.Context, client redis.Cmdable, key string, duration time.Duration,
throughput int) (Limiter, error)
ParameterDescription
keyRedis key name
durationTime interval for the allowed operation throughput
throughputNumber of operations allowed within the given time interval

2.4 Sliding Time Window

NewSlideTimeWindowLimiter(throughput int, duration time.Duration, windowBuckets int) (Limiter, error)
ParameterDescription
durationTime interval for the allowed operation throughput
throughputNumber of operations allowed within the given time interval
windowBucketsNumber of buckets representing a segment of the time window (duration/windowBuckets)

Note: The sliding window limiter operates in-memory and doesn't use Redis, making it unsuitable for distributed rate-limiting scenarios.

Example

More examples

package main
import (
"context""fmt""github.com/go-redis/redis/v8""github.com/arpan491/API-RateLimiter"
slog "github.com/vearne/simplelog""sync""time"
)
funcconsume(r ratelimit.Limiter, group*sync.WaitGroup, c*ratelimit.Counter, targetCountint) {
defergroup.Done()
varokboolfor {
ok=trueerr:=r.Wait(context.Background())
slog.Debug("r.Wait:%v", err)
iferr!=nil {
ok=falseslog.Error("error:%v", err)
}
ifok {
value:=c.Incr()
slog.Debug("---value--:%v", value)
ifvalue>=targetCount {
break
}
}
}
}
funcmain() {
client:=redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "xxeQl*@nFE", // passwordDB: 0, // use default DB
})
limiter, err:=ratelimit.NewTokenBucketRateLimiter(
context.Background(),
client,
"key:token",
time.Second,
10,
5,
2,
)
iferr!=nil {
fmt.Println("error", err)
return
}
varwg sync.WaitGrouptotal:=50counter:=ratelimit.NewCounter()
start:=time.Now()
fori:=0; i<10; i++ {
wg.Add(1)
goconsume(limiter, &wg, counter, total)
}
wg.Wait()
cost:=time.Since(start)
fmt.Println("cost", cost, "rate", float64(total)/cost.Seconds())
}

Dependency

go-redis/redis

About

A Go-based distributed rate-limiting library using Redis, supporting Token Bucket, Leaky Bucket, Sliding Window, and Counter algorithms. It's lightweight, scalable, and thread-safe, ideal for API throttling with minimal overhead.

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Distributed Rate-Limiting Library Using Redis

Overview

This library is designed to implement distributed rate limiting in a simple, no-nonsense way. Similar to how an ID generator works, the client retrieves data from Redis in batches (essentially just values). As long as these values aren't consumed, the rate limit is not exceeded.

Key Advantages

  • Minimal dependencies—only Redis is required, no additional services
  • Utilizes Redis' internal clock, so clients don't need synchronized clocks
  • Thread- and coroutine-safe
  • Low overhead on the system and minimal pressure on Redis

Important Notes

Different limiter types use different Redis key data structures, so they cannot share the same Redis key name.

Example:

127.0.0.1:6379> type key:leaky
string
127.0.0.1:6379> type key:token
hash
127.0.0.1:6379> hgetall key:token
"token_count"
"0"
"updateTime"
"1613805726567122"
127.0.0.1:6379> get key:leaky
"1613807035353864"

Installation

go get github.com/arpan491/API-RateLimiter

Usage

1. Create a Redis client

Using the "github.com/go-redis/redis" package, the library supports both master-slave and cluster Redis modes.

client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "xxx", // no password
DB: 0, // default DB
})

Or, for Redis cluster mode:

client := redis.NewClusterClient(&redis.ClusterOptions{
Addrs: []string{"127.0.0.1:6379"},
Password: "xxxx",
})

2. Create a RateLimiter

For a token bucket rate limiter that allows 200 operations per second:

limiter, err := ratelimit.NewTokenBucketRateLimiter(ctx, client, "push", time.Second, 200, 20, 5)

For 200 operations per minute:

limiter, err := ratelimit.NewTokenBucketRateLimiter(ctx, client, "push", time.Minute, 200, 20, 5)

2.1 Counter Algorithm

func NewCounterRateLimiter(ctx context.Context, client redis.Cmdable, key string, duration time.Duration,
throughput int, batchSize int) (Limiter, error)
ParameterDescription
keyRedis key name
durationTime interval for the allowed operation throughput
throughputAllowed number of operations within the given time interval
batchSizeNumber of operations retrieved from Redis in one batch

2.2 Token Bucket Algorithm

func NewTokenBucketRateLimiter(ctx context.Context, client redis.Cmdable, key string, duration time.Duration,
throughput int, maxCapacity int, batchSize int) (Limiter, error)
ParameterDescription
keyRedis key name
durationTime interval for the allowed operation throughput
throughputNumber of operations allowed within the given time interval
maxCapacityMaximum tokens that can be stored in the token bucket
batchSizeNumber of operations retrieved from Redis in one batch

2.3 Leaky Bucket Algorithm

func NewLeakyBucketLimiter(ctx context.Context, client redis.Cmdable, key string, duration time.Duration,
throughput int) (Limiter, error)
ParameterDescription
keyRedis key name
durationTime interval for the allowed operation throughput
throughputNumber of operations allowed within the given time interval

2.4 Sliding Time Window

NewSlideTimeWindowLimiter(throughput int, duration time.Duration, windowBuckets int) (Limiter, error)
ParameterDescription
durationTime interval for the allowed operation throughput
throughputNumber of operations allowed within the given time interval
windowBucketsNumber of buckets representing a segment of the time window (duration/windowBuckets)

Note: The sliding window limiter operates in-memory and doesn't use Redis, making it unsuitable for distributed rate-limiting scenarios.

Example

More examples

package main
import (
"context""fmt""github.com/go-redis/redis/v8""github.com/arpan491/API-RateLimiter"
slog "github.com/vearne/simplelog""sync""time"
)
funcconsume(r ratelimit.Limiter, group*sync.WaitGroup, c*ratelimit.Counter, targetCountint) {
defergroup.Done()
varokboolfor {
ok=trueerr:=r.Wait(context.Background())
slog.Debug("r.Wait:%v", err)
iferr!=nil {
ok=falseslog.Error("error:%v", err)
}
ifok {
value:=c.Incr()
slog.Debug("---value--:%v", value)
ifvalue>=targetCount {
break
}
}
}
}
funcmain() {
client:=redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "xxeQl*@nFE", // passwordDB: 0, // use default DB
})
limiter, err:=ratelimit.NewTokenBucketRateLimiter(
context.Background(),
client,
"key:token",
time.Second,
10,
5,
2,
)
iferr!=nil {
fmt.Println("error", err)
return
}
varwg sync.WaitGrouptotal:=50counter:=ratelimit.NewCounter()
start:=time.Now()
fori:=0; i<10; i++ {
wg.Add(1)
goconsume(limiter, &wg, counter, total)
}
wg.Wait()
cost:=time.Since(start)
fmt.Println("cost", cost, "rate", float64(total)/cost.Seconds())
}

Dependency

go-redis/redis

About

A Go-based distributed rate-limiting library using Redis, supporting Token Bucket, Leaky Bucket, Sliding Window, and Counter algorithms. It's lightweight, scalable, and thread-safe, ideal for API throttling with minimal overhead.

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

Distributed Rate-Limiting Library Using Redis

Overview

This library is designed to implement distributed rate limiting in a simple, no-nonsense way. Similar to how an ID generator works, the client retrieves data from Redis in batches (essentially just values). As long as these values aren't consumed, the rate limit is not exceeded.

Key Advantages

  • Minimal dependencies—only Redis is required, no additional services
  • Utilizes Redis' internal clock, so clients don't need synchronized clocks
  • Thread- and coroutine-safe
  • Low overhead on the system and minimal pressure on Redis

Important Notes

Different limiter types use different Redis key data structures, so they cannot share the same Redis key name.

Example:

127.0.0.1:6379> type key:leaky
string
127.0.0.1:6379> type key:token
hash
127.0.0.1:6379> hgetall key:token
"token_count"
"0"
"updateTime"
"1613805726567122"
127.0.0.1:6379> get key:leaky
"1613807035353864"

Installation

go get github.com/arpan491/API-RateLimiter

Usage

1. Create a Redis client

Using the "github.com/go-redis/redis" package, the library supports both master-slave and cluster Redis modes.

client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "xxx", // no password
DB: 0, // default DB
})

Or, for Redis cluster mode:

client := redis.NewClusterClient(&redis.ClusterOptions{
Addrs: []string{"127.0.0.1:6379"},
Password: "xxxx",
})

2. Create a RateLimiter

For a token bucket rate limiter that allows 200 operations per second:

limiter, err := ratelimit.NewTokenBucketRateLimiter(ctx, client, "push", time.Second, 200, 20, 5)

For 200 operations per minute:

limiter, err := ratelimit.NewTokenBucketRateLimiter(ctx, client, "push", time.Minute, 200, 20, 5)

2.1 Counter Algorithm

func NewCounterRateLimiter(ctx context.Context, client redis.Cmdable, key string, duration time.Duration,
throughput int, batchSize int) (Limiter, error)
ParameterDescription
keyRedis key name
durationTime interval for the allowed operation throughput
throughputAllowed number of operations within the given time interval
batchSizeNumber of operations retrieved from Redis in one batch

2.2 Token Bucket Algorithm

func NewTokenBucketRateLimiter(ctx context.Context, client redis.Cmdable, key string, duration time.Duration,
throughput int, maxCapacity int, batchSize int) (Limiter, error)
ParameterDescription
keyRedis key name
durationTime interval for the allowed operation throughput
throughputNumber of operations allowed within the given time interval
maxCapacityMaximum tokens that can be stored in the token bucket
batchSizeNumber of operations retrieved from Redis in one batch

2.3 Leaky Bucket Algorithm

func NewLeakyBucketLimiter(ctx context.Context, client redis.Cmdable, key string, duration time.Duration,
throughput int) (Limiter, error)
ParameterDescription
keyRedis key name
durationTime interval for the allowed operation throughput
throughputNumber of operations allowed within the given time interval

2.4 Sliding Time Window

NewSlideTimeWindowLimiter(throughput int, duration time.Duration, windowBuckets int) (Limiter, error)
ParameterDescription
durationTime interval for the allowed operation throughput
throughputNumber of operations allowed within the given time interval
windowBucketsNumber of buckets representing a segment of the time window (duration/windowBuckets)

Note: The sliding window limiter operates in-memory and doesn't use Redis, making it unsuitable for distributed rate-limiting scenarios.

Example

More examples

package main
import (
"context""fmt""github.com/go-redis/redis/v8""github.com/arpan491/API-RateLimiter"
slog "github.com/vearne/simplelog""sync""time"
)
funcconsume(r ratelimit.Limiter, group*sync.WaitGroup, c*ratelimit.Counter, targetCountint) {
defergroup.Done()
varokboolfor {
ok=trueerr:=r.Wait(context.Background())
slog.Debug("r.Wait:%v", err)
iferr!=nil {
ok=falseslog.Error("error:%v", err)
}
ifok {
value:=c.Incr()
slog.Debug("---value--:%v", value)
ifvalue>=targetCount {
break
}
}
}
}
funcmain() {
client:=redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "xxeQl*@nFE", // passwordDB: 0, // use default DB
})
limiter, err:=ratelimit.NewTokenBucketRateLimiter(
context.Background(),
client,
"key:token",
time.Second,
10,
5,
2,
)
iferr!=nil {
fmt.Println("error", err)
return
}
varwg sync.WaitGrouptotal:=50counter:=ratelimit.NewCounter()
start:=time.Now()
fori:=0; i<10; i++ {
wg.Add(1)
goconsume(limiter, &wg, counter, total)
}
wg.Wait()
cost:=time.Since(start)
fmt.Println("cost", cost, "rate", float64(total)/cost.Seconds())
}

Dependency

go-redis/redis

About

A Go-based distributed rate-limiting library using Redis, supporting Token Bucket, Leaky Bucket, Sliding Window, and Counter algorithms. It's lightweight, scalable, and thread-safe, ideal for API throttling with minimal overhead.

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages