Spark のシリアル化、依存関係、永続性

シリアル化

閉鎖チェック

シリアル化のメソッドとプロパティ

依存関係 

RDDの血縁関係

RDD 狭い依存関係

RDD の広い依存関係

RDDタスク分割

RDD 永続性

RDD キャッシュ キャッシュ

RDD チェックポイント チェックポイント

キャッシュとチェックポイントの違い


シリアル化

閉鎖チェック

        計算の観点から、演算子以外のコードは Driver 側で実行され、演算子内のコードは Executor 側で実行されます。次に、scala関数型プログラミングでは、演算子の外側のデータが演算子の中で使用されることが多く、このようにクロージャの効果が形成されます.使用される演算子の外側のデータがシリアル化できない場合、それはデータをシリアル化できないことを意味します.渡すときにエラーが発生します.実行のために Executor 側に値を渡すため、タスクの計算を実行する前に、クロージャ内のオブジェクトがシリアル化できるかどうかを確認する必要があります.この操作をクロージャ検出と呼びます. Scala2.12以降、クロージャーのコンパイル方法が変わった

シリアル化のメソッドとプロパティ

        計算の観点から、演算子以外のコードは Driver 側で実行され、演算子内のコードは Executor 側で実行されます。

object spark_02 {
  def main(args: Array[String]): Unit = {
    //准备环境
    //"*"代表线程的核数   应用程序名称"RDD"
    val sparkConf = new SparkConf().setMaster("local[*]").setAppName("RDD")
    val sc = new SparkContext(sparkConf)
    val rdd: RDD[String] = sc.makeRDD(Array("hello world", "hello spark", "hive", "atguigu"))


    //创建查询对象
    val search = new Search("h")
    //函数传递,打印:ERROR Task not serializable
    search.getMatch1(rdd).collect().foreach(println)

    println("========================================")
    
    //属性传递,打印:ERROR Task not serializable
    search.getMatch2(rdd).collect().foreach(println)
    
    //关闭环境
    sc.stop()
  }
}

//查询对象
//类的构造参数是类的属性,构造参数需要进行闭包检查(对类进行闭包检查)
class Search(query:String) extends Serializable {
  def isMatch(s: String): Boolean = {
    s.contains(query)
  }
  // 函数序列化案例
  def getMatch1 (rdd: RDD[String]): RDD[String] = {
    rdd.filter(isMatch)
  }
  // 属性序列化案例
  def getMatch2(rdd: RDD[String]): RDD[String] = {
    rdd.filter(x => x.contains(query))
  }
}

依存関係 

        隣接する 2 つの RDD 関係は依存関係と呼ばれます

RDDの血縁関係

        複数の連続するRDDの依存関係を血縁と呼ぶ

        RDD は粗粒度の変換、つまり多数のレコードに対して実行される単一の操作のみをサポートします。失われたパーティションを復元するために記録する RDD の一連の Lineage (系統) を作成します。RDDの系統は、RDDのメタデータ情報と変換動作を記録します.RDDの一部のパーティションデータが失われた場合、この情報に基づいて失われたデータパーティションを再計算して復元できます.

val fileRDD: RDD[String] = sc.textFile("input/1.txt")
println(fileRDD.toDebugString) //打印输出血缘关系
println("----------------------")
val wordRDD: RDD[String] = fileRDD.flatMap(_.split(" "))
println(wordRDD.toDebugString)
println("----------------------")
val mapRDD: RDD[(String, Int)] = wordRDD.map((_,1))
println(mapRDD.toDebugString)
println("----------------------")
val resultRDD: RDD[(String, Int)] = mapRDD.reduceByKey(_+_)
println(resultRDD.toDebugString)
resultRDD.collect()

RDD 狭い依存関係

        狭い依存関係は、各親 (上流) RDD のパーティションが、子 (下流) RDD の最大 1 つのパーティションによって使用されることを意味します. 狭い依存関係は、イメージ内の唯一の子と比較されます.

RDD の広い依存関係

        広い依存関係は、同じ親 (上流) RDD のパーティションが複数の子 (下流) RDD のパーティションに依存していることを意味し、シャッフルが発生します。

