ダボにおけるタイムホイールアルゴリズムの応用

ダボにおけるタイムホイールアルゴリズムの応用

[[346568]]

1 スケジュールされたタスク

Netty、Quartz、Kafka、Linux にはすべてスケジュールされたタスク機能があります。

JDK に付属する java.util.Timer と DelayedQueue は、単純なスケジュールされたタスクを実装できます。基礎となるレイヤーはヒープを使用し、アクセスの複雑さは O(nlog(n)) ですが、大規模なスケジュールされたタスクをサポートすることはできません。

タスク量が多く、パフォーマンス要件が高いシナリオでは、タイムホイールアルゴリズムを使用して、タスクアクセスとキャンセル操作の時間計算量を O(1) に削減します。

2 タイムホイールモデルとその応用

スケジュールされたタスクを効率的にバッチ管理するためのスケジューリング モデル。これは通常、時計に似たリング構造として実装され、多くのスロットに分割され、1 つのスロットは時間間隔を表し、各スロットは双方向リンク リストを使用してスケジュールされたタスクを格納します。

ポインタは定期的にジャンプし、スロットにジャンプすると、そのスロットのタイミング タスクが実行されます。

ハッシュタイミングホイール構造図

  • 障害回復
  • フロー制御
  • スケジューリングアルゴリズム
  • ネットワーク内のパケットのライフサイクルを制御する

タイマーの維持には費用がかかる

  • プロセッサはクロックごとに中断される
  • きめ細かいタイマーを使用する
  • 未完成のタイマーが多数あります

全体的な割り込みオーバーヘッドを削減するには、効率的なタイマー アルゴリズムが必要です。

単層タイムホイールの容量と精度には限界があります。特に高い精度が求められるシナリオ、特に長い時間範囲、またはスケジュールする必要のある大量のタスクがある場合、通常は、マルチレベル タイムホイールと、永続ストレージとタイムホイールを組み合わせたソリューションが使用されます。

モデルとパフォーマンスの指標

モデルのルール

クライアントからの呼び出し:

  • START_TIMER(間隔、リクエストID、有効期限アクション)
  • STOP_TIMER (リクエストID)

タイマーティック呼び出し:

  • ティックごとのブックキーピング
  • 有効期限処理

パフォーマンス指標

  • 空間

データ構造で使用されるメモリ

  • 遅れ

上記のルーチンの開始と終了にかかる時間

3 ダボのタイムホイール構造

Dubbo タイマーは、dubbo-common モジュールの org.apache.dubbo.common.timer パッケージに実装されています。次に、タイマーに関係するコア インターフェースと実装を分析します。

コアインターフェース

タイマータスク

Dubbo では、スケジュールされたすべてのタスクは TimerTask インターフェイスを実装する必要があります。定義されている run() メソッドは 1 つだけであり、入力パラメーターは Timeout インターフェイス オブジェクトです。

タイムアウト

Timeout オブジェクトは、スレッド プールによって返される Future オブジェクトとスレッド プールに送信されたタスク オブジェクトの関係と同様に、TimerTask オブジェクトと 1 対 1 で対応します。
Timeout オブジェクトを使用すると、スケジュールされたタスクのステータスを表示できるだけでなく、スケジュールされたタスクを操作することもできます (たとえば、関連するスケジュールされたタスクをキャンセルするなど)。

Timeout インターフェースのメソッド:

Timer インターフェイスはタイマーの基本的な動作を定義します。その中核となるのは newTimeout() です。つまり、スレッド プールにタスクを送信するのと同様に、時間制限付きタスク (TimerTask) を送信し、関連付けられた Timeout オブジェクトを返します。

ハッシュホイールタイムアウト

HashedWheelTimeout は、Timeout インターフェイスの唯一の実装であり、HashedWheelTimer の内部クラスです。 HashedWheelTimeout には 2 つの役割があります。

タイムホイール内の双方向リンクリストのノード、つまりHashedWheelTimer内のタイマータスクTimerTaskのコンテナ

タイマー タスク TimerTask が HashedWheelTimer に送信された後に返されるハンドルは、タイム ホイールの外部でタイマー タスクを表示および制御するために使用されます。

コア分野

前へ、次へ。二重リンク リストは、HashedWheelTimerBucket でタイムアウトを連鎖するために使用されます。これは WorkerThread でのみ機能するため、同期/揮発性は必要ありません。

task 、スケジュールされている実際のタスク

期限、スケジュールされたタスクが実行される時間。 HashedWheelTimeoutを作成するときは、計算式を指定します:currentTime(HashedWheelTimeoutが作成された時刻)+ delay(タスク遅延時間)- startTime(HashedWheelTimerの開始時刻)、ns

