Skip to content

Commit 628ec15

Browse files
committed
docs: update throttling
1 parent 16fbd26 commit 628ec15

File tree

3 files changed

+85
-65
lines changed

3 files changed

+85
-65
lines changed

throttling/README.md

Lines changed: 83 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,49 @@
11
---
22
title: Throttling
3-
category: Behavioral
3+
category: Resource management
44
language: en
55
tag:
6-
- Performance
7-
- Cloud distributed
6+
- API design
7+
- Fault tolerance
8+
- Performance
9+
- Resilience
10+
- Scalability
811
---
912

13+
## Also known as
14+
15+
* Rate Limiting
16+
1017
## Intent
1118

12-
Ensure that a given client is not able to access service resources more than the assigned limit.
19+
Throttling limits the number of requests a system can process within a given time frame to prevent overload and ensure stability.
1320

1421
## Explanation
1522

1623
Real-world example
1724

18-
> A young human and an old dwarf walk into a bar. They start ordering beers from the bartender.
19-
> The bartender immediately sees that the young human shouldn't consume too many drinks too fast
20-
> and refuses to serve if enough time has not passed. For the old dwarf, the serving rate can
21-
> be higher.
25+
> Imagine a popular amusement park that limits the number of visitors who can enter per hour to prevent overcrowding. This ensures that all visitors can enjoy the park without long wait times and maintain a pleasant experience. Similarly, the Throttling design pattern in software controls the rate of requests to a system, preventing it from being overwhelmed and ensuring consistent performance for all users.
2226
2327
In plain words
2428

