魂の拷問:同時実行性の高いシナリオにいる場合、システムの電流制限を達成するために何をしますか?

高い同時実行性を考慮しない場合、通常はビジネスシステムが正常に動作していても、同時実行性の量が増えると、さまざまな奇妙なビジネス上の問題が頻繁に発生します。たとえば、eコマースビジネスでは、ユーザーの注文や在庫が失われる可能性があります。控除。異常、売られ過ぎ、その他の問題。

電流制限はサービス低下の手段です。名前が示すように、システムを保護する目的は、システムのフローを制限することによって達成されます。

合理的な電流制限構成では、システムのスループットを理解する必要があります。したがって、電流制限には通常、容量計画 と 圧力テストの組み合わせが必要  です。

外部要求がシステムの最大しきい値に近づくか達すると、現在の制限がトリガーされ、システムが圧倒されるのを防ぐためにダウングレードするための他の手段が取られます。一般的なダウングレード戦略は、 遅延処理 、 サービス拒否 、 ランダム拒否、 など

現在の制限戦略は、実際にはJava並行プログラミングのスレッドプールと非常によく似ています。スレッドプールがいっぱいになると、次のようなさまざまな拒否戦略を構成できることは誰もが知っています。

  • AbortPolicyは、タスクを破棄し、例外をスローします
  • DiscardPolicy、例外をスローせずにタスクを破棄する
  • DiscardOldestPolicyなどはもちろん、自分で拒否ポリシーを実装することもできます

Javaのスレッドプールは開発における小さなファンクションポイントですが、システムの設計とアーキテクチャに拡張することもでき、知識を合理的に転送して再利用することができます。

電流制限方式には、電流流量が設定した最大値に達していると判断する方法という非常に重要なポイント  がありますさまざまな実装戦略があります。以下は簡単な分析です。

1.カウンター方式

一般的に、電流を制限するときは、単位時間あたりのリクエスト数を使用します。これは一般にQPSと呼ばれます。QPSをカウントする最も直接的なアイデアは、カウンターを実装することです。

カウンター方式は、現在の制限アルゴリズムの中で最も単純なアルゴリズムです。インターフェースは、100秒以内の訪問数を10,000回以下に制限すると想定しています。カウンターは維持されます。新しい要求が来るたびに、カウンターは次のように増加します。 1.1。

この時点で判断すると、

  • カウンターの値が現在の制限値より小さく、最後の要求からの時間間隔が100秒以内の場合、要求は通過できます。それ以外の場合、要求は拒否されます。
  • 時間間隔を超えた場合は、カウンターをクリアしてください

次のコードは、参照として使用できるカウンターとしてAtomicIntegerを使用します。

public class CounterLimiter { 
    //初始时间 
    private static long startTime = System.currentTimeMillis(); 
    //初始计数值 
    private static final AtomicInteger ZERO = new AtomicInteger(0); 
    //时间窗口限制 
    private static final int interval = 10000; 
    //限制通过请求 
    private static int limit = 100; 
    //请求计数 
    private AtomicInteger requestCount = ZERO; 
    //获取限流 
    public boolean tryAcquire() { 
        long now = System.currentTimeMillis(); 
        //在时间窗口内 
        if (now < startTime + interval) { 
            //判断是否超过最大请求 
            if (requestCount.get() < limit) { 
                requestCount.incrementAndGet(); 
                return true; 
            } 
            return false; 
        } else { 
            //超时重置 
            requestCount = ZERO; 
            startTime = now; 
            return true; 
        } 
    } 
} 

カウンター戦略は電流を制限し、単一ポイントからクラスターに拡張できます。これは、分散環境でのアプリケーションに適しています。

シングルポイントの電流制限はメモリを使用できます。クラスターの電流制限に拡張すると、ストレージにRedisやMemcachedなどの別のストレージノードを使用できます。有効期限を一定の時間間隔で設定すると、トラフィックをクラスター化し、全体的な制限を実行します。

カウンター戦略には大きな欠点 があり、クリティカルフローに適していないため、電流制限が十分にスムーズではありません 。

このようなシナリオを想定して、ユーザーの注文は1分間に100,000回以下に制限します。現在、2つの時間枠の交差点で、1秒以内に100,000件のリクエストが送信されます。つまり、ウィンドウ切り替えから2秒以内に、システムは200,000の注文要求を受信しました。このピーク値は、システムのしきい値を超え、サービスの安定性に影響を与える可能性があります。

