ホームページ >バックエンド開発 >Golang >Redis を使用した Golang API のレート制限

Redis を使用した Golang API のレート制限

Barbara Streisand
Barbara Streisandオリジナル
2024-11-15 04:28:02578ブラウズ

レート制限 を簡単に言うと、ユーザーまたはクライアントが特定の時間枠内で API に対して実行できるリクエストの数を制限する手法です。過去に天気予報やジョーク API にアクセスしようとしたときに、「レート制限を超えました」というメッセージが表示されたことがあるかもしれません。 API をレート制限する理由については多くの議論がありますが、いくつかの重要な議論は、API を公正に使用すること、セキュリティを確保すること、過負荷からリソースを保護することなどです。

このブログでは、Gin フレームワークを使用して Golang で HTTP サーバーを作成し、Redis を使用してエンドポイントにレート制限機能を適用し、一定期間内に IP によってサーバーに対して行われたリクエストの総数を保存します。設定した制限を超える場合は、エラー メッセージが表示されます。

Gin と Redis が何なのかわからない場合のために説明します。 Gin は Golang で書かれた Web フレームワークです。大量のコードを記述せずに、シンプルで高速なサーバーを作成するのに役立ちます。 Redis は、データベースまたはキャッシュ機能として使用できる、メモリ内のキーと値のデータ ストアです。

前提条件

  • Golang、Gin、Redis についての知識
  • Redis インスタンス (Docker またはリモート マシンを使用できます)

さて、始めましょう。

プロジェクトを初期化するには、 go mod init を実行します。たとえば、 go mod init github.com/Pradumnasaraf/go-redis.

次に、Gin Framework を使用して単純な HTTP サーバーを作成し、それにレート制限のロジックを適用します。以下のコードをコピーできます。とても基本的なことです。 /message エンドポイントに到達すると、サーバーはメッセージで応答します。

以下のコードをコピーした後、 go mod tiny を実行して、インポートしたパッケージを自動的にインストールします。

package main

import (
    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()
    r.GET("/message", func(c *gin.Context) {
        c.JSON(200, gin.H{
            "message": "You can make more requests",
        })
    })
    r.Run(":8081") //listen and serve on localhost:8081
} 

ターミナルで go run main.go を実行すると、サーバーを実行でき、ターミナルにこのメッセージが表示されます。

Rate Limiting a Golang API using Redis

テストするには、localhost:8081/message に移動します。ブラウザにこのメッセージが表示されます。

Rate Limiting a Golang API using Redis

サーバーが稼働しているので、/message ルートにレート制限機能を設定しましょう。 go-redis/redis_rate パッケージを使用します。このパッケージの作成者のおかげで、制限を処理およびチェックするためのロジックを最初から作成する必要はありません。面倒な作業はすべてやってくれます。

以下は、レート制限機能を実装した後の完全なコードです。私たちはそれを一つ一つ理解していきます。混乱を避け、さまざまな部分がどのように連携するかを理解するために、完全なコードを早めに提供してください。

コードをコピーしたら、go mod tinyを実行して、インポートされたパッケージをすべてインストールします。それでは、コードを理解してみましょう (コード スニペットの下)。

package main

import (
    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()
    r.GET("/message", func(c *gin.Context) {
        c.JSON(200, gin.H{
            "message": "You can make more requests",
        })
    })
    r.Run(":8081") //listen and serve on localhost:8081
} 

まず、rateLimiter() 関数に直接ジャンプして、それを理解しましょう。この関数は、メイン関数の c.ClientIP() を介して取得できるリクエストの IP アドレスである引数を要求します。そして、制限に達した場合はエラーを返し、それ以外の場合は nil のままにします。コードの大部分は、公式 GitHub リポジトリから取得した定型コードです。ここで詳しく調べる重要な機能は、limitter.Allow() 関数です。 Addr: Redis インスタンスの URL パス値を取得します。 Dockerを使用してローカルで実行しています。何でも使用できますが、URL は適宜置き換えてください。

