Spark (1) -- Spark を 1 つの記事で理解する

スパークの紹介:        

Spark は、効率的な分散データ処理および分析機能を提供する、高速で汎用的なビッグ データ処理フレームワークです。

Spark と Hadoop の関係: 

        Spark は Hadoop の一部ではありませんが、Hadoop エコシステムと緊密に統合されています。Spark は、より高速なデータ処理と分析機能を提供し、バッチ処理、ストリーム処理、機械学習、グラフ コンピューティングなどの機能を備えており、Hadoop の MapReduce のアップグレードされたコンピューティング モデルとして理解できます。

Hadoop VS Spark
ハドゥープ スパーク
タイプ コンピューティング、ストレージ、スケジューリングなどをサポートする完全な分散型基本プラットフォーム。 分散コンピューティング ツール。反復コンピューティング、インタラクティブ コンピューティング、ストリーム コンピューティングに使用できます。
生態系 Hive、Pig、HBase、Sqoop などの完全なビッグデータ処理および分析エコシステムを備えています。 Hive、Pig、HBase、Kafka などとの統合をサポート、クロスプラットフォームをサポートし、さまざまなデータ ストレージおよび処理システムと統合可能
マシンの要件 低い 高いメモリ要件
データ処理モデル データ処理には MapReduce モデルを使用します。データは HDFS を通じて複数のノードに分散され、Map および Reduce 操作は各ノードで実行されます。 RDD 抽象化を使用して分散データ セットを表現および処理し、メモリベースのコンピューティング モードを採用し、メモリ コンピューティングによるデータ分析と処理の速度を向上させます。
計算速度 MapReduce モデルはバッチ タスクの処理に適していますが、ディスク IO が遅いため、反復計算とリアルタイム データ処理は比較的遅くなります。 Spark は、メモリ コンピューティングと高レベルのデータ抽象化 (RDD、データフレーム、データセットなど) を通じてより高速なコンピューティング速度を提供し、反復コンピューティング、ストリーム処理、および対話型クエリで利点をもたらします。
データ処理の柔軟性 Hadoop の HDFS は長期保存やバッチ処理に適していますが、複雑なデータ処理のニーズには、Hive や Pig などの他のツールやテクノロジーが必要です。 Spark は、バッチ処理、ストリーム処理、機械学習、グラフ コンピューティングなどをサポートし、より複雑なデータ分析と処理のための高度な API (Spark SQL など) と特殊なライブラリ (MLlib や GraphX など) を提供します。
データストレージ構造 MapReduceの途中計算結果はHDFSディスクに保存されるため遅延が大きい RDDの途中演算結果はメモリに格納され、遅延が小さい
プログラミングパラダイム Map+Reduce、API は比較的低レベルであり、アルゴリズムの適応性は低い RDD は DAG 有向非巡回グラフを形成し、API は比較的トップレベルであり、使いやすいです。
動作モード タスクがプロセスとして保持され、タスクの起動が遅い タスクはスレッドモードで維持され、タスクの起動は高速です

スパークアーキテクチャ: 

  • Spark コア: Spark のコア コンポーネント。RDD、分散タスク スケジューリング、メモリ コンピューティング、データ送信、エラー回復、ストレージ システムとの対話などの基本機能を提供し、他の Spark コンポーネントの基礎となります。
    • RDD (Resilient Distributed Datasets): Resilient Distributed Datasets は、Spark のコアとなるデータ抽象化であり、分割して並列計算できる不変のデータセットを表します。RDD は、柔軟なフォールト トレランス、データ パーティショニング、およびデータ変換操作を提供し、分散コンピューティングの基本単位です。
  • Spark SQL: Spark の SQL クエリおよび処理モジュールであり、構造化データを処理する機能を提供し、データのクエリと分析のための SQL ステートメントの使用をサポートし、RDD とシームレスに統合することもできます。
  • Spark Streaming: リアルタイム データ ストリームを処理するための Spark のストリーム処理モジュール。さまざまなデータ ソースからのデータをリアルタイムで計算および処理するための高レベル API を提供します
  • MLib (機械学習ライブラリ): Spark の機械学習ライブラリ。大規模なデータセットに対する機械学習タスクに一般的に使用される一連の機械学習アルゴリズムとツールを提供します。
  • GraphX: データ処理とグラフ計算のための Spark のグラフ処理ライブラリ。グラフの構築と操作のための API を提供し、グラフ アルゴリズムやグラフ分析などのタスクをサポートします。
  • Spark ジョブ: Spark を介して実行するためにクラスターに送信されるタスク。これには、実行する必要があるコード、データ、設定が含まれます。

