When I started this I didn't know that there are a lot of rate-limiting projects(commercial, personal). I just wanted to solve a situation with my code and I learned something while making this project.
This is an app that you should put in front of your app to limiting incoming HTTP traffic. Works on L7 and acts as a reverse proxy. I'm sure there are a lot of similar projects but this project is exactly for my need.
Note: Putting in front of means that you should redirect the incoming traffic to this app instead of your app. This app will redirect the traffic to your app if it should.
I prefer telling these by using an example configuration. Here is an example configuration.
app:
port: 8081
timeout: 3s
hosts:
- 12.34.56.78
- 12.34.56.79
- 12.34.56.80
server:
addr: :8080
readTimeout: 1000
writeTimeout: 1000
cache:
inMemory: true
redis:
addr: localhost:6379
username: ""
password: ""
db: 0
defaultRuleScope: path
rules:
- scope: path
pattern: GET /users/4/addresses
limit: 4
tracing:
enabled: false
provider: new-relic
newRelic:
appName: appName
licenseKey: licenseKey
distributedTracerEnabled: true
In the app
object you fulfill your app's information.
Name | Description | Required | Default |
---|---|---|---|
port | Your app port. You can specify this on each of your hosts | yes | None |
hosts | Your app instances. Can be host only or host:port |
yes | None |
timeout | Your app's timeout when redirecting | no | 1000ms |
In the server
object you set up a server.
Name | Description | Required | Default |
---|---|---|---|
addr | Address to listen | yes | None |
readTimeout | Server read timeout in millisecond format | no | 1000ms |
writeTimeout | Server read timeout in millisecond format | no | 1000ms |
In the cache
object you specify whether you want to use in-memory cache or Redis. If you use in-memory than the only
thing you have to do is set cache.inMemory
field as true
. However, if you use Redis than you only have to specify
the Redis settings.
In the rules
array, you specify your rules. The pattern on the rule is basically a Regular Expression. Rules are
processed sequentially.
Name | Description | Required | Default |
---|---|---|---|
pattern | Regular expression to comparison pattern. | yes | None |
limit | Limit of the total requests | yes | 0 |
scope | Specifies the increment key. Can be rule or path . Rule pattern is used as increment key. Otherwise request's METHOD PATH |
no | $defaultRuleScope |
In the tracing
object, you specify a tracing method for this app. We support only NewRelic right now.
Name | Description | Required | Default |
---|---|---|---|
enabled | Enabled the tracing | no | false |
provider | Your tracing provider. Available providers is: [new-relic ] |
no | new-relic |
newRelic.appName | App name on NewRelic | yes | rate-limiter |
newRelic.licenseKey | License key to access to NewRelic | yes | None |
newRelic.distributedTracerEnabled | Specifies whether Distributed Tracing is enabled or not | no | false |
Your regexp is compared with this format METHOD PATH
, for example, you get a request like DELETE /users?name=John
but this is compared with your regexp as this format DELETE /users
.
Let's make another example. Assume that we have already some rules as defined above. Here is an example curl
and the
processing of this.
$ curl -X GET localhost:8000/users/4/addresses?country=tr
You can do this request 4 times on each 30 seconds.
- Implement windowLengthInSeconds
- Kubernetes Operator
- OpenTelemetry Support
- Rich algorithm support