IOStatistics API を使用した統計情報の収集

@InterfaceAudience.Public
@InterfaceStability.Unstable

IOStatistics API は、入力ストリームや出力ストリームなど、個々の IO クラスに関する統計情報を *アプリケーションがクエリできる標準的な方法で* 提供することを目的としています。

多くのファイルシステム関連クラスは、統計情報の収集を実装し、これらにクエリするための非公開/不安定な方法を提供してきましたが、実装間で共通していなかったため、アプリケーションがこれらの値を参照することは安全ではありませんでした。例:S3AInputStream とその統計情報API。これは内部テストで使用されますが、Apache Hive や Apache HBase などのアプリケーションでダウンストリームで使用することはできません。

IOStatistics API は、以下のことを目的としています。

  1. インスタンス固有であること。クラスの複数のインスタンス間で共有されるものではなく、スレッドローカルでもないこと。
  2. アプリケーションで使用できるほど公開され、安定していること。
  3. Java、Scala、および libhdfs を介した C/C++ で記述されたアプリケーションで簡単に使用できること。
  4. hadoop-common JAR に基本的なインターフェースとクラスを持つこと。

コアモデル

任意のクラスは、統計情報を提供するために IOStatisticsSource を実装 *できます*。

FSDataInputStreamFSDataOutputStream などのラッパー I/O クラスは、インターフェースを実装し、ラップされたクラスにも実装されている場合はそれを転送する *べき* であり、実装されていない場合は null を返す必要があります。

IOStatisticsSource 実装の getIOStatistics() は、その特定のインスタンスの統計情報を列挙する IOStatistics のインスタンスを返します。

IOStatistics インターフェースは、5種類の統計情報を公開します。

カテゴリ 説明
カウンター long 値が増加する可能性のあるカウンター。SHOULD BE >= 0
ゲージ long 上下する可能性のある任意の値。SHOULD BE >= 0
最小値 long 最小値。負になる可能性があります。
最大値 long 最大値。負になる可能性があります。
平均統計 MeanStatistic 算術平均とサンプルサイズ。平均は負になる可能性があります。

4つは単純な long 値であり、変化の仕方と集計方法が異なります。

統計値の集計

異なる統計カテゴリについて、aggregate(x, y) の結果は次のとおりです。

カテゴリ 集計
カウンター max(0, x) + max(0, y)
ゲージ max(0, x) + max(0, y)
最小値 min(x, y)
最大値 max(x, y)
平均統計 xy の平均の計算

クラス MeanStatistic

パッケージ org.apache.hadoop.fs.statistics

このパッケージには、アプリケーションで使用するための公開統計APIが含まれています。

MeanStatistic は、集計をサポートするための (mean, samples) のタプルです。

サンプルが 0MeanStatistic は、空の統計とみなされます。

sample = 0 のすべての MeanStatistic インスタンスは、mean の値に関係なく、等しいとみなされます。

平均を計算するアルゴリズム

if x.samples = 0:
    y
else if y.samples = 0 :
    x
else:
    samples' = x.samples + y.samples
    mean' = (x.mean * x.samples) + (y.mean * y.samples) / samples'
    (samples', mean')

暗黙的に、これは両方のサンプルが空の場合、集計値も空であることを意味します。

public final class MeanStatistic implements Serializable, Cloneable {
  /**
   * Arithmetic mean.
   */
  private double mean;

  /**
   * Number of samples used to calculate
   * the mean.
   */
  private long samples;

  /**
   * Get the mean value.
   * @return the mean
   */
  public double getMean() {
    return mean;
  }

  /**
   * Get the sample count.
   * @return the sample count; 0 means empty
   */
  public long getSamples() {
    return samples;
  }

  /**
   * Is a statistic empty?
   * @return true if the sample count is 0
   */
  public boolean isEmpty() {
    return samples == 0;
  }
   /**
   * Add another mean statistic to create a new statistic.
   * When adding two statistics, if either is empty then
   * a copy of the non-empty statistic is returned.
   * If both are empty then a new empty statistic is returned.
   *
   * @param other other value
   * @return the aggregate mean
   */
  public MeanStatistic add(final MeanStatistic other) {
    /* Implementation elided. */
  }
  @Override
  public int hashCode() {
    return Objects.hash(mean, samples);
  }