スパークコア: 

 RDD:

RDD (Resilient Distributed Datasets): Resilient Distributed Datasets は、Spark のコアとなるデータ抽象化であり、分割して並列計算できる不変のデータセットを表します。RDD は、柔軟なフォールト トレランス、データ パーティショニング、およびデータ変換操作を提供し、分散コンピューティングの基本単位です。

  • Resilient  :弾力性があり、RDD 内のデータはメモリまたはディスクに保存できます。
  • Distributed  : 要素は分散された方法で保存され、分散コンピューティングに使用できます。
  • データセット多くの要素を格納できるコレクションです。

RDDのソースコードにはこんな記述があります。 

A list of partitions
A function for computing each split
A list of dependencies on other RDDs
Optionally, a Partitioner for key-value RDDs (e.g. to say that the RDD is hash-partitioned)
Optionally, a list of preferred locations to compute each split on(e.g. block locations for an HDFS file)
  • パーティションのリスト: パーティションのリスト。パーティションは RDD の計算単位であり、パーティションの数によって並列度が決まります。
  • 各スプリットを計算する関数: 各パーティションに関数が適用され、パーティション単位で RDD が計算されます。
  • 他の RDD への依存関係のリスト: RDD は他の複数の RDD に依存し、RDD が変換されるたびに新しい RDD が生成されます。パーティション データが失われると、この依存関係を通じて失われたパーティションのデータを再計算できます。(Spark の耐障害性メカニズム)
  • オプションで、キーと値の RDD のパーティショナー (たとえば、RDD がハッシュ パーティション化されていると言うため): オプション KV タイプ RDD のパーティショナー (パーティション関数) があります。デフォルトは HashPartitioner です。
  • オプションで、各分割を計算するための優先場所のリスト (HDFS ファイルのブロックの場所など):オプション、ストレージ パーティションの優先場所。HDFS ファイルの場合、リストには各パーティションが配置されているブロックの位置が保存されます。

上記の説明は、Spark のパーティション リスト、計算関数、依存関係、パーティション関数、最適な場所に一旦対応します。

  • パーティション リスト、パーティション関数、および最適な場所 これら 3 つの属性は、実際にはデータ セットがどこにあるか、計算するのがより適切な場所、およびデータ セットを分割する方法を指します。
  • 計算関数と依存関係、これら 2 つのプロパティは、実際にはデータ セットがどのように形成されたかを表します。

RDD のいくつかの主要なプロパティと使用法:

  1. パーティショニング: RDD は、データ セットを複数の論理パーティション (論理パーティション) に分割し、これらのパーティションをクラスター内の複数のノードに分散します。パーティションの数によって、並列コンピューティングの程度が決まります。

  2. 復元力: RDD には復元力の特性があります。つまり、特定のパーティションのデータまたはノードに障害が発生した場合、Spark はリネージを通じて失われたパーティションを再計算し、フォールト トレランスを実現します

  3. 不変性: RDD は不変であり、一度作成すると変更することはできません。RDD で変換または操作を実行するには、新しい RDD を生成する必要があります。

  4. 変換: RDD は、マップ、フィルター、リデュース、結合などの一連の変換操作を提供します。これらの変換操作により、1つのRDDからデータ構造や内容が異なる別のRDDを作成し、データの変換・加工を実現します。

  5. アクション: RDD は、カウント、収集、削減などのいくつかのアクション操作を提供します。アクション操作は実際の計算をトリガーし、結果をドライバーに返すか、結果を外部ストレージ システムに保存します。

  6. データの永続性: RDD は、データをメモリにキャッシュすることでデータ アクセスの高速化をサポートします。RDD をシリアル化された方法でメモリ、ディスク、またはストアに永続化することを選択できます。

RDD API

1.RDDの作成 

RDD の作成には 3 つの方法があります。 

1.1 コレクションから RDD を作成するには、SparkContext のParallelize メソッドを使用します。 

val sparkConf = new SparkConf().setAppName("RDD creation")
val sc = new SparkContext(sparkConf)

val data = List(1, 2, 3, 4, 5)
val rdd = sc.parallelize(data)

1.2 外部ストレージからRDDを作成し、SparkContextのtextFileメソッドを適用する

val sparkConf = new SparkConf().setAppName("RDD creation")
val sc = new SparkContext(sparkConf)

// 指定读取文件路径或包含文件的目录路径
val rdd = sc.textFile("hdfs://path/to/textfile.txt")
// 指定分区数
val rdd2 = sc.textFile("hdfs://path/to/textfile.txt", 7)

