パニック、メーカーは実際に電流制限I非常に並行システムで最後の時間を尋ねましたか?

:偉大な神はタオはブログで述べて開かれたキャッシュ、降格および電流制限:3つの高度並行システムの開発でシステムを保護するために使用する武器があります記事の著者と組み合わせるいくつかの経験は、関連する概念、アルゴリズムおよび従来の実装の電流制限を記述する。

キャッシュ

キャッシュがよりよく理解され、大規模な高並行システムでは、何のキャッシュデータベースは毎分できなくなりますがある場合、システムが瞬時に麻痺し、破裂しました。アクセス速度を向上させ、同時アクセスの量だけでなく、データベースの保護を強化、システムを保護するための効果的な方法ことができるだけでなく、キャッシュシステムを使用してください。大規模なサイトでは、一般的に「読み取り」キャッシュの使用を簡単に考えることができます。大きな「書き込み」システムでは、キャッシュは、多くの場合、非常に重要な役割が演じています。例えば、バッチデータの累積数等キュー内のメモリキャッシュ(生産と消費)、及びHBaseのデータ書き込みメカニズムは、また、リフトシステムまたはをキャッシュすることによってスループット保護システムを実現するための措置であり、書かれています。でも、ミドルウェアメッセージングは​​、分散データ・キャッシュであると思うかもしれません。

降格

サービス劣化サーバーは、このようにコア業務の正常な動作を保証するために、サーバーのリソースを解放し、いくつかのサービスおよびページの現在のビジネスの状況や交通ダウングレードポリシーに従って、圧力サージであるとき。ダウングレードが異なるレベルを指定する傾向があり、顔の異なる異常なレベルは異なる処理を行います。サービスによると:あなたがサービスを拒否することができ、サービスはそれが時々ランダムにサービスすることができ、遅れることがあります。サービスの範囲によると:あなたは機能をカットすることができ、あなたはまた、いくつかのモジュールをカットすることができます。短いサービスの低下は、ビジネス・ニーズの格下げに応じて、様々な戦略が必要です。主な目的は、かかわらず、何もより良いサービスを弱体化することです。

限定的

制限サービスは、ダウングレードを考慮することができるシステムを保護する目的を達しているインバウンドとアウトバウンドのトラフィック制限システムを制限しています。彼らは必要な限界値に達するとシステムの一般的なスループットに推定することができ、システムの安定動作を確保するために、あなたが制限トラフィックに何らかの措置をとると目標を完了するために、流れを制限する必要があります。たとえば、次の遅延処理は、処理、または部分的にゴミ等の処理を拒否します。

アルゴリズムを制限します

アルゴリズムを制限する一般的な電流は、次のとおりです。カウンター、リーキーバケット及びトークンバケットアルゴリズム。

カウンター

カウンターは最もシンプルかつ粗製のアルゴリズムです。例えば、サービスは、毎秒100件のリクエストを処理することができます。我々は、1秒のスライディングウィンドウ、ウィンドウ10グリッドがあり、各グリッド100ミリ秒を設定することができ、各移動ニーズ、一回100ミリ秒ごとの移動は、現在のサービス・リクエストの数を記録します。メモリの10倍の数を保存する必要があります。LinkedListのデータ構造を実現することができます。格子ごと移動する際の判断現在の訪問やLinkedListの差100以上の最後かどうかという、あなたは、より多くの電流制限よりも必要とする場合。

明らかに、より多くのグリッドがスライディングウィンドウ分割時に、より多くのスライディングウィンドウをスクロール滑らか、統計を制限することは、より正確になります。

次のようにサンプルコードは次のとおりです。

//服务访问次数,可以放在Redis中,实现分布式系统的访问计数
Long counter = 0L;
//使用LinkedList来记录滑动窗口的10个格子。
LinkedList<Long> ll = new LinkedList<Long>();

public static void main(String[] args)
{
    Counter counter = new Counter();

    counter.doCheck();
}

private void doCheck()
{
    while (true)
    {
        ll.addLast(counter);

        if (ll.size() > 10)
        {
            ll.removeFirst();
        }

        //比较最后一个和第一个,两者相差一秒
        if ((ll.peekLast() - ll.peekFirst()) > 100)
        {
            //To limit rate
        }

        Thread.sleep(100);
    }
}
复制代码

リーキーバケットアルゴリズム

すなわち、リーキーバケットアルゴリズムリーキーバケット非常に一般的な制限アルゴリズムであり、トラフィックシェーピング(トラフィックシェーピング)とフロー制御(トラフィックポリシング)を実装するために使用することができます。理解の助けにウィキペディアに模式図を掲示されます:

次のようにリーキーバケットアルゴリズムのメインコンセプトは以下のとおりです。

  • バケットの固定容量、固定された定数に応じて水滴の流出速度。
  • バケットが空である場合は、アウト水滴の必要はありません。
  • 水滴は、任意のレートでバケットに流れることができます。
  • 流入ドラム滴の容量を超えた場合、オーバーフロー(廃棄)に流入滴、バケット容量は一定です。

