SparkStreaming + Flumeメソッドは初期のフォームです。新しいバージョンのSparkでは、Flumeに直接接続することはお勧めしませんが、データを処理するためにこのフォームが必要になる場合があります。
SparkはFlumeのデータを統合します。Sparkには、ポーリングプルとプッシュプッシュの2つの方法があります。2つのモードと比較して、ポーリングモードが優先されます。
プルモードでは、Sparkがシンクを提供し、SparkStreamingが主導権を握ってチャネルからデータを取得し、安定性の高い独自の条件に従ってデータを取得します。
プッシュモードでは、Flumeはキャッシュとして機能し、データを保存します。そして、Sparkを監視し、Sparkに到達できる場合は、データをプッシュします。(単純な低結合)欠点は、SparkStreamingプログラムが開始されていない場合、Flume側でエラーが報告され、SparkStreamingプログラムがデータを失うのが遅すぎて消費できない可能性があることです。
まず、Pollでデータをプルする方法を紹介します
次のように、jarをインポートする必要があります
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-streaming-flume_2.11</artifactId>
<version>2.0.2</version>
</dependency>
Pollをプルするときは、Flumeのバージョンが1.6以上である必要があり、1.8を使用し、flumeのlibディレクトリに2つのjarがあることを確認する必要があることに注意してください。私のバージョンは次のとおりです。
scala-library-2.11.8.jar
spark-streaming-flume-sink_2.11-2.0.2.jar
scala-library-2.11.8.jarは、libに配置した後、名前をscala-library-2.10.5.jar.BAKに変更する必要があります。
以下はFlumeのエージェントを書くことです、ソースはncツールを使用します、あなたはあなた自身のエージェントを使うこともできます
a1.sources = r1
a1.sinks = k1
a1.channels = c1
# source需要改动的是源和目的地,此处是源,使用nc工具
a1.sources.r1.type = netcat
a1.sources.r1.bind = localhost
a1.sources.r1.port = 44444
# Describe the sink 需要改动的是源和目的地,此处是目的地,且为Spark配置一个连接的地址
a1.sinks.k1.type = org.apache.spark.streaming.flume.sink.SparkSink
a1.sinks.k1.hostname=192.168.182.146
a1.sinks.k1.port = 8888
a1.sinks.k1.batchSize= 2000
# Use a channel which buffers events in memory
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100
# Bind the source and sink to the channel
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1
水路を開始します
bin/flume-ng agent --conf conf --conf-file conf/socket-source.properties --name a1 -Dflume.root.logger=INFO,console
水路が開始された後、以前に設定されたncポートを介してデータを生成でき、Pollメソッドはエラーを報告せず、データはチャネルに一時的に保存されます。
コードを書いて始めましょう
package com.stream
import org.apache.spark.{
SparkConf}
import org.apache.spark.streaming.flume.{
FlumeUtils}
import org.apache.spark.streaming.{
Seconds, StreamingContext}
object StreamFromFlume {
def main(args: Array[String]): Unit = {
val conf = new SparkConf().setAppName("StreamFromKafka").setMaster("local[2]")
val scc = new StreamingContext(conf,Seconds(10))
//设置checkpoint,可以忽略
scc.checkpoint("D:\\checkpoint")
// 从flume中拉取数据 这里的ip和端口是你agent中sink配置的
val flumeStream = FlumeUtils.createPollingStream(scc,"192.168.182.146",8888)
val lineStream= flumeStream.map(x=>new String(x.event.getBody.array()))
//实现单词汇总
val result = lineStream.flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_)
result.print()
scc.start()
scc.awaitTermination()
}
}
次に、データをプッシュするプッシュ方式を紹介します
データをプッシュするのは、Flumeが主導権を握っているため、あまりお勧めできません。また、作業で使用される可能性は低いです。結局のところ、データの損失はデータプロジェクトにとって不快な時間です。
Pushのときに最初にSparkを起動する必要があります。次に、Flume自体が所有するavroシリアル化を使用して、Pushが主導権を握るFlumeです。この方法では、Sparkだけでなくほとんどのフレームワークにデータを実際にプッシュできます。
受信コードとPollの違いは、APIが変更されたことです。
package com.stream
import org.apache.spark.{
SparkConf}
import org.apache.spark.streaming.flume.{
FlumeUtils}
import org.apache.spark.streaming.{
Seconds, StreamingContext}
object StreamFromFlume {
def main(args: Array[String]): Unit = {
val conf = new SparkConf().setAppName("StreamFromKafka").setMaster("local[2]")
val scc = new StreamingContext(conf,Seconds(10))
//设置checkpoint,用来提高数据消费的安全
scc.checkpoint("D:\\checkpoint")
// ip和port任然是Flume配置文件中的
val flumeStream: ReceiverInputDStream[SparkFlumeEvent] = FlumeUtils.createStream(scc,"192.168.182.146",8888,StorageLevel.MEMORY_AND_DISK)
val lineStream= flumeStream.map(x=>new String(x.event.getBody.array()))
//实现单词汇总
val result = lineStream.flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_)
result.print()
scc.start()
scc.awaitTermination()
}
}
Spark Pushメソッドが開始された後、通常はFlumeがデータをプッシュするのを待ちます。次に、Flume側の準備を開始します。
a1.sources = r1
a1.sinks = k1
a1.channels = c1
# source需要改动的是源和目的地,此处是源,使用nc工具
a1.sources.r1.type = netcat
a1.sources.r1.bind = localhost
a1.sources.r1.port = 44444
# Describe the sink 需要改动的是源和目的地
a1.sinks.k1.type = avro
a1.sinks.k1.hostname=192.168.182.146
a1.sinks.k1.port = 8888
# Use a channel which buffers events in memory
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100
# Bind the source and sink to the channel
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1
Flumeを起動した後、Sparkをチェックし、ncツールにデータを入力すると、対応する出力がSparkにあることがわかります。
最後に、補足を作成します。次のエラーの途中で2つのモードを実行すると、次のエラーが発生します。
org.apache.avro.AvroRuntimeException: Unknown datum type: java.lang.Exception:
java.lang.NoClassDefFoundError: Could not initialize class
org.apache.spark.streaming.flume.sink.EventBatch
このエラーは、Flumeのavroシリアル化バージョンがSparkと互換性がないためです。個別にインポートする必要があります。pomファイルに次のjarをインポートしてください。
<dependency>
<groupId>org.apache.avro</groupId>
<artifactId>avro</artifactId>
<version>1.8.2</version>
</dependency>
<dependency>
<groupId>org.apache.avro</groupId>
<artifactId>avro-ipc</artifactId>
<version>1.8.2</version>
</dependency>
そして、これら2つのjarファイルをFlumeのlibディレクトリにコピーし、lib内の元のjarファイルを削除します。