状態、スケジュールされたタスクの現在の状態

オプションのステータス:

STATE_UPDATER は、状態変更のアトミック性を実装するために使用されます。

residualRounds : 現在のタスクに残っているクロック サイクルの数。タイム ホイールが表すことができる時間の長さには制限があります。タスクの有効期限と現在の時刻の差が、タイム ホイールの 1 回転で表すことができる時間の長さを超えると、ループが発生し、残りのクロック サイクルを表すためにこのフィールドの値が必要になります。

コアAPI

キャンセルされました()

期限切れです()

州()
現在のHashedWheelTimeoutステータスを確認する

cancel()メソッド

expire()メソッド

取り除く()

ハッシュホイールバケット

時の車輪の中の隙間。
タイム ホイールのスロットは、実際には二重リンク リストをキャッシュして管理するためのコンテナーです。二重リンク リストの各ノードは、TimerTask タイミング タスクに関連付けられた HashedWheelTimeout オブジェクトです。

HashedWheelBucket は、双方向リンク リストの最初と最後のノード (先頭と末尾) を保持します。さらに、各 HashedWheelTimeout ノードは先行参照と後続参照を保持するため、リンク リスト全体を前方および後方にトラバースできます。

コアAPI

タイムアウトを追加します。

ポーリングタイムアウト()

取り除く()
指定された HashedWheelTimeout ノードを二重リンク リストから削除します。

タイムアウトをクリアする()
pollTimeout() メソッドは周期的に呼び出され、二重リンク リスト全体を処理して、タイムアウトまたはキャンセルされていないすべてのタスクを返します。

有効期限切れ()
二重リンク リスト内のすべての HashedWheelTimeout ノードを走査します。期限切れのスケジュールされたタスクを処理する場合、そのタスクは remove() メソッドによって取り出され、expire() メソッドが呼び出されて実行されます。キャンセルされたタスクの場合は、remove() メソッドによって取り出された後、直接破棄されます。期限切れになっていないタスクの場合は、remainingRounds フィールド (残りのクロック サイクル数) が 1 つ減ります。

ハッシュホイールタイマー

タイム ホイール アルゴリズムを通じてタイマーを実装する Timer インターフェイスの実装。

機能

現在のタイムホイール ポインターに従って対応する HashedWheelBucket スロットを選択し、リンク リストの先頭から反復処理して、各 HashedWheelTimeout スケジュール タスクを計算します。

  • 現在のクロックサイクルに属する場合は、取り出されて実行されます
  • グループに属していない場合は、残りのクロック サイクル数が 1 つ減少します。

コアドメイン

ワーカーステート
タイムホイールの現在の状態。AtomicIntegerFieldUpdater によってアトミックに変更される 3 つのオプション値。

開始時間
現在のタイム ホイールの開始時刻。このタイム ホイールに送信されたスケジュールされたタスクの期限フィールド値は、このタイムスタンプに基づいて計算されます。

車輪
タイムホイールの循環キュー。各要素はスロットです。タイムスロットの数がnと指定されている場合、nに最も近い2番目の累乗値が上方に取られます。

タイムアウト、キャンセルされたタイムアウト
HashedWheelTimer は、HashedWheelBucket の双方向リンク リストを処理する前に、これら 2 つのキューのデータを処理します。

タイムアウト キュー<br /> 外部送信タイムホイールでスケジュールされたタスクをバッファリングする

キャンセルされたタイムアウト キュー<br /> キャンセルされたスケジュールされたタスクを一時的に保存する

チェック
HashedWheelTimer$Workerにある、タイムホイールのポインター。ステップサイズが1の単調に増加するカウンター。

マスク
マスク、mask = wheel.length - 1、ticksとmaskを実行して対応するクロックスロットを見つけます

ティック期間
時間ポインターの各増分によって表される実際の時間はナノ秒単位です。

保留タイムアウト
現在のタイムラウンドに残っているスケジュールされたタスクの合計数。

ワーカースレッド
実際にタイミング タスクを実行するタイム ホイール内のスレッド。

ワーカー
スケジュールされたタスクを実際に実行するロジックは、この Runnable オブジェクトにカプセル化されます。

新しいタイムアウト()

スケジュールされたタスクを送信します。スケジュールされたタスクがタイムアウト キューに入る前に、start() メソッドが呼び出されてタイム ホイールが開始され、次の 2 つの重要な手順が完了します。

  1. タイムホイールのstartTimeフィールドを決定する
  2. workerThread スレッドを開始し、ワーカー タスクの実行を開始します。

