目次
构造限流器" >构造限流器
使用限流器" >使用限流器
Wait/WaitN" >Wait/WaitN
Allow/AllowN" >Allow/AllowN
Reserve/ReserveN" >Reserve/ReserveN
ホームページ バックエンド開発 Golang Golang公式電流リミッターの使い方を詳しく解説

Golang公式電流リミッターの使い方を詳しく解説

Jul 25, 2023 pm 03:08 PM
golang

電流リミッタは、サービスの安定性を向上させるための非常に重要なコンポーネントであり、リクエスト レートを制限し、サービスを保護してサービスの過負荷を回避するために使用できます。電流制限器を実装するには多くの方法があります。一般的な電流制限アルゴリズムには、固定ウィンドウ、スライディング ウィンドウ、リーキー バケット、およびトークン バケットが含まれます。これについては、以前の記事 「一般的に使用される電流制限の応用」で説明しました。 「アルゴリズム、シナリオと実装原則」 では、これらの電流制限方式の特徴と適用シナリオについて説明しています。その中で、トークン バケットは、電流を制限しながら特定のバースト トラフィックにも対処できます。インターネット アプリケーションは、次の理由によりホット スポットになりやすいです。イベント時の突然のトラフィックピークの特性に適しています。

簡単に言うと、トークン バケットは固定サイズのバケットです。システムは一定の割合でトークンをバケットに入れます。バケットがいっぱいの場合は、トークンを入れません。一時的に置かれる。リクエストが比較的少ない場合、バケットは突然のトラフィックに対処するために最初にいくつかのトークンを「保存」でき、バケット内にトークンが残っている場合は継続的に引き出すことができます。トークンが残っていない場合は、トークンがバケットに配置されるまで待つ必要があります。

トークン バケットの電流制限の詳細については、次の記事を参照してください: 一般的に使用される電流制限アルゴリズムのアプリケーション シナリオと実装原理

いくつか学生たちはこれを読んでいます トークンバケットの原理を理解した後、実際に電流リミッターを実装して自分のプロジェクトに適用したいと思っています... なんというか、ホイールの構築は確かにレベルアップに役立ちますが、これは商用プロジェクトに適用されます。実際、ホイールを自分で構築する必要はありません。Golang が公式にホイールを構築してくれました...~!

Golang によって公式に提供される拡張ライブラリには、電流制限アルゴリズムの実装 (golang.org/x/time/rate) が付属しています。この電流リミッターもトークン バケットに基づいて実装されます。

電流リミッターの内部構造

time/rateLimiter タイプのペアパッケージ 電流リミッターが定義されています。すべての電流制限機能は、Limiter タイプに基づいて実装されます。その内部構造は次のとおりです:

type Limiter struct {
 mu     sync.Mutex
 limit  Limit
 burst  int // 令牌桶的大小
 tokens float64
 last time.Time // 上次更新tokens的时间
 lastEvent time.Time // 上次发生限速器事件的时间(通过或者限制都是限速器事件)
}
ログイン後にコピー

その主要フィールドの機能は次のとおりです:

  • limit:limit字段表示往桶里放Token的速率,它的类型是Limit,是int64的类型别名。设置limit时既可以用数字指定每秒向桶中放多少个Token,也可以指定向桶中放Token的时间间隔,其实指定了每秒放Token的个数后就能计算出放每个Token的时间间隔了。
  • burst: 令牌桶的大小。
  • tokens: 桶中的令牌。
  • last: 上次往桶中放 Token 的时间。
  • lastEvent:上次发生限速器事件的时间(通过或者限制都是限速器事件)

可以看到在 timer/rate 的限流器实现中,并没有单独维护一个 Timer 和队列去真的每隔一段时间向桶中放令牌,而是仅仅通过计数的方式表示桶中剩余的令牌。每次消费取 Token 之前会先根据上次更新令牌数的时间差更新桶中Token数

大概了解了time/rate限流器的内部实现后,下面的内容我们会集中介绍下该组件的具体使用方法:

构造限流器

我们可以使用以下方法构造一个限流器对象:

limiter := rate.NewLimiter(10, 100);
ログイン後にコピー

这里有两个参数:

  1. 第一个参数是 r Limit,设置的是限流器Limiter的limit字段,代表每秒可以向 Token 桶中产生多少 token。Limit 实际上是 float64 的别名。
  2. 第二个参数是 b int,b 代表 Token 桶的容量大小,也就是设置的限流器 Limiter 的burst字段。

那么,对于以上例子来说,其构造出的限流器的令牌桶大小为 100, 以每秒 10 个 Token 的速率向桶中放置 Token。

