简体   繁体   English

使用 `didip/tollbooth` 限制每小时最大请求数

[英]Limit Max Number of Requests Per Hour with `didip/tollbooth`

I'm new to rate limiting and want to use tollbooth to limit HTTP requests.我是速率限制的新手,想使用收费站来限制 HTTP 请求。

I also read the Token Bucket Algorithm page on Wikipedia.我还阅读了 Wikipedia 上的令牌桶算法页面。

For a simple test app, I want to limit the max number of concurrent requests to 10 regardless of request IP, and have a max burst size of 3 based on request IP.对于一个简单的测试应用程序,我想将最大并发请求数限制为10 ,而不管请求 IP,并且根据请求 IP,最大突发大小为3

NOTE: The 10 and 3 are just to make rate limiting easier to observe.注意: 103只是为了使速率限制更易于观察。

Below is my code based on the examples on tollbooth 's GitHub page :以下是我基于tollboothGitHub 页面上的示例的代码:

package main

import (
    "net/http"
    "time"

    "github.com/didip/tollbooth/v7"
    "github.com/didip/tollbooth/v7/limiter"
)

func main() {
    lmt := tollbooth.NewLimiter(3, &limiter.ExpirableOptions{DefaultExpirationTTL: time.Hour})

    http.Handle("/", tollbooth.LimitFuncHandler(lmt, HelloHandler))
    http.ListenAndServe(":8080", nil)
}

func HelloHandler(w http.ResponseWriter, req *http.Request) {
    w.Write([]byte("Hello, World!"))
}

I test the code by running curl -i localhost:8080 several times in rapid succession, and I do get HTTP/1.1 429 Too Many Requests errors whenever I exceed the rate limit I set.我通过快速连续多次运行curl -i localhost:8080来测试代码,每当我超过我设置的速率限制时,我都会收到HTTP/1.1 429 Too Many Requests错误。

Below are my questions:以下是我的问题:

  1. How do I use tollbooth to limit max number of concurrent requests to something like 10 ?如何使用tollbooth将最大并发请求数限制为10 And does it even make sense to do so?这样做是否有意义? I assume it does because rate limiting based only on IPs sounds like the server could still go out of memory when too many IPs access it at once.我认为确实如此,因为仅基于 IP 的速率限制听起来像服务器仍然可以 go 超出 memory 当太多 IP 一次访问它时。

  2. Am I approaching rate limiting correctly, or am I missing something?我是否正确接近速率限制,或者我错过了什么? Perhaps this is something that's better handled by whatever load balancer is working with the app in the cloud?也许这是由任何负载均衡器与云中的应用程序一起工作的更好处理的事情?

UPDATE: Here's my working code based on Woody1193 's answer:更新:这是我基于Woody1193的回答的工作代码:

package main

import (
    "net/http"
    "sync"
    "time"

    "github.com/didip/tollbooth/v7"
    "github.com/didip/tollbooth/v7/limiter"
)

func main() {
    ipLimiter := tollbooth.NewLimiter(3, &limiter.ExpirableOptions{DefaultExpirationTTL: time.Hour})
    globalLimiter := NewConcurrentLimiter(10)

    http.Handle("/", globalLimiter.LimitConcurrentRequests(ipLimiter, HelloHandler))
    http.ListenAndServe(":8080", nil)
}

func HelloHandler(w http.ResponseWriter, req *http.Request) {
    w.Write([]byte("Hello, World!"))
}

type ConcurrentLimiter struct {
    max     int
    current int
    mut     sync.Mutex
}

func NewConcurrentLimiter(limit int) *ConcurrentLimiter {
    return &ConcurrentLimiter{
        max: limit,
    }
}