package main

import (
    "context"
    "errors"
    "net/http"

    "github.com/gin-gonic/gin"
    "github.com/go-redis/redis_rate/v10"
    "github.com/redis/go-redis/v9"
)

func main() {
    r := gin.Default()
    r.GET("/message", func(c *gin.Context) {
        err := rateLimiter(c.ClientIP())
        if err != nil {
            c.JSON(http.StatusTooManyRequests, gin.H{
                "message": "you have hit the limit",
            })
            return
        }
        c.JSON(http.StatusOK, gin.H{
            "message": "You can make more requests",
        })
    })
    r.Run(":8081")
}

func rateLimiter(clientIP string) error {
    ctx := context.Background()
    rdb := redis.NewClient(&redis.Options{
        Addr: "localhost:6379",
    })

    limiter := redis_rate.NewLimiter(rdb)
    res, err := limiter.Allow(ctx, clientIP, redis_rate.PerMinute(10))
    if err != nil {
        panic(err)
    }
    if res.Remaining == 0 {
        return errors.New("Rate")
    }

    return nil
}

これは 3 つの引数を取ります。最初の引数は ctx で、2 番目の引数は Redis データベースの Key、Key (値のキー)、そして 3 番目の引数は制限です。したがって、この関数は clientIP アドレスをキーとして、デフォルトの制限を値として保存し、リクエストが行われたときに制限を減らします。この構造の理由は、Redis データベースにはキーと値のペアの種類のデータを保存するための一意の識別と一意のキーが必要であり、すべての IP アドレスは独自の方法で一意であるためです。これが、ユーザー名の代わりに IP アドレスを使用している理由です。 3 番目の引数 redis_rate.PerMinute(10) は必要に応じて変更でき、制限 PerSecond を設定できます。 PerHour など、1 分/秒/時間あたりに実行できるリクエストの数を括弧内の値に設定します。私たちの場合、1 分あたり 10 です。はい、設定はとても簡単です。

最後に、res.Remaining によって not の割り当てが残っているかどうかを確認しています。ゼロの場合はメッセージとともにエラーを返します。それ以外の場合は nil を返します。たとえば、 res.Limit.Rate を実行して制限レートなどを確認することもできます。試してみたり、さらに深く掘り下げたりすることができます。

main() 関数が登場します:

res, err := limiter.Allow(ctx, clientIP, redis_rate.PerMinute(10))

すべてがほぼ同じです。 /message ルートでは、ルートがヒットするたびに rateLimit() 関数を呼び出し、ClientIP アドレスを渡し、戻り値 (エラー) の値を err 変数に格納します。エラーがある場合は、429、つまり http.StatusTooManyRequests と、メッセージ "message": "制限に達しました" を返します。その人に残りの制限があり、rateLimit() がエラーを返さなかった場合、以前と同様に正常に動作し、リクエストが処理されます。

説明は以上です。動作をテストしてみましょう。同じコマンドを実行してサーバーを再実行します。初めて、前に受け取ったのと同じメッセージが表示されます。ここでブラウザを 10 回更新します (1 分あたり 10 回という制限を設定しているため)。ブラウザにエラー メッセージが表示されます。

Rate Limiting a Golang API using Redis

ターミナルのログを見てこれを確認することもできます。 Gin はすぐに使える優れたログ機能を提供します。 1 分後に制限割り当てが復元されます。

Rate Limiting a Golang API using Redis

このブログはこれで終わりです。私がこの記事を書いて楽しんでいるのと同じように、皆さんも読んで楽しんでいただければ幸いです。最後までやり遂げてよかったです。ご支援ありがとうございました。また、Golang や、オープンソースや Docker などのその他のことについても X (Twitter) で定期的に話しています。あそこに繋いでもらえますよ。

以上がRedis を使用した Golang API のレート制限の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。