搜索
首页后端开发GolangGolang实现ip限流

Golang实现ip限流

May 10, 2023 am 09:21 AM

随着互联网和移动互联网的快速发展,服务器面对的压力越来越大,如何限制客户端对服务器的请求,避免服务器崩溃成为了一个大问题。在实际项目中,我们经常需要限制IP的请求数,保证网站的可用性。

在这里,我们将介绍如何使用Golang实现IP限流。总的来说,我们将利用令牌桶算法来实现基于IP地址的限流。 令牌桶算法是一种流量控制算法,它允许一定数量的请求在一定时间内通过并限制一段时间内的请求流量。

实现细节

令牌桶算法以恒定速率往桶中放入令牌,令牌桶有一个容量限制,意味着桶中的令牌数量不会超过容量。对于每个请求,从桶中移除一个令牌,如果桶中没有令牌,则请求无法通过。

为了实现基于IP地址的限流,我们需要为每个IP地址创建一个令牌桶,每个令牌桶都有一个最大容量和一个恒定的速度。当请求到来时,我们从令牌桶中移除一个令牌,如果桶中没有令牌,则拒绝请求。

基于此,我们可以定义一个IP限流器:

type IPRateLimiter struct {
    limiterBuckets map[string]*rate.Limiter
    mu             *sync.Mutex
    r              rate.Limit
    b              int
}

其中, limiterBuckets 是一个映射,将字符串 IP 地址映射到令牌桶。mu 是一个互斥锁, r 是速率限制器每秒放入令牌的速率, b 是令牌桶的容量。

为了为每个IP地址创建令牌桶,我们定义一个函数NewIPRateLimiter :

func NewIPRateLimiter(r rate.Limit, b int) *IPRateLimiter {
    return &IPRateLimiter{
        limiterBuckets: make(map[string]*rate.Limiter),
        mu:             &sync.Mutex{},
        r:              r,
        b:              b,
    }
}

func (i *IPRateLimiter) AddIP(ip string) *rate.Limiter {
    i.mu.Lock()
    defer i.mu.Unlock()

    limiter := rate.NewLimiter(i.r, i.b)
    i.limiterBuckets[ip] = limiter

    return limiter
}

AddIP函数用于为IP地址创建令牌桶。如果为该IP地址创建了令牌桶,则返回现有的令牌桶,否则创建一个新的令牌桶并返回。

最后,我们可以实现HTTP中间件来限制IP地址的请求数:

func (i *IPRateLimiter) Limit(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        ip := r.RemoteAddr
        limiter, ok := i.limiterBuckets[ip]
        if !ok {
            limiter = i.AddIP(ip)
        }

        if !limiter.Allow() {
            http.Error(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests)
            return
        }

        next.ServeHTTP(w, r)
    })
}

该中间件允许在指定的速率和容量下通过请求。如果请求数超过容量,则返回HTTP错误代码429(太多请求)。

完整代码如下:

package main

import (
    "net/http"
    "strconv"
    "sync"

    "golang.org/x/time/rate"
)

type IPRateLimiter struct {
    limiterBuckets map[string]*rate.Limiter
    mu             *sync.Mutex
    r              rate.Limit
    b              int
}

func NewIPRateLimiter(r rate.Limit, b int) *IPRateLimiter {
    return &IPRateLimiter{
        limiterBuckets: make(map[string]*rate.Limiter),
        mu:             &sync.Mutex{},
        r:              r,
        b:              b,
    }
}

func (i *IPRateLimiter) AddIP(ip string) *rate.Limiter {
    i.mu.Lock()
    defer i.mu.Unlock()

    limiter := rate.NewLimiter(i.r, i.b)
    i.limiterBuckets[ip] = limiter

    return limiter
}

func (i *IPRateLimiter) Limit(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        ip := r.RemoteAddr
        limiter, ok := i.limiterBuckets[ip]
        if !ok {
            limiter = i.AddIP(ip)
        }

        if !limiter.Allow() {
            http.Error(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests)
            return
        }

        next.ServeHTTP(w, r)
    })
}

func IndexHandler(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("welcome."))
}

func main() {
    limit := rate.Limit(10) // 速率,每秒放入令牌的数量
    capacity := 100        // 容量,桶的大小

    ipRateLimiter := NewIPRateLimiter(limit, capacity)

    http.Handle("/", ipRateLimiter.Limit(http.HandlerFunc(IndexHandler)))

    err := http.ListenAndServe(":8080", nil)
    if err != nil {
        panic(err)
    }
}

在这个例子中,我们允许每秒放入10个令牌,并限制桶的容量为100。这意味着该限制器可以处理每秒最多10个请求,但如果对同一IP地址的请求达到100个,则无法通过请求。同时,我们定义了一个简单的处理程序,它将响应“欢迎”。