func (limiter *ConcurrentLimiter) LimitConcurrentRequests(lmt *limiter.Limiter,
    handler func(http.ResponseWriter, *http.Request)) http.Handler {

    middle := func(w http.ResponseWriter, r *http.Request) {

        limiter.mut.Lock()
        maxHit := limiter.current == limiter.max

        if maxHit {
            limiter.mut.Unlock()
            http.Error(w, http.StatusText(429), http.StatusTooManyRequests)
            return
        }

        limiter.current += 1
        limiter.mut.Unlock()

        defer func() {
            limiter.mut.Lock()
            limiter.current -= 1
            limiter.mut.Unlock()
        }()

        // There's no rate-limit error, serve the next handler.
        handler(w, r)
    }

    return tollbooth.LimitHandler(lmt, http.HandlerFunc(middle))
}

It appears that tollbooth doesn't offer the functionality you're looking for.收费亭似乎不提供您正在寻找的功能。 However, you can roll your own:但是,您可以自己滚动:

type ConcurrentLimiter struct {
    max int
    current int
    mut sync.Mutex
}

func NewConcurrentLimiter(limit int) *ConcurrentLimiter {
    return &ConcurrentLimiter {
        max: limit,
        mut: new(sync.Mutex),
    }
}

func (limiter *ConcurrentLimiter) LimitConcurrentRequests(lmt *limiter.Limiter, 
    next http.Handler) http.Handler {

    middle := func(w http.ResponseWriter, r *http.Request) {

        limiter.mut.Lock()
        maxHit := limiter.current == limiter.max
        if maxHit {
            limiter.mut.Unlock()
            httpError := // Insert your HTTP error here
            return
        }

        limiter.current += 1
        limiter.mut.Unlock()

        defer func() {
            limiter.mut.Lock()
            limiter.current -= 1
            limiter.mut.Unlock()
        }()

        // There's no rate-limit error, serve the next handler.
        next.ServeHTTP(w, r)
    }

    return tollbooth.LimitHandler(lmt, http.HandlerFunc(middle))
}

Then, in your setup you can do:然后,在您的设置中,您可以执行以下操作:

http.Handle("/", NewConcurrentLimiter(10).LimitConcurrentRequests(HelloHandler))

This code works by maintaining a value describing how many requests the API is currently handling and returning an error if the maximum value has been met.此代码通过维护一个值来工作,该值描述 API 当前正在处理多少请求,如果已达到最大值,则返回错误。 The Mutex is used to ensure that the value is updated regardless of concurrent requests. Mutex用于确保无论并发请求如何都更新该值。

I had to inject the tollbooth.Limiter into the limiter I wrote because of the way tollbooth handles such functions (ie it doesn't operate as a middleware).由于 tollbooth 处理此类功能的方式(即它不作为中间件运行),我不得不将tollbooth.Limiter注入到我编写的限制器中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 限制每小时 AWS Lambda 次调用的最简单方法 - Easiest way to limit AWS Lambda invocations per hour 如何限制lambda function每分钟的通话次数? - how to limit the number of lambda function calls per minute? 如何访问我的 App Engine 应用程序每小时/每天/每周返回的错误数? - How can I access the number of errors that my App Engine app is returning per hour/day/week? 如何限制 Google Cloud Tasks 每分钟执行 200 个 API 请求? - How to limit Google Cloud Tasks to execute 200 API requests per minute? 如何执行最大限制号。 SQL 中每个日期每天的行数? - How to enforce a max limit no. of rows per day per date in SQL? 从 GCP 存储桶流式传输大文件超过 1 小时的最长 Cloud Run 限制 - Streaming a large file from a GCP Bucket exceeds 1-hour max Cloud Run limit 每组只留下最大值 - Left only MAX value per group AWS KMS 请求每秒限制的解决方法 - Workaround for AWS KMS request per second limit watson assistant、dialog flow 和 amazon lex 每秒支持的请求数 - number of requests supported per second by watson assistance, dialog flow and amazon lex EC2 Windows 实例是按小时收费还是按秒收费? - Are EC2 Windows instances charged per hour or per second?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM