欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Go 如何基于IP限制HTTP訪問頻率的方法實(shí)現(xiàn)

 更新時(shí)間:2019年11月25日 09:45:51   投稿:zx  
這篇文章主要介紹了Go 如何基于IP限制HTTP訪問頻率的方法實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

如果你運(yùn)行 HTTP 服務(wù),并且希望限制 HTTP 的訪問頻率,那么你可以借助一些比較穩(wěn)定的工具,例如: github.com/didip/tollbooth。不過如果你構(gòu)建的應(yīng)用比較簡單,也可以自己來實(shí)現(xiàn)。

我們可以使用一個(gè)現(xiàn)有的 Go 包 x/time/rate。

本課程,我們將創(chuàng)建一個(gè)簡單的中間件實(shí)現(xiàn)基于 IP 限制 HTTP 訪問頻率。

簡單的 HTTP 服務(wù)

讓我們從創(chuàng)建一個(gè)簡單的 HTTP 服務(wù)開始,它有非常簡單的終端。 但是,因?yàn)樗脑L問頻率可能非常高,因此我們要為它添加頻率限制。

package main

import (
 "log"
 "net/http"
)

func main() {
 mux := http.NewServeMux()
 mux.HandleFunc("/", okHandler)

 if err := http.ListenAndServe(":8888", mux); err != nil {
  log.Fatalf("unable to start server: %s", err.Error())
 }
}

func okHandler(w http.ResponseWriter, r *http.Request) {
 // 某些消耗很高的數(shù)據(jù)庫請(qǐng)求
 w.Write([]byte("alles gut"))
}

通過 main.go 我們啟動(dòng)服務(wù),監(jiān)聽 :8888 端口,這樣我們就有了一個(gè)簡單的終端 /。

golang.org/x/time/rate

我們將使用名為 x/time/rate 的 Go 包,它提供了一個(gè)令牌桶速率限制器算法。rate#Limiter 控制允許事件發(fā)生的頻率。它實(shí)現(xiàn)了一個(gè)大小為 b 的「令牌桶」,最初是滿的,并以每秒 r 的速度重新填充令牌。通俗地講,就是在任何足夠大的時(shí)間間隔內(nèi),限制器將速率限制為每秒 r 個(gè)令牌,最大突發(fā)大小為 b 個(gè)事件。

由于我們希望實(shí)現(xiàn)每個(gè) IP 地址的速率限制器,我們還需要維護(hù)一個(gè)限制器映射。

package main

import (
 "sync"

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

// IPRateLimiter .
type IPRateLimiter struct {
 ips map[string]*rate.Limiter
 mu *sync.RWMutex
 r rate.Limit
 b int
}

// NewIPRateLimiter .
func NewIPRateLimiter(r rate.Limit, b int) *IPRateLimiter {
 i := &IPRateLimiter{
  ips: make(map[string]*rate.Limiter),
  mu: &sync.RWMutex{},
  r: r,
  b: b,
 }

 return i
}

// AddIP 創(chuàng)建了一個(gè)新的速率限制器,并將其添加到 ips 映射中,
// 使用 IP地址作為密鑰
func (i *IPRateLimiter) AddIP(ip string) *rate.Limiter {
 i.mu.Lock()
 defer i.mu.Unlock()

 limiter := rate.NewLimiter(i.r, i.b)

 i.ips[ip] = limiter

 return limiter
}

// GetLimiter 返回所提供的IP地址的速率限制器(如果存在的話).
// 否則調(diào)用 AddIP 將 IP 地址添加到映射中
func (i *IPRateLimiter) GetLimiter(ip string) *rate.Limiter {
 i.mu.Lock()
 limiter, exists := i.ips[ip]

 if !exists {
  i.mu.Unlock()
  return i.AddIP(ip)
 }

 i.mu.Unlock()

 return limiter
}

NewIPRateLimiter 創(chuàng)建一個(gè) IP 限制器實(shí)例,HTTP 服務(wù)器必須調(diào)用這個(gè)實(shí)例的 GetLimiter 來獲得指定 IP 的限制器 (從映射或生成一個(gè)新的)。

中間件

讓我們升級(jí)的 HTTP 服務(wù)并將中間件添加到所有端點(diǎn),如果 IP 達(dá)到限制,它將響應(yīng) 429 Too Many Requests,否則,它將繼續(xù)該請(qǐng)求。

每一個(gè)經(jīng)過中間件的請(qǐng)求,我們都會(huì)調(diào)用 limitMiddleware 函數(shù)中的全局方法 Allow()。如果存儲(chǔ)桶中沒有令牌了,該方法會(huì)返回 false,該請(qǐng)求會(huì)收到 429 Too Many Requests 的響應(yīng)。否則 Allow() 方法將消耗一個(gè)令牌,并將請(qǐng)求傳遞給下一個(gè)程序。

package main

import (
 "log"
 "net/http"
)

var limiter = NewIPRateLimiter(1, 5)

func main() {
 mux := http.NewServeMux()
 mux.HandleFunc("/", okHandler)

 if err := http.ListenAndServe(":8888", limitMiddleware(mux)); err != nil {
  log.Fatalf("unable to start server: %s", err.Error())
 }
}

func limitMiddleware(next http.Handler) http.Handler {
 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  limiter := limiter.GetLimiter(r.RemoteAddr)
  if !limiter.Allow() {
   http.Error(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests)
   return
  }

  next.ServeHTTP(w, r)
 })
}