1.3 他の RDD からの変換 RDD の作成: RDD 変換演算 (変換演算子) ( mapなど)filterを使用できます。flatMap

val sparkConf = new SparkConf().setAppName("RDD creation")
val sc = new SparkContext(sparkConf)

val input = sc.parallelize(List(1, 2, 3, 4, 5))
val rdd = input.map(x => x * 2)

2. RDDオペレーター

RDDは実際に計算対象のデータを保存するのではなく、データの場所とデータの変換関係(どのようなメソッドを呼び出したのか、どのような関数を渡したのか)を記録します。

RDD 演算子は主に 2 つのカテゴリに分類されます。 

  • 変換: 新しい RDD を返します。RDD のすべての変換は遅延評価/遅延されます。つまり、直接計算されません。これらの変換は、結果を返す必要があるアクションが発生した場合にのみ実際に実行されます Driver 。 Actionこれにより、RDD 操作でステージ分割と並列最適化を実行して、アクション中に DAG 有向非巡回グラフを形成できるため、この設計により Spark がより効率的に実行されます。
  • アクション演算子 (action): 戻り値は RDD ではありません (戻り値なし、またはその他を返す)。

変換演算子(変換)

  1. 単一要素の変換:
    1. map(func): RDD 内の各要素に関数を適用しfunc、新しい RDD を返します。
    2. flatMap(func): RDD 内の各要素に関数を適用しfunc、フラット化された結果セットを含む新しい RDD を返します。
    3. filter(func)func:関数の戻り値が true または false であることに応じて、RDD 内の要素をフィルターし、新しい RDD を返します。
    4. mapPartitions(func):map に似ていますが、RDD の各スライスで独立して動作するため、タイプ T の RDD で動作する場合、func の関数タイプは Iterator[T] => Iterator[U] である必要があります。
    5. mapPartitionsWithIndex(func): mapPartitions と似ていますが、func にはパーティションのインデックス値を表す整数パラメータがあるため、タイプ T の RDD で実行する場合、func の関数タイプは (Int, Interator[T]) => である必要があります。イテレータ[U]
  2. 複数の要素の変換:
    1. union(other): other 2 つの RDD (現在の RDD と RDD) のすべての要素を含む新しい RDDを返します。
    2. intersection(other): 2 つの RDD (現在の RDD とRDD)other の共通要素を含む新しい RDDを返します。
    3. subtract(other):現在の RDD には存在するが、RDD には存在しない要素のみを含むother 新しい RDDを返します。
    4. distinct([numTasks]): 重複排除後に新しい RDD を返します
    5. cartesian(other)other : 2 つの RDD (現在の RDD とRDD)の要素のすべての組み合わせを含む新しい RDD を返します。
    6. join(otherDataset, [numTasks]): タイプ (K, V) および (K, W) の RDD で呼び出され、同じキー RDD に対応するすべての要素の (K, (V, W)) ペアを返します。
    7. cogroup(otherDataset, [numTasks]): タイプ (K,V) および (K,W) の RDD で呼び出され、タイプ (K,(Iterable,Iterable)) の RDD を返します。
    8. cartesian(otherDataset): デカルト積
  3. パーティション関連の変換:
    1. repartition(numPartitions): repartition、指定された数のパーティションを持つ新しい RDD を返します。
    2. coalesce(numPartitions): 再パーティション化、RDD のパーティション数を指定値まで減らします。大量のデータをフィルタリングした後、次のことができます。
    3. partitionBy(partitioner): 指定されたパーティショナーに従って RDD を分割し、新しい RDD を返します。
    4. groupByKey([numTasks]): (K, V) RDD で呼び出され、(K, Iterator[V]) RDD を返します。
    5. reduceByKey(func, [numTasks]): (K, V) RDD で呼び出され、(K, V) RDD を返します。指定されたreduce 関数を使用して、groupByKey と同様に同じキーの値を集計します。 Reduce タスクの数は 2 番目のオプションのパラメータで設定できます
    6. sortByKey([ascending], [numTasks]): (K, V) RDD で呼び出されます。K は Ordered インターフェイスを実装する必要があり、キーでソートされた (K, V) RDD を返します。
    7. sortBy(func, ascending=True, numPartitions=None):func関数の戻り値に従って RDD をソートし、ソートされた新しい RDD を返します。
  4. その他の変換
    1. sample(withReplacement, fraction, seed): 指定されたサンプリング率に従ってfraction、RDD がサンプリングされ、新しい RDD が返されます。
    2. glom(): 各パーティションの要素を配列に変換し、新しい RDD を返します。
    3. Pipe(command, [envVars]): rdd でのパイプライン操作

