{"id":34160190,"url":"https://github.com/souviks22/decentralized-rate-limiter","last_synced_at":"2026-06-09T07:31:03.192Z","repository":{"id":295499388,"uuid":"990193412","full_name":"souviks22/decentralized-rate-limiter","owner":"souviks22","description":"High performance API rate limiter optimized for availability","archived":false,"fork":false,"pushed_at":"2026-01-26T11:20:14.000Z","size":1892,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-27T01:01:46.648Z","etag":null,"topics":["api-security","libp2p","rate-limiting"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/souviks22.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-05-25T17:31:25.000Z","updated_at":"2026-01-26T11:20:18.000Z","dependencies_parsed_at":"2026-01-13T13:03:07.137Z","dependency_job_id":null,"html_url":"https://github.com/souviks22/decentralized-rate-limiter","commit_stats":null,"previous_names":["souviks22/decentralized-rate-limiter"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/souviks22/decentralized-rate-limiter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/souviks22%2Fdecentralized-rate-limiter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/souviks22%2Fdecentralized-rate-limiter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/souviks22%2Fdecentralized-rate-limiter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/souviks22%2Fdecentralized-rate-limiter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/souviks22","download_url":"https://codeload.github.com/souviks22/decentralized-rate-limiter/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/souviks22%2Fdecentralized-rate-limiter/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34096950,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-09T02:00:06.510Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api-security","libp2p","rate-limiting"],"created_at":"2025-12-15T08:19:36.636Z","updated_at":"2026-06-09T07:31:03.187Z","avatar_url":"https://github.com/souviks22.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Decentralized Rate Limiter\n\n[![Go Report Card](https://goreportcard.com/badge/github.com/souviks22/decentralized-rate-limiter)](https://goreportcard.com/report/github.com/souviks22/decentralized-rate-limiter)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n[![Made with Go](https://img.shields.io/badge/Made%20with-Go-1f425f.svg)](https://golang.org)\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/souviks22/decentralized-rate-limiter/issues)\n\n\n\u003e **A decentralized rate limiter that continues to function under network partitions, built to study why centralized Redis-based designs break at scale.**\n\nMost production rate limiters assume a **central truth** — a single Redis instance, a leader, or a globally consistent counter.\n\nThis project assumes the opposite:\n**coordination is expensive, failures are normal, and partitions happen.**\n\nEach node enforces rate limits **locally**, never blocking on global state, and reconciles usage **eventually** using CRDTs and peer-to-peer gossip.\n\n**Design goal**\n\n\u003e *Never block locally, never trust globally — and still converge.*\n\nThis design targets infra teams operating across regions where availability and latency matter more than strict global enforcement.\n\n---\n\n## Why This Exists (and What Breaks in Practice)\n\nCentralized rate limiting (Redis, API gateways, single coordinators) works well — **until it doesn’t**:\n\n* cross-region latency leaks into the hot path,\n* a single dependency becomes a blast radius,\n* failure handling turns into policy ambiguity (“should we allow or deny?”).\n\nIn large distributed systems, **availability often matters more than perfect precision**.\n\nThis project explores a different trade-off:\n\n* allow **temporary divergence**,\n* guarantee **eventual convergence**,\n* keep the request path **fast and local**.\n\n---\n\n## The Core Idea (High-Level)\n\nEvery node is a full authority for rate limiting.\n\n```\nClient → Any Node → Local Decision → Async Reconciliation\n```\n\n* No global coordinator\n* No synchronous cross-node calls\n* No blocking on consensus\n\nSynchronization happens **off the hot path**.\n\nIf the node is alive, it answers.\n\n---\n\n## How It Works (End-to-End)\n\n```\n                           ┌──────────────────────────┐\n                           │      Client Request      │\n                           └────────────┬─────────────┘\n                                        │\n                                        ▼\n                         ┌────────────────────────────────┐\n                         │        Peer Node (A)           │\n                         │ ────────────────────────────── │\n                         │  1. Receive userID request     │\n                         │  2. Check in-memory LRU        │\n                         │  3. If miss, load from disk    │\n                         │  4. TokenBucket.consume()      │\n                         │  5. Record CRDT delta          │\n                         └────────────┬───────────────────┘\n                                      │\n        ┌─────────────────────────────┼────────────────────────────┐\n        ▼                             ▼                            ▼\n┌────────────────┐         ┌──────────────────────┐        ┌────────────────────┐\n│ In-Memory LRU  │◄───────▶│ Disk Storage (/data) │        │  CRDT Delta Cache  │\n│  Token Buckets │         └──────────────────────┘        └────────▲───────────┘\n└────▲───────────┘                                           ┌──────┴────────┐\n     │                                                       │ libp2p Gossip │\n     │                                                       └──────┬────────┘\n     │                                                              │\n     │     Broadcast deltas (every 100ms or 100 entries)            │\n     └──────────────────────────────────────────────────────────────┘\n                                                                    │\n                                                 ┌──────────────────┴─────────────────┐\n                                                 ▼                                    ▼\n                                     ┌─────────────────────┐                 ┌─────────────────────┐\n                                     │    Peer Node B      │◄───────────────▶│     Peer Node C     │\n                                     │  (Same architecture)│     P2P Sync    │  (Same architecture)│\n                                     └─────────────────────┘                 └─────────────────────┘\n```\n\n### Critical invariant\n\n\u003e **The request path never waits for gossip.**\n\nLocal decisions are final *for that node*.\n\n---\n\n## Design Components \u0026 Trade-offs\n\n### Token Bucket (Local Authority)\n\nEach user is governed by a standard token bucket:\n\n* burst capacity,\n* steady refill rate.\n\nWhy keep this simple:\n\n* constant-time decisions,\n* predictable latency,\n* easy reasoning under load.\n\nNo hidden concurrency tricks. Thread safety is explicit.\n\n---\n\n### CRDT Deltas (Eventual Global Convergence)\n\nNodes exchange **deltas**, not full state.\n\nWhy deltas:\n\n* small payloads,\n* less merge ambiguity,\n* faster convergence.\n\nCRDT properties:\n\n* commutative\n* idempotent\n* monotonic\n\nThis guarantees convergence even under:\n\n* message loss,\n* duplication,\n* reordering.\n\n**Exact precision is not promised.\nBounded divergence is.**\n\n---\n\n### libp2p Gossip (Coordination Without Leaders)\n\nThere is:\n\n* no leader,\n* no coordinator,\n* no central broker.\n\nNodes discover peers and exchange deltas via libp2p gossip.\n\nFailures are treated as routine:\n\n* if a node disappears, others continue,\n* when it returns, state reconverges.\n\n---\n\n### LRU + Disk (Scaling Beyond Memory)\n\nKeeping all users in memory doesn’t scale.\n\nSo the system:\n\n* keeps hot buckets in an **in-memory LRU**,\n* evicts cold buckets to **disk**,\n* reloads lazily on access.\n\nThis keeps:\n\n* memory bounded,\n* hot paths fast,\n* cold users cheap.\n\nDurability is pragmatic, not transactional.\n\n---\n\n## Performance Snapshot (3-node mesh)\n\n| Metric                 | Observation    |\n| ---------------------- | -------------- |\n| Throughput per node    | ~3,000 req/sec |\n| p99 request latency    | ~2 ms          |\n| p99 gossip convergence | ~2 ms          |\n| Gossip payload size    | ~3 KB          |\n\nInterpretation:\n\n* request latency is dominated by **local execution**,\n* coordination cost is **asynchronous and amortized**.\n\n---\n\n## Failure Semantics (Explicit by Design)\n\nThis system chooses **availability over strict correctness**.\n\n* **Network partitions** → nodes operate independently\n* **Node crashes** → local state lost, global state reconverges\n* **Delayed gossip** → temporary over-allowing possible\n\nObserved behavior:\n\n* ~15% bounded over-acceptance at 3 nodes\n* grows roughly linearly with node count\n\nThis is acceptable for:\n\n* abuse mitigation,\n* fairness control,\n* soft enforcement.\n\nIt is **not acceptable** for strict accounting.\n\nThis complexity is the cost paid to remove a global coordinator from the hot path.\n\n---\n\n## Design Walkthrough (Optional Deep Dive)\n\nFor a longer-form architectural walkthrough and design rationale, see:\n[**High-Level Design of a Decentralized Rate Limiter**](https://medium.com/@souviksarkar2k3/high-level-design-of-a-decentralized-rate-limiter-1bcc33154ce9)\n\n---\n\n## When *Not* to Use This\n\nThis design is **not** a good fit if:\n\n* every request must respect a single global counter,\n* over-allowing is unacceptable (e.g., billing),\n* centralized infrastructure is cheap and reliable for you.\n\nIn those cases, a Redis-backed or coordinator-based design is simpler and safer.\n\n---\n\n## Example Usage\n\n```go\nlimiter := drl.NewRateLimiter(10, 1) // capacity, refill rate\n\nif limiter.AllowRequest(\"user-123\") {\n    // request proceeds\n} else {\n    // rate limited locally\n}\n```\n\nThe API stays intentionally boring.\nThe complexity lives inside.\n\n---\n\n## What This Project Is (and Isn’t)\n\nThis project is **not** about replacing Redis.\n\nIt’s about answering a harder question:\n\n\u003e *What does rate limiting look like when the system itself refuses to be centralized?*\n\nIf that question matters in your environment, this design might be useful.\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsouviks22%2Fdecentralized-rate-limiter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsouviks22%2Fdecentralized-rate-limiter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsouviks22%2Fdecentralized-rate-limiter/lists"}