次に、スケジュールされたタスクの期限が startTime に従って計算され、最後にスケジュールされたタスクは HashedWheelTimeout にカプセル化され、タイムアウト キューに追加されます。

4 タイムホイールポインターの1回転の実行フロー

HashedWheelTimer$Worker.run():

  1. タイムホイールのポインターが回転し、タイムホイールのサイクルが始まります
  2. ユーザーによって積極的にキャンセルされたスケジュールされたタスクをクリーンアップします。これらのスケジュールされたタスクがユーザーによってキャンセルされると、cancelledTimeouts キューに記録されます。ポインタが動くたびに、タイムホイールはキューをクリアします
  3. タイムアウトキューにキャッシュされたスケジュールされたタスクをタイムホイールの対応するスロットに転送します。
  4. 現在のポインタに従って対応するスロットを見つけ、スロットの双方向リンクリスト内のスケジュールされたタスクを処理します。
  5. タイムホイールの状態を確認します。タイムホイールが実行状態にある場合、上記の手順が周期的に実行され、タイミングタスクが継続的に実行されます。タイマーが停止状態の場合、次の手順を実行して、実行されていない時間指定タスクを取得し、それらを unprocessedTimeouts キューに追加します。タイマー内の各スロットを走査して clearTimeouts() メソッドを呼び出し、タイムアウト キューに追加されていないスロットに対して poll() を周期的に呼び出します。
  6. 最後に、ユーザーによってアクティブにキャンセルされた、cancelledTimeouts キュー内のスケジュールされたタスクをクリアします。

5 スケジュールされたタスクアプリケーション

これは定期的な操作に直接使用されるのではなく、タイム ホイールにスケジュールされた単一のタスクを送信するだけです。前のタスクが完了したら、newTimeout() メソッドを呼び出して現在のタスクを再度送信し、次のサイクルでタスクが実行されるようにします。タスク実行中に GC や I/O ブロッキングなどが発生し、タスクの遅延や詰まりが発生した場合でも、同じタスクが連続して送信されることはなく、タスクが蓄積されます。

Dubbo タイムホイールの用途は主に以下の分野です。

  1. 失敗の再試行。たとえば、プロバイダーがレジストリへの登録に失敗した場合や、コンシューマーがレジストリへのサブスクライブに失敗した場合などに再試行します。
  2. 定期的にスケジュールされたタスク(ハートビート要求を定期的に送信する、要求のタイムアウトを処理する、ネットワーク接続が切断された後に再接続するなど)

参照する

https://zhuanlan.zhihu.com/p/32906730

<<:  ノーコード プラットフォーム トップ 8: 2020 年に見逃せない機械学習プラットフォーム

>>:  アリババが国際AIサミットを主催、医療AIとマルチメディアコンテンツ理解が話題に

ブログ    
ブログ    
ブログ    
ブログ    

推薦する

Transformerのランクを下げ、LLMのパフォーマンスを低下させることなく、特定のレイヤーのコンポーネントの90%以上を削除する

大規模モデルの時代において、Transformer は科学研究分野全体を一手にサポートします。 Tr...

...

PyTorch Lightning モデルを本番環境にデプロイするにはどうすればいいですか?

[51CTO.com クイック翻訳] 機械学習の分野を見ると、ソフトウェアエンジニアリングの原理を...

Googleトレンドから、主要なディープラーニングフレームワークの人気がわかる

ディープラーニングはコンピュータービジョンや自然言語処理などの分野でますます大きな成果を上げており、...

清華大学唐傑チーム: NLP事前トレーニングモデルの歴史の簡単な紹介

[[422829]]この記事はAI新メディアQuantum Bit(公開アカウントID:QbitAI...

AI セキュリティの大手企業は 2020 年にどのような行動を取るのでしょうか?

7月9日から7月11日まで、2020年世界人工知能会議クラウドサミットが上海で閉幕しました。「イン...

グラフやグラフニューラルネットワークについて学びたいですか?論文を読むより良い方法はありません。

グラフ埋め込み、グラフ表現、グラフ分類、グラフニューラルネットワーク、この記事では必要なグラフモデリ...

...

Keras によるステートフル LSTM リカレント ニューラル ネットワークの理解

[[327815]]この記事を読むと、次のことがわかります。 1. シーケンス予測問題のための単純な...

...

...

...

在庫 | 今年の世界の AI 事情

​​​ [[253255]]​​ 1. 2018 年の世界の AI 業界の発展は非常に爆発的でした。...

フードデリバリー広告向け大規模ディープラーニングモデルのエンジニアリング実践

著者: Yajie Yingliang、Chen Long 他導入美団のフードデリバリー事業が成長を...