アクション演算子 (アクション):

  1. 基本動作 
    1. reduce(func):func関数を使用して RDD 内の要素を削減し、削減された結果を返します。
    2. collect(): RDD 内のすべての要素を配列として返します。
    3. count(): RDD 内の要素の数を返します。
    4. first(): RDD の最初の要素を返します。
    5. take(n): RDD の最初の n 要素を返します。
  2. 統計関連のアクション
    1. max(): RDD の最大値を返します。
    2. min(): RDD の最小値を返します。
    3. sum(): RDD 内のすべての要素の合計を返します。
    4. mean(): RDD の平均値を返します。
    5. variance(): RDD 内の要素の分散を返します。
    6. stdev(): RDD 内の要素の標準偏差を返します。
  3. その他のアクション
    1. foreach(func): RDD の各要素にfunc関数を適用します。
    2. foreachPartition(func): RDD 内の各パーティションにfunc関数を適用します。
    3. countByValue(): (K, V) 型の RDD の場合、各値に対応する要素の数を示す (V, Int) のマップを返します。
    4. countByKey(): タイプ (K, V) の RDD の場合、各キーに対応する要素の数を示す (K, Int) のマップを返します。

3. RDD 永続化/キャッシュ 

        一部の RDD 計算や変換には時間がかかる場合がありますが、これらを RDD 後で頻繁に使用する場合は、 RDD 永続化/キャッシュして RDD の再利用と計算効率を向上させることができます。永続化およびキャッシュ操作により、RDD データをメモリまたはディスクに保存できるため、計算の繰り返しが回避され、データ アクセス速度が向上します。

val rdd1 = sc.textFile("hdfs://node01:8020/words.txt")
val rdd2 = rdd1.flatMap(x=>x.split(" ")).map((_,1)).reduceByKey(_+_)
rdd2.cache //缓存, 等同于rdd2.persist(StorageLevel.MEMORY_ONLY)
rdd2.sortBy(_._2,false).collect//触发action,会去读取HDFS的文件,rdd2会真正执行持久化
rdd2.sortBy(_._2,false).collect//触发action,会去读缓存中的数据,执行速度会比之前快,因为rdd2已经持久化到内存中了

3.1 persist(storageLevel: StorageLevel)方法: RDD を永続としてマークし、データ ストレージ レベルを指定します。 ストレージ レベル:

  1. MEMORY_ONLY: RDDデータをメモリに保存します
  2. MEMORY_AND_DISK: メモリが不足している場合は、RDD データをメモリに保存し、残りのデータはディスクにオーバーフローします (通常、開発で使用されます)
  3. MEMORY_ONLY_SER: RDDデータをシリアル化してメモリに保存します
  4. MEMORY_AND_DISK_SERMEMORY_AND_DISK,:メモリに収まらない場合のディスクへのオーバーフロー書き込みに似ていますが、データはシリアル化された方法で保存されます。
  5. DISK_ONLY: RDD パーティションをディスクに保存します
  6. MEMORY_ONLY_2, MEMORY_AND_DISK_2等:将持久化数据存储为2份,备份每个分区存储在两个集群节点上

3.2 cache()メソッド: これはpersist()メソッドの簡略化された形式であり、デフォルトのストレージ レベルを使用してMEMORY_ONLYRDD を永続的としてマークします。

知らせ: 

  • 永続化とキャッシュは後続の操作でのみ有効であり、RDD 変換操作の前に実行する必要があります。
  • アクション操作が実行される場合にのみ、RDD データが実際に永続化/キャッシュされます。
  • RDD 内のデータの量が多く、すべてのデータを保持するにはメモリが十分ではない場合は、必要なときにデータをディスクから読み取れるように、RDD をディスク ( または ) に保存することを選択できますMEMORY_AND_DISKMEMORY_AND_DISK_SER
  • unpersist()永続的な RDD をメモリから手動で削除するメソッドを使用します。

3.3 チェックポイントの永続性 (フォールト トレランス メカニズム)

RDD のチェックポイントは、Spark の永続性のためのフォールト トレラント メカニズムであり、中間結果を信頼性の高い分散ストレージ システム (HDFS など) に保存できるため、ノードに障害が発生した場合に迅速に復元できます。

チェックポイントを設定します:

val conf = new SparkConf()
        .setAppName("CheckpointExample")
        .set("spark.checkpoint.dir", "hdfs://path/to/checkpoints")
