SparkSQL结合SparkStreaming的使用

Flume+Kafka+SparkStreaming已经发展为一个比较成熟的实时日志收集与计算架构,利用Kafka,即可以支持将用于离线分析的数据流到HDFS,又可以同时支撑多个消费者实时消费数据,包括SparkStreaming。然而,在SparkStreaming程序中如果有复杂业务逻辑的统计,使用scala代码实现起来比较困难,也不易于别人理解。但如果在SparkSteaming中也使用SQL来做统计分析,是不是就简单的多呢?

本文介绍将SparkSQL与SparkStreaming结合起来,使用SQL完成实时的日志数据统计。SparkStreaming程序以yarn-cluster模式运行在YARN上,不单独部署Spark集群。

环境部署

Hadoop-2.3.0-cdh5.0.0(YARN)

spark-1.5.0-bin-hadoop2.3

kafka_2.10-0.8.2.1

另外,还编译了SparkStreaming用于读取Kafka数据的插件:

spark-streaming-kafka_2.10-1.5.0.jar

相关环境的部署本文不做介绍,请参考文章最后的相关阅读。

实时统计需求

以60秒为间隔,统计60秒内的pv,ip数,uv

最终结果包括:

时间点:pv:ips:uv

原始日志格式

2015-11-11T14:59:59|~|xxx|~|202.109.201.181|~|xxx|~|xxx|~|xxx|~|B5C96DCA0003DB546E7
2015-11-11T14:59:59|~|xxx|~|125.119.144.252|~|xxx|~|xxx|~|xxx|~|B1611D0E00003857808
2015-11-11T14:59:59|~|xxx|~|125.119.144.252|~|xxx|~|xxx|~|xxx|~|1555BD0100016F2E76F
2015-11-11T15:00:00|~|xxx|~|125.119.144.252|~|xxx|~|xxx|~|xxx|~|C0EA13670E0B942E70E
2015-11-11T15:00:00|~|xxx|~|125.119.144.252|~|xxx|~|xxx|~|xxx|~|C0EA13670E0B942E70E
2015-11-11T15:00:01|~|xxx|~|125.119.144.252|~|xxx|~|xxx|~|xxx|~|4E3512790001039FDB9

每条日志包含7个字段,分隔符为|~|,其中,第3列为ip,第7列为cookieid。假设原始日志已经由Flume流到Kafka中。

SparkStreaming程序代码

程序中使用下面的SQL语句完成对一个批次的数据统计:

SELECT date_format(current_timestamp(),'yyyy-MM-dd HH:mm:ss') AS time,
COUNT(1) AS pv,
COUNT(DISTINCT ip) AS ips,
COUNT(DISTINCT cookieid) as uv
FROM daplog

SparkStreaming程序代码:

package com.lxw.test

import scala.reflect.runtime.universe

import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.SQLContext
import org.apache.spark.storage.StorageLevel
import org.apache.spark.streaming.Seconds
import org.apache.spark.streaming.StreamingContext
import org.apache.spark.streaming.Time
import org.apache.spark.streaming.kafka.KafkaUtils
/**
* auth:lxw1234
* http://lxw1234.com
*/
object DapLogStreaming { def main (args : Array[String]) {
val sparkConf = new SparkConf().setMaster("yarn-cluster").setAppName("DapLogStreaming")
//每60秒一个批次
val ssc = new StreamingContext(sparkConf, Seconds(60))
//从Kafka中读取数据,topic为daplog,该topic包含两个分区
val kafkaStream = KafkaUtils.createStream(
ssc,
"bj11-65:2181", //Kafka集群使用的zookeeper
"group_spark_streaming", //该消费者使用的group.id
Map[String, Int]("daplog" -> 0,"daplog" -> 1), //日志在Kafka中的topic及其分区
StorageLevel.MEMORY_AND_DISK_SER)
.map(x => x._2.split("\\|~\\|", -1)) //日志以|~|为分隔符 kafkaStream.foreachRDD((rdd: RDD[Array[String]], time: Time) => {
val sqlContext = SQLContextSingleton.getInstance(rdd.sparkContext)
import sqlContext.implicits._
//构造case class: DapLog,提取日志中相应的字段
val logDataFrame = rdd.map(w => DapLog(w(0).substring(0, 10),w(2),w(6))).toDF()
//注册为tempTable
logDataFrame.registerTempTable("daplog")
//查询该批次的pv,ip数,uv
val logCountsDataFrame =
sqlContext.sql("select date_format(current_timestamp(),'yyyy-MM-dd HH:mm:ss') as time,count(1) as pv,count(distinct ip) as ips,count(distinct cookieid) as uv from daplog")
//打印查询结果
logCountsDataFrame.show()
}) ssc.start()
ssc.awaitTermination() } } case class DapLog(day:String, ip:String, cookieid:String) object SQLContextSingleton {
@transient private var instance: SQLContext = _
def getInstance(sparkContext: SparkContext): SQLContext = {
if (instance == null) {
instance = new SQLContext(sparkContext)
}
instance
}
}