RDDタスク分割

        RDD タスクのセグメンテーションは、アプリケーション、ジョブ、ステージ、およびタスクに分けられます。

  • アプリケーション: アプリケーションを生成するために SparkContext を初期化します。
  • ジョブ: アクション オペレーターはジョブを生成します。
  • ステージ: ステージは、ShuffleDependencies に 1 を加えた数に等しくなります。
  • タスク: ステージでは、最後の RDD のパーティションの数がタスクの数です。

注: Application->Job->Stage->Task の各層は 1 対 n の関係にあります。

RDD 永続性

RDD キャッシュ キャッシュ

        RDD は Cache または Persist メソッドを介して以前の計算結果をキャッシュします. デフォルトでは、データは JVM のヒープ メモリにキャッシュされます。ただし、これら 2 つのメソッドが呼び出されたときにすぐにキャッシュされるわけではありませんが、後続のアクション オペレーターがトリガーされると、RDD はコンピューティング ノードのメモリにキャッシュされ、後で再利用されます。

// cache 操作会增加血缘关系,不改变原有的血缘关系
println(wordToOneRdd.toDebugString)
// 数据缓存。
wordToOneRdd.cache()
// 可以更改存储级别
//mapRdd.persist(StorageLevel.MEMORY_AND_DISK_2)

        キャッシュが失われたり、メモリ不足によりメモリに格納されたデータが削除されたりする可能性があります.RDDのキャッシュフォールトトレランスメカニズムにより、キャッシュが失われた場合でも正しく計算を実行できます. RDD に基づく一連の変換により、失われたデータが再計算されます. RDD の各パーティションは比較的独立しているため、欠落した部分のみを計算する必要があり、すべてのパーティションを再計算する必要はありません. Spark は、一部のシャッフル操作 (reduceByKey など) の中間データに対して永続的な操作を自動的に実行します。これの目的は、ノード シャッフルが失敗したときに入力全体を再計算しないようにすることです。ただし、実際の使用では、データを再利用する場合は、persist または cache を呼び出すことをお勧めします。

RDD チェックポイント チェックポイント

        いわゆるチェックポイントは、実際にはRDDの中間結果をディスクに書き込むことによるものですが、長い血縁依存関係によりフォールトトレランスのコストが高くなりすぎるため、中間段階でチェックポイントフォールトトレランスを行う方がよいでしょう。チェックポイント以降のノードに問題がある場合は、チェックポイント 開始から開始して、ブラッドラインをやり直すことができ、オーバーヘッドが軽減されます。RDD でのチェックポイント操作はすぐには実行されず、それをトリガーするにはアクション操作を実行する必要があります。

// 设置检查点路径
sc.setCheckpointDir("./checkpoint1")
// 创建一个 RDD,读取指定位置文件:hello atguigu atguigu
val lineRdd: RDD[String] = sc.textFile("input/1.txt")
// 业务逻辑
val wordRdd: RDD[String] = lineRdd.flatMap(line => line.split(" "))
val wordToOneRdd: RDD[(String, Long)] = wordRdd.map {
 word => {
 (word, System.currentTimeMillis())
 }
}
// 增加缓存,避免再重新跑一个 job 做 checkpoint
wordToOneRdd.cache()
// 数据检查点:针对 wordToOneRdd 做检查点计算
wordToOneRdd.checkpoint()
// 触发执行逻辑
wordToOneRdd.collect().foreach(println)

キャッシュとチェックポイントの違い

  1. キャッシュ キャッシュは、血液の依存関係を断ち切らずにデータのみを保存します。チェックポイント チェックポイントは血の依存関係を遮断します。
  2. Cache によってキャッシュされたデータは、通常、ディスクやメモリなどに保存され、信頼性が低くなります。通常、チェックポイント データは、信頼性の高い HDFS など、フォールト トレラントで可用性の高いファイル システムに格納されます。
  3. checkpoint() の RDD にキャッシュ キャッシュを使用することをお勧めします。これにより、チェックポイント ジョブはキャッシュ キャッシュからデータを読み取るだけで済みます。それ以外の場合は、RDD を最初から計算する必要があります。

おすすめ

転載: blog.csdn.net/dafsq/article/details/129466546