io.github.kidminks:rate-limiter-java

A Java library for rate limiting, assembled using extensible storage and application framework adaptors. The library's interfaces support thread-safe sync, async, and reactive usage patterns.


License
Apache-2.0

Documentation

Rate Limiter Java Library

A Java library for rate limiting, assembled using extensible storage and application framework adaptors. The library's interfaces support thread-safe sync, async, and reactive usage patterns.

Modules

RateLimiterJava provides the following stable pluggable modules

  • Fixed Window rate limiter
  • Sliding Window rate limiter

Features

Configuration can be made to store the user data in redis using these modules. Lua scripts is used in following cases to reduce redis calls

  • Sliding Window rate limiter
  • In case user data is handled using this library

Installation

Add the dependency to your pom.xml file

<dependency>
    <groupId>io.github.kidminks</groupId>
    <artifactId>rate-limiter-java</artifactId>
    <version>0.0.1</version>
</dependency>

Then run from the root dir of the project:

mvn install

Prerequisite

  • jedis
  • javax.validation
  • guava
  • lombok

Examples

Example Rate Limiter Service

Create a service RateLimiterService which will handle the library linking

package com.example.demo;

import io.github.kidminks.rate.limiter.core.abst.AbstractRateLimiter;
import io.github.kidminks.rate.limiter.core.factory.RateLimiterFactory;
import io.github.kidminks.rate.limiter.model.dto.Configuration;
import io.github.kidminks.rate.limiter.model.dto.LimitDetails;
import io.github.kidminks.rate.limiter.model.enums.RateLimiterType;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

@Component
@Service
public class RateLimiterService {

    private AbstractRateLimiter slidingWindowRateLimiter;
    private AbstractRateLimiter fixedWindowRateLimiter;

    private void initSlidingWindowRateLimiter() {
        Configuration configuration = Configuration.builder()
                .redisHost("localhost")
                .redisPort(6379)
                .redisDb(1)
                .maxTotal(10)
                .maxIdle(1)
                .useLuaScript(true)
                .build();
        this.slidingWindowRateLimiter = RateLimiterFactory.getRateLimiter(configuration, RateLimiterType.SLIDING_WINDOW);
    }

    private void initFixedWindowRateLimiter() {
        Configuration configuration = Configuration.builder()
                .redisHost("localhost")
                .redisPort(6379)
                .redisDb(1)
                .maxTotal(10)
                .maxIdle(1)
                .useLuaScript(false)
                .build();
        this.fixedWindowRateLimiter = RateLimiterFactory.getRateLimiter(configuration, RateLimiterType.FIXED_WINDOW);
    }

    public RateLimiterService() {
        initSlidingWindowRateLimiter();
        initFixedWindowRateLimiter();
    }

    public Boolean checkSlidingWindowLimit(String key) {
        return slidingWindowRateLimiter.check(new LimitDetails(key, 100L, 3600000L));
    }

    public Boolean checkFixedWindowLimit(String key) {
        return fixedWindowRateLimiter.check(new LimitDetails(key, 100L, 3600000L));
    }
}

Sliding Window

Checking limits left using sliding rate limiter api. These checks using lua scripts. Old request data are deleted with every request

@RestController
@RequestMapping("/")
@Slf4j
public class RateLimiterTestController {

    @Autowired
    private RateLimiterService rateLimiterService;

    @GetMapping("/sliding-window")
    public void slidingWindowTest(@RequestHeader("X-AUTH-TOKEN") String token) {
        if(rateLimiterService.checkSlidingWindowLimit(token)) {
            log.info("limit available");
            return;
        }
        log.info("limit not available");
    }
}

Fixed Window

increment function of redis is used to increase the key count. Every time a new key is created expiry is set and that key is deleted after the end.

@RestController
@RequestMapping("/")
@Slf4j
public class RateLimiterTestController {

    @Autowired
    private RateLimiterService rateLimiterService;

    @GetMapping("/fixed-window")
    public void fixedWindowTest(@RequestHeader("X-AUTH-TOKEN") String token) {
        if(rateLimiterService.checkFixedWindowLimit(token)) {
            log.info("limit available");
            return;
        }
        log.info("limit not available");
    }
}

Roadmap

Feature Status
Sliding Window rate limiter Released
Fixed Window rate limiter Released
Store user data Ongoing