25-
> Throttling pattern is used to rate-limit access to a resource.
29+
> Throttling pattern is used to rate-limit access to a resource.
2630
2731
[Microsoft documentation](https://docs.microsoft.com/en-us/azure/architecture/patterns/throttling) says
2832

29-
> Control the consumption of resources used by an instance of an application, an individual tenant,
30-
> or an entire service. This can allow the system to continue to function and meet service level
31-
> agreements, even when an increase in demand places an extreme load on resources.
33+
> Control the consumption of resources used by an instance of an application, an individual tenant, or an entire service. This can allow the system to continue to function and meet service level agreements, even when an increase in demand places an extreme load on resources.
3234
3335
**Programmatic Example**
3436

35-
`BarCustomer` class presents the clients of the `Bartender` API. `CallsCount` tracks the number of
36-
calls per `BarCustomer`.
37+
In this example a young human and an old dwarf walk into a bar. They start ordering beers from the bartender. The bartender immediately sees that the young human shouldn't consume too many drinks too fast and refuses to serve if enough time has not passed. For the old dwarf, the serving rate can be higher.
38+
39+
`BarCustomer` class presents the clients of the `Bartender` API. `CallsCount` tracks the number of calls per `BarCustomer`.
3740

3841
```java
42+
43+
@Getter
3944
public class BarCustomer {
4045

41-
@Getter
4246
private final String name;
43-
@Getter
4447
private final int allowedCallsPerSecond;
4548

4649
public BarCustomer(String name, int allowedCallsPerSecond, CallsCount callsCount) {
@@ -55,60 +58,57 @@ public class BarCustomer {
5558

5659
@Slf4j
5760
public final class CallsCount {
58-
private final Map<String, AtomicLong> tenantCallsCount = new ConcurrentHashMap<>();
61+
private final Map<String, AtomicLong> tenantCallsCount = new ConcurrentHashMap<>();
5962

60-
public void addTenant(String tenantName) {
61-
tenantCallsCount.putIfAbsent(tenantName, new AtomicLong(0));
62-
}
63+
public void addTenant(String tenantName) {
64+
tenantCallsCount.putIfAbsent(tenantName, new AtomicLong(0));
65+
}
6366

64-
public void incrementCount(String tenantName) {
65-
tenantCallsCount.get(tenantName).incrementAndGet();
66-
}
67+
public void incrementCount(String tenantName) {
68+
tenantCallsCount.get(tenantName).incrementAndGet();
69+
}
6770

68-
public long getCount(String tenantName) {
69-
return tenantCallsCount.get(tenantName).get();
70-
}
71+
public long getCount(String tenantName) {
72+
return tenantCallsCount.get(tenantName).get();
73+
}
7174

72-
public void reset() {
73-
tenantCallsCount.replaceAll((k, v) -> new AtomicLong(0));
74-
LOGGER.info("reset counters");
75-
}
75+
public void reset() {
76+
tenantCallsCount.replaceAll((k, v) -> new AtomicLong(0));
77+
LOGGER.info("reset counters");
78+
}
7679
}
7780
```
7881

79-
Next, the service that the tenants are calling is introduced. To track the call count, a throttler
80-
timer is used.
82+
Next, the service that the tenants are calling is introduced. To track the call count, a throttler timer is used.
8183

8284
```java
8385
public interface Throttler {
84-
85-
void start();
86+
void start();
8687
}
8788

8889
public class ThrottleTimerImpl implements Throttler {
8990

90-
private final int throttlePeriod;
91-
private final CallsCount callsCount;
92-
93-
public ThrottleTimerImpl(int throttlePeriod, CallsCount callsCount) {
94-
this.throttlePeriod = throttlePeriod;
95-
this.callsCount = callsCount;
96-
}
97-
98-
@Override
99-
public void start() {
100-
new Timer(true).schedule(new TimerTask() {
101-
@Override
102-
public void run() {
103-
callsCount.reset();
104-
}
105-
}, 0, throttlePeriod);
106-
}
91+
private final int throttlePeriod;
92+
private final CallsCount callsCount;
93+
94+
public ThrottleTimerImpl(int throttlePeriod, CallsCount callsCount) {
95+
this.throttlePeriod = throttlePeriod;
96+
this.callsCount = callsCount;
97+
}
98+
99+
@Override
100+
public void start() {
101+
new Timer(true).schedule(new TimerTask() {
102+
@Override
103+
public void run() {
104+
callsCount.reset();
105+
}
106+
}, 0, throttlePeriod);
107+
}
107108
}
108109
```
109110

110-
`Bartender` offers the `orderDrink` service to the `BarCustomer`s. The customers probably don't
111-
know that the beer serving rate is limited by their appearances.
111+
`Bartender` offers the `orderDrink` service to the `BarCustomer`s. The customers probably don't know that the beer serving rate is limited by their appearances.
112112

113113
```java
114114
class Bartender {
@@ -129,7 +129,7 @@ class Bartender {
129129
return -1;
130130
}
131131
callsCount.incrementCount(tenantName);
132-
LOGGER.debug("Serving beer to {} : [{} consumed] ", barCustomer.getName(), count+1);
132+
LOGGER.debug("Serving beer to {} : [{} consumed] ", barCustomer.getName(), count + 1);
133133
return getRandomCustomerId();
134134
}
135135

@@ -139,8 +139,7 @@ class Bartender {
139139
}
140140
```
141141

142-
Now it is possible to see the full example in action. `BarCustomer` young human is rate-limited to 2
143-
calls per second and the old dwarf to 4.
142+
Now it is possible to see the full example in action. `BarCustomer` young human is rate-limited to 2 calls per second and the old dwarf to 4.
144143

145144
```java
146145
public static void main(String[] args) {
@@ -205,14 +204,38 @@ An excerpt from the example's console output:
205204

206205
## Class diagram
207206

208-
![alt text](./etc/throttling_urm.png "Throttling pattern class diagram")
207+
![Throttling](./etc/throttling_urm.png "Throttling pattern class diagram")
209208

210209
## Applicability
211210

212-
The Throttling pattern should be used:
211+
* You need to protect resources from being overwhelmed by too many requests.
212+
* You want to ensure fair usage of a service among multiple users.
213+
* You need to maintain the quality of service under high load conditions.
214+
215+
## Known Uses
216+
217+
* APIs of major cloud providers like AWS, Google Cloud, and Azure use throttling to manage resource usage.
218+
* Web services to prevent denial-of-service (DoS) attacks by limiting the number of requests from a single IP address.
219+
* Online platforms like social media sites and e-commerce websites to ensure even distribution of server load.
220+
221+
## Consequences
222+
223+
Benefits:
224+
225+
* Prevents resource exhaustion, ensuring system stability.
226+
* Helps in maintaining consistent performance and quality of service.
227+
* Improves fault tolerance by avoiding system crashes under high load.
228+
229+
Trade-offs:
230+
231+
* May cause increased latency or delay in request processing.
232+
* Requires careful tuning to balance between resource protection and user experience.
233+
* Could lead to denial of service to legitimate users if not configured correctly.
234+
235+
## Related Patterns
213236

214-
* When service access needs to be restricted not to have high impact on the performance of the service.
215-
* When multiple clients are consuming the same service resources and restriction has to be made according to the usage per client.
237+
* [Circuit Breaker](https://java-design-patterns.com/patterns/circuit-breaker/): Works in tandem with throttling to prevent repeated attempts to access an overloaded service.
238+
* Bulkhead: Isolates different parts of the system to limit the impact of throttling on other components.
216239

217240
## Credits
218241

throttling/src/main/java/com/iluwatar/throttling/BarCustomer.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,10 @@
3030
/**
3131
* BarCustomer is a tenant with a name and a number of allowed calls per second.
3232
*/
33+
@Getter
3334
public class BarCustomer {
3435

35-
@Getter
3636
private final String name;
37-
@Getter
3837
private final int allowedCallsPerSecond;
3938

4039
/**

throttling/src/test/java/com/iluwatar/throttling/BarCustomerTest.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@ class BarCustomerTest {
3636

3737
@Test
3838
void constructorTest() {
39-
assertThrows(InvalidParameterException.class, () -> {
40-
new BarCustomer("sirBrave", -1, new CallsCount());
41-
});
39+
assertThrows(InvalidParameterException.class, () -> new BarCustomer("sirBrave", -1, new CallsCount()));
4240
}
4341
}

0 commit comments

Comments
 (0)