  @Override
  public boolean equals(final Object o) {
    if (this == o) { return true; }
    if (o == null || getClass() != o.getClass()) { return false; }
    MeanStatistic that = (MeanStatistic) o;
    if (this.isEmpty()) {
      return that.isEmpty();
    }
    return Double.compare(that.mean, mean) == 0 &&
        samples == that.samples;
  }

  @Override
  public MeanStatistic clone() {
    return new MeanStatistic(this);
  }

  public MeanStatistic copy() {
    return new MeanStatistic(this);
  }

}

クラス org.apache.hadoop.fs.statistics.IOStatisticsSource

/**
 * A source of IO statistics.
 * These statistics MUST be instance specific, not thread local.
 */
@InterfaceStability.Unstable
public interface IOStatisticsSource {

  /**
   * Return a statistics instance.
   * It is not a requirement that the same instance is returned every time.
   * {@link IOStatisticsSource}.
   * If the object implementing this is Closeable, this method
   * may return null if invoked on a closed object, even if
   * it returns a valid instance when called earlier.
   * @return an IOStatistics instance or null
   */
  IOStatistics getIOStatistics();
}

これは、IOStatistics 情報のソースである場合、オブジェクトインスタンスが実装 *しなければならない* インターフェースです。

不変条件

getIOStatistics() の結果は次のいずれかになります。

  • null
  • エントリの各マップが空のマップである、変更不能な IOStatistics
  • 統計が IOStatisticsSource を実装するクラスのそのインスタンスに固有のものでなければならない IOStatistics のインスタンス。

非公式には、返される統計マップが空でない場合、すべての統計はクラスの現在のインスタンスから収集されなければならず、一部の FileSystem 統計の収集方法のように、他のインスタンスからは収集されません。

getIOStatistics() の結果は、null でない場合、すべての呼び出しで異なるインスタンスになる *可能性があります*。

クラス org.apache.hadoop.fs.statistics.IOStatistics

これらは、IOStatisticsSource を実装するオブジェクトによって提供されるインスタンスごとの統計情報です。

@InterfaceAudience.Public
@InterfaceStability.Unstable
public interface IOStatistics {

  /**
   * Map of counters.
   * @return the current map of counters.
   */
  Map<String, Long> counters();

  /**
   * Map of gauges.
   * @return the current map of gauges.
   */
  Map<String, Long> gauges();

  /**
   * Map of minumums.
   * @return the current map of minumums.
   */
  Map<String, Long> minumums();

  /**
   * Map of maximums.
   * @return the current map of maximums.
   */
  Map<String, Long> maximums();

  /**
   * Map of meanStatistics.
   * @return the current map of MeanStatistic statistics.
   */
  Map<String, MeanStatistic> meanStatistics();

}

統計の名前付け

統計の名前付けポリシーは、可読性、共有性、そして理想的には IOStatisticSource 実装全体での一貫性を考慮して設計されています。

  • キー名内の文字は、最初の文字を除いて正規表現 [a-z|0-9|_] に一致する *必要があり*、最初の文字は [a-z] の範囲内にある *必要があり* ます。したがって、有効な統計名のための完全な正規表現は次のとおりです。

    [a-z][a-z|0-9|_]+
    
  • 可能な限り、統計の名前は共通名で定義されたものを使用する *べき* です。

    org.apache.hadoop.fs.statistics.StreamStatisticNames
    org.apache.hadoop.fs.statistics.StoreStatisticNames
    

注記 1.: これらは進化しています。クライアントがその統計を名前で安全に参照するには、アプリケーションにコピーする *べき* です。(つまり、hadoop 3.4.2 でコンパイルされたアプリケーションが hadoop 3.4.1 にリンクする場合、文字列をコピーします)。

注記 2: これらのクラスで定義されているキーは、後続の Hadoop リリースから削除されません。

  • 共通の統計名は、他の統計を報告するために使用される *べきではなく*、事前に定義された測定単位を使用する *必要があり* ます。

  • 1つのマップ内の統計名は、別のマップで再利用される *べきではありません*。これは、ログに記録された統計の診断を支援します。