示例中只是将实时统计的结果打印到标准输出,真实场景一般是将结果持久化到数据库中。

将该程序打包成DapLogStreaming.jar,上传至网关机。

运行SparkStreaming程序

进入$SPARK_HOME/bin执行下面的命令,将SparkStreaming程序提交到YARN:

./spark-submit \
--class com.lxw.test.DapLogStreaming \
--master yarn-cluster \
--executor-memory 2G \
--num-executors 6 \
--jars /home/liuxiaowen/kafka-clients-0.8.2.1.jar,/home/liuxiaowen/metrics-core-2.2.0.jar,/home/liuxiaowen/zkclient-0.3.jar,/home/liuxiaowen/spark-streaming-kafka_2.10-1.5.0.jar,/home/liuxiaowen/kafka_2.10-0.8.2.1.jar \
/home/liuxiaowen/DapLogStreaming.jar

注意:SparkStreaming及Kafka插件运行时候需要依赖相应的jar包。

查看运行结果

进入YARN ResourceManager的WEB界面,找到该程序对应的Application,点击ApplicationMaster的链接,进入SparkMaster界面:

每个批次(60秒),会生成一个Job。

点击TAB页”Streaming”,进入Streaming的监控页面:

在最下方,显示正在处理的批次和已经完成的批次,包括每个批次的events数量。

最后,最主要的,点击ApplicationMaster的logs链接,查看stdout标准输出:

已经按照SQL中统计的字段,打印出统计结果,每60秒一个批次打印一次。

注意事项

由于kafka_2.10-0.8.2.1是基于Scala2.10的,因此Spark、Spark的Kafka插件、SparkStreaming应用程序都需要使用Scala2.10,如果使用Scala2.11,运行时候会报出因Scala版本不一致而造成的错误,比如:

