Skip to content

Commit

Permalink
creating first version of documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
vladimir-bukhtoyarov committed May 4, 2015
1 parent 097c8f0 commit cb76a83
Showing 1 changed file with 132 additions and 54 deletions.
186 changes: 132 additions & 54 deletions README.markdown
Original file line number Diff line number Diff line change
@@ -1,89 +1,167 @@
Bandwidth limiting library for java
===================================
# Warning! Project is under development

Bucket4j - is a java implementation of token/leaky bucket algorithm for rate limiting
=====================================================================================
[![Build Status](https://travis-ci.org/vladimir-bukhtoyarov/bucket4j.svg?branch=master)](https://travis-ci.org/vladimir-bukhtoyarov/bucket4j)
[![Coverage Status](https://coveralls.io/repos/vladimir-bukhtoyarov/bucket4j/badge.svg)](https://coveralls.io/r/vladimir-bukhtoyarov/bucket4j)

### Algorithm in high level

Introduction
------------
This library provides an implementation of a token bucket algorithm which is useful for providing rate limited access
to a portion of code. The implementation provided is that of a "leaky bucket" in the sense that the bucket has a finite
capacity and any added tokens that would exceed this capacity will "overflow" out of the bucket and be lost forever.

In this implementation the rules for refilling the bucket are encapsulated in a provided RefillStrategy instance. Prior
to attempting to consume any tokens the refill strategy will be consulted to see how many tokens should be added to the
bucket
The token bucket algorithm can be conceptually understood as follows:

We use [Travis CI](http://about.travis-ci.org) for build verification. [![Build Status](https://secure.travis-ci.org/bbeck/token-bucket.png?branch=master)](http://travis-ci.org/bbeck/token-bucket)
* A token is added to the bucket every `1/r` seconds.
* The bucket can hold at the most `b` tokens. If a token arrives when the bucket is full, it is discarded.
* When trying to consume `n` tokens, `n` tokens are removed from bucket.
* If fewer than `n` tokens are available, then consumption is disallowed.

See also:
See for more details:

* [Wikipedia - Token Bucket](http://en.wikipedia.org/wiki/Token_bucket)
* [Wikipedia - Leaky Bucket](http://en.wikipedia.org/wiki/Leaky_bucket)
* [Wikipedia - Generic cell rate algorithm](http://en.wikipedia.org/wiki/Generic_cell_rate_algorithm)

### Advantages of Bucket4j

* Implemented around ideas of well known family of algorithms, which are by de facto standard for rate limiting in the IT industry.
* Effective lock free implementation without any critical section, Bucket4j is good scalable for multithreading environment.
* Rich API:
* More then one bandwidth per bucket. For example you can limit 1000 events per hours but no often then 100 events per minute.
* Customizable time measurement. You are able to specify how to time will be measurement: as `System.nanotime()` or `System.currentTimeMillis()`
or you can to specify own way to measure time.
* Ability to have guaranteed bandwidth. Think about guaranteed bandwidth like a 911 number which you can to call when no money on your balance.
* Dynamic capacity. If needs capacity of the bucket can be changed over time.
* Ability to switch from one JVM to cluster in one line of code, so using Bucket4j you are able to limiting something in the JVM cluster.
At the moment following grids are supported:
* [Oracle Coherence](http://www.oracle.com/technetwork/middleware/coherence/overview/index-087514.html) - One of the oldest and most reliable commercial In-Memory Grid.
* [Hazelcast](http://hazelcast.com/products/hazelcast/) - The most popular Open Source In-Memory Data Grid.
* [Apache Ignite(GridGain in the past)](http://www.oracle.com/technetwork/middleware/coherence/overview/index-087514.html) - The Open Source In-Memory Data Grid with most richest API in the world.

### Usage

#### Maven Setup

The bucket4j library is distributed through [Bintray](http://bintray.com/), so you need to add Bintray repository to your `pom.xml`

```xml
<repositories>
<repository>
<id>jcenter</id>
<url>http://jcenter.bintray.com</url>
</repository>
</repositories>
```

Usage
-----
Using a token bucket is incredibly easy and is best illustrated by an example. Suppose you have a piece of code that
polls a website and you would only like to be able to access the site once per second:
Then include Bucket4j as dependency to your `pom.xml`

```xml
<dependency>
<groupId>com.github</groupId>
<artifactId>bucket4j</artifactId>
<version>1.0.0</version>
</dependency>
```

#### Simple example
Imagine that you develop WEB application and want to limit user to access for application no often then 10 times for second:

```java
// Create a token bucket with a capacity of 1 token that refills at a fixed interval of 1 token/sec.
TokenBucket bucket = TokenBuckets.builder()
.withCapacity(1)
.withFixedIntervalRefillStrategy(1, 1, TimeUnit.SECONDS)
.build();
public class ThrottlingFilter implements javax.servlet.Filter {

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
HttpSession session = httpRequest.getSession(true);

Bucket bucket = (Bucket) session.getAttribute("throttler");
if (bucket == null) {
// build bucket with required capacity and associate it with particular user
bucket = Buckets.withNanoTimePrecision()
.withLimitedBandwidth(10, TimeUnit.SECONDS.toNanos(1))
.build();
session.setAttribute("throttler", bucket);
}

// tryConsumeSingleToken returns false immediately if no tokens available with the bucket
if (bucket.tryConsumeSingleToken()) {
filterChain.doFilter(servletRequest, servletResponse);
} else {
HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
httpResponse.setContentType("text/plain");
httpResponse.setStatus(429);
httpResponse.getWriter().append("Too many requests");
}
}

// ...
}
```


#### Yet another simple example

Suppose you have a piece of code that polls a website and you would only like to be able to access the site 100 time per minute:

```java

// Create a token bucket with required capacity.
Bucket bucket = Buckets.withNanoTimePrecision()
.withLimitedBandwidth(100, TimeUnit.MINUTES.toNanos(1))
.build();

// ...
while (true) {
// Consume a token from the token bucket. If a token is not available this method will block until
// the refill strategy adds one to the bucket.
// the refill adds one to the bucket.
bucket.consume(1);

poll();
}
```

As another example suppose you wanted to rate limit the size response of a server to the client to 20 kb/sec but want to
allow for a periodic burst rate of 40 kb/sec:
#### Example of multiple bandwidth

Imagine that you are developing load testing tool, in order to be ensure that testable system is able to dispatch 1000 requests per 1 minute.
But you do not want to randomly kill the testable system by generation all 1000 events in one second instead of 1 minute.
To solve problem you can construct following bucket:
```java
// Create a token bucket with a capacity of 40 kb tokens that refills at a fixed interval of 20 kb tokens per second
TokenBucket bucket = TokenBuckets.builder()
.withCapacity(40960)
.withFixedIntervalRefillStrategy(20480, 1, TimeUnit.SECONDS)
.build();
Bucket bucket = Buckets.withNanoTimePrecision()
// allows 1000 tokens per 1 minute
.withLimitedBandwidth(1000, TimeUnit.MINUTES.toNanos(1))
// but not often then 50 tokens per 1 second
.withLimitedBandwidth(50, TimeUnit.SECOND.toNanos(1))
.build();

// ...

while (true) {
String response = prepareResponse();

// Consume tokens from the bucket commensurate with the size of the response
bucket.consume(response.length());
// Consume a token from the token bucket. If a token is not available this method will block until
// the refill adds one to the bucket.
bucket.consume(1);

send(response);
workloadExecutor.execute(new LoadTask());
}
```

Maven Setup
-----------
The token bandwidth library is distributed through maven central. Just include it as a dependency in your ```pom.xml```.
#### Example of guaranteed bandwidth
... **TBD**

```xml
<repositories>
<repository>
<id>jcenter</id>
<url>http://jcenter.bintray.com</url>
</repository>
</repositories>
...
<dependency>
<groupId>org.isomorphism</groupId>
<artifactId>token-bucket</artifactId>
<version>1.3</version>
</dependency>
```
#### Example of Oracle Coherence integration
... **TBD**

#### Example of Hazelcast integration
... **TBD**

#### Example of Apache Ignite(GridGain) integration
... **TBD**

### Advanced usages

#### Using dynamic capacity
... **TBD**

#### Using initial capacity
... **TBD**

#### Using custom time metter
... **TBD**

License
-------
Expand Down

0 comments on commit cb76a83

Please sign in to comment.