最近学んだ現在の制限知識

序文

禿げた頭だけが強くなることができます。
テキストは私のGitHubリポジトリに含まれています。スターへようこそ:https//github.com/ZhongFuCheng3y/3y
以前に勉強していたときは、高い同時実行性や大量のトラフィックなどにアクセスできなかったので、もちろん現在の制限には触れていません。アップ。会社のプロジェクトを見てみると、現在の(RateLimiter)を制限して、それについて学ぶことが役立つことがわかりました。

1.電流制限の基本的な知識の紹介

なぜあなたは流れを制限したいのですか、私はこれ以上言う必要はないと思います。

  • たとえば、週末にレストランに夕食に行くのですが、人が多すぎて、フロントに行って番号を取得し、番号が届くのを待ってからレストランで食事をするしかありません。ホテルに現在の制限がない場合はどうなりますか?食事が到着すると、人が殺到し、人の流れに対応できないため、事故が発生しやすくなります(人でいっぱいで行き方がありません。ホテルのスタッフが倒れて対応できませんでした)。
  • 世界のコードに戻ると、サーバーは限られた数の要求を処理できます。特に、大量の要求がある場合は、フローを制限する必要があります(要求を待機させるか、要求をスローする)。世界のコードを
    最近学んだ現在の制限知識
    制限
    します。電流制限には、2つの一般的なアルゴリズムがあります。

  • トークンバケットアルゴリズム
  • リークバケットアルゴリズム

    1.1リークバケットアルゴリズムとは

たとえば、今はバケツがあり、緑色のバケツは水を保持できる容量です。保持できる容量を超えてからバケツに水を注ぐと、オーバーフローします(流量が制限されます)。

最近学んだ現在の制限知識
バケット
について現在知ることができるのは次のとおりです。

  • バケットの容量は固定されています(写真の緑色の容量です)
  • バケットの容量を超えると、オーバーフローします(待機するか、直接破棄します)
    。OK、バケットに穴を掘って、穴から水が流れ出るようにします。

最近学んだ現在の制限知識
穴を掘り、穴から流出する水
の入ったバケツの開口部の大きさを固定したので、穴から流出する水の速度も固定しました。

要約すると、アルゴリズムに必要なパラメータは2つだけです。

  • バケット容量

  • 2つで実装されたリークレートリークバケットアルゴリズム:
  1. 突然の流れの状況は許可されていません。水の流入速度が水の流出速度よりも大きい場合は、余分な水を直接廃棄してください。たとえば、私のバケットは100Lを保持できますが、私のバケットの水出力速度は10L / sです。このとき、100L / sの水が入ってくると、10Lの水だけをバケツに入れ、残りは制限します。(リクエスト速度の制限)
  2. トラフィックの特定のバーストを許可します。バケットは100Lを保持できます。バケットが空の場合、100Lの水が即座にバケットに入る可能性があります。私は10L / sの速度で水を流出させます。それでも100Lの水が入ってくる場合、私は流れを制限することしかできません。
    上記の分析の後、次のことがわかります。

リークバケットアルゴリズムは、ネットワーク上のバーストトラフィックをスムーズにすることができます(水漏れの速度が固定されているため)

1.2トークンバケットアルゴリズムとは

今、私は別のバケットを持っています。このバケットは水ではなく、トークンに使用されます。

最近学んだ現在の制限知識
バケット内のトークンは
特定の速度でバケットにスローされます。たとえば、1秒あたり10個のトークンをバケットにスローします。

最近学んだ現在の制限知識
トークンを一定の割合でバケットに
投入します。ロードできるトークンの数には上限があります。たとえば、私のバケットは最大で1000個のトークンしか保持できません。

すべてのリクエストが届き、トークンを取得するためにバケットに移動します

  • たとえば、この2番目に1001のリクエストがある場合、バケットに移動して1001のトークンを取得します。現時点では、次の2つの状況が考えられます。
  • バケットには10​​01トークンはなく、1000トークンしかないため、トークンを取得しないリクエストはブロック(待機)のみできます。
  • バケットには10​​01個のトークンがあり、すべての要求を実行できます。
    最近学んだ現在の制限知識

    トークンバケットアルゴリズムは、ネットワーク上のバーストトラフィックをサポートします

リークバケットとトークンバケットの違い:上記の例からわかるように、リークバケットは固定レートでのみリクエストを処理できますが、トークンバケットはバケット内のトークンの最大数でリクエストを処理できます。

二、RateLimiter使用

RateLimiterはGuavaの電流制限コンポーネントであり、私のシステムはこの電流制限コンポーネントを使用しているため、非常に便利です。

pom依存関係を導入します。

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>20.0</version>
</dependency>

RateLimiterはトークンバケットアルゴリズムに基づいており、APIは非常に単純です。次のデモを参照してください。

public static void main(String[] args) {
        //线程池
        ExecutorService exec = Executors.newCachedThreadPool();
        //速率是每秒只有3个许可
        final RateLimiter rateLimiter = RateLimiter.create(3.0);

        for (int i = 0; i < 100; i++) {
            final int no = i;
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    try {
                        //获取许可
                        rateLimiter.acquire();
                        System.out.println("Accessing: " + no + ",time:"
                                + new SimpleDateFormat("yy-MM-dd HH:mm:ss").format(new Date()));

                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                }
            };
            //执行线程
            exec.execute(runnable);
        }
        //退出线程池
        exec.shutdown();
    }

結果から、1秒間に実行できるのは3つだけであることがわかります。

最近学んだ現在の制限知識
1秒あたり3回実行

3つの分散電流制限

RateLimiterは、単一マシンの電流制限コンポーネントです。分散アプリケーションの場合、どうすればよいですか?

これは、Redis + Luaを使用して実現できます。おおよそのluaスクリプトコードは、次のとおりです。

local key = "rate.limit:" .. KEYS[1] --限流KEY
local limit = tonumber(ARGV[1])        --限流大小
local current = tonumber(redis.call('get', key) or "0")
if current + 1 > limit then --如果超出限流大小
  return 0
else  --请求数+1,并设置1秒过期
  redis.call("INCRBY", key,"1")
   redis.call("expire", key,"1")
   return current + 1
end

Javaコードは次のとおりです。

public static boolean accquire() throws IOException, URISyntaxException {
    Jedis jedis = new Jedis("127.0.0.1");
    File luaFile = new File(RedisLimitRateWithLUA.class.getResource("/").toURI().getPath() + "limit.lua");
    String luaScript = FileUtils.readFileToString(luaFile);

    String key = "ip:" + System.currentTimeMillis()/1000; // 当前秒
    String limit = "5"; // 最大限制
    List<String> keys = new ArrayList<String>();
    keys.add(key);
    List<String> args = new ArrayList<String>();
    args.add(limit);
    Long result = (Long)(jedis.eval(luaScript, keys, args)); // 执行lua脚本,传入参数
    return result == 1;
}

説明:

最近学んだ現在の制限知識

200以上のオリジナル記事技術記事
膨大なビデオリソース
絶妙なマインドマップ
顔の質問
プレススキャンコードは、
視聴と共有の取得について懸念している可能性があります私にとって非常に重要です!

おすすめ

転載: blog.51cto.com/15082392/2590346