目次
#go-zero コードの実装" >#go-zero コードの実装
ホームページ バックエンド開発 Golang Go でユーザーの 1 日あたりの制限を実装する方法

Go でユーザーの 1 日あたりの制限を実装する方法

Jan 10, 2022 pm 03:55 PM
go go-zero マイクロサービス

この記事は、golang チュートリアル コラムによって、Go でユーザーの 1 日の制限を実装する方法を紹介するために書かれたものです。困っている友人の役に立てば幸いです。

Go にユーザーの 1 日あたりの制限を実装します (たとえば、特典は 1 日に 3 回しか受け取れません)

バグ管理システムを作成し、この PeriodLimit を使用する場合、各テスターが 1 日に 1 つのバグのみを送信するように制限できます。仕事はずっと楽になりましたか? :P

現在、マイクロサービス アーキテクチャが非常に人気がある本質的な理由は、システム全体の複雑さを軽減し、システム リスクをサブシステムに均等に分散してシステムの安定性を最大化し、それをさまざまなサブシステムに分割することです。サブシステム導入後は、各サブシステムを独立して開発、テスト、リリースすることができ、研究開発のリズムと効率が大幅に向上します。

しかし、呼び出しリンクが長すぎる、展開アーキテクチャの複雑さが増す、さまざまなミドルウェアが分散シナリオをサポートする必要があるなどの問題も生じます。マイクロサービスの正常な動作を保証するには、サービス ガバナンスが不可欠であり、これには通常、電流制限、ダウングレード、サーキット ブレーカーが含まれます。

電流制限とは、負荷制限を超えてシステムがダウンすることを避けるために、インターフェイス呼び出しの頻度を制限することを指します。例:

  • #E コマース フラッシュ セール シナリオ

  • #さまざまな販売者の API の現在の制限

一般的に使用される電流制限アルゴリズムは次のとおりです。

  • 固定時間ウィンドウ電流制限
  • スライディング タイム ウィンドウ電流制限
  • リーキー バケット電流制限
  • トークンバケット制限フロー

この記事では主に固定時間ウィンドウ電流制限アルゴリズムについて説明します。

動作原理

ある時点から、各リクエストのリクエスト数は 1 になります。同時に、リクエストの数が 1 であるかどうかを判断します。現在の時間枠内のリクエストは制限を超えています。制限を超えた場合、リクエストは拒否されます。次の時間枠がリクエストの待機を開始すると、リクエストはクリアされます。

Go でユーザーの 1 日あたりの制限を実装する方法

メリットとデメリット

メリット

簡単これは効率的であり、ユーザーが 1 日に記事を 10 件しか投稿できない、SMS 認証コードを 5 回しか送信できない、ログインを 5 回しか試行できないなど、制限されたシナリオに特に適しています。このようなシナリオは実際には非常に一般的です。仕事。

欠点

固定時間ウィンドウ電流制限の欠点は、クリティカル セクションの要求バースト シナリオを処理できないことです。

現在の制限が 1 秒あたり 100 リクエストで、ユーザーが 500 ミリ秒の中間から開始して 1 秒以内に 200 リクエストを開始したとします。この時点で、200 リクエストはすべて通過できます。これは、電流を 1 秒あたり 100 回に制限するという予想と矛盾します。根本的な原因は、電流制限の粒度が粗すぎることです。

Go でユーザーの 1 日あたりの制限を実装する方法

##core/limit/periodlimit.go

Go-zero は、redis の有効期限を使用して、固定時間枠をシミュレートします。

redis lua スクリプト:

-- KYES[1]:限流器key-- ARGV[1]:qos,单位时间内最多请求次数-- ARGV[2]:单位限流窗口时间-- 请求最大次数,等于p.quotalocal limit = tonumber(ARGV[1])-- 窗口即一个单位限流周期,这里用过期模拟窗口效果,等于p.permitlocal window = tonumber(ARGV[2])-- 请求次数+1,获取请求总数local current = redis.call("INCRBY",KYES[1],1)-- 如果是第一次请求,则设置过期时间并返回 成功if current == 1 then
  redis.call("expire",KYES[1],window)
  return 1-- 如果当前请求数量小于limit则返回 成功elseif current limit则返回 失败else
  return 0end
ログイン後にコピー
固定時間ウィンドウ電流リミッターの定義

