免責事項:この記事はブロガーオリジナル記事です、ソースを明記してください。https://blog.csdn.net/u010597819/article/details/88927028
ディレクトリ
初期化フロー制御ルール
- 消費初期化メッセージフロー制御ルールの前に開始しPullConsumerDemo.main _initFlowControlRule_
- FlowRule:フロー制御ルールを作成します。
- GROUP_NAMEグループ名とトピック名TOPIC_NAME次のような設定されたリソースのリソース、
- フロー制御しきい値カウントを設定します。
- :フローコントロールの種類のグレードを設定しFLOW_GRADE_THREADスレッドベースのフロー制御は、ベースのフロー制御QPSをFLOW_GRADE_QPS
- 名前limitAppの適用を制限するために設定します。ソースデータの制限によると、デフォルトでは、すべてのアプリケーションのためのデフォルトです
- フロー制御動作controlBehaviorを設定します。CONTROL_BEHAVIOR_DEFAULT、CONTROL_BEHAVIOR_WARM_UP、CONTROL_BEHAVIOR_RATE_LIMITER(トークンバケットアルゴリズム)、CONTROL_BEHAVIOR_WARM_UP_RATE_LIMITER
- キューの最大タイムアウトmaxQueueingTimeMsを設定します。より多くの要求がそこに来ている場合は、要求がタイムアウト設定はすぐにブロックされる超えた場合、彼らは、タイムアウトを待っているキューを待っているキューに置かれます
- フローコントロールマネージャFlowRuleManagerロードされたルール_loadRules_
- 現在のプロパティの更新ルール_currentProperty(DynamicSentinelProperty).updateValue(ルール)は、valueプロパティにバインドし、もしあれば、リスナーのリストを知らせます_
まあ、構成がシンプルなグレーが多い低下し、アルゴリズムをより柔軟であるため、我々はセンチネルのサポートを参照してくださいすることができます。Googleのグアバのアルゴリズムを参照して、フロー制御アルゴリズムの核心
流量制御
- 個人消費のニュース
- 走査メッセージ
- 呼び出し元のコンテキストにキーによるContextUtil.enter
- それは実行コンテキストのコンテキストを作成して存在しない場合、ThreadLocalのから入手しました
- 、2000を超える上限は、_NULL_CONTEXT以上が返されるかどうかが決定されるない場合、DefaultNode応じてプロパティ名キャッシュを取得します。そうしないとロックは名前によると、空気が、そこDefaultNodeをするかどうか、存在しないかどうかを判断する(すなわちキー:GROUP_NAMEとTOPIC_NAME)_EntranceNodeを作成し、子を追加は、コンテキスト復帰ルートノードのキャッシュノード、コンテキストを、ノード
- SphUは、キー、タイプEntryTypeを入力してください。OUT(デフォルトはfalseで、優先順位が開きません)への優先順位に従って
- プロセスはNULL_CONTEXTタイプCtEntry鎖戻りスロットでない場合
- コンテキストがnullの場合、デフォルトCtEntryに戻ります
- スイッチが有効になっていない場合、グローバル処理チェーンが処理されていない戻り型CtEntry NULL_CONTEXTスロットチェーンと同じです
- スロットリソース発見プロセスチェーンlookProcessChainをよると、作成し、存在しないとキャッシュ
- スロットチェーンSlotChainProviderを作成します。NewSlotChain
- ビルダーが空の建物を返さない場合は負荷は、まだデフォルト空の場合は、直接、SPIまたは負荷ビルダーによると、構築DefaultSlotChainBuilder
- デフォルトコンストラクタは、スロットチェーンリンクスロットを構築します
public ProcessorSlotChain build() {
ProcessorSlotChain chain = new DefaultProcessorSlotChain();
chain.addLast(new NodeSelectorSlot());
chain.addLast(new ClusterBuilderSlot());
chain.addLast(new LogSlot());
chain.addLast(new StatisticSlot());
chain.addLast(new SystemSlot());
chain.addLast(new AuthoritySlot());
chain.addLast(new FlowSlot());
chain.addLast(new DegradeSlot());
return chain;
}
各鎖スロットスロットのデフォルトのノードのプロセス
DefaultProcessorSlotChainチェーンリンクドリスト構造AbstractLinkedProcessorSlot、すなわちFIFO、実際の順序が最後のノードから実行されるように、存在下で次、次のノードに渡す続けるされ、我々は、各スロットの特定のノードを見るために従わプロセス
ノード選択されたスロットNodeSelectorSlot
スロットのClusterBuilderSlotクラスタ
LogSlotログスロット
StatisticSlot監視統計スロット
- 直接火次のノード
- 統計データレコード、increaseThreadNumは、ステップに従ってリクエスト数の増加カウントスレッドの数をインクリメントaddPassRequest
- 起点ノードは、同様にスレッドのヌル数、リクエストの数でない場合
- もし定数定数と同じようにエントリの種類。リクエストのスレッド数ENTRY_NODE
- コールバックハンドルチェーン
- 異常PriorityWaitExceptionを待って優先順位をキャプチャし、唯一のスレッドの数を増やします
- 異常BlockExceptionを遮断キャプチャし、唯一のブロックされた要求の数を増やします
- リクエストの数が他の異常な異常な増加のみ
SystemSlotシステム保護スロット
- システムルールマネージャの検証リソースresourceWrapper
- 検証システムは、真の_checkSystemStatus =(つまり、デフォルトはfalseであることを確認していません)_になっています
- リソースタイプのエントリには、直接のリターンである場合
- QPS、スレッド、RT、システム負荷(負荷を。BBRアルゴリズムを。)を確認し、CPU使用率がしきい値を超えた場合は、例外がスローされますSystemBlockExceptionにあります
- 次のノードを発射
AuthoritySlotブラックとホワイトリスト認証スロット
- ブラックリストをチェックしてください
- 認証ルール場合は直接リターンAuthorityRuleはありません
- ダイレクトリターン空の場合は、リソース名に基づいて、対応する認証ルールAuthorityRuleのリストを取得
- ルールチェックを走査チェック、検証は例外がスローされますAuthorityExceptionを失敗します
- 次のノードを発射
FlowSlot流量制御スロット
- 流れをチェック
- フロー制御ルールマネージャFlowRuleManagerは、トラフィック制御ルールマップを取得します
- リソース名のリストに基づいて、フロー制御ルールを取得します。
- フロー制御ルールを横断、流れをチェックし、チェックが例外がスローされますFlowException失敗します
- 次のノードを発射
DegradeSlot吹き降格スロット
- ルール・マネージャは、ヒューズのダウングレードダウングレード確認します。DegradeRuleManagerをCheckDegrade
- リソース名に基づいたルールのリスト吹きダウングレードを取得
- ダイレクトリターン空の場合
- トラバーサルルールチェックは、検証がDegradeExceptionスローされる例外経由ではありません
- 次のノードを発射
フロー制御アルゴリズム一般的に使用される学習
センチネル種のフロー制御アルゴリズム、カテゴリについての合計:直接拒否、ウォームアップ、均一なラインアップ
private static TrafficShapingController generateRater(/*@Valid*/ FlowRule rule) {
if (rule.getGrade() == RuleConstant.FLOW_GRADE_QPS) {
switch (rule.getControlBehavior()) {
//令牌桶算法
case RuleConstant.CONTROL_BEHAVIOR_WARM_UP:
return new WarmUpController(rule.getCount(), rule.getWarmUpPeriodSec(),
ColdFactorProperty.coldFactor);
//漏桶算法
case RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER:
return new RateLimiterController(rule.getMaxQueueingTimeMs(), rule.getCount());
case RuleConstant.CONTROL_BEHAVIOR_WARM_UP_RATE_LIMITER:
return new WarmUpRateLimiterController(rule.getCount(), rule.getWarmUpPeriodSec(),
rule.getMaxQueueingTimeMs(), ColdFactorProperty.coldFactor);
case RuleConstant.CONTROL_BEHAVIOR_DEFAULT:
default:
// Default mode or unknown mode: default traffic shaping controller (fast-reject).
}
}
//超出直接拒绝
return new DefaultController(rule.getCount(), rule.getGrade());
}
リーキーバケットアルゴリズム
RateLimiterControllerトークンバケットアルゴリズムにおけるセンチネルを達成するために使用されます
- 重要な特性レート制限コントローラ
- カウント:しきい値の数を数えます
- maxQueueingTimeMs:キューのタイムアウト(ミリ秒)の最大数
- もしアプリケーションacquireCount <= 0によって直接
- 数<= 0は拒否された場合
- 平均値を計算することは要求ごとに数ミリ秒を取ります
// Calculate the interval between every two requests.
long costTime = Math.round(1.0 * (acquireCount) / count * 1000);
- 平均値を計算することは要求ごとに数ミリ秒を取ります
- 希望expectedTimeを要求することにより、現在の時刻で最後の時間を計算し
// Expected pass time of this request.
long expectedTime = costTime + latestPassedTime.get();
- 所望の時間は、現在時間に等しい未満である場合
- が最後に設定した時間
- 真で返します。
- 所望の時間が現在時間よりも大きい場合(すなわち、待機)
long waitTime = costTime + latestPassedTime.get() - TimeUtil.currentTimeMillis();
- WAITTIMEを待つ時間を計算します
- 最大キュー時間WAITTIMEよりも大きいが場合はfalseを拒否した場合
- 前回は、キューが最大待機時間を超えたか否かを再び決定するために、現在の時刻を減算することにより、時間コストが上昇するのにかかります
- 回復は時間によって前回よりも大きくなると偽の否定を返した場合
- それ以外の場合は、通過スリープ後にtrueを返します
// Calculate the time to wait.
long waitTime = costTime + latestPassedTime.get() - TimeUtil.currentTimeMillis();
if (waitTime > maxQueueingTimeMs) {
return false;
} else {
long oldTime = latestPassedTime.addAndGet(costTime);
try {
waitTime = oldTime - TimeUtil.currentTimeMillis();
if (waitTime > maxQueueingTimeMs) {
latestPassedTime.addAndGet(-costTime);
return false;
}
// in race condition waitTime may <= 0
if (waitTime > 0) {
Thread.sleep(waitTime);
}
return true;
} catch (InterruptedException e) {
}
}
トークンバケットアルゴリズム
WarmUpControllerにおけるセンチネルは、主に安定の期間にわたって、システムが処理能力の多くを持っていても、それが遅くなったりしても、システムのダウンタイムかもしれませんが、システムが受信した要求パルスの種類を解決するために、リーキーバケットアルゴリズムの実装です。その後、我々はクラスの実装を見てみましょう
- ウォームアップコントローラのコンストラクタ重要な属性
- カウント:しきい値カウント
- warmUpPeriodInSec:秒でのウォームアップ時間
- coldFactor:冷却要因
- warningToken:トークン警告=(int型)(warmUpPeriodInSec *回数)/(coldFactor - 1);トークン暖かい/クールファクター1の数の全ての間に、第2のトークン*暖かい秒、すなわちあたりのカウント、ガード値を算出しました。
- maxToken:最大トークン= warningToken +(int型)(2 * warmUpPeriodInSec *数/(1.0 + coldFactor))
- 勾配:斜坡=(coldFactor - 1.0)/(maxToken - warningToken)/カウント
- 秒当たりのトークンの平均数がwarmUpPeriodInSec乗算について図の最大値であります
- 例如:warmUpPeriodInSec = 3、coldFactor = 3、= 10カウント则warningToken = 3。10 /(3-1)= 15、maxToken = 15 + 2 3 * 10 /(1 + 3)= 30、勾配=(3- 1)/ 10 /(30-15)≈0.013
- canPassかどうかを判断することができます
public boolean canPass(Node node, int acquireCount, boolean prioritized) {
long passQps = (long) node.passQps();
long previousQps = (long) node.previousPassQps();
syncToken(previousQps);
// 开始计算它的斜率
// 如果进入了警戒线,开始调整他的qps
long restToken = storedTokens.get();
if (restToken >= warningToken) {
long aboveToken = restToken - warningToken;
// 消耗的速度要比warning快,但是要比慢
// current interval = restToken*slope+1/count
double warningQps = Math.nextUp(1.0 / (aboveToken * slope + 1.0 / count));
if (passQps + acquireCount <= warningQps) {
return true;
}
} else {
if (passQps + acquireCount <= count) {
return true;
}
}
return false;
}
- 同期トークンsyncToken
protected void syncToken(long passQps) {
long currentTime = TimeUtil.currentTimeMillis();
currentTime = currentTime - currentTime % 1000;
long oldLastFillTime = lastFilledTime.get();
if (currentTime <= oldLastFillTime) {
return;
}
long oldValue = storedTokens.get();
long newValue = coolDownTokens(currentTime, passQps);
if (storedTokens.compareAndSet(oldValue, newValue)) {
long currentValue = storedTokens.addAndGet(0 - passQps);
if (currentValue < 0) {
storedTokens.set(0L);
}
lastFilledTime.set(currentTime);
}
}
- 現在の時刻は百、10、数字、丸め他のビットを消去します
- 現在時刻が直接戻され、最後の充填時間に処理された等しい未満である場合、トークン充填された最後の時刻を取得する(全てのビットは、丸めた後に数秒を消去するため、すなわち充填あたり1回)
- 最後の人口値storedTokens.getは、()を取得します
- クーリングトークン
private long coolDownTokens(long currentTime, long passQps) {
long oldValue = storedTokens.get();
long newValue = oldValue;
// 添加令牌的判断前提条件:
// 当令牌的消耗程度远远低于警戒线的时候
if (oldValue < warningToken) {
newValue = (long)(oldValue + (currentTime - lastFilledTime.get()) * count / 1000);
} else if (oldValue > warningToken) {
if (passQps < (int)count / coldFactor) {
newValue = (long)(oldValue + (currentTime - lastFilledTime.get()) * count / 1000);
}
}
return Math.min(newValue, maxToken);
}
- *回数(しきい値カウント)+古いトークン - トークンが古い警告トークン、新しいトークン=(最後の充填時間/ 1000(すなわち、第二に)現在の時間)よりも小さい場合
- トークンが古いトークン警告未満でない場合は、QPS時間ウィンドウは、(カウント/冷却因子)未満です。=同じトークンによって算出された新たなトークンは、警告アルゴリズムよりも小さくなっています。新しいトークンを追加する以上でない場合
- 2つの最大のトークンと新しいトークンの間の最小値を返します。
- 成功した場合、それは、0未満を差し引いた後、0に設定されている場合は、新しいトークンは、QPSマイナスの窓から最後の時間で設定します
- 充填時間を設定
- 完全な同期トークン
- トークンバケットからトークンを取得storeTokens
- 現在のトークンは、以上警戒トークンである場合
- マイナス現在のトークンのアラートトークン(警告部を超えトークン)aboveToken
- スロープ警告QPSから計算
- バック真介して、そうでない場合は本人拒否を返し、現在のアプリケーションシステムQPS + acquireCount <= QPSアラート
- 現在のトークンは、トークンの警告よりも小さい場合
- 現在のアプリケーションの値QPS + acquireCount <=カウント数(しきい値カウント)バック真通じ、そうでない場合はfalseを返す拒否