val sc = new SparkContext(conf)
val rdd = sc.parallelize(Seq(1, 2, 3, 4, 5))
rdd.checkpoint()

チェックポイントを使用したデータの復元: 

val conf = new SparkConf().setAppName("CheckpointRecovery").set("spark.checkpoint.dir", "hdfs://path/to/checkpoints")
val sc = new SparkContext(conf)
sc.setCheckpointDir("hdfs://path/to/checkpoints")

チェックポイント メカニズムを使用する場合は、次の点に注意する必要があります。

  • チェックポイント処理は、データをディスクに書き込む必要があるため、コストがかかる操作です。したがって、長時間かかる場合や中間結果を再利用する必要がある場合にのみ使用してください。
  • チェックポイントは RDD の依存関係グラフを中断するため、結果を保持する必要がある直後にチェックポイントを実行することをお勧めします。
  • チェックポイント データはディスク ストレージ領域を占有するため、利用可能なリソースとアプリケーションのニーズに基づいて適切に管理およびクリーンアップする必要があります。

永続化との比較: 

  • Persist は、RDD データを繰り返し使用する必要があるシナリオ、または後続の計算のために中間結果をキャッシュする必要があるシナリオに適しています。
  • Checkpoint は、長期のデータ保持、信頼性の保護、または長い RDD 依存関係グラフを必要とするシナリオに適しています。

スパークSQL 

Spark SQL の概要:

Spark SQL は、従来の RDD API と SQL クエリ言語を組み合わせたもので、開発者が SQL ステートメントまたは Spark 独自の DataFrame API を使用してデータの操作と分析を行うことができるため、構造化データをより便利かつ効率的に処理できます。

主な特徴:

  1. DataFrame と Dataset: Spark SQL には、より高度なデータ操作インターフェイスを提供する DataFrame と Dataset という 2 つの抽象概念が導入されています。

    1. DataFrame は、RDD に基づいた分散データ コレクションであり、リレーショナル データベースのテーブルに似た構造を持ち、フィルタリング、集計、SQL クエリなどの操作を実行できます。これは JSON 構造として理解でき、列名とフィールド値の型によってのみ制限されます。

    2. Dataset は、コンパイル時の検証を通じて実行時エラーを回避できる、よりタイプセーフな API を提供します。DataFrame と比較すると、DataSet は Entity として理解され、フィールド名とフィールド値の型の制限に加えて、エンティティの型の制限もあります。

  2. SQL クエリと組み込み関数: Spark SQL は、標準 SQL クエリ ステートメントを使用したデータ クエリと集計操作をサポートしているため、開発者は使い慣れた SQL 構文をデータ分析に使用できます。さらに、Spark SQL には、データをより便利に処理するために、一般的に使用される多くの SQL 関数 (集計関数、日付関数など) も組み込まれています。

  3. データ ソース拡張: Spark SQL は、リレーショナル データベース (MySQL、PostgreSQL など)、Hive、Parquet、Avro、JSON、CSV などを含むさまざまなデータ ソースの接続と操作をサポートします。Spark SQL のデータ ソース インターフェイスを利用すると、さまざまな形式のデータを簡単に読み取り、書き込み、処理できます。

  4. Catalyst オプティマイザー: Spark SQL は Catalyst オプティマイザーを使用して、クエリ分析、論理最適化、物理プラン生成、実行の最適化などの SQL クエリを最適化します。Catalyst は、ルールベースおよびコストベースの最適化戦略を使用して、クエリ プランを自動的に変換および最適化し、クエリのパフォーマンスを向上させます。

Spark SQL の単純なシェル操作の例:

Spark SQL の DSL スタイルの例:

# 打开Spark shell 控制台
sh bin/spark-shell

# 读取文件,创建RDD 
val lineRDD = sc.textFile("file:///Users/zhoushimiao/Desktop/people.txt").map(_.split(" ")) 

# 定义Person 字段和字段类型
case class Person(id:Int, name:String, age:Int)

#将 RDD 和 Person 关联
val personRDD = lineRDD.map(x => Person(x(0).toInt, x(1), x(2).toInt)) //RDD[Person] , DataSet
# 将 RDD 转换成 DataFrame
val personDF = personRDD.toDF //DataFrame

# 查看数据
personDF.show
personDF.select(personDF.col("name")).show
personDF.select(personDF("name")).show
personDF.select(col("name")).show
personDF.select("name").show 

DataFrame を直接構築することも可能です。

val dataFrame=spark.read.text("file:///Users/zhoushimiao/Desktop/people.txt")
dataFrame.show //注意:直接读取的文本文件没有完整schema信息
dataFrame.printSchema

