Go 言語でのレート制限の実装

Beginner

This tutorial is from open-source community. Access the source code

はじめに

この実験では、goroutine、チャネル、およびタイカーを使用して Go 言語でレート制限を実装する方法を示します。

レート制限

問題は、サービス品質を維持し、リソースの利用を制御するために、着信リクエストの処理を制限することです。

  • Go 言語
  • goroutine、チャネル、およびタイカーに関する基本的な理解
## プログラムを実行すると、最初のバッチのリクエストが
## 約 200 ミリ秒ごとに 1 回ずつ処理されることがわかります。
$ go run rate-limiting.go
request 1 2012-10-19 00:38:18.687438 +0000 UTC
request 2 2012-10-19 00:38:18.887471 +0000 UTC
request 3 2012-10-19 00:38:19.087238 +0000 UTC
request 4 2012-10-19 00:38:19.287338 +0000 UTC
request 5 2012-10-19 00:38:19.487331 +0000 UTC

## 2 番目のバッチのリクエストに対しては、バースト可能なレート制限のため、
## 最初の 3 つのリクエストをすぐに処理し、その後、残りの 2 つのリクエストを
## それぞれ約 200ms の遅延で処理します。
request 1 2012-10-19 00:38:20.487578 +0000 UTC
request 2 2012-10-19 00:38:20.487645 +0000 UTC
request 3 2012-10-19 00:38:20.487676 +0000 UTC
request 4 2012-10-19 00:38:20.687483 +0000 UTC
request 5 2012-10-19 00:38:20.887542 +0000 UTC

以下に完全なコードがあります:

// [_レート制限_](https://en.wikipedia.org/wiki/Rate_limiting)
// は、リソースの利用を制御し、サービス品質を維持するための
// 重要なメカニズムです。Go 言語は、goroutine、チャネル、および
// [タイカー](tickers) を使って、レート制限を簡潔にサポートしています。

package main

import (
    "fmt"
    "time"
)

func main() {

    // まずは基本的なレート制限を見てみましょう。
    // 着信リクエストの処理を制限したいとします。
    // これらのリクエストは同じ名前のチャネルから処理されます。
    requests := make(chan int, 5)
    for i := 1; i <= 5; i++ {
        requests <- i
    }
    close(requests)

    // この `limiter` チャネルは 200 ミリ秒ごとに値を受け取ります。
    // これが私たちのレート制限方式の調整装置です。
    limiter := time.Tick(200 * time.Millisecond)

    // 各リクエストを処理する前に `limiter` チャネルからの受信をブロックすることで、
    // 200 ミリ秒ごとに 1 つのリクエストに制限します。
    for req := range requests {
        <-limiter
        fmt.Println("request", req, time.Now())
    }

    // 全体的なレート制限を維持しながら、レート制限方式で短時間のバーストを許可したい場合があります。
    // これは、`limiter` チャネルをバッファリングすることで達成できます。
    // この `burstyLimiter` チャネルは最大 3 つのイベントのバーストを許可します。
    burstyLimiter := make(chan time.Time, 3)

    // 許可されたバーストを表すためにチャネルを満たします。
    for i := 0; i < 3; i++ {
        burstyLimiter <- time.Now()
    }

    // 200 ミリ秒ごとに、`burstyLimiter` に新しい値を追加しようとします。
    // その制限は 3 つです。
    go func() {
        for t := range time.Tick(200 * time.Millisecond) {
            burstyLimiter <- t
        }
    }()

    // 今度はさらに 5 つの着信リクエストをシミュレートします。
    // これらの最初の 3 つは、`burstyLimiter` のバースト機能の恩恵を受けます。
    burstyRequests := make(chan int, 5)
    for i := 1; i <= 5; i++ {
        burstyRequests <- i
    }
    close(burstyRequests)
    for req := range burstyRequests {
        <-burstyLimiter
        fmt.Println("request", req, time.Now())
    }
}

まとめ

この実験では、goroutine、チャネル、およびタイカーを使って Go 言語でレート制限を実装し、リソースの利用を制御し、サービス品質を維持する方法を示します。