除了给r Limit参数直接指定每秒产生的 Token 个数外,还可以用 Every 方法来指定向桶中放置 Token 的间隔,例如:

limit := rate.Every(100 * time.Millisecond);
limiter := rate.NewLimiter(limit, 100);
ログイン後にコピー

以上就表示每 100ms 往桶中放一个 Token。本质上也是一秒钟往桶里放 10 个。

使用限流器

Limiter 提供了三类方法供程序消费 Token,可以每次消费一个 Token,也可以一次性消费多个 Token。每种方法代表了当 Token 不足时,各自不同的对应手段,可以阻塞等待桶中Token补充,也可以直接返回取Token失败。

Wait/WaitN

func (lim *Limiter) Wait(ctx context.Context) (err error)
func (lim *Limiter) WaitN(ctx context.Context, n int) (err error)
ログイン後にコピー

Wait 实际上就是 WaitN(ctx,1)

当使用 Wait 方法消费 Token 时,如果此时桶内 Token 数组不足 (小于 N),那么 Wait 方法将会阻塞一段时间,直至 Token 满足条件。如果充足则直接返回。

这里可以看到,Wait 方法有一个 context 参数。我们可以设置 context 的 Deadline 或者 Timeout,来决定此次 Wait 的最长时间。

// 一直等到获取到桶中的令牌
err := limiter.Wait(context.Background())
if err != nil {
 fmt.Println("Error: ", err)
}

// 设置一秒的等待超时时间
ctx, _ := context.WithTimeout(context.Background(), time.Second * 1)
err := limiter.Wait(ctx)
if err != nil {
 fmt.Println("Error: ", err)
}
ログイン後にコピー

Allow/AllowN

func (lim *Limiter) Allow() bool
func (lim *Limiter) AllowN(now time.Time, n int) bool
ログイン後にコピー

Allow 实际上就是对 AllowN(time.Now(),1) 进行简化的函数。

AllowN 方法表示,截止到某一时刻,目前桶中数目是否至少为 n 个,满足则返回 true,同时从桶中消费 n 个 token。反之不消费桶中的Token,返回false。

对应线上的使用场景是,如果请求速率超过限制,就直接丢弃超频后的请求。

if limiter.AllowN(time.Now(), 2) {
    fmt.Println("event allowed")
} else {
    fmt.Println("event not allowed")
}
ログイン後にコピー

Reserve/ReserveN

func (lim *Limiter) Reserve() *Reservation
func (lim *Limiter) ReserveN(now time.Time, n int) *Reservation
ログイン後にコピー

Reserve 相当于 ReserveN(time.Now(), 1)

ReserveN 的用法就相对来说复杂一些,当调用完成后,无论 Token 是否充足,都会返回一个 *Reservation 对象。你可以调用该对象的Delay()方法,该方法返回的参数类型为time.Duration,反映了需要等待的时间,必须等到等待时间之后,才能进行接下来的工作。如果不想等待,可以调用Cancel()方法,该方法会将 Token 归还。

举一个简单的例子,我们可以这么使用 Reserve 方法。

r := limiter.Reserve()
f !r.OK() {
    // Not allowed to act! Did you remember to set lim.burst to be > 0 ?
    return
}
time.Sleep(r.Delay())
Act() // 执行相关逻辑
ログイン後にコピー

动态调整速率和桶大小

Limiter 支持创建后动态调整速率和桶大小:

  1. SetLimit(Limit) 改变放入 Token 的速率
  2. SetBurst(int) 改变 Token 桶大小

有了这两个方法,可以根据现有环境和条件以及我们的需求,动态地改变 Token 桶大小和速率。

总结

今天我们总结了 Golang 官方限流器的使用方法,它是一种令牌桶算实现的限流器。其中 Wait/WaitNAllow/AllowN 这两组方法在平时用的比较多,前者是消费Token时如果桶中Token不足可以让程序等待桶中新Token的放入(最好设置上等待时长)后者则是在桶中的Token不足时选择直接丢弃请求。

Golang が公式に提供する電流リミッターの実装に加えて、Uber のオープンソースの電流リミッター uber-go/ratelimit も良い選択です Golang の公式の電流リミッターとの違いは、Uber のリミッターの流れですコントローラはリーキーバケットアルゴリズムによって実装されていますが、従来のリーキーバケットアルゴリズムが改良されており、興味のある学生は自ら体験することができます。

以上がGolang公式電流リミッターの使い方を詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Golang を使用してファイルを安全に読み書きするにはどうすればよいですか? Golang を使用してファイルを安全に読み書きするにはどうすればよいですか? Jun 06, 2024 pm 05:14 PM

