sparkStreaming结合SparkSql实例
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实例的更多相关文章
- 071 SparkStreaming与SparkSQL集成
1.说明 虽然DStream可以转换成RDD,但是如果比较复杂,可以考虑使用SparkSQL. 2.集成方式 Streaming和Core整合: transform或者foreachRDD方法 Cor ...
- 运行SparkStreaming的NetworkWordCount实例出错:Error connecting to localhost:9999 java.net.ConnectException: Connection refused 解决办法
一.背景 首先按照Spark的官方文档来运行此实例,具体方法参见这里,当运行命令$ nc -lk 9999开启端口后,再运行命令$ ./bin/run-example streaming.Networ ...
- sparkStreaming结合sparkSql进行日志分析
package testimport java.util.Propertiesimport org.apache.spark.SparkConfimport org.apache.spark.Spar ...
- spark-sql做ETL时遇到的两个问题
项目中使用spark-sql来作ETL,遇到两个问题,记录一下. 问题1: spark-sql –master yarn –hiveconf load_date=`date –d ..` -e 'i ...
- SequoiaDB 巨杉数据库
传统单点数据库的容量瓶颈,仅仅是分布式数据库所解决的问题之一.更重要的是在未来微服务化应用开发以及云化平台的趋势下,应用不再以“烟囱式”的中间件加数据库模式进行构建,而是采用数千甚至上万的微服务程序构 ...
- 最近学习工作流 推荐一个activiti 的教程文档
全文地址:http://www.mossle.com/docs/activiti/ Activiti 5.15 用户手册 Table of Contents 1. 简介 协议 下载 源码 必要的软件 ...
- flume+sparkStreaming实例 实时监控文件demo
1,flume所在的节点不和spark同一个集群 v50和 10-15节点 flume在v50里面 flume-agent.conf spark是开的work节点,就是单点计算节点,不涉及到mast ...
- Spark入门实战系列--6.SparkSQL(下)--Spark实战应用
[注]该系列文章以及使用到安装包/测试数据 可以在<倾情大奉送--Spark入门实战系列>获取 .运行环境说明 1.1 硬软件环境 线程,主频2.2G,10G内存 l 虚拟软件:VMwa ...
- SparkStreaming入门及例子
看书大概了解了下Streaming的原理,但是木有动过手啊...万事开头难啊,一个wordcount 2小时怎么都运行不出结果.是我太蠢了,好了言归正传. SparkStreaming是一个批处理的流 ...
随机推荐
- mkdir和_mkdir的区别
没有下划线的位不符合ISO c++ 标准的写法,标准要求带下划线的标准,没有下划线的是为了兼容以前的版本.
- Promise 的深度学习
1.Promise 是什么? Promise 是异步编程的一种解决方案,比传统的解决方案–回调函数和事件--更合理和更强大.Promise ,简单说就是一个容器,里面保存着某个未来才回结束的事件(通常 ...
- JS window对象取消计时器clearInterval() clearInterval() 方法可取消由 setInterval() 设置的交互时间。
取消计时器clearInterval() clearInterval() 方法可取消由 setInterval() 设置的交互时间. 语法: clearInterval(id_of_setInterv ...
- 随笔记录 shell脚本相关内容 2019-8-26
字符串截取: 假设变量为var=http://www.hao.com/123.htm1. # 号截取,删除左边字符,保留右边字符.echo ${var#*//}其中 var 是变量名,# 号是运算符, ...
- Replication Controller、Replica Set
假如我们现在有一个Pod正在提供线上的服务,我们来想想一下我们可能会遇到的一些场景: 某次运营活动非常成功,网站访问量突然暴增 运行当前Pod的节点发生故障了,Pod不能正常提供服务了 第一种情况,可 ...
- js实现正则判断手机号
//判断是否为手机号的正则表达式 function phoneFun(phones){ var myreg = /^[1][3,4,5,7,8,9][0-9]{9}$/; if (!myreg.tes ...
- [原创] Java 流布局管理器 FlowLayout
参数原型: public FlowLayout(int align, int hgap, int vgap) { this.hgap = hgap; this.vgap = vgap; setAlig ...
- Java——单例模式初步
1.7 单例模式初步 好书推荐:java与模式 1.7.1 什么是设计模式 设计模式是在大量的实践中总结和理论化之后优选的代码结构.编程风格.以及解决问题的思考方式.设计模式就像是经典的棋谱,不同的棋 ...
- Perl 循环
Perl 循环 有的时候,我们可能需要多次执行同一块代码.一般情况下,语句是按顺序执行的:函数中的第一个语句先执行,接着是第二个语句,依此类推. 编程语言提供了更为复杂执行路径的多种控制结构. 循环语 ...
- 基本算数定理快速求约数个数——lightoj1208
#include<bits/stdc++.h> using namespace std; #define ll long long #define maxn 1000005 bool vi ...