.
675 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | This repository contains free resources to learn System Design concepts and prepare for interviews.
6 |
7 | 👉 Subscribe to my [AlgoMaster Newsletter](https://bit.ly/amghsd) and get a **FREE System Design Interview Handbook** in your inbox.
8 |
9 | ✅ If you are new to System Design, start here: [System Design was HARD until I Learned these 30 Concepts](https://blog.algomaster.io/p/30-system-design-concepts)
10 |
11 | ## 📌 System Design Key Concepts
12 | - [Scalability](https://blog.algomaster.io/p/scalability)
13 | - [Availability](https://blog.algomaster.io/p/system-design-what-is-availability)
14 | - [CAP Theorem](https://blog.algomaster.io/p/cap-theorem-explained)
15 | - [ACID Transactions](https://blog.algomaster.io/p/what-are-acid-transactions-in-databases)
16 | - [Consistent Hashing](https://blog.algomaster.io/p/consistent-hashing-explained)
17 | - [Rate Limiting](https://blog.algomaster.io/p/rate-limiting-algorithms-explained-with-code)
18 | - [SPOF](https://blog.algomaster.io/p/system-design-how-to-avoid-single-point-of-failures)
19 | - [Fault Tolerance](https://www.cockroachlabs.com/blog/what-is-fault-tolerance/)
20 | - [Consensus Algorithms](https://medium.com/@sourabhatta1819/consensus-in-distributed-system-ac79f8ba2b8c)
21 | - [Gossip Protocol](http://highscalability.com/blog/2023/7/16/gossip-protocol-explained.html)
22 | - [Service Discovery](https://blog.algomaster.io/p/service-discovery-in-distributed-systems)
23 | - [API Design](https://abdulrwahab.medium.com/api-architecture-best-practices-for-designing-rest-apis-bf907025f5f)
24 | - [Disaster Recovery](https://cloud.google.com/learn/what-is-disaster-recovery)
25 | - [Distributed Tracing](https://www.dynatrace.com/news/blog/what-is-distributed-tracing/)
26 |
27 | ## 🛠️ System Design Building Blocks
28 | - [APIs](https://blog.algomaster.io/p/whats-an-api)
29 | - [Content Delivery Network (CDN)](https://blog.algomaster.io/p/content-delivery-networks)
30 | - [Proxy vs Reverse Proxy](https://blog.algomaster.io/p/proxy-vs-reverse-proxy-explained)
31 | - [Domain Name System (DNS)](https://www.cloudflare.com/learning/dns/what-is-dns/)
32 | - [Caching](https://blog.algomaster.io/p/4d7d6f8a-6803-4c7b-85ca-864c87c2cbf2)
33 | - [Caching Strategies](https://blog.algomaster.io/p/top-5-caching-strategies-explained)
34 | - [Distributed Caching](https://blog.algomaster.io/p/distributed-caching)
35 | - [API Gateway](https://blog.algomaster.io/p/what-is-an-api-gateway)
36 | - [Load Balancing](https://blog.algomaster.io/p/load-balancing-algorithms-explained-with-code)
37 | - [Databases Types](https://blog.algomaster.io/p/15-types-of-databases)
38 | - [SQL vs NoSQL](https://blog.algomaster.io/p/sql-vs-nosql-7-key-differences)
39 | - [Database Indexes](https://blog.algomaster.io/p/a-detailed-guide-on-database-indexes)
40 | - [Consistency Patterns](https://systemdesign.one/consistency-patterns/)
41 | - [HeartBeats](https://blog.algomaster.io/p/heartbeats-in-distributed-systems)
42 | - [Circuit Breaker](https://medium.com/geekculture/design-patterns-for-microservices-circuit-breaker-pattern-276249ffab33)
43 | - [Idempotency](https://blog.algomaster.io/p/idempotency-in-distributed-systems)
44 | - [Database Scaling](https://blog.algomaster.io/p/system-design-how-to-scale-a-database)
45 | - [Data Replication](https://redis.com/blog/what-is-data-replication/)
46 | - [Data Redundancy](https://blog.algomaster.io/p/489440f1-9c80-4241-9ec8-de156964c3b9)
47 | - [Database Sharding](https://blog.algomaster.io/p/what-is-database-sharding)
48 | - [Database Architectures](https://www.mongodb.com/developer/products/mongodb/active-active-application-architectures/)
49 | - [Failover](https://www.druva.com/glossary/what-is-a-failover-definition-and-related-faqs)
50 | - [Bloom Filters](https://blog.algomaster.io/p/bloom-filters)
51 | - [Message Queues](https://blog.algomaster.io/p/message-queues)
52 | - [WebSockets](https://blog.algomaster.io/p/websockets)
53 | - [Checksums](https://blog.algomaster.io/p/what-are-checksums)
54 | - [Microservices Guidelines](https://newsletter.systemdesign.one/p/netflix-microservices)
55 | - [Distributed Locking](https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html)
56 |
57 | ## ⚖️ System Design Tradeoffs
58 | - [Top 15 Tradeoffs](https://blog.algomaster.io/p/system-design-top-15-trade-offs)
59 | - [Vertical vs Horizontal Scaling](https://blog.algomaster.io/p/system-design-vertical-vs-horizontal-scaling)
60 | - [Concurrency vs Parallelism](https://blog.algomaster.io/p/concurrency-vs-parallelism)
61 | - [Long Polling vs WebSockets](https://blog.algomaster.io/p/long-polling-vs-websockets)
62 | - [Batch vs Stream Processing](https://blog.algomaster.io/p/batch-processing-vs-stream-processing)
63 | - [Stateful vs Stateless Design](https://blog.algomaster.io/p/741dff8e-10ea-413e-8dd2-be57434917d2)
64 | - [Strong vs Eventual Consistency](https://blog.algomaster.io/p/7d9da525-fe25-4e16-94e8-8056e7c57934)
65 | - [Read-Through vs Write-Through Cache](https://blog.algomaster.io/p/59cae60d-9717-4e20-a59e-759e370db4e5)
66 | - [Push vs Pull Architecture](https://blog.algomaster.io/p/af5fe2fe-9a4f-4708-af43-184945a243af)
67 | - [REST vs RPC](https://blog.algomaster.io/p/106604fb-b746-41de-88fb-60e932b2ff68)
68 | - [Synchronous vs. asynchronous communications](https://blog.algomaster.io/p/aec1cebf-6060-45a7-8e00-47364ca70761)
69 | - [Latency vs Throughput](https://aws.amazon.com/compare/the-difference-between-throughput-and-latency/)
70 |
71 | ## 🖇️ System Design Architectural Patterns
72 | - [Client-Server Architecture](https://blog.algomaster.io/p/4585cf8e-30a4-4295-936f-308a25cb716c)
73 | - [Microservices Architecture](https://medium.com/hashmapinc/the-what-why-and-how-of-a-microservices-architecture-4179579423a9)
74 | - [Serverless Architecture](https://blog.algomaster.io/p/2edeb23b-cfa5-4b24-845e-3f6f7a39d162)
75 | - [Event-Driven Architecture](https://www.confluent.io/learn/event-driven-architecture/)
76 | - [Peer-to-Peer (P2P) Architecture](https://www.spiceworks.com/tech/networking/articles/what-is-peer-to-peer/)
77 |
78 | ## ✅ [How to Answer a System Design Interview Problem](https://blog.algomaster.io/p/how-to-answer-a-system-design-interview-problem)
79 |
80 | ## 💻 System Design Interview Problems
81 | ### Easy
82 | - [Design URL Shortener like TinyURL](https://blog.algomaster.io/p/design-a-url-shortener)
83 | - [Design Leaderboard](https://systemdesign.one/leaderboard-system-design/)
84 | - [Design Content Delivery Network (CDN)](https://www.youtube.com/watch?v=8zX0rue2Hic)
85 | - [Design Parking Garage](https://www.youtube.com/watch?v=NtMvNh0WFVM)
86 | - [Design Vending Machine](https://www.youtube.com/watch?v=D0kDMUgo27c)
87 | - [Design Distributed Key-Value Store](https://www.youtube.com/watch?v=rnZmdmlR-2M)
88 | - [Design Distributed Cache](https://www.youtube.com/watch?v=iuqZvajTOyA)
89 | - [Design Authentication System](https://www.youtube.com/watch?v=uj_4vxm9u90)
90 | - [Design Unified Payments Interface (UPI)](https://www.youtube.com/watch?v=QpLy0_c_RXk)
91 | ### Medium
92 | - [Design WhatsApp](https://blog.algomaster.io/p/design-a-chat-application-like-whatsapp)
93 | - [Design Spotify](https://blog.algomaster.io/p/design-spotify-system-design-interview)
94 | - [Design Distributed Job Scheduler](https://blog.algomaster.io/p/design-a-distributed-job-scheduler)
95 | - [Design a Scalable Notification Service](https://blog.algomaster.io/p/design-a-scalable-notification-service)
96 | - [Design Instagram](https://www.youtube.com/watch?v=VJpfO6KdyWE)
97 | - [Design Tinder](https://www.youtube.com/watch?v=tndzLznxq40)
98 | - [Design Facebook](https://www.youtube.com/watch?v=9-hjBGxuiEs)
99 | - [Design Twitter](https://www.youtube.com/watch?v=wYk0xPP_P_8)
100 | - [Design Reddit](https://www.youtube.com/watch?v=KYExYE_9nIY)
101 | - [Design Netflix](https://www.youtube.com/watch?v=psQzyFfsUGU)
102 | - [Design Youtube](https://www.youtube.com/watch?v=jPKTo1iGQiE)
103 | - [Design Google Search](https://www.youtube.com/watch?v=CeGtqouT8eA)
104 | - [Design E-commerce Store like Amazon](https://www.youtube.com/watch?v=EpASu_1dUdE)
105 | - [Design TikTok](https://www.youtube.com/watch?v=Z-0g_aJL5Fw)
106 | - [Design Shopify](https://www.youtube.com/watch?v=lEL4F_0J3l8)
107 | - [Design Airbnb](https://www.youtube.com/watch?v=YyOXt2MEkv4)
108 | - [Design Autocomplete for Search Engines](https://www.youtube.com/watch?v=us0qySiUsGU)
109 | - [Design Rate Limiter](https://www.youtube.com/watch?v=mhUQe4BKZXs)
110 | - [Design Distributed Message Queue like Kafka](https://www.youtube.com/watch?v=iJLL-KPqBpM)
111 | - [Design Flight Booking System](https://www.youtube.com/watch?v=qsGcfVGvFSs)
112 | - [Design Online Code Editor](https://www.youtube.com/watch?v=07jkn4jUtso)
113 | - [Design Stock Exchange System](https://www.youtube.com/watch?v=dUMWMZmMsVE)
114 | - [Design an Analytics Platform (Metrics & Logging)](https://www.youtube.com/watch?v=kIcq1_pBQSY)
115 | - [Design Payment System](https://www.youtube.com/watch?v=olfaBgJrUBI)
116 | - [Design a Digital Wallet](https://www.youtube.com/watch?v=4ijjIUeq6hE)
117 | ### Hard
118 | - [Design Location Based Service like Yelp](https://www.youtube.com/watch?v=M4lR_Va97cQ)
119 | - [Design Uber](https://www.youtube.com/watch?v=umWABit-wbk)
120 | - [Design Food Delivery App like Doordash](https://www.youtube.com/watch?v=iRhSAR3ldTw)
121 | - [Design Google Docs](https://www.youtube.com/watch?v=2auwirNBvGg)
122 | - [Design Google Maps](https://www.youtube.com/watch?v=jk3yvVfNvds)
123 | - [Design Zoom](https://www.youtube.com/watch?v=G32ThJakeHk)
124 | - [Design Distributed Counter](https://systemdesign.one/distributed-counter-system-design/)
125 | - [Design File Sharing System like Dropbox](https://www.youtube.com/watch?v=U0xTu6E2CT8)
126 | - [Design Ticket Booking System like BookMyShow](https://www.youtube.com/watch?v=lBAwJgoO3Ek)
127 | - [Design Distributed Web Crawler](https://www.youtube.com/watch?v=BKZxZwUgL3Y)
128 | - [Design Code Deployment System](https://www.youtube.com/watch?v=q0KGYwNbf-0)
129 | - [Design Distributed Cloud Storage like S3](https://www.youtube.com/watch?v=UmWtcgC96X8)
130 | - [Design Distributed Locking Service](https://www.youtube.com/watch?v=v7x75aN9liM)
131 | - [Design Slack](https://systemdesign.one/slack-architecture/)
132 | - [Design Live Comments](https://systemdesign.one/live-comment-system-design/)
133 |
134 | ## 📚 Books
135 | - [Designing Data-Intensive Applications](https://www.amazon.in/dp/9352135245)
136 |
137 | ## 📩 Newsletters
138 | - [AlgoMaster Newsletter](https://blog.algomaster.io/)
139 |
140 | ## 📺 YouTube Channels
141 | - [Tech Dummies Narendra L](https://www.youtube.com/@TechDummiesNarendraL)
142 | - [Gaurav Sen](https://www.youtube.com/@gkcs)
143 | - [codeKarle](https://www.youtube.com/@codeKarle)
144 | - [ByteByteGo](https://www.youtube.com/@ByteByteGo)
145 | - [System Design Interview](https://www.youtube.com/@SystemDesignInterview)
146 | - [sudoCODE](https://www.youtube.com/@sudocode)
147 | - [Success in Tech](https://www.youtube.com/@SuccessinTech/videos)
148 |
149 | ## 📜 Must-Read Engineering Articles
150 | - [How Discord stores trillions of messages](https://discord.com/blog/how-discord-stores-trillions-of-messages)
151 | - [Building In-Video Search at Netflix](https://netflixtechblog.com/building-in-video-search-936766f0017c)
152 | - [How Canva scaled Media uploads from Zero to 50 Million per Day](https://www.canva.dev/blog/engineering/from-zero-to-50-million-uploads-per-day-scaling-media-at-canva/)
153 | - [How Airbnb avoids double payments in a Distributed Payments System](https://medium.com/airbnb-engineering/avoiding-double-payments-in-a-distributed-payments-system-2981f6b070bb)
154 | - [Stripe’s payments APIs - The first 10 years](https://stripe.com/blog/payment-api-design)
155 | - [Real time messaging at Slack](https://slack.engineering/real-time-messaging/)
156 |
157 | ## 🗞️ Must-Read Distributed Systems Papers
158 | - [Paxos: The Part-Time Parliament](https://lamport.azurewebsites.net/pubs/lamport-paxos.pdf)
159 | - [MapReduce: Simplified Data Processing on Large Clusters](https://research.google.com/archive/mapreduce-osdi04.pdf)
160 | - [The Google File System](https://static.googleusercontent.com/media/research.google.com/en//archive/gfs-sosp2003.pdf)
161 | - [Dynamo: Amazon’s Highly Available Key-value Store](https://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf)
162 | - [Kafka: a Distributed Messaging System for Log Processing](https://notes.stephenholiday.com/Kafka.pdf)
163 | - [Spanner: Google’s Globally-Distributed Database](https://static.googleusercontent.com/media/research.google.com/en//archive/spanner-osdi2012.pdf)
164 | - [Bigtable: A Distributed Storage System for Structured Data](https://static.googleusercontent.com/media/research.google.com/en//archive/bigtable-osdi06.pdf)
165 | - [ZooKeeper: Wait-free coordination for Internet-scale systems](https://www.usenix.org/legacy/event/usenix10/tech/full_papers/Hunt.pdf)
166 | - [The Log-Structured Merge-Tree (LSM-Tree)](https://www.cs.umb.edu/~poneil/lsmtree.pdf)
167 | - [The Chubby lock service for loosely-coupled distributed systems](https://static.googleusercontent.com/media/research.google.com/en//archive/chubby-osdi06.pdf)
168 |
169 | ---
170 |
171 |
172 | If you find this resource helpful, please give it a star ⭐️ and share it with others!
173 |
174 |
--------------------------------------------------------------------------------
/diagrams/interview-template.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ashishps1/awesome-system-design-resources/ca2bfbcf3176612614d62d493f8772538a134146/diagrams/interview-template.png
--------------------------------------------------------------------------------
/diagrams/system-design-github-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ashishps1/awesome-system-design-resources/ca2bfbcf3176612614d62d493f8772538a134146/diagrams/system-design-github-logo.png
--------------------------------------------------------------------------------
/implementations/java/consistent_hashing/ConsistentHashing.java:
--------------------------------------------------------------------------------
1 | package implementations.java.consistent_hashing;
2 |
3 | import java.security.MessageDigest;
4 | import java.security.NoSuchAlgorithmException;
5 | import java.util.*;
6 |
7 | public class ConsistentHashing {
8 | private final int numReplicas; // Number of virtual nodes per server
9 | private final TreeMap ring; // Hash ring storing virtual nodes
10 | private final Set servers; // Set of physical servers
11 |
12 | public ConsistentHashing(List servers, int numReplicas) {
13 | this.numReplicas = numReplicas;
14 | this.ring = new TreeMap<>();
15 | this.servers = new HashSet<>();
16 |
17 | // Add each server to the hash ring
18 | for (String server : servers) {
19 | addServer(server);
20 | }
21 | }
22 |
23 | private long hash(String key) {
24 | try {
25 | MessageDigest md = MessageDigest.getInstance("MD5");
26 | md.update(key.getBytes());
27 | byte[] digest = md.digest();
28 | return ((long) (digest[0] & 0xFF) << 24) |
29 | ((long) (digest[1] & 0xFF) << 16) |
30 | ((long) (digest[2] & 0xFF) << 8) |
31 | ((long) (digest[3] & 0xFF));
32 | } catch (NoSuchAlgorithmException e) {
33 | throw new RuntimeException("MD5 algorithm not found", e);
34 | }
35 | }
36 |
37 | public void addServer(String server) {
38 | servers.add(server);
39 | for (int i = 0; i < numReplicas; i++) {
40 | long hash = hash(server + "-" + i); // Unique hash for each virtual node
41 | ring.put(hash, server);
42 | }
43 | }
44 |
45 | public void removeServer(String server) {
46 | if (servers.remove(server)) {
47 | for (int i = 0; i < numReplicas; i++) {
48 | long hash = hash(server + "-" + i);
49 | ring.remove(hash);
50 | }
51 | }
52 | }
53 |
54 | public String getServer(String key) {
55 | if (ring.isEmpty()) {
56 | return null; // No servers available
57 | }
58 |
59 | long hash = hash(key);
60 | // Find the closest server in a clockwise direction
61 | Map.Entry entry = ring.ceilingEntry(hash);
62 | if (entry == null) {
63 | // If we exceed the highest node, wrap around to the first node
64 | entry = ring.firstEntry();
65 | }
66 | return entry.getValue();
67 | }
68 |
69 | public static void main(String[] args) {
70 | List servers = Arrays.asList("S0", "S1", "S2", "S3", "S4", "S5");
71 | ConsistentHashing ch = new ConsistentHashing(servers, 3);
72 |
73 | // Step 2: Assign requests (keys) to servers
74 | System.out.println("UserA is assigned to: " + ch.getServer("UserA"));
75 | System.out.println("UserB is assigned to: " + ch.getServer("UserB"));
76 |
77 | // Step 3: Add a new server dynamically
78 | ch.addServer("S6");
79 | System.out.println("UserA is now assigned to: " + ch.getServer("UserA"));
80 |
81 | // Step 4: Remove a server dynamically
82 | ch.removeServer("S2");
83 | System.out.println("UserB is now assigned to: " + ch.getServer("UserB"));
84 | }
85 | }
86 |
87 |
--------------------------------------------------------------------------------
/implementations/java/load_balancing_algorithms/IPHash.java:
--------------------------------------------------------------------------------
1 | import java.util.List;
2 |
3 | public class IPHash {
4 | private List servers;
5 |
6 | public IPHash(List servers) {
7 | this.servers = servers;
8 | }
9 |
10 | public String getNextServer(String clientIp) {
11 | int hash = clientIp.hashCode();
12 | int serverIndex = Math.abs(hash) % servers.size();
13 | return servers.get(serverIndex);
14 | }
15 |
16 | public static void main(String[] args) {
17 | List servers = List.of("Server1", "Server2", "Server3");
18 | IPHash ipHash = new IPHash(servers);
19 |
20 | List clientIps = List.of("192.168.0.1", "192.168.0.2", "192.168.0.3");
21 | for (String ip : clientIps) {
22 | System.out.println(ip + " is mapped to " + ipHash.getNextServer(ip));
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/implementations/java/load_balancing_algorithms/LeastConnections.java:
--------------------------------------------------------------------------------
1 | import java.util.HashMap;
2 | import java.util.List;
3 | import java.util.Map;
4 |
5 | public class LeastConnections {
6 | private Map serverConnections;
7 |
8 | public LeastConnections(List servers) {
9 | serverConnections = new HashMap<>();
10 | for (String server : servers) {
11 | serverConnections.put(server, 0);
12 | }
13 | }
14 |
15 | public String getNextServer() {
16 | return serverConnections.entrySet().stream()
17 | .min(Map.Entry.comparingByValue())
18 | .map(Map.Entry::getKey)
19 | .orElse(null);
20 | }
21 |
22 | public void releaseConnection(String server) {
23 | serverConnections.computeIfPresent(server, (k, v) -> v > 0 ? v - 1 : 0);
24 | }
25 |
26 | public static void main(String[] args) {
27 | List servers = List.of("Server1", "Server2", "Server3");
28 | LeastConnections leastConnectionsLB = new LeastConnections(servers);
29 |
30 | for (int i = 0; i < 6; i++) {
31 | String server = leastConnectionsLB.getNextServer();
32 | System.out.println(server);
33 | leastConnectionsLB.releaseConnection(server);
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/implementations/java/load_balancing_algorithms/LeastResponseTime.java:
--------------------------------------------------------------------------------
1 | import java.util.ArrayList;
2 | import java.util.List;
3 | import java.util.Random;
4 |
5 | public class LeastResponseTime {
6 | private List servers;
7 | private List responseTimes;
8 |
9 | public LeastResponseTime(List servers) {
10 | this.servers = servers;
11 | this.responseTimes = new ArrayList<>(servers.size());
12 | for (int i = 0; i < servers.size(); i++)
13 | responseTimes.add(0.0);
14 | }
15 |
16 | public String getNextServer() {
17 | double minResponseTime = responseTimes.get(0);
18 | int minIndex = 0;
19 | for (int i = 1; i < responseTimes.size(); i++) {
20 | if (responseTimes.get(i) < minResponseTime) {
21 | minResponseTime = responseTimes.get(i);
22 | minIndex = i;
23 | }
24 | }
25 | return servers.get(minIndex);
26 | }
27 |
28 | public void updateResponseTime(String server, double responseTime) {
29 | int index = servers.indexOf(server);
30 | responseTimes.set(index, responseTime);
31 | }
32 |
33 | public static double simulateResponseTime(String server) {
34 | // Simulating response time with random delay
35 | Random random = new Random();
36 | double delay = 0.1 + (1.0 - 0.1) * random.nextDouble();
37 | try {
38 | Thread.sleep((long) (delay * 1000));
39 | } catch (InterruptedException e) {
40 | e.printStackTrace();
41 | }
42 | return delay;
43 | }
44 |
45 | public static void main(String[] args) {
46 | List servers = List.of("Server1", "Server2", "Server3");
47 | LeastResponseTime leastResponseTimeLB = new LeastResponseTime(servers);
48 |
49 | for (int i = 0; i < 6; i++) {
50 | String server = leastResponseTimeLB.getNextServer();
51 | System.out.println("Request " + (i + 1) + " -> " + server);
52 | double responseTime = simulateResponseTime(server);
53 | leastResponseTimeLB.updateResponseTime(server, responseTime);
54 | System.out.println("Response Time: " + String.format("%.2f", responseTime) + "s");
55 | }
56 |
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/implementations/java/load_balancing_algorithms/RoundRobin.java:
--------------------------------------------------------------------------------
1 | import java.util.List;
2 | import java.util.concurrent.atomic.AtomicInteger;
3 |
4 | public class RoundRobin {
5 | private List servers;
6 | private AtomicInteger index;
7 |
8 | public RoundRobin(List servers) {
9 | this.servers = servers;
10 | this.index = new AtomicInteger(-1);
11 | }
12 |
13 | public String getNextServer() {
14 | int currentIndex = index.incrementAndGet() % servers.size();
15 | return servers.get(currentIndex);
16 | }
17 |
18 | public static void main(String[] args) {
19 | List servers = List.of("Server1", "Server2", "Server3");
20 | RoundRobin roundRobinLB = new RoundRobin(servers);
21 |
22 | for (int i = 0; i < 6; i++) {
23 | System.out.println(roundRobinLB.getNextServer());
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/implementations/java/load_balancing_algorithms/WeightedRoundRobin.java:
--------------------------------------------------------------------------------
1 | import java.util.List;
2 |
3 | public class WeightedRoundRobin {
4 | private List servers;
5 | private List weights;
6 | private int currentIndex;
7 | private int currentWeight;
8 |
9 | public WeightedRoundRobin(List servers, List weights) {
10 | this.servers = servers;
11 | this.weights = weights;
12 | this.currentIndex = -1;
13 | this.currentWeight = 0;
14 | }
15 |
16 | public String getNextServer() {
17 | while (true) {
18 | currentIndex = (currentIndex + 1) % servers.size();
19 | if (currentIndex == 0) {
20 | currentWeight--;
21 | if (currentWeight <= 0) {
22 | currentWeight = getMaxWeight();
23 | }
24 | }
25 | if (weights.get(currentIndex) >= currentWeight) {
26 | return servers.get(currentIndex);
27 | }
28 | }
29 | }
30 |
31 | private int getMaxWeight() {
32 | return weights.stream().max(Integer::compare).orElse(0);
33 | }
34 |
35 | public static void main(String[] args) {
36 | List servers = List.of("Server1", "Server2", "Server3");
37 | List weights = List.of(5, 1, 1);
38 | WeightedRoundRobin weightedRoundRobinLB = new WeightedRoundRobin(servers, weights);
39 |
40 | for (int i = 0; i < 7; i++) {
41 | System.out.println(weightedRoundRobinLB.getNextServer());
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/implementations/java/rate_limiting/FixedWindowCounter.java:
--------------------------------------------------------------------------------
1 | package implementations.java.rate_limiting;
2 |
3 | import java.time.Instant;
4 |
5 | public class FixedWindowCounter {
6 | private final long windowSizeInSeconds; // Size of each window in seconds
7 | private final long maxRequestsPerWindow; // Maximum number of requests allowed per window
8 | private long currentWindowStart; // Start time of the current window
9 | private long requestCount; // Number of requests in the current window
10 |
11 | public FixedWindowCounter(long windowSizeInSeconds, long maxRequestsPerWindow) {
12 | this.windowSizeInSeconds = windowSizeInSeconds;
13 | this.maxRequestsPerWindow = maxRequestsPerWindow;
14 | this.currentWindowStart = Instant.now().getEpochSecond();
15 | this.requestCount = 0;
16 | }
17 |
18 | public synchronized boolean allowRequest() {
19 | long now = Instant.now().getEpochSecond();
20 |
21 | // Check if we've moved to a new window
22 | if (now - currentWindowStart >= windowSizeInSeconds) {
23 | currentWindowStart = now; // Start a new window
24 | requestCount = 0; // Reset the count for the new window
25 | }
26 |
27 | if (requestCount < maxRequestsPerWindow) {
28 | requestCount++; // Increment the count for this window
29 | return true; // Allow the request
30 | }
31 | return false; // We've exceeded the limit for this window, deny the request
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/implementations/java/rate_limiting/LeakyBucket.java:
--------------------------------------------------------------------------------
1 | package implementations.java.rate_limiting;
2 |
3 | import java.time.Instant;
4 | import java.util.LinkedList;
5 | import java.util.Queue;
6 |
7 | public class LeakyBucket {
8 | private final long capacity; // Maximum number of requests the bucket can hold
9 | private final double leakRate; // Rate at which requests leak out of the bucket (requests per second)
10 | private final Queue bucket; // Queue to hold timestamps of requests
11 | private Instant lastLeakTimestamp; // Last time we leaked from the bucket
12 |
13 | public LeakyBucket(long capacity, double leakRate) {
14 | this.capacity = capacity;
15 | this.leakRate = leakRate;
16 | this.bucket = new LinkedList<>();
17 | this.lastLeakTimestamp = Instant.now();
18 | }
19 |
20 | public synchronized boolean allowRequest() {
21 | leak(); // First, leak out any requests based on elapsed time
22 |
23 | if (bucket.size() < capacity) {
24 | bucket.offer(Instant.now()); // Add the new request to the bucket
25 | return true; // Allow the request
26 | }
27 | return false; // Bucket is full, deny the request
28 | }
29 |
30 | private void leak() {
31 | Instant now = Instant.now();
32 | long elapsedMillis = now.toEpochMilli() - lastLeakTimestamp.toEpochMilli();
33 | int leakedItems = (int) (elapsedMillis * leakRate / 1000.0); // Calculate how many items should have leaked
34 |
35 | // Remove the leaked items from the bucket
36 | for (int i = 0; i < leakedItems && !bucket.isEmpty(); i++) {
37 | bucket.poll();
38 | }
39 |
40 | lastLeakTimestamp = now;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/implementations/java/rate_limiting/SlidingWindowCounter.java:
--------------------------------------------------------------------------------
1 | package implementations.java.rate_limiting;
2 |
3 | import java.time.Instant;
4 |
5 | public class SlidingWindowCounter {
6 | private final long windowSizeInSeconds; // Size of the sliding window in seconds
7 | private final long maxRequestsPerWindow; // Maximum number of requests allowed in the window
8 | private long currentWindowStart; // Start time of the current window
9 | private long previousWindowCount; // Number of requests in the previous window
10 | private long currentWindowCount; // Number of requests in the current window
11 |
12 | public SlidingWindowCounter(long windowSizeInSeconds, long maxRequestsPerWindow) {
13 | this.windowSizeInSeconds = windowSizeInSeconds;
14 | this.maxRequestsPerWindow = maxRequestsPerWindow;
15 | this.currentWindowStart = Instant.now().getEpochSecond();
16 | this.previousWindowCount = 0;
17 | this.currentWindowCount = 0;
18 | }
19 |
20 | public synchronized boolean allowRequest() {
21 | long now = Instant.now().getEpochSecond();
22 | long timePassedInWindow = now - currentWindowStart;
23 |
24 | // Check if we've moved to a new window
25 | if (timePassedInWindow >= windowSizeInSeconds) {
26 | previousWindowCount = currentWindowCount;
27 | currentWindowCount = 0;
28 | currentWindowStart = now;
29 | timePassedInWindow = 0;
30 | }
31 |
32 | // Calculate the weighted count of requests
33 | double weightedCount = previousWindowCount * ((windowSizeInSeconds - timePassedInWindow) / (double) windowSizeInSeconds)
34 | + currentWindowCount;
35 |
36 | if (weightedCount < maxRequestsPerWindow) {
37 | currentWindowCount++; // Increment the count for this window
38 | return true; // Allow the request
39 | }
40 | return false; // We've exceeded the limit, deny the request
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/implementations/java/rate_limiting/SlidingWindowLog.java:
--------------------------------------------------------------------------------
1 | package implementations.java.rate_limiting;
2 |
3 | import java.time.Instant;
4 | import java.util.LinkedList;
5 | import java.util.Queue;
6 |
7 | public class SlidingWindowLog {
8 | private final long windowSizeInSeconds; // Size of the sliding window in seconds
9 | private final long maxRequestsPerWindow; // Maximum number of requests allowed in the window
10 | private final Queue requestLog; // Log of request timestamps
11 |
12 | public SlidingWindowLog(long windowSizeInSeconds, long maxRequestsPerWindow) {
13 | this.windowSizeInSeconds = windowSizeInSeconds;
14 | this.maxRequestsPerWindow = maxRequestsPerWindow;
15 | this.requestLog = new LinkedList<>();
16 | }
17 |
18 | public synchronized boolean allowRequest() {
19 | long now = Instant.now().getEpochSecond();
20 | long windowStart = now - windowSizeInSeconds;
21 |
22 | // Remove timestamps that are outside of the current window
23 | while (!requestLog.isEmpty() && requestLog.peek() <= windowStart) {
24 | requestLog.poll();
25 | }
26 |
27 | if (requestLog.size() < maxRequestsPerWindow) {
28 | requestLog.offer(now); // Log this request
29 | return true; // Allow the request
30 | }
31 | return false; // We've exceeded the limit for this window, deny the request
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/implementations/java/rate_limiting/TokenBucket.java:
--------------------------------------------------------------------------------
1 | package implementations.java.rate_limiting;
2 |
3 | import java.time.Instant;
4 |
5 | public class TokenBucket {
6 | private final long capacity; // Maximum number of tokens the bucket can hold
7 | private final double fillRate; // Rate at which tokens are added to the bucket (tokens per second)
8 | private double tokens; // Current number of tokens in the bucket
9 | private Instant lastRefillTimestamp; // Last time we refilled the bucket
10 |
11 | public TokenBucket(long capacity, double fillRate) {
12 | this.capacity = capacity;
13 | this.fillRate = fillRate;
14 | this.tokens = capacity; // Start with a full bucket
15 | this.lastRefillTimestamp = Instant.now();
16 | }
17 |
18 | public synchronized boolean allowRequest(int tokens) {
19 | refill(); // First, add any new tokens based on elapsed time
20 |
21 | if (this.tokens < tokens) {
22 | return false; // Not enough tokens, deny the request
23 | }
24 |
25 | this.tokens -= tokens; // Consume the tokens
26 | return true; // Allow the request
27 | }
28 |
29 | private void refill() {
30 | Instant now = Instant.now();
31 | // Calculate how many tokens to add based on the time elapsed
32 | double tokensToAdd = (now.toEpochMilli() - lastRefillTimestamp.toEpochMilli()) * fillRate / 1000.0;
33 | this.tokens = Math.min(capacity, this.tokens + tokensToAdd); // Add tokens, but don't exceed capacity
34 | this.lastRefillTimestamp = now;
35 | }
36 | }
--------------------------------------------------------------------------------
/implementations/python/consistent_hashing/consistent-hashing.py:
--------------------------------------------------------------------------------
1 | import hashlib
2 | import bisect
3 |
4 | class ConsistentHashing:
5 | def __init__(self, servers, num_replicas=3):
6 | """
7 | Initializes the consistent hashing ring.
8 |
9 | - servers: List of initial server names (e.g., ["S0", "S1", "S2"])
10 | - num_replicas: Number of virtual nodes per server for better load balancing
11 | """
12 | self.num_replicas = num_replicas # Number of virtual nodes per server
13 | self.ring = {} # Hash ring storing virtual node mappings
14 | self.sorted_keys = [] # Sorted list of hash values (positions) on the ring
15 | self.servers = set() # Set of physical servers (used for tracking)
16 |
17 | # Add each server to the hash ring
18 | for server in servers:
19 | self.add_server(server)
20 |
21 | def _hash(self, key):
22 | """Computes a hash value for a given key using MD5."""
23 | return int(hashlib.md5(key.encode()).hexdigest(), 16)
24 |
25 | def add_server(self, server):
26 | """
27 | Adds a server to the hash ring along with its virtual nodes.
28 |
29 | - Each virtual node is a different hash of the server ID to distribute load.
30 | - The server is hashed multiple times and placed at different positions.
31 | """
32 | self.servers.add(server)
33 | for i in range(self.num_replicas): # Creating multiple virtual nodes
34 | hash_val = self._hash(f"{server}-{i}") # Unique hash for each virtual node
35 | self.ring[hash_val] = server # Map hash to the server
36 | bisect.insort(self.sorted_keys, hash_val) # Maintain a sorted list for efficient lookup
37 |
38 | def remove_server(self, server):
39 | """
40 | Removes a server and all its virtual nodes from the hash ring.
41 | """
42 | if server in self.servers:
43 | self.servers.remove(server)
44 | for i in range(self.num_replicas):
45 | hash_val = self._hash(f"{server}-{i}") # Remove each virtual node's hash
46 | self.ring.pop(hash_val, None) # Delete from hash ring
47 | self.sorted_keys.remove(hash_val) # Remove from sorted key list
48 |
49 | def get_server(self, key):
50 | """
51 | Finds the closest server for a given key.
52 |
53 | - Hash the key to get its position on the ring.
54 | - Move clockwise to find the nearest server.
55 | - If it exceeds the last node, wrap around to the first node.
56 | """
57 | if not self.ring:
58 | return None # No servers available
59 |
60 | hash_val = self._hash(key) # Hash the key
61 | index = bisect.bisect(self.sorted_keys, hash_val) % len(self.sorted_keys) # Locate nearest server
62 | return self.ring[self.sorted_keys[index]] # Return the assigned server
63 |
64 | # ----------------- Usage Example -------------------
65 |
66 | # Step 1: Initialize Consistent Hashing with servers
67 | servers = ["S0", "S1", "S2", "S3", "S4", "S5"]
68 | ch = ConsistentHashing(servers)
69 |
70 | # Step 2: Assign requests (keys) to servers
71 | print(ch.get_server("UserA")) # Maps UserA to a server
72 | print(ch.get_server("UserB")) # Maps UserB to a server
73 |
74 | # Step 3: Add a new server dynamically
75 | ch.add_server("S6")
76 | print(ch.get_server("UserA")) # Might be reassigned if affected
77 |
78 | # Step 4: Remove a server dynamically
79 | ch.remove_server("S2")
80 | print(ch.get_server("UserB")) # Might be reassigned if affected
--------------------------------------------------------------------------------
/implementations/python/load_balancing_algorithms/ip_hash.py:
--------------------------------------------------------------------------------
1 | import hashlib
2 |
3 | class IPHash():
4 | def __init__(self, servers):
5 | self.servers = servers
6 |
7 | def get_next_server(self, client_ip):
8 | hash_value = hashlib.md5(client_ip.encode()).hexdigest()
9 | index = int(hash_value, 16) % len(self.servers)
10 | return self.servers[index]
11 |
12 | # Example usage
13 | servers = ["Server1", "Server2", "Server3"]
14 | load_balancer = IPHash(servers)
15 |
16 | client_ips = ["192.168.0.1", "192.168.0.2", "192.168.0.3", "192.168.0.4"]
17 | for ip in client_ips:
18 | server = load_balancer.get_next_server(ip)
19 | print(f"Client {ip} -> {server}")
--------------------------------------------------------------------------------
/implementations/python/load_balancing_algorithms/least_connections.py:
--------------------------------------------------------------------------------
1 | import random
2 |
3 | class LeastConnections:
4 | def __init__(self, servers):
5 | self.servers = {server: 0 for server in servers}
6 |
7 | def get_next_server(self):
8 | # Find the minimum number of connections
9 | min_connections = min(self.servers.values())
10 | # Get all servers with the minimum number of connections
11 | least_loaded_servers = [server for server, connections in self.servers.items() if connections == min_connections]
12 | # Select a random server from the least loaded servers
13 | selected_server = random.choice(least_loaded_servers)
14 | self.servers[selected_server] += 1
15 | return selected_server
16 |
17 | def release_connection(self, server):
18 | if self.servers[server] > 0:
19 | self.servers[server] -= 1
20 |
21 | # Example usage
22 | servers = ["Server1", "Server2", "Server3"]
23 | load_balancer = LeastConnections(servers)
24 |
25 | for i in range(6):
26 | server = load_balancer.get_next_server()
27 | print(f"Request {i + 1} -> {server}")
28 | load_balancer.release_connection(server)
--------------------------------------------------------------------------------
/implementations/python/load_balancing_algorithms/least_response_time.py:
--------------------------------------------------------------------------------
1 | import time
2 | import random
3 |
4 | class LeastResponseTime:
5 | def __init__(self, servers):
6 | self.servers = servers
7 | self.response_times = [0] * len(servers)
8 |
9 | def get_next_server(self):
10 | min_response_time = min(self.response_times)
11 | min_index = self.response_times.index(min_response_time)
12 | return self.servers[min_index]
13 |
14 | def update_response_time(self, server, response_time):
15 | index = self.servers.index(server)
16 | self.response_times[index] = response_time
17 |
18 | # Simulated server response time function
19 | def simulate_response_time():
20 | # Simulating response time with random delay
21 | delay = random.uniform(0.1, 1.0)
22 | time.sleep(delay)
23 | return delay
24 |
25 | # Example usage
26 | servers = ["Server1", "Server2", "Server3"]
27 | load_balancer = LeastResponseTime(servers)
28 |
29 | for i in range(6):
30 | server = load_balancer.get_next_server()
31 | print(f"Request {i + 1} -> {server}")
32 | response_time = simulate_response_time()
33 | load_balancer.update_response_time(server, response_time)
34 | print(f"Response Time: {response_time:.2f}s")
--------------------------------------------------------------------------------
/implementations/python/load_balancing_algorithms/round_robin.py.py:
--------------------------------------------------------------------------------
1 | class RoundRobin:
2 | def __init__(self, servers):
3 | self.servers = servers
4 | self.current_index = -1
5 |
6 | def get_next_server(self):
7 | self.current_index = (self.current_index + 1) % len(self.servers)
8 | return self.servers[self.current_index]
9 |
10 | # Example usage
11 | servers = ["Server1", "Server2", "Server3"]
12 | load_balancer = RoundRobin(servers)
13 |
14 | for i in range(6):
15 | server = load_balancer.get_next_server()
16 | print(f"Request {i + 1} -> {server}")
--------------------------------------------------------------------------------
/implementations/python/load_balancing_algorithms/weighted_round_robin.py:
--------------------------------------------------------------------------------
1 | class WeightedRoundRobin:
2 | def __init__(self, servers, weights):
3 | self.servers = servers
4 | self.weights = weights
5 | self.current_index = -1
6 | self.current_weight = 0
7 |
8 | def get_next_server(self):
9 | while True:
10 | self.current_index = (self.current_index + 1) % len(self.servers)
11 | if self.current_index == 0:
12 | self.current_weight -= 1
13 | if self.current_weight <= 0:
14 | self.current_weight = max(self.weights)
15 | if self.weights[self.current_index] >= self.current_weight:
16 | return self.servers[self.current_index]
17 |
18 | # Example usage
19 | servers = ["Server1", "Server2", "Server3"]
20 | weights = [5, 1, 1]
21 | load_balancer = WeightedRoundRobin(servers, weights)
22 |
23 | for i in range(7):
24 | server = load_balancer.get_next_server()
25 | print(f"Request {i + 1} -> {server}")
--------------------------------------------------------------------------------
/implementations/python/rate_limiting/fixed_window_counter.py:
--------------------------------------------------------------------------------
1 | import time
2 |
3 | class FixedWindowCounter:
4 | def __init__(self, window_size, max_requests):
5 | self.window_size = window_size # Size of the window in seconds
6 | self.max_requests = max_requests # Maximum number of requests per window
7 | self.current_window = time.time() // window_size
8 | self.request_count = 0
9 |
10 | def allow_request(self):
11 | current_time = time.time()
12 | window = current_time // self.window_size
13 |
14 | # If we've moved to a new window, reset the counter
15 | if window != self.current_window:
16 | self.current_window = window
17 | self.request_count = 0
18 |
19 | # Check if we're still within the limit for this window
20 | if self.request_count < self.max_requests:
21 | self.request_count += 1
22 | return True
23 | return False
24 |
25 | # Usage example
26 | limiter = FixedWindowCounter(window_size=60, max_requests=5) # 5 requests per minute
27 |
28 | for _ in range(10):
29 | print(limiter.allow_request()) # Will print True for the first 5 requests, then False
30 | time.sleep(0.1) # Wait a bit between requests
31 |
32 | time.sleep(60) # Wait for the window to reset
33 | print(limiter.allow_request()) # True
--------------------------------------------------------------------------------
/implementations/python/rate_limiting/leaky_bucket.py:
--------------------------------------------------------------------------------
1 | from collections import deque
2 | import time
3 |
4 | class LeakyBucket:
5 | def __init__(self, capacity, leak_rate):
6 | self.capacity = capacity # Maximum number of requests in the bucket
7 | self.leak_rate = leak_rate # Rate at which requests leak (requests/second)
8 | self.bucket = deque() # Queue to hold request timestamps
9 | self.last_leak = time.time() # Last time we leaked from the bucket
10 |
11 | def allow_request(self):
12 | now = time.time()
13 | # Simulate leaking from the bucket
14 | leak_time = now - self.last_leak
15 | leaked = int(leak_time * self.leak_rate)
16 | if leaked > 0:
17 | # Remove the leaked requests from the bucket
18 | for _ in range(min(leaked, len(self.bucket))):
19 | self.bucket.popleft()
20 | self.last_leak = now
21 |
22 | # Check if there's capacity and add the new request
23 | if len(self.bucket) < self.capacity:
24 | self.bucket.append(now)
25 | return True
26 | return False
27 |
28 | # Usage example
29 | limiter = LeakyBucket(capacity=5, leak_rate=1) # 5 requests, leak 1 per second
30 |
31 | for _ in range(10):
32 | print(limiter.allow_request()) # Will print True for the first 5 requests, then False
33 | time.sleep(0.1) # Wait a bit between requests
34 |
35 | time.sleep(1) # Wait for bucket to leak
36 | print(limiter.allow_request()) # True
--------------------------------------------------------------------------------
/implementations/python/rate_limiting/sliding_window_counter.py:
--------------------------------------------------------------------------------
1 | import time
2 |
3 | class SlidingWindowCounter:
4 | def __init__(self, window_size, max_requests):
5 | self.window_size = window_size # Size of the sliding window in seconds
6 | self.max_requests = max_requests # Maximum number of requests per window
7 | self.current_window = time.time() // window_size
8 | self.request_count = 0
9 | self.previous_count = 0
10 |
11 | def allow_request(self):
12 | now = time.time()
13 | window = now // self.window_size
14 |
15 | # If we've moved to a new window, update the counts
16 | if window != self.current_window:
17 | self.previous_count = self.request_count
18 | self.request_count = 0
19 | self.current_window = window
20 |
21 | # Calculate the weighted request count
22 | window_elapsed = (now % self.window_size) / self.window_size
23 | threshold = self.previous_count * (1 - window_elapsed) + self.request_count
24 |
25 | # Check if we're within the limit
26 | if threshold < self.max_requests:
27 | self.request_count += 1
28 | return True
29 | return False
30 |
31 | # Usage example
32 | limiter = SlidingWindowCounter(window_size=60, max_requests=5) # 5 requests per minute
33 |
34 | for _ in range(10):
35 | print(limiter.allow_request()) # Will print True for the first 5 requests, then gradually become False
36 | time.sleep(0.1) # Wait a bit between requests
37 |
38 | time.sleep(30) # Wait for half the window to pass
39 | print(limiter.allow_request()) # Might be True or False depending on the exact timing
--------------------------------------------------------------------------------
/implementations/python/rate_limiting/sliding_window_log.py:
--------------------------------------------------------------------------------
1 | import time
2 | from collections import deque
3 |
4 | class SlidingWindowLog:
5 | def __init__(self, window_size, max_requests):
6 | self.window_size = window_size # Size of the sliding window in seconds
7 | self.max_requests = max_requests # Maximum number of requests per window
8 | self.request_log = deque() # Log to keep track of request timestamps
9 |
10 | def allow_request(self):
11 | now = time.time()
12 |
13 | # Remove timestamps that are outside the current window
14 | while self.request_log and now - self.request_log[0] >= self.window_size:
15 | self.request_log.popleft()
16 |
17 | # Check if we're still within the limit
18 | if len(self.request_log) < self.max_requests:
19 | self.request_log.append(now)
20 | return True
21 | return False
22 |
23 | # Usage example
24 | limiter = SlidingWindowLog(window_size=60, max_requests=5) # 5 requests per minute
25 |
26 | for _ in range(10):
27 | print(limiter.allow_request()) # Will print True for the first 5 requests, then False
28 | time.sleep(0.1) # Wait a bit between requests
29 |
30 | time.sleep(60) # Wait for the window to slide
31 | print(limiter.allow_request()) # True
--------------------------------------------------------------------------------
/implementations/python/rate_limiting/token_bucket.py:
--------------------------------------------------------------------------------
1 | import time
2 |
3 | class TokenBucket:
4 | def __init__(self, capacity, fill_rate):
5 | self.capacity = capacity # Maximum number of tokens the bucket can hold
6 | self.fill_rate = fill_rate # Rate at which tokens are added (tokens/second)
7 | self.tokens = capacity # Current token count, start with a full bucket
8 | self.last_time = time.time() # Last time we checked the token count
9 |
10 | def allow_request(self, tokens=1):
11 | now = time.time()
12 | # Calculate how many tokens have been added since the last check
13 | time_passed = now - self.last_time
14 | self.tokens = min(self.capacity, self.tokens + time_passed * self.fill_rate)
15 | self.last_time = now
16 |
17 | # Check if we have enough tokens for this request
18 | if self.tokens >= tokens:
19 | self.tokens -= tokens
20 | return True
21 | return False
22 |
23 | # Usage example
24 | limiter = TokenBucket(capacity=10, fill_rate=1) # 10 tokens, refill 1 token per second
25 |
26 | for _ in range(15):
27 | print(limiter.allow_request()) # Will print True for the first 10 requests, then False
28 | time.sleep(0.1) # Wait a bit between requests
29 |
30 | time.sleep(5) # Wait for bucket to refill
31 | print(limiter.allow_request()) # True
--------------------------------------------------------------------------------