Go ではファイルを安全に読み書きすることが重要です。ガイドラインには以下が含まれます。 ファイル権限の確認 遅延を使用してファイルを閉じる ファイル パスの検証 コンテキスト タイムアウトの使用 これらのガイドラインに従うことで、データのセキュリティとアプリケーションの堅牢性が確保されます。

Golang データベース接続用の接続プールを構成するにはどうすればよいですか? Golang データベース接続用の接続プールを構成するにはどうすればよいですか? Jun 06, 2024 am 11:21 AM

Go データベース接続の接続プーリングを構成するにはどうすればよいですか?データベース接続を作成するには、database/sql パッケージの DB タイプを使用します。同時接続の最大数を制御するには、MaxOpenConns を設定します。アイドル状態の接続の最大数を設定するには、ConnMaxLifetime を設定します。

GolangでJSONデータをデータベースに保存するにはどうすればよいですか? GolangでJSONデータをデータベースに保存するにはどうすればよいですか? Jun 06, 2024 am 11:24 AM

JSON データは、gjson ライブラリまたは json.Unmarshal 関数を使用して MySQL データベースに保存できます。 gjson ライブラリは、JSON フィールドを解析するための便利なメソッドを提供します。json.Unmarshal 関数には、JSON データをアンマーシャリングするためのターゲット型ポインターが必要です。どちらの方法でも、SQL ステートメントを準備し、データをデータベースに永続化するために挿入操作を実行する必要があります。

Golang フレームワークと Go フレームワーク: 内部アーキテクチャと外部機能の比較 Golang フレームワークと Go フレームワーク: 内部アーキテクチャと外部機能の比較 Jun 06, 2024 pm 12:37 PM

GoLang フレームワークと Go フレームワークの違いは、内部アーキテクチャと外部機能に反映されています。 GoLang フレームワークは Go 標準ライブラリに基づいてその機能を拡張していますが、Go フレームワークは特定の目的を達成するための独立したライブラリで構成されています。 GoLang フレームワークはより柔軟であり、Go フレームワークは使いやすいです。 GoLang フレームワークはパフォーマンスの点でわずかに優れており、Go フレームワークはよりスケーラブルです。ケース: gin-gonic (Go フレームワーク) は REST API の構築に使用され、Echo (GoLang フレームワーク) は Web アプリケーションの構築に使用されます。

フロントエンドからバックエンドの開発に変身すると、JavaやGolangを学ぶことはより有望ですか? フロントエンドからバックエンドの開発に変身すると、JavaやGolangを学ぶことはより有望ですか? Apr 02, 2025 am 09:12 AM

バックエンド学習パス:フロントエンドからバックエンドへの探査の旅は、フロントエンド開発から変わるバックエンド初心者として、すでにNodeJSの基盤を持っています...

Golang フレームワーク開発実践チュートリアル: FAQ Golang フレームワーク開発実践チュートリアル: FAQ Jun 06, 2024 am 11:02 AM

Go フレームワーク開発 F​​AQ: フレームワークの選択: アプリケーションの要件と開発者の好み (Gin (API)、Echo (拡張可能)、Beego (ORM)、Iris (パフォーマンス) など) によって異なります。インストールと使用: gomod コマンドを使用して、フレームワークをインストールし、インポートして使用します。データベース対話: gorm などの ORM ライブラリを使用して、データベース接続と操作を確立します。認証と認可: gin-contrib/sessions などのセッション管理および認証ミドルウェアを使用します。実際のケース: Pin フレームワークを使用して、POST、GET、その他の関数を提供する単純なブログ API を構築します。

Golangの目的:効率的でスケーラブルなシステムの構築 Golangの目的:効率的でスケーラブルなシステムの構築 Apr 09, 2025 pm 05:17 PM

GO言語は、効率的でスケーラブルなシステムの構築においてうまく機能します。その利点には次のものがあります。1。高性能:マシンコードにコンパイルされ、速度速度が速い。 2。同時プログラミング:ゴルチンとチャネルを介してマルチタスクを簡素化します。 3。シンプルさ:簡潔な構文、学習コストとメンテナンスコストの削減。 4。クロスプラットフォーム:クロスプラットフォームのコンパイル、簡単な展開をサポートします。

GOのどのライブラリが大企業によって開発されていますか、それとも有名なオープンソースプロジェクトによって提供されていますか? GOのどのライブラリが大企業によって開発されていますか、それとも有名なオープンソースプロジェクトによって提供されていますか? Apr 02, 2025 pm 04:12 PM

大企業または有名なオープンソースプロジェクトによって開発されたGOのどのライブラリが開発されていますか? GOでプログラミングするとき、開発者はしばしばいくつかの一般的なニーズに遭遇します...

See all articles