リーキーバケットアルゴリズムは、より優れたキューを使用して、スタンドアロンシステムに実装実装することができている(.NETはTPLデータフローに良く似た問題に対処することができ、あなたはここでプレゼンテーションを見つけることができます)、分散環境におけるミドルウェアメッセージングかRedisのは、オプションのプログラムです。

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

トークンバケットアルゴリズムは、タブの固定容量ストレージトークン(トークン)は、固定された速度は、トークンバケットに追加されます。いくつかの基本的な概念のトークンバケットアルゴリズムは、以下に説明することができます。

  • トークンは、固定金利トークンバケットに置かれています。例えば、毎秒10を置きます。
  • トークンアップB浴槽ストア、バケツがいっぱいになると、新しく追加されたトークンは廃棄されるか、または拒否されます。
  • Nのサイズは、パケットのバイト場合、トークンバケットからN削除到着すると、パケットはネットワークに送信されます。
  • トークンバケットはn個未満である場合には、(いずれかの廃棄または待ちバッファ)トークンが削除されず、パケットは、制限フローです。

図は次のとおりです。

アルゴリズムは、図のネットワークの速度でトークンの出力の放電速度を制御するためにトークンレートです。ネットワークに我々は、メッセージハンドラを理解し、特定のサービスを実行したり、RPCを呼び出すことができます。

ドレインバケット及びトークンバケットを比較

バーストが流れる際、制御することができるトークンバケットと、実行時にデータ処理の速度を調節します。放電の周波数は速度を増加またはトークン支払いを遅くし、各トークン数で取得されたデータの全体的な処理速度を低下させる、速度を処理するトークン全体のデータを増強するために増加させることができます。それが固定されているためではないバケツ、流出率は、プログラムの処理速度が固定されています。その他の関連するアルゴリズム:アルゴリズム重合

全体的に、トークンバケットアルゴリズムは良いですが、実装はより複雑です。

制限アルゴリズム

グアバ

バーストリミットは、達成するために、フロー(SmoothBursty)と滑らかな温かい制限(SmoothWarmingUp)をスムーズ:グアバは、Javaプロジェクトの数はRateLimiterトークンバケットアルゴリズムを提供し、Googleのコアライブラリ、に広く依存しているが含まれ、Googleのオープンソースプロジェクトです。

1.一般的な料金:

2:トークンの第二提供番号ごとに配置された流れ制限器を作成します。RateLimiter返されるオブジェクトは、以下の2つのトークン1秒に保証することができ、固定速度に配置されます。スムーズな出力を実現

public void test()
{
    /**
     * 创建一个限流器,设置每秒放置的令牌数:2个。速率是每秒可以2个的消息。
     * 返回的RateLimiter对象可以保证1秒内不会给超过2个令牌,并且是固定速率的放置。达到平滑输出的效果
     */
    RateLimiter r = RateLimiter.create(2);

    while (true)
    {
        /**
         * acquire()获取一个令牌,并且返回这个获取这个令牌所需要的时间。如果桶里没有令牌则等待,直到有令牌。
         * acquire(N)可以获取多个令牌。
         */
        System.out.println(r.acquire());
    }
}
复制代码

上記のコードの結果を図に続いて実行される、データ・ベースは0.5秒です。トークンを取得するために、データを処理した後、又はデータ・コールは、インターフェース出力平滑に達します。取得()戻り値はトークンの待機時間である特定のトラフィックバーストを治療するのに必要であれば、戻り値は、破棄期限切れと異なる状況に応じて閾値処理に設定してもよいです。

2.バースト性トラフィック:

トラフィックの突然のバーストはもっとすることができ、それはあまり突然のかもしれません。マルチバーストの例で初見。流れの例またはデータトークンあたり上記の二つ。次のコードは、指定されたパラメータを使用して取得する方法。

System.out.println(r.acquire(2));
System.out.println(r.acquire(1));
System.out.println(r.acquire(1));
System.out.println(r.acquire(1));
复制代码

次のような出力が得られます。

あなたが新しいハンドルより多くのデータが必要な場合は、我々はより多くのトークンを必要とします。コードは、最初の2つのトークンを取得し、その後、次のトークンは、後0.5秒又は1秒後に得られず、後で通常の速度を再開します。トラフィックがバースト的には、次のコードではない場合、これは、マルチバーストの一例です。

System.out.println(r.acquire(1));
Thread.sleep(2000);
System.out.println(r.acquire(1));
System.out.println(r.acquire(1));
System.out.println(r.acquire(1));
复制代码

次のように同様の結果が得られました。

2秒間待機した後、その内部のトークンバケットは、3つのトークンを蓄積してきた、あなたはそれに時間連続アクセスを過ごすことができません。実際には、バースト処理は、単位時間定数に出力されます。サブクラスSmoothBurstyこれらの2つの方法は、のRateLimiterを使用しています。別のサブクラスはSmoothWarmingUpで、それが提供する特定の流量出力バッファのソリューションがあります。