type (
  // PeriodOption defines the method to customize a PeriodLimit.
  // go中常见的option参数模式
  // 如果参数非常多,推荐使用此模式来设置参数
  PeriodOption func(l *PeriodLimit)

  // A PeriodLimit is used to limit requests during a period of time.
  // 固定时间窗口限流器
  PeriodLimit struct {
    // 窗口大小,单位s
    period     int
    // 请求上限
    quota      int
    // 存储
    limitStore *redis.Redis
    // key前缀
    keyPrefix  string
    // 线性限流,开启此选项后可以实现周期性的限流
    // 比如quota=5时,quota实际值可能会是5.4.3.2.1呈现出周期性变化
    align      bool
  }
)
ログイン後にコピー

align パラメーターに注意してください。 = true の場合、リクエストの上限は定期的に変更されます。
たとえば、クォータ = 5 の場合、実際のクォータは 5.4.3.2.1 になる可能性があり、定期的な変更を示します


電流制限ロジック

実際には、電流制限ロジックは上記 lua スクリプトが実装されていますが、戻り値

0: Redis の障害やオーバーロードなどのエラーを示していることに注意してください
  • 1: allowed
  • ##2: 許可 ただし、現在のウィンドウでは上限に達しています。バッチ業務を実行している場合は、スリープして次のウィンドウを待つことができます (作成者は慎重に検討しました)
  • 3: 拒否
  • // Take requests a permit, it returns the permit state.
    // 执行限流
    // 注意一下返回值:
    // 0:表示错误,比如可能是redis故障、过载
    // 1:允许
    // 2:允许但是当前窗口内已到达上限
    // 3:拒绝
    func (h *PeriodLimit) Take(key string) (int, error) {
      // 执行lua脚本
      resp, err := h.limitStore.Eval(periodScript, []string{h.keyPrefix + key}, []string{
        strconv.Itoa(h.quota),
        strconv.Itoa(h.calcExpireSeconds()),
      })
    
      if err != nil {
        return Unknown, err
      }
    
      code, ok := resp.(int64)
      if !ok {
        return Unknown, ErrUnknownCode
      }
    
      switch code {
      case internalOverQuota:
        return OverQuota, nil
      case internalAllowed:
        return Allowed, nil
      case internalHitQuota:
        return HitQuota, nil
      default:
        return Unknown, ErrUnknownCode
      }
    }
    ログイン後にコピー
  • この固定ウィンドウの現在の制限は、たとえば、ユーザーが確認コードのテキスト メッセージを 1 日に 5 回しか送信できないように制限するために使用できます。中国のタイムゾーン (GMT 8) に対応させるため、実際には現在の制限時間は 0 時から開始する必要がありますが、この時点では追加のアライメント (align を true に設定) が必要です。
  • // 计算过期时间也就是窗口时间大小
    // 如果align==true
    // 线性限流,开启此选项后可以实现周期性的限流
    // 比如quota=5时,quota实际值可能会是5.4.3.2.1呈现出周期性变化
    func (h *PeriodLimit) calcExpireSeconds() int {
      if h.align {
        now := time.Now()
        _, offset := now.Zone()
        unix := now.Unix() + int64(offset)
        return h.period - int(unix%int64(h.period))
      }
    
      return h.period
    }
    ログイン後にコピー
    プロジェクト アドレス

    github.com/zeromicro/go-zero

    go-zero

    および

    star の使用を歓迎します私たちを応援してください!

    以上がGo でユーザーの 1 日あたりの制限を実装する方法の詳細内容です。詳細については、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衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

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

SublimeText3 中国語版

SublimeText3 中国語版

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

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

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

Go WebSocket メッセージを送信するにはどうすればよいですか? Go WebSocket メッセージを送信するにはどうすればよいですか? Jun 03, 2024 pm 04:53 PM

Go では、gorilla/websocket パッケージを使用して WebSocket メッセージを送信できます。具体的な手順: WebSocket 接続を確立します。テキスト メッセージを送信します。 WriteMessage(websocket.TextMessage,[]byte("message")) を呼び出します。バイナリ メッセージを送信します。WriteMessage(websocket.BinaryMessage,[]byte{1,2,3}) を呼び出します。

PHP フレームワークとマイクロサービス: クラウド ネイティブの導入とコンテナ化 PHP フレームワークとマイクロサービス: クラウド ネイティブの導入とコンテナ化 Jun 04, 2024 pm 12:48 PM

