Sign inSign up

khos2ow/ratelimiter

By khos2ow

•Updated about 2 years ago

Distributed rate limiting in Go

Image
0

1.9K

khos2ow/ratelimiter repository overview

⁠ratelimiter

Build Status GoDoc Go Report Card codecov License Latest release

ratelimiter is an app to do dirstibuted rate limiting in front of backend services. It consists of:

  • A command line interface (ratelimiter⁠) built on these packages.
  • Docker image⁠ to run ratelimiter in a containerized workload.
  • Go package⁠, which can directly be used in other projects.

⁠Table of Contents

⁠Installation

The latest version can be installed using go get:

GO111MODULE="on" go get github.com/khos2ow/[email protected]

NOTE: please use the latest go to do this, ideally go 1.13.5 or greater. We use go 1.14.

This will put ratelimiter in $(go env GOPATH)/bin. If you encounter the error ratelimiter: command not found after installation then you may need to either add that directory to your $PATH as shown here⁠ or do a manual installation by cloning the repo and run make build from the repository which will put ratelimiter in:

$(go env GOPATH)/src/github.com/khos2ow/ratelimiter/bin/$(uname | tr '[:upper:]' '[:lower:]')-amd64/ratelimiter

Stable binaries are also available on the releases⁠ page. To install, download the binary for your platform from "Assets" and place this into your $PATH:

curl -Lo ./ratelimiter https://github.com/khos2ow/ratelimiter/releases/download/v0.1.1/ratelimiter-v0.1.1-$(uname | tr '[:upper:]' '[:lower:]')-amd64
chmod +x ./ratelimiter
mv ./ratelimiter /some-dir-in-your-PATH/ratelimiter

NOTE: Windows releases are in EXE format.

⁠Running

There are multiple ways of running ratelimiter service.

⁠CLI binary

You can run ratelimiter binary with provided flags as standalone binary:

ratelimiter \
    --rate-limit <number> \
    --rate-interval <number> \
    --rate-timeunit <time-unit> \
    --use-redis <use-redis-or-in-memory-cache> \
    --redis-url <ip-of-redis> \
    --redis-port <port-of-redis> \
    --redis-password <password-for-redis> \
    --backend-server <fdqn-or-ip-of-backend-service>

Note that you can provide multiple --backend-server <string> or one comma-separated list of servers. e.g:

ratelimiter --backend-server 1.2.3.4 --backend-server 5.6.7.8
or
ratelimiter --backend-server 1.2.3.4,5.6.7.8

You can also use environment variables defined on the host instead of using the flags.

NameFlag
RATE_LIMIT--rate-limit
RATE_INTERVAL--rate-interval
RATE_TIMEUNIT--rate-timeunit
USE_REDIS--use-redis
REDIS_URL--redis-url
REDIS_PORT--redis-port
REDIS_PASSWORD--redis-password
BACKEND_SERVER--backend-server

Note: You have to only use comma-separated value in BACKEND_SERVER environment variable.

⁠Docker Container

Docker images are created on each release with the following tag format:

khos2ow/ratelimiter:latest
khos2ow/ratelimiter:0.1.1 # <git-tag-without-leading-v>

also HEAD of master which might be unstable:

khos2ow/ratelimiter:edge

and you can simply use the image:

docker run -d \
    --name ratelimiter \
    --restart always \
    -p 8080:8080 \
    khos2ow/ratelimiter:0.1.1 \
    --rate-limit=<number> \
    --rate-interval=<number> \
    --rate-timeunit=<time-unit> \
    --use-redis=<use-redis-or-in-memory-cache> \
    --redis-url=<ip-of-redis> \
    --redis-port=<port-of-redis> \
    --redis-password=<password-for-redis> \
    --backend-server=<comma-separated-list-of-backend-service>
⁠Kubernetes