# 或者, 直接读取JSON文件, json中已经包含了schema信息
val jsonDF= spark.read.json("file:///Users/zhoushimiao/Desktop/people.json")
jsonDF.show

SQL スタイル: 

# 将DataFrame 转换成注册表
personDF.createOrReplaceTempView("t_person")

# 执行查询SQL
spark.sql("select id,name from t_person where id > 3").show

        Spark SQL は、SQL 構文と Spark SQL DSL (Domain Specific Language) とも呼ばれる DataFrame/Dataset API という 2 つの異なる API を提供します。

  • SQL 構文: Spark SQL は標準 SQL クエリ構文をサポートしており、SQL ステートメントを使用してデータのクエリ、フィルター、集計を行うことができます。SQL 構文を使用する利点は、新しい API を学習しなくても、使い慣れた SQL ステートメントをデータ処理に直接使用できることです。SQL 構文は、構造化データを操作する場合に直感的で便利であり、SQL に精通した開発者に適しています。
  • DataFrame/Dataset API (Spark SQL DSL): DataFrame/Dataset API は、Spark SQL によって提供されるプログラミング インターフェイスのセットであり、RDD に基づいていますが、構造化された方法でデータを整理する機能を提供します。DataFrame/Dataset API は豊富な操作メソッドを定義しており、開発者はクエリと変換操作をプログラムで構築できます。タイプセーフな操作を提供し、コンパイル時にエラーをキャッチし、より優れたパフォーマンスの最適化とコードチューニング機能を提供します。

Sparkのストリーム処理

        Spark Streaming と Structured Streaming はどちらも、リアルタイム データ ストリームを処理するための Apache Spark のストリーム処理モジュールです。

スパークストリーミング: 

        Spark Streaming は、Spark Core に基づいたリアルタイム コンピューティング フレームワークであり、多くのデータ ソースからのデータを消費し、リアルタイムでデータを処理でき、高スループットと強力なフォールト トレランスの特性を備えています。Spark Streaming は、データ処理に高度な機能と RDD 操作を使用できる DStreams (Discrete Streams) を使用します。

Spark ストリーミングの特徴: 

  1. 低レイテンシー: Spark Streaming は、入力ストリーム データを小さなバッチに分割し、バッチごとに処理することで、低レイテンシーのストリーム処理を実現します。デフォルトでは、各バッチ サイズは秒です。
  2. フォールト トレランス: Spark Streaming は、ノードの障害やデータ損失を処理できるフォールト トレランス メカニズムを提供します。Spark の Resilient Distributed Datasets (RDD) を使用して、失われたデータと障害が発生したノードを回復します。

  3. スケーラビリティ: Spark Streaming は、Spark の他のモジュール (Spark SQL、MLlib など) と統合して、より複雑なストリーム処理および分析タスクを実現できます。大規模なクラスター上で実行でき、データ量と負荷に基づいて自動的に拡張できます。

  4. 豊富なデータ ソースのサポート: Spark Streaming は、Kafka、Flume、Hadoop HDFS、Apache NiFi などを含むさまざまなデータ ソースをサポートします。これにより、複数のソースからストリーミング データを取得し、データ処理結果を複数の宛先に送信することが簡単になります。

サンプルコード: 

import org.apache.spark.streaming._

// 创建StreamingContext,批次时间间隔为5秒
val ssc = new StreamingContext(sparkConf, Seconds(5)) 
// 从TCP套接字获取流数据
val lines = ssc.socketTextStream("localhost", 9999)

// 对流数据进行处理
val words = lines.flatMap(_.split(" "))
val wordCounts = words.map(word => (word, 1)).reduceByKey(_ + _)

// 打印处理结果
wordCounts.print()

// 启动StreamingContext 和 等待流数据的到达和处理
ssc.start() 
ssc.awaitTermination() 

ssc.stop()

構造化ストリーミング

        Structured Streaming は DataFrame および Dataset API に基づいているため、ストリーム処理コードとバッチ処理コード間の変換が非常に簡単になります。開発者は SQL クエリ、DataFrame 操作、組み込み関数を使用してリアルタイムのストリーミング データを処理できるため、静的データ処理と同様の方法でストリーム処理を実行できます。