/**
* 创建一个限流器,设置每秒放置的令牌数:2个。速率是每秒可以210的消息。
* 返回的RateLimiter对象可以保证1秒内不会给超过2个令牌,并且是固定速率的放置。达到平滑输出的效果
* 设置缓冲时间为3秒
*/
RateLimiter r = RateLimiter.create(2,3,TimeUnit.SECONDS);

while (true) {
    /**
     * acquire()获取一个令牌,并且返回这个获取这个令牌所需要的时间。如果桶里没有令牌则等待,直到有令牌。
     * acquire(N)可以获取多个令牌。
     */
    System.out.println(r.acquire(1));
    System.out.println(r.acquire(1));
    System.out.println(r.acquire(1));
    System.out.println(r.acquire(1));
}
复制代码

以下の出力、バッファ時間は3秒、トークンバケットはなく、0.5秒であるので、メッセージを開始するのではなく、滑らかな勾配を形成するためには3秒で、周波数の増加とともに、直線的に減少します元の設定周波数は、固定周波数出力した後、達成されます。

図は、3回3秒まで追加を正確にコイル赤。この機能は、適切なシステムは、単に「ウォームアップ」シーンに少し時間がかかり始めていますさ。

nginxの

アクセス層nginxのnginxのを制限するための二つのモジュールを使用しています:

  • モジュールの接続を制限するngx_http_limit_conn_module
  • モジュールngx_http_limit_req_moduleを制限するリーキーバケットアルゴリズムをリクエスト

1. ngx_http_limit_conn_module

私たちはしばしばこのような状況が発生した、サーバーのトラフィックが異常、負荷が大きすぎる、と上のようにします。悪意のある攻撃への大量アクセスの場合、それは多くの場合、いくつかの制約で、同じIPへの接続数と考え、事業に影響を与え、サーバーのストレスを、帯域幅の浪費をもたらすでしょう。

この要件を達成するためのngx_http_limit_conn_moduleモジュール。モジュールは、ソースIP接続として、キーに応じて、各キーに対して定義された接続の数を制限することができます。すべての接続がモジュールをカウントされない接続がカウントされる場合、のみ要求が(これらの要求は、ヘッダ情報が完全に読み込まれた)処理されます。

:私たちは、実装されます。http {}制限nginx_conf、以下を追加することができます

#限制每个用户的并发连接数,取名one
limit_conn_zone $binary_remote_addr zone=one:10m;

#配置记录被限流后的日志级别,默认error级别
limit_conn_log_level error;
#配置被限流后返回的状态码,默认返回503
limit_conn_status 503;
复制代码

その後、次のコードにサーバ{}を追加します。

#限制用户并发连接数为1
limit_conn one 1;
复制代码

その後、我々は同時要求をシミュレートするために、ABテストを使用します。

ab -n 5 -c 5 http://10.23.22.239/index.html
复制代码

以下の結果、同時が、ロックアウトさ503が表示されているしきい値を超えるされていることは明らかです。

また、ちょうど並行処理制限は、単一のIP用に設定されている、またはドメイン名、クライアントのIPの設定と同様の上の制約によって複雑にすることができます。

#http{}段配置
limit_conn_zone $ server_name zone=perserver:10m;
#server{}段配置
limit_conn perserver 1;
复制代码

2. ngx_http_limit_req_module

我々はngx_http_limit_conn_moduleモジュールに使用の上、接続数を制限します。だから、要求の数がそれを行う方法である制限?これは、キー値の処理要求によって定義された周波数を制限することができるngx_http_limit_req_moduleモジュールによって達成される必要があります。

具体的には、規制要求は、単一のIPアドレスからの周波数を処理することができます。この方法は、漏斗アルゴリズムの使用を制限することで、第二の定着プロセスあたりの要求の数は、あまりにも多くの要求を遅らせました。要求された値が限界周波数領域の設定を超えた場合、要求処理は、すべての要求が定義された周波数で処理されるように、遅延又は廃棄されます。

HTTP {}内に配置されました

#区域名称为one,大小为10m,平均处理的请求频率不能超过每秒一次。

limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
复制代码

} {サーバーに配置され

#设置每个IP桶的数量为5
limit_req zone=one burst=5;
复制代码

上記で定義された秒ごとに1つだけに限定されている各IP要求処理のために提供されます。また、各IP、削除5操作要求のためのキャッシュサーバ5缶要求は、要求が破棄されます。

abでのテストでは、クライアントに10倍への継続的なアクセスをシミュレートします:

ab -n 10 -c 10 http://10.23.22.239/index.html
复制代码

以下に、それは数5を介して提供されます。10要求の合計は、最初の要求を即座に処理されます。最初の2-6は、バケットに格納されています。槽が満杯であるため、残りの4つの要求は破棄され、したがってNODELAY設けられていません。

おすすめ

転載: juejin.im/post/5de22cd66fb9a071b23b73b5