Comments (2)
Ended up rolling a fully custom solution. The TokenBucketGroup-equivalent part:
object TokenBuckets {
val NanosPerSecond: Long = 1000L * 1000 * 1000
}
class TokenBuckets(size: Int, rate: Double, minNanosPerUpdate: Long = TokenBuckets.NanosPerSecond)
(implicit actorSystem: ActorSystem) {
require(size > 0)
require(rate >= 0.0001)
require(rate < 1e6)
def now(): Long = System.nanoTime()
//private val floor = 0
private val floor = -size // Penalize abusers a little
private val buckets = new ConcurrentHashMap[String, AtomicInteger]()
private var lastUpdateAt: Long = now()
private val tokensPerNano: Double = rate / TokenBuckets.NanosPerSecond
private val nanosPerToken: Double = 1 / tokensPerNano
private val nanosPerUpdate: Long = Math.max(nanosPerToken.ceil.toLong, minNanosPerUpdate)
def consume(ip: String): Int = {
var int = buckets.get(ip)
if (int == null) {
int = new AtomicInteger(size)
buckets.put(ip, int) // May drop a token if there's a concurrent request, that's ok
}
if (int.get() > floor) int.decrementAndGet() else floor
}
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
actorSystem.scheduler.schedule(nanosPerUpdate.nanos, nanosPerUpdate.nanos) {
val deltaNanos: Long = now() - lastUpdateAt
val tokensToAdd = (deltaNanos * tokensPerNano).round.toInt
if (tokensToAdd > 0) { // Should always be true
buckets.forEach((ip: String, int: AtomicInteger) => {
val tokensInBucket = int.addAndGet(tokensToAdd)
if (tokensInBucket >= size) buckets.remove(ip) // May drop a token if there's a concurrent request, that's ok
})
lastUpdateAt += (tokensToAdd * nanosPerToken).ceil.toLong
}
}
}
This way there's no synchronization and only constant-time operations in the critical-path consume call, and the cleanup / adding of new tokens is done at a fixed rate in the background.
The tradeoff is that it's no longer 100% exact, so there will be an extra connection allowed through every now and then, and if the background job gets stalled for whatever reason, then there will be no new tokens granted => request stoppage.
Anyway, feel free to use or ignore, I'll close this issue in the meantime.
from play-guard.
sorry for the late response, I somehow didn't notice the issue. I've also been thinking about a more relaxed approach in favour of performance. But when I did some throughput measurements I was surprised that the bucket rebuild cost seems to be negligible. Did you notice any performance issues?
from play-guard.
Related Issues (9)
- the limit action cannot compotion other play actions HOT 1
- Whitelist IP when using IpRateLimitFilter HOT 2
- RateLimiter rate type does not match TocketBucketGroup rate HOT 16
- Does play-guard support rate-limit control based on request body/url HOT 1
- Read access for bucket values for Rate Limit Headers HOT 1
- Using Play Guard in HttpErrorHandler HOT 5
- X-Forwarded-For parsing does not support more than one proxy, is a dangerous default HOT 1
- Max global rate limit HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from play-guard.