PHP フレームワークとマイクロサービスを組み合わせる利点: スケーラビリティ: アプリケーションを簡単に拡張し、新しい機能を追加したり、より多くの負荷を処理したりできます。柔軟性: マイクロサービスは独立してデプロイおよび保守されるため、変更や更新が容易になります。高可用性: 1 つのマイクロサービスの障害が他の部分に影響を与えないため、高可用性が確保されます。実践的なケース: Laravel と Kubernetes を使用したマイクロサービスのデプロイ ステップ: Laravel プロジェクトを作成します。マイクロサービスコントローラーを定義します。 Dockerfileを作成します。 Kubernetes マニフェストを作成します。マイクロサービスをデプロイします。マイクロサービスをテストします。

Golang の技術的なパフォーマンスの最適化でメモリ リークを回避するにはどうすればよいですか? Golang の技術的なパフォーマンスの最適化でメモリ リークを回避するにはどうすればよいですか? Jun 04, 2024 pm 12:27 PM

メモリ リークは、ファイル、ネットワーク接続、データベース接続などの使用されなくなったリソースを閉じることによって、Go プログラムのメモリを継続的に増加させる可能性があります。弱参照を使用してメモリ リークを防ぎ、強参照されなくなったオブジェクトをガベージ コレクションの対象にします。 go coroutine を使用すると、メモリ リークを避けるために、終了時にコルーチンのスタック メモリが自動的に解放されます。

Golang のエラー ラッパーを使用するにはどうすればよいですか? Golang のエラー ラッパーを使用するにはどうすればよいですか? Jun 03, 2024 pm 04:08 PM

Golang では、エラー ラッパーを使用して、元のエラーにコンテキスト情報を追加することで新しいエラーを作成できます。これを使用すると、さまざまなライブラリまたはコンポーネントによってスローされるエラーの種類を統一し、デバッグとエラー処理を簡素化できます。手順は次のとおりです。errors.Wrap 関数を使用して、元のエラーを新しいエラーにラップします。新しいエラーには、元のエラーのコンテキスト情報が含まれています。 fmt.Printf を使用してラップされたエラーを出力し、より多くのコンテキストとアクション性を提供します。異なる種類のエラーを処理する場合は、errors.Wrap 関数を使用してエラーの種類を統一します。

Go で優先順位付きのゴルーチンを作成するにはどうすればよいですか? Go で優先順位付きのゴルーチンを作成するにはどうすればよいですか? Jun 04, 2024 pm 12:41 PM

Go 言語で優先度のゴルーチンを作成するには、カスタム ゴルーチン作成関数の登録 (ステップ 1) と優先度の値の指定 (ステップ 2) の 2 つの手順があります。このようにして、異なる優先度を持つゴルーチンを作成し、リソース割り当てを最適化し、実行効率を向上させることができます。

Java フレームワークはマイクロサービスの水平スケーリングをどのようにサポートしていますか? Java フレームワークはマイクロサービスの水平スケーリングをどのようにサポートしていますか? Jun 04, 2024 pm 04:34 PM

Java フレームワークは、マイクロサービスの水平拡張をサポートします。具体的な方法は次のとおりです。 Spring Cloud は、サーバー側とクライアント側の負荷分散のために、Ribbon と Feign を提供します。 NetflixOSS は、サービス検出、負荷分散、フェイルオーバーを実装するための Eureka と Zuul を提供します。 Kubernetes は、自動スケーリング、ヘルスチェック、自動再起動により水平スケーリングを簡素化します。

Golang関数がマップパラメータを受け取る際の注意点 Golang関数がマップパラメータを受け取る際の注意点 Jun 04, 2024 am 10:31 AM

Go の関数にマップを渡すと、デフォルトでコピーが作成され、コピーへの変更は元のマップには影響しません。元のマップを変更する必要がある場合は、ポインタを介してそれを渡すことができます。空のマップは技術的には nil ポインターであり、空ではないマップを期待する関数に空のマップを渡すとエラーが発生するため、空のマップは慎重に扱う必要があります。

Golang マイクロサービス フレームワークを使用して分散システムを作成する Golang マイクロサービス フレームワークを使用して分散システムを作成する Jun 05, 2024 pm 06:36 PM

Golang マイクロサービス フレームワークを使用して分散システムを作成します。Golang をインストールし、マイクロサービス フレームワーク (Gin など) を選択し、Gin マイクロサービスを作成し、エンドポイントを追加してマイクロサービスをデプロイし、アプリケーションを構築して実行し、注文と在庫のマイクロサービスを作成し、注文と在庫を処理するエンドポイント Kafka などのメッセージング システムを使用してマイクロサービスに接続する sarama ライブラリを使用して注文情報を生成および消費する

See all articles