15/11/11 15:36:26 ERROR yarn.ApplicationMaster: User class threw exception: java.lang.NoSuchMethodError: scala.Predef$.ArrowAssoc(Ljava/lang/Object;)Ljava/lang/Object;
java.lang.NoSuchMethodError: scala.Predef$.ArrowAssoc(Ljava/lang/Object;)Ljava/lang/Object;
at org.apache.spark.streaming.kafka.KafkaUtils$.createStream(KafkaUtils.scala:59)
at com.lxw.test.DapLogStreaming$.main(DapLogStreaming.scala:23)
at com.lxw.test.DapLogStreaming.main(DapLogStreaming.scala)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.apache.spark.deploy.yarn.ApplicationMaster$$anon$2.run(ApplicationMaster.sc

sparkStreaming结合SparkSql实例的更多相关文章

  1. 071 SparkStreaming与SparkSQL集成

    1.说明 虽然DStream可以转换成RDD,但是如果比较复杂,可以考虑使用SparkSQL. 2.集成方式 Streaming和Core整合: transform或者foreachRDD方法 Cor ...

  2. 运行SparkStreaming的NetworkWordCount实例出错:Error connecting to localhost:9999 java.net.ConnectException: Connection refused 解决办法

    一.背景 首先按照Spark的官方文档来运行此实例,具体方法参见这里,当运行命令$ nc -lk 9999开启端口后,再运行命令$ ./bin/run-example streaming.Networ ...

  3. sparkStreaming结合sparkSql进行日志分析

    package testimport java.util.Propertiesimport org.apache.spark.SparkConfimport org.apache.spark.Spar ...

  4. spark-sql做ETL时遇到的两个问题

    项目中使用spark-sql来作ETL,遇到两个问题,记录一下. 问题1: spark-sql –master yarn –hiveconf load_date=`date –d ..`  -e 'i ...

  5. SequoiaDB 巨杉数据库

    传统单点数据库的容量瓶颈,仅仅是分布式数据库所解决的问题之一.更重要的是在未来微服务化应用开发以及云化平台的趋势下,应用不再以“烟囱式”的中间件加数据库模式进行构建,而是采用数千甚至上万的微服务程序构 ...

  6. 最近学习工作流 推荐一个activiti 的教程文档

    全文地址:http://www.mossle.com/docs/activiti/ Activiti 5.15 用户手册 Table of Contents 1. 简介 协议 下载 源码 必要的软件 ...

  7. flume+sparkStreaming实例 实时监控文件demo

    1,flume所在的节点不和spark同一个集群  v50和 10-15节点 flume在v50里面 flume-agent.conf spark是开的work节点,就是单点计算节点,不涉及到mast ...

  8. Spark入门实战系列--6.SparkSQL(下)--Spark实战应用

    [注]该系列文章以及使用到安装包/测试数据 可以在<倾情大奉送--Spark入门实战系列>获取 .运行环境说明 1.1 硬软件环境 线程,主频2.2G,10G内存 l  虚拟软件:VMwa ...

  9. SparkStreaming入门及例子

    看书大概了解了下Streaming的原理,但是木有动过手啊...万事开头难啊,一个wordcount 2小时怎么都运行不出结果.是我太蠢了,好了言归正传. SparkStreaming是一个批处理的流 ...

随机推荐

  1. 简单谈谈Python中的几种常见的数据类型

    简单谈谈Python中的几种常见的数据类型 计算机顾名思义就是可以做数学计算的机器,因此,计算机程序理所当然地可以处理各种数值.但是,计算机能处理的远不止数值,还可以处理文本.图形.音频.视频.网页等 ...

  2. Guava Spiltter类

    Splitter 提供了各种方法来处理分割操作字符串,对象等. 类声明 以下是com.google.common.base.Splitter类的声明: @GwtCompatible(emulated= ...

  3. DQL 数据查询语言 show

    2.show show databases; 查看所有的库 show tables; 查看当前库的所有的表 show tables from database; 查看指定的库下的所有表 show pr ...

  4. python3 可变数据类型和不可变数据类型

    python内置有6种对象类型: Number 数值型 int 整型 不可变 float 浮点型 不可变 complex 复数 不可变 String 字符串   不可变 Tuple 元组   不可变 ...

  5. leetcode.字符串.205同构字符串-Java

    1. 具体题目 给定两个字符串 s 和 t,判断它们是否是同构的.如果 s 中的字符可以被替换得到 t ,那么这两个字符串是同构的.所有出现的字符都必须用另一个字符替换,同时保留字符的顺序.两个字符不 ...

  6. Linux基本知识点

    压缩和解压类 7.8.1 gzip/gunzip 压缩 1.基本语法 gzip 文件 (功能描述:压缩文件,只能将文件压缩为*.gz文件) gunzip 文件.gz (功能描述:解压缩文件命令) 2. ...

  7. nth_element函数

    使用方法:nth_element(start, start+n, end) 使第n大元素处于第n位置(从0开始,其位置是下标为n的元素),并且比这个元素小的元素都排在这个元素之前,比这个元素大的元素都 ...

  8. Yacc - 一个生成 LALR(1) 文法分析器的程序

    SYNOPSIS 总览 yacc [ -dlrtv ] [ -b file_prefix ] [ -p symbol_prefix ] filename DESCRIPTION 描述 Yacc 从 f ...

  9. Google 公司的代码规范

    如题: C++ , Objective-C, Java, Python, R, Shell, HTML/CSS, JavaScript, AngularJS, Common Lisp ,Vimscri ...

  10. windows 远程登录

    在我的电脑  属性当中开启远程登录功能 然后制作账号,这里对于账号的命名是有要求的,具体网上查找说是要用户名和全名一样,我没有做测试,不过新创建了一个用户用来登录,总是告知我密码错误,导致登录失败,所 ...