Structured Streaming は、データ ソースをリレーショナル データベースと同様のテーブルにマッピングし、計算結果を別のテーブルにマッピングして、ストリーミング データを構造化して操作するというプログラミング モデルであることがわかります。このプログラミング モデルは、構造化されたデータの処理と分析に非常に役立ちます        。リアルタイム データ; Spark Structured Streaming は、より簡素化され統合されたストリーム処理プログラミング モデルを提供し、リアルタイム ストリーミング データの処理をより簡単かつ直感的にします。より複雑なクエリと操作をサポートし、さまざまなリアルタイム データ処理のニーズを満たす高レベルの抽象化とセマンティック保証を提供します。        

主な機能と利点:

  1. イベント時間に基づく (イベント時間): 構造化ストリーミングは、イベント時間に基づいたデータの処理をサポートします。つまり、データが到着した時間ではなく、イベントが発生したときのリアルタイムに従ってデータを処理できます。これは、遅れたり順序が狂ったりするイベント データを処理する場合に役立ちます。

  2. 厳密に 1 回のセマンティック保証: 構造化ストリーミングは、出力結果の一貫性と信頼性を保証するために、「厳密に 1 回」(厳密に 1 回) のセマンティック保証を提供します。データ。

  3. 高度な抽象化: 構造化ストリーミングは、ウィンドウ操作、ストリームと静的データ接続、ストリームとストリーム接続などの高度な抽象化を提供し、より複雑なストリーム処理シナリオをより簡単かつ直感的に処理できるようにします。

  4. 豊富なデータ ソースとデータ シンクのサポート: 構造化ストリーミングは、Kafka、Socket、File、HDFS などの複数のデータ ソースとデータ シンクをサポートし、処理結果を外部ストレージ システム (Hadoop HDFS、Apache Cassandra など) に送信できます。さらに分析するために、Spark SQL などの他のモジュールを統合します。

サンプルコード: 

// 导入必要的库
import org.apache.spark.sql.SparkSession

// 创建SparkSession, 也是一个Structured Streaming作业
val spark = SparkSession
  .builder()
  .appName("StructuredStreamingExample")
  .getOrCreate()

// 从数据源创建输入DataFrame
val inputData = spark
  .readStream
  .format("socket")
  .option("host", "localhost")
  .option("port", 9999)
  .load()

// 对输入数据进行转换和处理
val transformedData = inputData
  .groupBy("word")
  .count()

// 将结果DataFrame写入输出数据接收器
val query = transformedData
  .writeStream
  .format("console")
  .outputMode("complete")
  .start()

query.awaitTermination()

Spark ストリーミング VS 構造化ストリーミング

共通点: 

  1. Spark ベース: どちらも Spark フレームワーク IQ 上に構築されており、Spark の分散コンピューティング機能と最適化エンジンを活用できます。
  2. 高い信頼性とフォールト トレランス: どちらも、ノードの障害やデータ損失に対処するためのフォールト リカバリ機能とフォールト トレランス機能を備えています。
  3. 統合されたデータ ソースとデータ レシーバー: どちらも Kafka、Flume、Hadoop HDFS などを含む幅広いデータ ソースをサポートし、処理結果を外部ストレージ システムに送信したり、他のモジュールを統合して処理したりできます。

違い: 

  1. データ処理モデル:
    1. Spark Streaming は、リアルタイム データ ストリームを小さな時間バッチに分割し、各バッチを処理するマイクロバッチ処理モデルに基づいています。
    2. Structured Steaming は連続処理モデルに基づいており、静的テーブルに似た形式でデータを処理するため、リアルタイムに近い結果が得られます。
  2. フォールトトレランスと一貫性: 
    1. Spark Streaming のフォールト トレランスはバッチ間隔に大きく依存しており、厳密な一貫性保証は提供されません。
    2. 構造化ストリーミングは、一貫性と信頼性の高い結果を保証するために、1 回限りのセマンティック保証を提供します。
  3. API とセマンティクス: 
    1. Spark Streaming は、データ処理に高度な機能と RDD 操作を使用できる DStream (ディスクリート ストリーム) を使用します。
    2. 構造化ストリーミングは、一貫性と信頼性の高い結果を保証するために、1 回限りのセマンティック保証を提供します。

        さらに、構造化ストリーミングは、よりシンプルで直感的なプログラミング モデルを提供し、開発者は静的テーブルと同様の API を通じて開発できるため、バッチ処理のプログラミング パラダイム間の学習コストが削減されます。

スパークシャッフル 

        シャッフルとは、データの再パーティション化および再編成中に発生するデータ シャッフル操作を指します。

        MapReduce フレームワークでは、Shuffle ステージは Map と Reduce を接続するブリッジであり、Map ステージは Shuffle プロセスを通じてデータを Reduce に送信します。シャッフルにはディスクの読み書きとネットワーク IO が含まれるため、シャッフルのパフォーマンスはプログラム全体のパフォーマンスに直接影響します。SparkにはMapステージとReduceステージもあるので、シャッフルも発生します。

