現在のリミッターアルゴリズム
現在、2つの一般的な電流リミッターアルゴリズムがあります:トークンバケットアルゴリズムと漏れやすいバケットアルゴリズム。主な違いは、漏れやすいバケットアルゴリズムが要求レートとスムーズなバーストリクエストを強制的に制限できることですが、トークンバケットアルゴリズムにより、平均レートを制限するときに一定量のバースト要求が可能になります。
以下は、インターネット上で見つかった2つのアルゴリズム図であり、これらの2つのアルゴリズムの特性と簡単に区別できます。
リークバケットアルゴリズム
トークンバケットアルゴリズム
インターフェイスの場合、一定数のバーストリクエストを処理することが許可され、制限には平均レートのみが必要なため、トークンバケットアルゴリズムがより一般的です。
トークンバケットアルゴリズムツールRatelimiter
最も一般的に使用される最も一般的に使用するトークンバケットアルゴリズムの実装クラスは、Google GuavaのRatelimiterです。 Guavaはトークンバケットアルゴリズムを実装するだけでなく、キャッシュ、新しいコレクションクラス、同時ツールクラス、文字列処理クラスなども実装しています。これは強力なツールセットです。
Ratelimiter APIは、CONCURRENTプログラミングネットワークでGuava Ratelimiterの導入を表示できます
Ratelimiterソースコード分析
デフォルトでは、Ratelimiterの最もコア属性は2つのNextFreeTicketMicrosです。トークン時間は次回、保存されたバケツのトークンの数を取得できます。
トークンを取得するかどうかを決定します。
トークンを取得するたびに、バケットのトークンの数に基づいて、次回のトークンを取得するための最速の時間を計算します。リソースを取得できるかどうかを判断するときは、NextFreeticketMicrosを現在の時刻と比較してください。
トークン操作を取得:
トークンを取得するには、NextFreeTicketMicrosと現在の時刻に基づいて新しいトークンの数を計算し、現在のトークンバケットトークン番号を書き、次のFreeticketMicrosを再計算します。バケットにトークンがある場合は、現在の時刻を書き、このリクエストで取得したトークンの数を減らします。
JavaのAQSクラスと同じように、RatelimiterのコアはTryAcquireメソッドです
public boolean tryacquire(int Permits、long timeout、timeUnit unit){//最大待機時間を取得してみてくださいlong timeoutmicros = max(unit.tomicros(タイムアウト)、0); //取得したリソースの数が正しいチェックパーミット(許可)であるかどうかを確認します。長いマイクロストア。 // lock synchronized(mutex()){//現在の時間long nowmicros = stopwatch.readmicros(); //タイムアウト時間内にリソースを取得できるかどうかを判断します(!canacquire(nowmicros、timeoutmicros)){return false; } else {//リソースを取得し、リソースを再計算し、現在のスレッドで必要な睡眠時間を返すことができます。 }} //スリープstopwatch.sleepmicrosun -intrumdibly(microstowait); trueを返します。 }トークンを取得するかどうかを決定します。
Private Boolean canacquire(長いnowmicros、long timeoutmicros){//最古のリソース時間で取得できます - 待ち時間<=リソースを取得する前に現在の時間を取得できますqueryearliestavailable(nowmicros)-timeoutmicros <= nowmicros;}ratelimiterデフォルトの実装クラスqueryearliestavailableは、メンバー変数nextfreeticketmicrosを取得することです
トークンを取得して、必要な待機時間操作を計算します。
final long ReserveandgetWaitlength(int Permits、long nowmicros){//次回の瞬間を取得する時間を取得します= ribersearliestavailable(permits、nowmicros); //現在のスレッドがmaxを返すために必要な睡眠時間を計算します(Momentabable -nowmicros、0);} final long risteearliestavailable(int rebysedpermits、long nowmicros){//バケツの貯留容量resync(nowmicros)のトークンの数を再計算します。 long returnValue = nextfreeticketmicros; //今回消費されたトークンの数は、double storedpermitstospend = min(必要なパミット、this.storedpermits); //次回の次の時間を取得する時間を再計算しますfreeTicketMicros double freshpermits =必須パーミット - storedpermitstospend; long waitmicros = storedpermitstowaittime(this.storedpermits、storedpermitstospend) +(long)(freshpermits * stable intervalmicros); this.nextfreeticketmicros = longmath.saturatedAdd(nextfreeticketmicros、waitmicros); //バケット内のトークンの数を減らすthis.storedpermits- = storedpermitstospend; ReturnValue; }単純なスプリングMVC電流リミットインターセプターを実装します
ハンドラーインターセプターを実装し、コンストラクターにラトリミッター電流リミッターを作成します
public SimpleratelimitInterceptor(int rate){if(rate> 0)globalRatelimiter = ratelimiter.create(reate);それ以外の場合は、新しいruntimeexceptionを投げます( "レートはゼロよりも大きい必要があります");}Prehandleの現在のリミッターのTryAcquireメソッドを呼び出して、制限レートがそれを超えたかどうかを判断します
public Boolean Prehandle(httpservletrequest request、httpservletresponse応答、オブジェクトハンドラー)exception {if(!globalrateLimiter.tryacquire()){loggerutil.log(request.getRequesturi()+"requestは現在の制限料金を超えています"); falseを返します。 } trueを返します。 }Dispatcher-servlet.xmlで現在の制限インターセプターを構成します
<MVC:インターセプター> <! - 電流リミットインターセプター - > <MVC:インターセプター> <MVC:マッピングpath = "/**"/> <bean> <constructor-arg index = "0" $ {totolrate} "/>> </bean> </mvc:インターセプター> </mvc:インターセプター>スプリングMVC電流リミットインターセプターの複雑なバージョン
プロパティを使用して、インターセプトされたURL式 - >レートレートで渡す
<MVC:Interceptor> <MVC:Mapping Path = "/**"/> <Bean> <! - 単一のURL電流制限 - > <プロパティ名= "urlproperties"> <props> <prop key = "/get/{id}各URL式に対応するラトリミッター電流リミッターを作成します。 URL式は、org.springframework.web.servlet.mvc.condition.patternsRequestConditionとしてカプセル化されています。 PatternSRequestConditionは、リクエストとコントローラーに合わせてSpringMVCのDispatcherServletで使用されるクラスです。リクエストがこれらのURL式に準拠しているかどうかを判断できます。
インターセプタープリハンドルメソッド
//現在の要求パス文字列Lookuppath = urlpathhelper.getRookuppathForRequest(request); //すべてのURL式に対応するパターンSREQUESTCONDITION(PatternSREQUESTCONDITION PatternSREQUESTCONDITION:URLRATEMAP.KEYET() patternSrequestCondition.getMatchingPatterns(lookuppath); if(!matches.isempty()){//一致が成功した場合、対応する電流リミッターのトークンを取得しますif(urlrratemap.get(patternsrequestcondition).tryacquire()){loggerutil.log(lookgerupath + "request mated beded" + joiner.on( ")。リミッター "); } else {// token loggerutil.log(lookuppath + "request creds" + joiner.on( "、")を取得できなかった。 falseを返します。 }}}特定の実装クラス
Githubをご覧ください
上記はこの記事のすべての内容です。みんなの学習に役立つことを願っています。誰もがwulin.comをもっとサポートすることを願っています。