结论

在本文中,我们使用Golang实现了IP限流,采用令牌桶算法来限制每个IP地址的请求速率。这种方法可以实现一个简单而有效的限流机制,并且可以在Golang中方便地实现。当你在编写高并发的网络应用程序时,这可能是一个非常有用的技巧。

以上是Golang实现ip限流的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
使用GO编程语言构建可扩展系统使用GO编程语言构建可扩展系统Apr 25, 2025 am 12:19 AM

goisidealforbuildingscalablesystemsduetoitssimplicity,效率和建筑物内currencysupport.1)go'scleansyntaxandaxandaxandaxandMinimalisticDesignenhanceProductivityAndRedCoductivityAndRedCuceErr.2)ItSgoroutinesAndInesAndInesAndInesAndineSandChannelsEnablenableNablenableNableNablenableFifficConcurrentscorncurrentprogragrammentworking torkermenticmminging

有效地使用Init功能的最佳实践有效地使用Init功能的最佳实践Apr 25, 2025 am 12:18 AM

Initfunctionsingorunautomationbeforemain()andareusefulforsettingupenvorments和InitializingVariables.usethemforsimpletasks,避免使用辅助效果,andbecautiouswithTestingTestingTestingAndLoggingTomaintAnainCodeCodeCodeClarityAndTestesto。

INIT函数在GO软件包中的执行顺序INIT函数在GO软件包中的执行顺序Apr 25, 2025 am 12:14 AM

goinitializespackagesintheordertheordertheyimported,thenexecutesInitFunctionswithinApcageIntheirdeFinityOrder,andfilenamesdetermineTheOrderAcractacractacrosmultiplefiles.thisprocessCanbeCanbeinepessCanbeInfleccessByendercrededBydeccredByDependenciesbetenciesbetencemendencenciesbetnependendpackages,whermayleLeadtocomplexinitialitialializizesizization

在GO中定义和使用自定义接口在GO中定义和使用自定义接口Apr 25, 2025 am 12:09 AM

CustomInterfacesingoarecrucialforwritingFlexible,可维护,andTestableCode.TheyEnableDevelostOverostOcusonBehaviorBeiroveration,增强ModularityAndRobustness.byDefiningMethodSigntulSignatulSigntulSignTypaterSignTyperesthattypesmustemmustemmustemmustemplement,InterfaceSallowForCodeRepodEreusaperia

在GO中使用接口进行模拟和测试在GO中使用接口进行模拟和测试Apr 25, 2025 am 12:07 AM

使用接口进行模拟和测试的原因是:接口允许定义合同而不指定实现方式,使得测试更加隔离和易于维护。1)接口的隐式实现使创建模拟对象变得简单,这些对象在测试中可以替代真实实现。2)使用接口可以轻松地在单元测试中替换服务的真实实现,降低测试复杂性和时间。3)接口提供的灵活性使得可以为不同测试用例更改模拟行为。4)接口有助于从一开始就设计可测试的代码,提高代码的模块化和可维护性。

在GO中使用init进行包装初始化在GO中使用init进行包装初始化Apr 24, 2025 pm 06:25 PM

在Go中,init函数用于包初始化。1)init函数在包初始化时自动调用,适用于初始化全局变量、设置连接和加载配置文件。2)可以有多个init函数,按文件顺序执行。3)使用时需考虑执行顺序、测试难度和性能影响。4)建议减少副作用、使用依赖注入和延迟初始化以优化init函数的使用。

GO的选择语句:多路复用并发操作GO的选择语句:多路复用并发操作Apr 24, 2025 pm 05:21 PM

go'SselectStatementTreamLinesConcurrentProgrambyMultiplexingOperations.1)itallowSwaitingOnMultipleChannEloperations,执行thefirstreadyone.2)theDefirstreadyone.2)thedefefcasepreventlocksbysbysbysbysbysbythoplocktrograpraproxrograpraprocrecrecectefnoopeready.3)

GO中的高级并发技术:上下文和候补组GO中的高级并发技术:上下文和候补组Apr 24, 2025 pm 05:09 PM

contextancandwaitgroupsarecrucialingoformanaginggoroutineseflect.1)context contextsallowsAllowsAllowsAllowsAllowsAllingCancellationAndDeadLinesAcrossapibiboundaries,确保GoroutinesCanbestoppedGrace.2)WaitGroupsSynChronizeGoroutines,确保Allimizegoroutines,确保AllizeNizeGoROutines,确保AllimizeGoroutines

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

将Eclipse与SAP NetWeaver应用服务器集成。

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

EditPlus 中文破解版

EditPlus 中文破解版

体积小,语法高亮,不支持代码提示功能