Spark Streaming消息的传输与保证及编程示例

来源:互联网 发布:win10网络没有本地连接 编辑:程序博客网 时间:2024/05/22 12:57

Spark streaming的文档其实已经比较详细的介绍了, 我简单的复述一次。   只要涉及到消息,就包含2个阶段, 获取数据以及存储处理后的数据。Spark高级API采用WAL + ZK的方式保证at least once(不能保证exactly once),  获取数据之后spark会先把数据写入WAL,并把拿到的offset存储到ZK里面。 处理完数据之后然后返回确认机制,表示消息已经发送成功。 如果是work失败了, spark只需要通过driver重新获取数据即可,如果是driver失败,很显然所有executor丢失,数据也同样丢失,这个时候如果使用了wal,那么只需要重启任务,从WAL获取上次的信息再处理,很显然这就是at least once。 

那么at most once什么时候出现呢? 那就是你不使用WAL, 因为不使用WAL, 即使有消息处理不成功,driver一旦失败,数据丢失,状态信息全无,spark也表示无能为力了,因为没有信息可以恢复这些数据。

exactly once使用高级API是不能实现的,只能使用低级API,也就是createdirectstream,低级API有几个功能很有用,比如自己指定offset消费,从我的测试来看,高级API初次获取数据只能从largest offset拿数据,不能够从latest offset开始处理,这个时候就要用低级API来处理了。低级API的offset默认是不保存在ZK的,为了避免性能问题也不使用WAL。

上面这些理论实际和storm有类似的地方,不同之处在于2者在处理上面3种模式的方法不同,storm才用的ACK + POP机制,而spark才用的是WAL。 另外storm是实时获取数据,而spark是才用频率的模式获取数据,所以2者在这个地方还有比较细微的差别。

下面我简单的写了一个程序,从KAFKA获取数据,然后不做任何处理,直接存储到HBASE。

package com.isesol.sparkimport kafka.utils.ZkUtilsimport kafka.serializer.Decoderimport org.apache.spark._import org.apache.spark.streaming._import org.apache.spark.streaming.StreamingContext._import java.util.HashMapimport org.apache.kafka.clients.producer.{ KafkaProducer, ProducerConfig, ProducerRecord }import org.apache.spark.streaming.kafka._import org.apache.hadoop.hbase.mapred.TableOutputFormatimport org.apache.hadoop.hbase.util.Bytesimport org.apache.spark.rdd.RDD.rddToPairRDDFunctionsimport org.apache.hadoop.hbase.client.Putimport org.apache.hadoop.hbase.io.ImmutableBytesWritableimport org.apache.hadoop.hbase.spark._import org.apache.hadoop.hbase.client.Scanimport org.apache.hadoop.hbase.TableNameimport org.apache.hadoop.hbase.filter._import org.apache.hadoop.hbase.filter.CompareFilter.CompareOpimport org.apache.hadoop.hbase.client.HTableimport org.apache.hadoop.hbase.HBaseConfigurationobject high_streaming {  def main(args: Array[String]) {    val conf = new SparkConf().setMaster("yarn-cluster").setAppName("this is the first spark streaming program!")    val ssc = new StreamingContext(conf, Seconds(5))    ssc.checkpoint("hdfs://nameservice1/tmp/high_streaming1")    val zk = "datanode01.isesol.com,datanode02.isesol.com,datanode03.isesol.com,datanode04.isesol.com,cmserver.isesol.com"    val group = "stream_2001"    val topics = "2001"    val numThreads = 2    val topicMap = topics.split(",").map((_, numThreads.toInt)).toMap    val lines = KafkaUtils.createStream(ssc, zk, group, topicMap).map(_._2)    // lines.foreachRDD(rdd => rdd.foreach { x => println(x) })       val tablename = "test"    lines.foreachRDD { rdd =>      rdd.foreachPartition { x =>        val hbaseconf = HBaseConfiguration.create()        hbaseconf.set("hbase.zookeeper.quorum", "datanode01.isesol.com,datanode02.isesol.com,datanode03.isesol.com,datanode04.isesol.com,cmserver.isesol.com")        hbaseconf.set("hbase.zookeeper.property.clientPort", "2181")        val myTable = new HTable(hbaseconf, TableName.valueOf(tablename))        //myTable.setAutoFlush(false)        myTable.setWriteBufferSize(3 * 1024 * 1024)        x.foreach { y =>          {            println(y)            val p = new Put(Bytes.toBytes(System.currentTimeMillis().toString()))            p.add(Bytes.toBytes("cf"), Bytes.toBytes("message"), Bytes.toBytes(y.toString()))            myTable.put(p)          }        }        myTable.close()      }    }    ssc.start()    ssc.awaitTermination()  }}


通过命令行提交, 提交JOB的时候记得把spark-streaming-kafka的包带进去,否者会提示找不到类.:

spark-submit --class com.isesol.spark.high_streaming  --master yarn --deploy-mode cluster --jars spark-streaming-kafka_2.10-1.6.0-cdh5.9.0.jar --driver-memory 1g --executor-memory 1G    --conf spark.streaming.receiver.writeAheadLog.enable=true  --num-executors 5  high_streaming.jar  

通过SPARK UI可以监控到启动的程序:





这里主要关注的点是处理的性能,也就是processing time(处理时间), 以及schedule delay (上一个batch如果没有处理完,下一个batch需要等待的时间), 从这2个时间就能看出spark处理数据是否有延迟,如果schedule delay如果时间超过秒级,我们就认为有延迟,如果毫秒级,我倒觉得这个是正常。


这篇文章讲述的是的消息和传输机制,以及一个简单的示例程序, 用来感受一下spark streaming到底是一个啥玩意,实际上来说比较简单,包括storm程序的开发也是如此,这个程序唯一和生产环境JOB不同的是中间的处理逻辑,因为我没有处理,只是直接写入,生产环境你会运用各种不同的SPARK方法来处理数据,再存储,仅仅如此而已。