シャッフルは通常、次の状況で発生します。

  1. データの再パーティション化: キーまたはその他の条件に従ってクラスター内の異なるノードにデータを再分散する必要がある場合、データの再パーティション化のシャッフル操作が発生します。GroupByKey、ReduceByKey、その他の操作など
  2. データのマージ: 異なるノードからのデータをマージする必要がある場合、データをマージするシャッフル操作が発生します。結合操作など

シャッフル プロセスは 3 つの段階に分かれています。

  1. マップ ステージ: 各 Executor は、データ キーまたはその他の条件に従って中間結果セットを生成し、それをローカル ディスクに書き込みます。
  2. シャッフル ステージ: Spark は、ターゲット パーティションに従って各 Executor の中間結果を並べ替え、同じパーティションのデータを 1 つのファイル ブロックにマージしてディスクに書き込みます。この段階では、大量のデータ送信と IO の読み書きが設計されます。
  3. Reduce フェーズ: 各パーティションのデータは、集計、マージ、計算のために対応する Reduce タスクに送信されます。

Spark には主に 3 つの Shuffle 実装があります。

  1. SortShuffle (ソート シャッフル):
    SortShuffle はソートに基づくシャッフル実装の一種で、最初に Map タスクによって出力されたデータをローカル ディスクに書き込み、次に Reducer タスクが Map タスクが配置されているノードからデータをプルします。キーでソートしてマージします。SortShuffle の利点は、結果データのグローバルな順序を保証できることであり、グローバルな並べ替えが必要なシナリオに適していますが、大量のディスク書き込みとネットワーク送信のオーバーヘッドが発生する可能性があります。

  2. HashShuffle (ハッシュ シャッフル):
    HashShuffle はハッシュ ベースの Shuffle 実装であり、Map タスクによって出力されたデータをキーのハッシュ値に従ってグループ化し、同じ Key のデータを同じ Reducer タスクに送信して処理します。HashShuffle は、ネットワーク送信中にデータが分散されるため、ディスク書き込みとネットワーク送信のオーバーヘッドが軽減され、優れたスケーラビリティを備えています。ただし、結果のグローバルな順序付けは保証されません。

  3. TungstenSortShuffle (タングステン ソート シャッフル):
    TungstenSortShuffle は、タングステン ソート エンジンを使用して SortShuffle のパフォーマンスを向上させる、最適化されたシャッフル実装です。TungstenSortShuffle は、ソートとマージにメモリとディスクを組み合わせて使用​​します。これにより、ソートとマージのプロセス中のディスクの読み取りおよび書き込みのオーバーヘッドが大幅に削減され、Shuffle のパフォーマンスが向上します。

        デフォルトでは、Spark は利用可能なリソースと構成パラメーターに基づいて適切な Shuffle 実装を自動的に選択します。通常、利用可能なメモリが少ない場合は SortShuffle が使用され、システムに十分なメモリ リソースがある場合はパフォーマンスを向上させるために TungstenSortShuffle が使用されます。

シャッフルパフォーマンスの最適化方法:

  • 並列処理の調整: パーティションの数と並列処理パラメータを調整することで、データの移動とネットワーク送信を削減し、Shuffle のパフォーマンスを向上させることができます。

  • 事前にマージする: 複数のシャッフル操作の場合、それらをマージしてシャッフルの数を減らすことができます。

  • 局所性の最適化を使用する: データの局所性スケジューリングと予測実行を使用することで、タスクがデータにできるだけ近いノードに割り当てられ、データの送信と読み取りのオーバーヘッドが削減されます。

  • メモリとディスクを組み合わせて使用​​します。メモリとディスクの使用率を合理的に構成し、適切なデータをメモリに保存し、ディスク上の読み取りおよび書き込み操作を減らします。

  • 圧縮を使用する: 大量のデータのシャッフル操作では、データ圧縮の使用を検討して、ネットワーク送信とディスク ストレージのオーバーヘッドを削減できます。

シャッフルのプロセスには、ディスクへのデータの移動、並べ替え、ディスクへのデータの読み書きが含まれるため、計算の中で非常にコストがかかります。したがって、Spark アプリケーションのパフォーマンスと効率を向上させるには、Shuffle 操作を最適化することが非常に重要です。

おすすめ

転載: blog.csdn.net/zhoushimiao1990/article/details/131794076