ホームページ >データベース >Redis >Redis はどのように電流制限を実装しますか? 3つの実装方法の紹介

Redis はどのように電流制限を実装しますか? 3つの実装方法の紹介

青灯夜游
青灯夜游転載
2020-07-21 17:06:284266ブラウズ

Redis はどのように電流制限を実装しますか? 3つの実装方法の紹介

#最初の操作: Redis ベースの setnx 操作

誰もが知っているように、Redis の分散ロックを使用する場合, setnx コマンドに依存します。CAS (比較およびスワップ) 操作中に、指定されたキーに対して有効期限の設定 (expire) が設定されます。電流を制限する主な目的は、単位時間内に制限することです。N 個だけがあります。コード プログラムにアクセスできるリクエストの数。したがって、setnx に依存すると、この機能を簡単に実現できます。

たとえば、10 秒以内に 20 件のリクエストを制限する必要がある場合、setnx の有効期限を 10 に設定できます。リクエストされた setnx の数が 20 に達すると、電流制限の効果が得られます。コードは比較的単純なので省略します。

もちろん、このアプローチには多くの欠点があります。たとえば、1 ~ 10 秒をカウントする場合、2 ~ 11 秒をカウントすることは不可能です。N 秒以内に M 件のリクエストをカウントする必要がある場合、 N 個のキーを維持する必要性などの Redis の問題

2 番目のタイプ: Redis ベースのデータ構造 zset

実際、現在のデータ構造に関係する最も重要なことは、制限は、上記のようにスライディング ウィンドウです。また、1 ~ 10 が 2 ~ 11 になる方法についても説明しました。実際、開始値と終了値は両方とも 1 です。

Redis のリスト データ構造を使用すると、この関数を簡単に実装できます。

リクエストを zset 配列に作成できます。各リクエストが受信されると、値は一意のままになります。 UUID を使用して生成され、スコアは現在のタイムスタンプで表すことができます。これは、スコアを使用して現在のタイムスタンプ内のリクエストの数を計算できるためです。 zset データ構造は、2 つのタイムスタンプ内のリクエストの数を簡単に取得できるように range メソッドも提供します。

コードは次のとおりです

public Response limitFlow(){
 Long currentTime = new Date().getTime();
 System.out.println(currentTime);
 if(redisTemplate.hasKey("limit")) {
 Integer count = redisTemplate.opsForZSet().rangeByScore("limit", currentTime -  intervalTime, currentTime).size();        // intervalTime是限流的时间
 System.out.println(count);
 if (count != null && count > 5) {
 return Response.ok("每分钟最多只能访问5次");
 }
 }
 redisTemplate.opsForZSet().add("limit",UUID.randomUUID().toString(),currentTime);
 return Response.ok("访问成功");
 }

上記のコードは、スライディング ウィンドウの効果を実現できます。 、N 秒ごとに最大 M リクエストを保証できますが、欠点は、zset のデータ構造がますます大きくなることです。実装方法は比較的簡単です。


3 番目のタイプ: Redis ベースのトークン バケット アルゴリズム

電流制限に関して言えば、トークン バケット アルゴリズムについて言及する必要があります。トークン バケット アルゴリズムはバケット アルゴリズムとも呼ばれます。詳細については、Du Niang によるトークン バケット アルゴリズムの説明を参照してください。

トークン バケット アルゴリズムでは、入力レートと出力レートについて説明します。出力レートが大きい場合入力レートを超えている場合は、トラフィック制限を超えています。

つまり、リクエストにアクセスするたびに、Redis からトークンを取得できます。トークンを取得できれば、制限を超えていないことを意味します。取得できない場合は、結果が返されます。その逆になります。

上記の考え方に基づいて、Redis の List データ構造を組み合わせることで、そのようなコードを簡単に実装できます。

List の leftPop を利用してトークンを取得します。

// 输出令牌
public Response limitFlow2(Long id){
 Object result = redisTemplate.opsForList().leftPop("limit_list");
 if(result == null){
 return Response.ok("当前令牌桶中无令牌");
 }
 return Response.ok(articleDescription2);
 }

Rely Java のスケジュールされたタスクでは、トークンをリストに定期的に右プッシュします。もちろん、トークンも一意である必要があるため、トークンの生成には依然として UUID を使用します。

// 10S的速率往令牌桶中添加UUID,只为保证唯一性
 @Scheduled(fixedDelay = 10_000,initialDelay = 0)
 public void setIntervalTimeTask(){
 redisTemplate.opsForList().rightPush("limit_list",UUID.randomUUID().toString());
 }

要約すると、コードの実装は難しくありません。これらの電流制限方法については、上記のコードを AOP またはフィルターに追加して、インターフェイスの現在のフローを制限し、最終的に Web サイトを保護できます。


Redis には実際には他にも多くの用途があり、その役割はキャッシュと分散ロックだけではありません。そのデータ構造は、String、Hash、List、Set、Zset だけではありません。興味のある方は、彼の GeoHash アルゴリズム、BitMap、HLL、Bloom フィルター データ (Redis 4.0 以降に追加され、Docker を使用して redislabs/rebloom を直接インストールできます) の構造をフォローしてください。

redis の詳細については、

redis 入門チュートリアル 列を参照してください。

以上がRedis はどのように電流制限を実装しますか? 3つの実装方法の紹介の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はcnblogs.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。