統計マップ

返される統計の各マップについて

  • エントリを追加/削除する操作はサポートされていません。返されるマップは、統計のソースによって変更可能になる *可能性があり* ます。

  • マップは空になる *可能性があり* ます。

  • マップキーはそれぞれ、測定された統計を表します。

  • マップ内のキーのセットは変更されない *べき* であり、キーを削除してはなりません。

  • 統計は動的である *べき* です。エントリのすべてのルックアップは最新の値を返す *べき* です。

  • 値は、Map.values()Map.entries() の呼び出し間で変更される *可能性があり* ます。

  • 更新は、返されたイテレータの iterable() 呼び出し内、または実際の iterable.next() 操作内で行われる *可能性があり* ます。つまり、評価が行われる時期は保証されません。

  • 返された Map.Entry インスタンスは、繰り返し getValue() を呼び出した場合でも同じ値を返す *必要があり* ます。(つまり、エントリを取得したら、変更不能です)。

  • 統計のクエリは、長時間動作中に呼び出された場合、最新の値よりも高速な返答を優先する程度に高速で非ブロッキングである *べき* です。

  • 統計は遅れる *可能性があり* ます。特に、別々の操作で収集された統計(例:ファイルシステムインスタンスによって提供されるストリームIO統計)の場合。

  • 時間を表す統計は、単位としてミリ秒を使用する *べき* です。

  • 時間を表し、異なる単位を使用する統計は、使用されている単位を文書化する *必要があり* ます。

スレッドモデル

  1. IOStatistics のインスタンスは、スレッド間で共有できます。

  2. 提供された統計マップへの読み取りアクセスは、スレッドセーフである *必要があり* ます。

  3. マップから返されたイテレータは、スレッド間で共有してはなりません。

  4. 収集された統計には、監視対象オブジェクトの作業を実行するすべてのスレッドで発生したすべての操作が含まれている *必要があり* ます。

  5. 報告された統計は、アクティブなスレッドにローカルのものであってはなりません。

これは、スレッドごとの統計が収集され報告される FileSystem.Statistics の動作とは異なります。

そのメカニズムは、同じ FS インスタンスを共有するさまざまなワーカースレッドの限定的な読み取り/書き込み統計の収集をサポートしますが、収集がスレッドローカルであるため、必然的に他のスレッドでワーカースレッドのために実行された IO を過少報告します。

統計スナップショット

現在の統計値のスナップショットは、IOStatisticsSupport.snapshotIOStatistics() を呼び出すことで取得できます。

  public static <X extends IOStatistics & Serializable> X
      snapshotIOStatistics(IOStatistics statistics)

このスナップショットは、Java シリアライゼーションと Jackson を介して JSON との間でシリアライズ可能です。

ヘルパークラス

クラス org.apache.hadoop.fs.statistics.IOStatisticsSupport

これは、IOStatistics ソースとインスタンスを操作するためのヘルパーメソッドを提供します。

その操作については、Javadoc を参照してください。

クラス org.apache.hadoop.fs.statistics.IOStatisticsLogging

IOStatistics/IOStatisticsSource インスタンスを効率的にログに記録するためのサポート。

これらは、ログレベルが必要な場合にのみ IOStatistics インスタンスの状態を列挙することを含め、ログの支援を目的としています。

LOG.info("IOStatistics after upload: {}", demandStringify(iostats));

// or even better, as it results in only a single object creations
Object latest = demandStringify(iostats);
LOG.info("IOStatistics : {}", latest);
/* do some work. */
LOG.info("IOStatistics : {}", latest);

パッケージ org.apache.hadoop.fs.statistics.impl

これには、アプリケーションに統計情報を提供するための実装クラスが含まれています。

これらはアプリケーションで使用してはなりません。このパッケージから機能が必要な場合は、公開実装の提供を Hadoop 開発チャネルを介して提案できます。

Hadoopソースツリー外のFileSystemAbstractFileSystem関連クラス実装で使用可能ですが、不安定でマイナーリリースで変更される可能性があります。ご注意ください。