func okHandler(w http.ResponseWriter, r *http.Request) {
 // 非常重要的數(shù)據(jù)請(qǐng)求(譯者注:這句話沒理解到位)
 w.Write([]byte("alles gut"))
}

編譯 & 執(zhí)行

go get golang.org/x/time/rate
go build -o server .
./server

測(cè)試

這是我喜歡使用的一個(gè)非常好的來進(jìn)行 HTTP 負(fù)載測(cè)試的工具,它叫做 vegeta (它也是用 Go 編寫的)。

brew install vegeta

我們需要?jiǎng)?chuàng)建一個(gè)簡單的配置文件,來展示我們希望生成的請(qǐng)求。

GET http://localhost:8888/

然后運(yùn)行攻擊 10 秒,每個(gè)時(shí)間單位 100 個(gè)請(qǐng)求。

vegeta attack -duration=10s -rate=100 -targets=vegeta.conf | vegeta report

結(jié)果,您將看到一些請(qǐng)求返回了 200,但是大多數(shù)都返回了 429。

以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Golang map實(shí)現(xiàn)原理深入分析

    Golang map實(shí)現(xiàn)原理深入分析

    map是一種無序的基于key-value的數(shù)據(jù)結(jié)構(gòu),Go語言中的map是引用類型,必須初始化才能使用,下面這篇文章主要給大家介紹了關(guān)于golang中map使用的幾點(diǎn)注意事項(xiàng),需要的朋友可以參考下
    2023-01-01
  • 關(guān)于Golang中for-loop與goroutine的問題詳解

    關(guān)于Golang中for-loop與goroutine的問題詳解

    這篇文章主要給大家介紹了關(guān)于Golang中for-loop與goroutine問題的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用golang具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-09-09
  • Go語言之嵌入類型詳解

    Go語言之嵌入類型詳解

    本文詳細(xì)講解了Go語言之嵌入類型,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-07-07
  • Golang中switch語句和select語句的用法教程

    Golang中switch語句和select語句的用法教程

    這篇文章主要給大家介紹了關(guān)于Golang中switch和select的用法教程,文中通過示例代碼將switch語句與select語句的使用方法介紹的非常詳細(xì),對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面跟著小編一起來學(xué)習(xí)學(xué)習(xí)吧。
    2017-06-06
  • goland 恢復(fù)已更改文件的操作

    goland 恢復(fù)已更改文件的操作

    這篇文章主要介紹了goland 恢復(fù)已更改文件的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • Golang并發(fā)繞不開的重要組件之Goroutine詳解

    Golang并發(fā)繞不開的重要組件之Goroutine詳解

    Goroutine、Channel、Context、Sync都是Golang并發(fā)編程中的幾個(gè)重要組件,這篇文中主要為大家介紹了Goroutine的相關(guān)知識(shí),需要的可以參考一下
    2023-06-06
  • Golang開發(fā)之接口的具體使用詳解

    Golang開發(fā)之接口的具體使用詳解

    在 Golang 中,接口是一種類型,它是由一組方法簽名組成的抽象集合。這篇文章主要為大家介紹了Golang接口的具體使用,希望對(duì)大家有所幫助
    2023-04-04
  • Golang你一定要懂的連接池實(shí)現(xiàn)

    Golang你一定要懂的連接池實(shí)現(xiàn)

    這篇文章主要介紹了Golang你一定要懂的連接池實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • Go語言使用singleflight解決緩存擊穿

    Go語言使用singleflight解決緩存擊穿

    在構(gòu)建高性能的服務(wù)時(shí),緩存是優(yōu)化數(shù)據(jù)庫壓力和提高響應(yīng)速度的關(guān)鍵技術(shù),但使用緩存也會(huì)帶來一些問題,其中就包括緩存擊穿,下面我們就來看看Go語言中如何使用singleflight解決緩存擊穿問題吧
    2024-03-03
  • GO中優(yōu)雅編碼與降低圈復(fù)雜度詳析

    GO中優(yōu)雅編碼與降低圈復(fù)雜度詳析

    Go語法簡單易用,有其他編程經(jīng)驗(yàn)的開發(fā)者,相信學(xué)習(xí)并快速上手Go語言的開發(fā),多數(shù)覺得不困難吧,下面這篇文章主要給大家介紹了關(guān)于GO中優(yōu)雅編碼與降低圈復(fù)雜度的相關(guān)資料,需要的朋友可以參考下
    2022-12-12

最新評(píng)論