カウンターアルゴリズムの最適化は、ウィンドウ制限の2倍の要求を回避することです。これは、スライディングウィンドウアルゴリズムを使用して実装でき、興味のある学生が行って調べることができます。

2.リーキーバケットとトークンバケットアルゴリズム

リーキーバケットアルゴリズムとトークンバケットアルゴリズムは、実際のアプリケーションではより広範囲であり、しばしば比較されます。

リーキーバケットアルゴリズムは、リーキーバケットと比較することができます。固定容量のバケットがあり、水を漏らすために下部に小さな穴が開けられていると仮定して、水漏れの速度を制御して電流を達成することにより、要求の処理を制御します。制限。

リーキーバケットアルゴリズムの拒否戦略は非常に単純です。外部リクエストが現在のしきい値を超えると、オーバーフローするまでバケットに蓄積され、システムはオーバーフロートラフィックを気にしません。

リーキーバケットアルゴリズムは、出口からの要求率を制限します。上記のカウンター方法に重大な問題はなく、要求曲線は常に滑らかです。

その主な問題の1つは、 リクエストのフィルタリングが正確すぎる ことです。「水が澄んでいるときは魚がいない」とよく言われますが、実際には現在の制限でも同じです。注文は1回あたり100,000回に制限されています。 2番目は100,000です。このリクエストはどうですか?私はそれを拒否する必要がありますか?

ほとんどのビジネスシナリオでは、答えはノーです。現在は限られていますが、システムが特定のトラフィックバーストを許可することが望まれます。現時点では、トークンバケットアルゴリズムが必要です。

トークンバケットアルゴリズムで、一定のサイズのバケットがあるとします。このバケットの容量は、設定されたしきい値に関連しています。バケットには多くのトークンがあります。固定レートで、トークンはバケットに入れられます。いっぱいになっている場合はトークンを破棄してください。バケットに保存できるトークンの最大数がバケットサイズを超えることはありません。リクエストが届くと、バケットからトークンを削除しようとします。バケットが空の場合、リクエストは拒否されます。

GoogleのGuavaオープンソースツールキットを使用したことがありますか?Guavaの制限付きフロー戦略のツールクラスRateLimiterであるRateLimiterは、トークンバケットアルゴリズムに基づいてフロー制限を実装します。これは非常に便利です。

RateLimiterは特定の頻度でトークンをバケットにスローし、スレッドはトークンを取得したときにのみトークンを実行できます。RateLimterのAPIは直接適用できます。主なメソッドはacquireとtryAcquireです。

取得はブロックされますが、tryAcquireメソッドは非ブロックです。

簡単な例を次に示します。

public class LimiterTest { 
    public static void main(String[] args) throws InterruptedException { 
        //允许10个,permitsPerSecond 
        RateLimiter limiter = RateLimiter.create(100); 
        for(int i=1;i<200;i++){ 
            if (limiter.tryAcquire(1)){ 
                System.out.println("第"+i+"次请求成功"); 
            }else{ 
                System.out.println("第"+i+"次请求拒绝"); 
            } 
        } 
    } 
} 

さまざまな電流制限アルゴリズムの比較

カウンターアルゴリズムは実装が比較的簡単で、クラスターでの使用に特に適しています。ただし、重大な状況を考慮する必要があり、スライディングウィンドウ戦略を最適化に使用できます。もちろん、特定の電流制限シナリオにも依存します。

リーキーバケットアルゴリズムとトークンバケットアルゴリズムリーキーバケットアルゴリズムは、比較的厳密な電流制限を提供します。トークンバケットアルゴリズムは、現在の制限に加えて、ある程度のバーストトラフィックを許可します。実際の開発では、フローをそれほど正確に制御する必要がないため、トークンバケットアルゴリズムにはより多くのアプリケーションがあります。

設定したピークトラフィックがpermitsPerSecond = N、つまり1秒あたりのリクエスト数である場合、カウンターアルゴリズムには2Nのトラフィックがあり、リーキーバケットアルゴリズムは常にNのトラフィックを制限し、トークンバケットアルゴリズムはNを超えるトラフィックを許可します。 、ただし2Nまでのピークには到達しません。

おすすめ

転載: blog.csdn.net/m0_46757769/article/details/112577393