Prerequisites

  1. Install kubectl⁠

  2. Deploy Redis cluster⁠

  3. Update Redis URL and port and optionally backend_server in deploy/config.yaml⁠:

    ---
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: rate-limiter-config
      namespace: rate-limiter
      labels:
        app: rate-limiter
    data:
      RATE_LIMIT: "<RATE.LIMIT>"
      RATE_INTERVAL: "<RATE.INTERVAL>"
      RATE_TIMEUNIT: "<RATE.TIMEUNIT>"
      USE_REDIS: "true | false"
      REDIS_URL: "<REDIS.URL>"
      REDIS_PORT: "<REDIS.PORT>"
      BACKEND_SERVER: ""
      # BACKEND_SERVER: "<COMMA.SEPARATED.BACKEND.SERVERS>"
    
  4. Update Redis password in deploy/secret.yaml⁠:

    ---
    apiVersion: v1
    kind: Secret
    metadata:
      name: rate-limiter-secret
      namespace: rate-limiter
    type: Opaque
    data:
      REDIS_PASSWORD: "<REDIS.PASSWORD>"
    
  5. Enable or update deploy/ingress.yaml⁠:

    ---
    apiVersion: networking.k8s.io/v1beta1
    kind: Ingress
    metadata:
      name: rate-limiter
      namespace: rate-limiter
      labels:
        app: rate-limiter
      annotations:
        kubernetes.io/ingress.class: nginx-internal
    spec:
      rules:
      - host: rate-limiter.example.com
        http:
        paths:
        - path: /
          backend:
            serviceName: rate-limiter-service
            servicePort: http
    

then you can deploy using kubectl:

kubectl apply -f deploy -n rate-limiter

⁠Go Package

ratelimiter exposes most of its functionality through Go Package which can be imported in other projects. To do that you can use package manager of your choice:

go get github.com/khos2ow/ratelimiter

and then

import "github.com/khos2ow/ratelimiter/pkg/ratelimiter"

example/main.go⁠:

package main

import (
    "fmt"
    "time"

    "github.com/khos2ow/ratelimiter/internal/data"
    "github.com/khos2ow/ratelimiter/pkg/ratelimiter"
)

func main() {
    resource := "foo"
    store := data.NewInMemory(&data.Options{})
    rule := ratelimiter.NewRule(10, 1, time.Second)
    limiter := ratelimiter.NewLimiter(rule, store)

    start := time.Now()
    fmt.Printf("limiting resource '%s' to %s\n\n", resource, rule.String())

    for i := 0; i < 25; i++ {
        allowed, err := limiter.IsAllowed(resource)
        if err != nil {
            fmt.Printf("hit #%-10derror: %-10velapsed: %f seconds\n", i+1, err.Error(), time.Now().Sub(start).Seconds())
        } else {
            fmt.Printf("hit #%-10dallowed: %-10velapsed: %f seconds\n", i+1, allowed, time.Now().Sub(start).Seconds())
        }
        time.Sleep(80 * time.Millisecond)
    }

    fmt.Printf("\ntook %f seconds\n", time.Now().Sub(start).Seconds())
}

// limiting resource 'foo' to 10 hits per second
//
// hit #1         allowed: true      elapsed: 0.000012 seconds
// hit #2         allowed: true      elapsed: 0.080239 seconds
// hit #3         allowed: true      elapsed: 0.160510 seconds
// hit #4         allowed: true      elapsed: 0.240883 seconds
// hit #5         allowed: true      elapsed: 0.321136 seconds
// hit #6         allowed: true      elapsed: 0.401298 seconds
// hit #7         allowed: true      elapsed: 0.481417 seconds
// hit #8         allowed: true      elapsed: 0.561576 seconds
// hit #9         allowed: true      elapsed: 0.641844 seconds
// hit #10        allowed: true      elapsed: 0.722082 seconds
// hit #11        allowed: false     elapsed: 0.802300 seconds
// hit #12        allowed: false     elapsed: 0.882519 seconds
// hit #13        allowed: false     elapsed: 0.962731 seconds
// hit #14        allowed: true      elapsed: 1.042958 seconds
// hit #15        allowed: true      elapsed: 1.123172 seconds
// hit #16        allowed: true      elapsed: 1.203390 seconds
// hit #17        allowed: true      elapsed: 1.283565 seconds
// hit #18        allowed: true      elapsed: 1.363771 seconds
// hit #19        allowed: true      elapsed: 1.443981 seconds
// hit #20        allowed: true      elapsed: 1.524204 seconds
// hit #21        allowed: true      elapsed: 1.604430 seconds
// hit #22        allowed: true      elapsed: 1.684739 seconds
// hit #23        allowed: true      elapsed: 1.764983 seconds
// hit #24        allowed: true      elapsed: 1.845355 seconds
// hit #25        allowed: false     elapsed: 1.925563 seconds
//
// took 2.009465 seconds

Tag summary

Content type

Image

Digest

sha256:4d8b45d2b…

Size

5.7 MB

Last updated

about 2 years ago

docker pull khos2ow/ratelimiter