高同時環境でのqps計算

3051 ワード

最近アリのいくつかの中間部品を研究して、最近sentinelを見て、私たちが今使っている統計-判断-警報-溶断と少し似ているので、ソースコードに深く入って詳しく見て、見なくても大丈夫で、見てびっくりしました.私たちの現在の溶断の粒度は分レベルで、sentinelが任意のレベル、さらにはミリ秒まで細かくできるとは思わなかった.とりあえず秒単位で話しましょう.比較すると、同じレベルではありません.
私たちの前のアーキテクチャは言わないで、やはりアリsentinelが使っているqpsの計算方法を話してみましょう.最も印象に残っているのはqpsの計算モードです.
qpsが2000で計算すると、ミリ秒ごとに2つのリクエストが処理され、qpsと同時環境でデータが正しいためにロック処理されると、cpuリソースが大幅に消費されることを知っておく必要があります.
またcurtime%1000をkeyとしてリクエスト数を統計すると,現在時間が200 msであれば,取得したqpsは総量の20%である可能性が高いので,だめに違いない.
実はこのようなファイルですhttps://github.com/Netflix/Hystrix/blob/master/hystrix-core/src/main/java/com/netflix/hystrix/util/HystrixRollingNumber.java
スライス
まずsentinelが採用した方法は、1 sを10枚に分けると、現在の100 ms内のデータを1枚ずつ統計し、現在のqpsは現在のqpsのために10格前進し、合計することであり、現在のqpsである.
さて問題ですが、スライスの受け渡し時点では、新しいスライスに対応するオブジェクトを作成する必要があり、制御を付けなければ、直接ロックをかけ、すべてのスレッドが待機します(現在のbucketを作成するスレッドは1つしかありません).しかしsentinelのモードは、新しいbucketを作成することを発見したら、1つのスレッドを作成させ、別のスレッドは前のbucketを取り出して処理します(時刻の正確さを犠牲にしますが、パフォーマンスのヒントを大量に交換します).
longadd
具体的には、あるbucketについては、現在のbucketのvalueを増やす必要があります.伝統的な考え方は、このbucketのvalueをロックすることです.では、この場所はまたブロックされ、良い方法はありません.確かにあります.sentinelの考えを見てみましょう.実はnetflixのhytrixRollinngNumberを使った方法です(https://github.com/Netflix/Hystrix).具体的にはStriped 64です.
データstripingとは、論理的に連続したデータを複数のセグメントに分けて、このシーケンスのセグメントを異なる物理デバイスに格納することである.セグメントを複数のデバイスに分散することで、アクセスの同時性を向上させ、全体的なスループットを向上させることができます.
JDK 8では、既に追加されているjava.util.concurrent.atomicの下のStriped64 。
abstract class Striped64 extends Number {
    static final int NCPU = Runtime.getRuntime().availableProcessors();

     //    Cell   。         2   。
    transient volatile Cell[] cells;

     // base  ,        ,               。
    transient volatile long base;

     //    ,  resizing  /    Cell   。
    transient volatile int cellsBusy;
}


@sun.misc.Contended static final class Cell {
     volatile long value;
     Cell(long x) { value = x; }
     final boolean cas(long cmp, long val) {
          return UNSAFE.compareAndSwapLong(this, valueOffset, cmp, val);
     }

     // Unsafe mechanics
     private static final sun.misc.Unsafe UNSAFE;
     private static final long valueOffset;
     static {
          try {
               UNSAFE = sun.misc.Unsafe.getUnsafe();
               Class> ak = Cell.class;
               valueOffset = UNSAFE.objectFieldOffset
                    (ak.getDeclaredField("value"));
          } catch (Exception e) {
               throw new Error(e);
          }
     }
}

の を ればわかるでしょうが、 の を さくするのが え で、qpsを するのにぴったりです.もちろん のvalueはStriped 64です.value + Cell[0-n].valueの なので、このような は にO(1)であり、 むと cpuに することができる.しかし、 たちが んでいるのです.