Add Redis rate limiter
This commit is contained in:
parent
c166a41c99
commit
550d96ea67
26 changed files with 2268 additions and 69 deletions
|
@ -1790,6 +1790,90 @@ spec:
|
|||
Period, in combination with Average, defines the actual maximum rate, such as:
|
||||
r = Average / Period. It defaults to a second.
|
||||
x-kubernetes-int-or-string: true
|
||||
redis:
|
||||
description: Redis hold the configs of Redis as bucket in rate
|
||||
limiter.
|
||||
properties:
|
||||
db:
|
||||
description: DB defines the Redis database that will be selected
|
||||
after connecting to the server.
|
||||
type: integer
|
||||
dialTimeout:
|
||||
anyOf:
|
||||
- type: integer
|
||||
- type: string
|
||||
description: |-
|
||||
DialTimeout sets the timeout for establishing new connections.
|
||||
Default value is 5 seconds.
|
||||
pattern: ^([0-9]+(ns|us|µs|ms|s|m|h)?)+$
|
||||
x-kubernetes-int-or-string: true
|
||||
endpoints:
|
||||
description: |-
|
||||
Endpoints contains either a single address or a seed list of host:port addresses.
|
||||
Default value is ["localhost:6379"].
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
maxActiveConns:
|
||||
description: |-
|
||||
MaxActiveConns defines the maximum number of connections allocated by the pool at a given time.
|
||||
Default value is 0, meaning there is no limit.
|
||||
type: integer
|
||||
minIdleConns:
|
||||
description: |-
|
||||
MinIdleConns defines the minimum number of idle connections.
|
||||
Default value is 0, and idle connections are not closed by default.
|
||||
type: integer
|
||||
poolSize:
|
||||
description: |-
|
||||
PoolSize defines the initial number of socket connections.
|
||||
If the pool runs out of available connections, additional ones will be created beyond PoolSize.
|
||||
This can be limited using MaxActiveConns.
|
||||
// Default value is 0, meaning 10 connections per every available CPU as reported by runtime.GOMAXPROCS.
|
||||
type: integer
|
||||
readTimeout:
|
||||
anyOf:
|
||||
- type: integer
|
||||
- type: string
|
||||
description: |-
|
||||
ReadTimeout defines the timeout for socket read operations.
|
||||
Default value is 3 seconds.
|
||||
pattern: ^([0-9]+(ns|us|µs|ms|s|m|h)?)+$
|
||||
x-kubernetes-int-or-string: true
|
||||
secret:
|
||||
description: Secret defines the name of the referenced Kubernetes
|
||||
Secret containing Redis credentials.
|
||||
type: string
|
||||
tls:
|
||||
description: |-
|
||||
TLS defines TLS-specific configurations, including the CA, certificate, and key,
|
||||
which can be provided as a file path or file content.
|
||||
properties:
|
||||
caSecret:
|
||||
description: |-
|
||||
CASecret is the name of the referenced Kubernetes Secret containing the CA to validate the server certificate.
|
||||
The CA certificate is extracted from key `tls.ca` or `ca.crt`.
|
||||
type: string
|
||||
certSecret:
|
||||
description: |-
|
||||
CertSecret is the name of the referenced Kubernetes Secret containing the client certificate.
|
||||
The client certificate is extracted from the keys `tls.crt` and `tls.key`.
|
||||
type: string
|
||||
insecureSkipVerify:
|
||||
description: InsecureSkipVerify defines whether the server
|
||||
certificates should be validated.
|
||||
type: boolean
|
||||
type: object
|
||||
writeTimeout:
|
||||
anyOf:
|
||||
- type: integer
|
||||
- type: string
|
||||
description: |-
|
||||
WriteTimeout defines the timeout for socket write operations.
|
||||
Default value is 3 seconds.
|
||||
pattern: ^([0-9]+(ns|us|µs|ms|s|m|h)?)+$
|
||||
x-kubernetes-int-or-string: true
|
||||
type: object
|
||||
sourceCriterion:
|
||||
description: |-
|
||||
SourceCriterion defines what criterion is used to group requests as originating from a common source.
|
||||
|
|
39
integration/fixtures/ratelimit/simple_redis.toml
Normal file
39
integration/fixtures/ratelimit/simple_redis.toml
Normal file
|
@ -0,0 +1,39 @@
|
|||
[global]
|
||||
checkNewVersion = false
|
||||
sendAnonymousUsage = false
|
||||
|
||||
[api]
|
||||
insecure = true
|
||||
|
||||
[log]
|
||||
level = "DEBUG"
|
||||
noColor = true
|
||||
|
||||
[entryPoints]
|
||||
[entryPoints.web]
|
||||
address = ":8081"
|
||||
|
||||
[providers.file]
|
||||
filename = "{{ .SelfFilename }}"
|
||||
|
||||
## dynamic configuration ##
|
||||
|
||||
[http.routers]
|
||||
[http.routers.router1]
|
||||
service = "service1"
|
||||
middlewares = [ "ratelimit" ]
|
||||
rule = "Path(`/`)"
|
||||
|
||||
[http.middlewares]
|
||||
[http.middlewares.ratelimit.rateLimit]
|
||||
average = 100
|
||||
burst = 1
|
||||
[http.middlewares.ratelimit.rateLimit.redis]
|
||||
endpoints = ["{{ .RedisEndpoint }}"]
|
||||
|
||||
[http.services]
|
||||
[http.services.service1]
|
||||
[http.services.service1.loadBalancer]
|
||||
passHostHeader = true
|
||||
[[http.services.service1.loadBalancer.servers]]
|
||||
url = "http://{{.Server1}}:80"
|
|
@ -1,6 +1,7 @@
|
|||
package integration
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -12,7 +13,8 @@ import (
|
|||
|
||||
type RateLimitSuite struct {
|
||||
BaseSuite
|
||||
ServerIP string
|
||||
ServerIP string
|
||||
RedisEndpoint string
|
||||
}
|
||||
|
||||
func TestRateLimitSuite(t *testing.T) {
|
||||
|
@ -26,6 +28,7 @@ func (s *RateLimitSuite) SetupSuite() {
|
|||
s.composeUp()
|
||||
|
||||
s.ServerIP = s.getComposeServiceIP("whoami1")
|
||||
s.RedisEndpoint = net.JoinHostPort(s.getComposeServiceIP("redis"), "6379")
|
||||
}
|
||||
|
||||
func (s *RateLimitSuite) TearDownSuite() {
|
||||
|
@ -58,3 +61,34 @@ func (s *RateLimitSuite) TestSimpleConfiguration() {
|
|||
s.T().Fatalf("requests throughput was too fast wrt to rate limiting: 100 requests in %v", elapsed)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *RateLimitSuite) TestRedisRateLimitSimpleConfiguration() {
|
||||
file := s.adaptFile("fixtures/ratelimit/simple_redis.toml", struct {
|
||||
Server1 string
|
||||
RedisEndpoint string
|
||||
}{
|
||||
Server1: s.ServerIP,
|
||||
RedisEndpoint: s.RedisEndpoint,
|
||||
})
|
||||
|
||||
s.traefikCmd(withConfigFile(file))
|
||||
|
||||
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.BodyContains("ratelimit", "redis"))
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
start := time.Now()
|
||||
count := 0
|
||||
for {
|
||||
err = try.GetRequest("http://127.0.0.1:8081/", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
|
||||
require.NoError(s.T(), err)
|
||||
count++
|
||||
if count > 100 {
|
||||
break
|
||||
}
|
||||
}
|
||||
stop := time.Now()
|
||||
elapsed := stop.Sub(start)
|
||||
if elapsed < time.Second*99/100 {
|
||||
s.T().Fatalf("requests throughput was too fast wrt to rate limiting: 100 requests in %v", elapsed)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,3 +2,10 @@ version: "3.8"
|
|||
services:
|
||||
whoami1:
|
||||
image: traefik/whoami
|
||||
|
||||
redis:
|
||||
image: redis:5.0
|
||||
command:
|
||||
- redis-server
|
||||
- --port
|
||||
- 6379
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue