一、SparkStreaming概述
Spark内置对象: sparkconf: SparkContext的初始化需要一个SparkConf对象,SparkConf包含了Spark集群配置的各种参数。 SparkContext: **SparkContext为Spark的主要入口点 ,SparkContext用于连接Spark集群、创建RDD、累加器(accumlator)、广播变量(broadcast variables),所以说SparkContext为Spark程序的根本都不为过** SqlContext: SQLContext是SQL进行结构化数据处理的入口,可以通过它进行DataFrame的创建及SQL的执行 StreamingContext: 创建应用程序主入口,并连上Driver上接收数据9999端口写入源数据
|
数据能够被推到文件系统和数据库以及仪表板。
SparkStreaming会实时接收到数据流,将其拆分成很多批次,再被Spark引擎处理,得到最终的结果(批次)
软件之间相互协作:
启动一个软件----启动一个进程------请求类型http/hdfs-------端口(服务进行监听)-----另一个软件进行访问------输入命令通过端口发送--------通过端口进行返回
不同计算机之间的相互协作
客户端-----目标服务交互-----配置一致
Kafka(消息中间件,能够以容错的方式存储流式数据)----数据计算-----能够对实时采集的数据进行计算----历史数据存储-------合并历史数据----延迟性比较低的效果。
特点:
1. 易用
2. 容错
3. 易整合
二、词频统计案例
1. spark-submit
root用户
yum install nc
bigdata用户
Nc 监听某个端口有没有数据进来/还可以发送数据
在Linux下安装netcat: root下 yum install nc
在linux下解压压缩包到c://windows/System32
nc -lk 9999
spark-submit --master local[2] \
--class org.apache.spark.examples.streaming.NetworkWordCount \
$SPARK_HOME/lib/spark-examples-1.6.3-hadoop2.6.0.jar hh 9999
参数解释类的全路径,jar包的位置 主机 端口号
2. spark-shell
spark-shell --master local[2] //根据CPU的核数分配线程,线程数为2
Intel超线程实际核数4有4个模拟核数
import org.apache.spark.streaming.{Seconds, StreamingContext}
val ssc = new StreamingContext(sc, Se6conds(1))
val lines = ssc.socketTextStream("hh", 8888)
val words = lines.flatMap(_.split(" "))
val wordCounts = words.map(x => (x, 1)).reduceByKey(_ + _)
wordCounts.print()
ssc.start()
ssc.awaitTermination()
三、SparkStreaming运行原理
1. 粗粒度
SparkStreaming接收实时数据流
根据给定的时间间隔进行拆分,变成小批次的处理
底层由Spark引擎计算
处理后的结果也是按批次的
2. 细粒度
在Driver端启动StreamingContext
同时启动Receiver
将接收到的数据拆分暂存在内存中
Receiver会向StreamingContext报告信息
StreamingContext会按预设的周期发布job
SparkContext会将job分发给Executor
四、StreamingContext
可以使用SparkConf获得,也可以使用SparkContext获得
使用Streaming需要定义数据输入的源(DStream)
需要定义计算模式,最终作用在DStream
使用StreamingContext的start方法启动
使用awaitTermination方法将停止方式设置为手动停止或由于某些错误停止
手工停止时可以使用stop方法
五、DStream
代表一个持续化的数据流,代表一系列的RDD,其中的每一个RDD都包含了一个批次的数据。
任何对于DStream的操作都相当于是对于每个RDD做相同的作。
六、Input DStream和Receivers
每一个Input DStream都需要关联一个Receiver
1. Input DStream
代表从源头接收的数据流
2. Receivers
从源头接收数据(除文件系统外),存放在内存中,在处理时使用
七、Transformation和Operations
1. Transformation
和RDD的操作类似,允许对Input DStream的数据进行修改
2. Operations
可以使用Output Operations输出计算结果,除此之外还支持窗口函数等
五、SparkStreaming处理Socket数据
build.sbt中添加依赖:
libraryDependencies += "org.apache.spark" %% "spark-streaming" % "1.6.3" % "provided"
import org.apache.spark.SparkConf
import org.apache.spark.streaming.dstream.{DStream, ReceiverInputDStream}
import org.apache.spark.streaming.{Seconds, StreamingContext}
object NetworkDataStream {
def main(args: Array[String]): Unit = {
//初始化配置-如果数据源不是文件类型-local[2](receiver)
val conf=new SparkConf().setMaster("local[*]").setAppName("MyStreaming")
//创建实时处理流对象,添加配置文件,添加时间间隔
val ssc=new StreamingContext(conf,Seconds(3))
//接下来是计算过程,指定数据来源,以及存储的数据类型
val lines:ReceiverInputDStream[String]=ssc.socketTextStream("localhost",9999)
//对数据进行处理
val result:DStream[(String,Int)]=lines.flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_)
//输出处理结果
result.print()
//开启进程
ssc.start()
//出现异常自动停止进程
ssc.awaitTermination()
//手动停止进程
//ssc.stop()
}
}
运行在window上 需要安装netcat 在dos下启动nc -pl 9999进行监听
在idea中启动程序
注意:需要sbt配置文件将省略压缩包打开
spark-streaming" % "1.6.3"//% "provided"
程序运行到虚拟机:
|
第一步:程序打包
File---project structure---Artifacts----+----第一项----第二项---moduel----创建的类---OK-----APPLY----OK
BUILD----build artifacts-----项目名---build----out中复制压缩包
第二步:上传到linux的datas中
启动两个客户端
第一个:nc -lk 9988
第二个:spark-submit --class com.qfedu.streaming.NetWorkData2 --master spark://hh:7077 untitled.jar
注意:端口启动过的就不要用了看不出效果:程序执行第二遍的话一定换一个端口,或重启各个服务
八、SparkStreaming处理文件系统数据
Streaming会监控指定的文件夹,当有任何文件被创建时将会进行计算(但不支持子目录)
数据文件必须含有相同的格式。
文件必须通过移动或重命名的方式进行创建
一旦发生移动,文件不能被改变,新增的数据不会被读取
spark-shell
import org.apache.spark.streaming.{Seconds, StreamingContext}
val ssc = new StreamingContext(sc,Seconds(3))
val lines = ssc.textFileStream("file:///home/hadoop/dataDir")
val result = lines.flatMap(_.split(" ")).map((_,1)).reduceByKey(_ + _)
result.print()
ssc.start()
ssc.awaitTermination()
九、UpdateStateByKey
UpdateStateByKey允许在使用持续更新的数据时保持状态信息,将最新的计算结果与历史结果做合并
定义一个状态-可以是任意的数据类型
定义一个状态更新的方法-如何使用先前状态和输入流中的新值更新
十、流式数据单词计数案例
import org.apache.spark.SparkConf
import org.apache.spark.streaming.dstream.DStream
import org.apache.spark.streaming.{Seconds, StreamingContext}
object StatefulWordCount {
def main(args: Array[String]): Unit = {
val sparkConf = new
SparkConf().setMaster("local[2]").setAppName("Streaming");
val ssc = new StreamingContext(sparkConf,Seconds(3))
//将当前的数据进行一个存储,基本上带状态的算子都会指定他
ssc.checkpoint(".")
val lines = ssc.socketTextStream("localhost",9999)
val result: DStream[(String, Int)] = lines.flatMap(_.split(" ").map((_,1)))
val state = result.updateStateByKey(updateFunction)
state.print()
ssc.start()
ssc.awaitTermination()
}
//seq中传进去的值为(1,1,1,1,1)
def updateFunction(curValues: Seq[Int], preValues:Option[Int]): Option[Int] = {
val curCount = curValues.sum
val preCount = preValues.getOrElse(0)
Some(curCount + preCount)
}
}
十一、Streaming写入结果至RDBMS
将统计结果写入MySQL,同时尽量保证高效运行
工程构建
libraryDependencies += "mysql" % "mysql-connector-java" % "5.1.46"
create table wordCount(
word varchar(50) default null,
counts int(11) default null
)
1. 实现一(错误示范)
连接出现序列化异常(数据库有最大连接数)
import org.apache.spark.SparkConf
import org.apache.spark.streaming.{Seconds, StreamingContext}
import org.apache.spark.streaming.dstream.DStream
object ForeachRDD {
def main(args: Array[String]): Unit = {
val sparkConf = new SparkConf().setMaster("local[2]").setAppName("Streaming");
val ssc = new StreamingContext(sparkConf,Seconds(3))
ssc.checkpoint(".")
val lines = ssc.socketTextStream("localhost",9999)
val result: DStream[(String, Int)] = lines.flatMap(_.split(" ").map((_,1))).reduceByKey(_ + _)
result.foreachRDD(rdd => {
val connection = createNewConnection()
rdd.foreach(record => {
val sql = "insert into wordCount values ('" + record._1 + "'," + record._2 + ")"
connection.createStatement().execute(sql)
})
})
ssc.start()
ssc.awaitTermination()
}
def createNewConnection() = {
Class.forName("com.mysql.jdbc.Driver")
DriverManager.getConnection("jdbc:mysql://localhost:3306/teach01","root","mysql")
}
}
2. 实现二(正确)
import java.sql.DriverManager
import org.apache.spark.SparkConf
import org.apache.spark.streaming.{Seconds, StreamingContext}
import org.apache.spark.streaming.dstream.DStream
object ForeachRDD {
def main(args: Array[String]): Unit = {
val sparkConf = new SparkConf().setMaster("local[2]").setAppName("Streaming");
val ssc = new StreamingContext(sparkConf,Seconds(3))
val lines = ssc.socketTextStream("localhost",9999)
val result: DStream[(String, Int)] = lines.flatMap(_.split(" ").map((_,1))).reduceByKey(_ + _)
result.print()
result.foreachRDD(rdd => {
rdd.foreachPartition(partitionOfRecords => {
val connection = createNewConnection()
partitionOfRecords.foreach(record => {
val sql = "insert into wordCount values ('" + record._1 + "'," + record._2 + ")"
connection.createStatement().execute(sql)
})
connection.close()
})
})
ssc.start()
ssc.awaitTermination()
}
def createNewConnection() = {
Class.forName("com.mysql.jdbc.Driver")
DriverManager.getConnection("jdbc:mysql://localhost:3306/teach01","root","mysql")
}
}
十二、黑名单过滤
数据源分为两部分:访问日志(流式数据)和黑名单列表(离线数据),在流式数据中将黑名单中出现的数据进行过滤
数据维度:点击时间,用户名称
数据分隔符:逗号
import org.apache.spark.SparkConf
import org.apache.spark.streaming.{Seconds, StreamingContext}
object BlackListFilter {
def main(args: Array[String]): Unit = {
val sparkConf = new SparkConf().setMaster("local[2]").setAppName("Streaming");
val ssc = new StreamingContext(sparkConf,Seconds(3))
//zhangsan true lisi true
val blackListRDD =
ssc.sparkContext.parallelize(List("ZhangSan","LiSi")).map((_,true))
val lines = ssc.socketTextStream("localhost",9999)
val result = lines.map(log => (log.split(",")(1),log)).transform(rdd => {
rdd.leftOuterJoin(blackListRDD).filter(_._2._2.getOrElse(false) != true).map(_._1)
})
result.print()
ssc.start()
ssc.awaitTermination()
}
}
十三.SparkStreaming整合FlumeSparkStreaming集群运行
Push方式实现Pull方式实现
(1)push -> 推送 -> Streaming(DataServer):Streaming先启动
接收数据时填写虚拟网卡相关ip地址,不要填写localhost
(2)pull -> 拉取 -> Flume先启动
一、Push-based(先启动程序端再启动flume端)
1. Flume配置
# Name the components on this agent
a1.sources = r1
a1.sinks = k1
a1.channels = c1
# Describe/configure the source
a1.sources.r1.type = exec
#监控一个文件
a1.sources.r1.command = tail -f /home/bigdata/webapp.log
# Describe the sink
a1.sinks.k1.type = avro //Avro是一个数据序列化系统,设计用于支持大批量数据交换的应用。
a1.sinks.k1.hostname = hh //指定需要将数据传送给那台机器,那台机器是Steaming中所在的服务器
a1.sinks.k1.port = 8888
# Use a channel which buffers events in memory
a1.channels.c1.type = memory
# Bind the source and sink to the channel
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1
flume-ng agent --name a1 --conf $FLUME_HOME/conf --conf-file $FLUME_HOME/conf/file-memory-push.conf -Dflume.root.logger=INFO.console
***********在启动flume测试的时候,如果没有程序对avro指定的主机端口进行监听flume会主线异常,所以先启动程序再启动flume
***************************
2. SparkStreaming开发(监控一个文件,并实现实时的单词计数,并且与历史计数结果进行组合得到最终结果)
*******环境构建:
libraryDependencies += "org.apache.spark" %% "spark-streaming-flume" % "1.6.3"
去除依赖(去除两条依赖的重复的包):
libraryDependencies += "org.apache.spark" %% "spark-streaming" % "1.6.3" exclude("javax.servlet", "*")
如果不去除依赖包的话程序将会报错
java.lang.SecurityException: class "javax.servlet.FilterRegistration"'s signer information does not match signer information of other classes in the same package at java.lang.ClassLoader.checkCerts(ClassLoader.java:898) at java.lang.ClassLoader.preDefineClass(ClassLoader.java:668) |
import org.apache.spark.SparkConf
|
打包运行
% "provided" 打包之前加上这个
libraryDependencies += "org.apache.kafka" % "kafka-clients" % "0.10.2.2"% "provided"
|
两种方式:
******先启动程序再启动flume**********
推荐:
spark-submit --master local[2] --class com.qfedu.streaming.FlumePush /home/bigdata/streaming.jar bigdata 8888
spark-submit --class com.qfedu.streaming.FlumePush --master spark://hh:7077 untitled.jar hh 8888
shutdown()
将线程池状态置为SHUTDOWN,并不会立即停止:
停止接收外部submit的任务
内部正在跑的任务和队列里等待的任务,会执行完
等到第二步完成后,才真正停止
shutdownNow()
将线程池状态置为STOP。企图立即停止,事实上不一定:
跟shutdown()一样,先停止接收外部提交的任务
忽略队列里等待的任务
尝试将正在跑的任务interrupt中断
返回未执行的任务列表
awaitTermination(long timeOut, TimeUnit unit)
当前线程阻塞,直到
等所有已提交的任务(包括正在跑的和队列中等待的)执行完
或者等超时时间到
或者线程被中断,抛出InterruptedException
然后返回true(shutdown请求后所有任务执行完毕)或false(已超时)
实验发现,shuntdown()和awaitTermination()效果差不多,方法执行之后,都要等到提交的任务全部执行完才停。
二、Pull-based(用的比较多的,消费完成再拉取)
1. Flume配置
# Name the components on this agent
a1.sources = r1
a1.sinks = k1
a1.channels = c1
# Describe/configure the source
a1.sources.r1.type = exec
a1.sources.r1.command = tail -f /home/bigdata/webapp.log
# Describe the sink
a1.sinks.k1.type = org.apache.spark.streaming.flume.sink.SparkSink
a1.sinks.k1.hostname = hh
a1.sinks.k1.port = 8888
# Use a channel which buffers events in memory
a1.channels.c1.type = memory
# Bind the source and sink to the channel
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1
复制jar包spark-streaming-flume-sink_2.10-1.6.3.jar至flume的lib目录下
运行flume
flume-ng agent --name a1 --conf $FLUME_HOME/conf --conf-file $FLUME_HOME/conf/example-pull.conf -Dflume.root.logger=INFO.console
2. SparkStreaming开发
import org.apache.spark.SparkConf
import org.apache.spark.streaming.{Seconds, StreamingContext}
import org.apache.spark.streaming.flume.FlumeUtils
object FlumePull {
def main(args: Array[String]): Unit = {
if (args.length < 2){
println("needs two params:<hostname> <port>")
System.exit(-1)
}
val Array(hostname, port) = args
val sparkConf = new SparkConf().setMas
ter("local[2]").setAppName("FlumeStreaming")
val ssc = new StreamingContext(sparkConf, Seconds(3))
val flumeStream = FlumeUtils.createPollingStream(ssc,hostname,port.toInt)
val products = flumeStream.map(data => new
String(data.event.getBody.array())).flatMap(_.split("-")(1))
val result = products.map((_,1)).reduceByKey(_ + _)
//print方法必须需要有,标记着计算流程的结束,不标记的话会报错
result.print()
ssc.start()
ssc.awaitTermination()
}
}
打包运行
spark-submit --class com.qfedu.streaming.FlumePull --master spark://hh:7077 untitled.jar hh 8888
十四.SparkStreaming整合KafkaSparkStreaming集群运行
问题产生:当SparkStream在flume中拉取数据的时候,当flume每次启动都会读取之前的数据,此时要引进kafka的技术,kafka使用偏移量 记录数据是否被消费。
kafka技术的优点:
(1) 解耦
在项目启动之初来预测将来项目会碰到什么需求,是极其困难的。消息系统在处理过程中间插入了一个隐含的、基于数据的接口层,两边的处理过程都要实现这一接口。这允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束。
(2) 冗余
有些情况下,处理数据的过程会失败。除非数据被持久化,否则将造成丢失。消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险。许多消息队列所采用的"插入-获取-删除"范式中,在把一个消息从队列中删除之前,需要你的处理系统明确的指出该消息已经被处理完毕,从而确保你的数据被安全的保存直到你使用完毕。
(3) 扩展性
因为消息队列解耦了你的处理过程,所以增大消息入队和处理的频率是很容易的,只要另外增加处理过程即可。不需要改变代码、不需要调节参数。扩展就像调大电力按钮一样简单。
(4) 灵活性 & 峰值处理能力
在访问量剧增的情况下,应用仍然需要继续发挥作用,但是这样的突发流量并不常见;如果为以能处理这类峰值访问为标准来投入资源随时待命无疑是巨大的浪费。使用消息队列能够使关键组件顶住突发的访问压力,而不会因为突发的超负荷的请求而完全崩溃。
(5) 顺序保证
在大多使用场景下,数据处理的顺序都很重要。大部分消息队列本来就是排序的,并且能保证数据会按照特定的顺序来处理。Kafka保证一个Partition内的消息的有序性。
(6) 缓冲
在任何重要的系统中,都会有需要不同的处理时间的元素。例如,加载一张图片比应用过滤器花费更少的时间。消息队列通过一个缓冲层来帮助任务最高效率的执行———写入队列的处理会尽可能的快速。该缓冲有助于控制和优化数据流经过系统的速度。
Receiver是使用Kafka的高层次Consumer API来实现的。receiver从Kafka中获取的数据都是存储在Spark Executor的内存中的,然后Spark Streaming启动的job会去处理那些数据。然而,在默认的配置下,这种方式可能会因为底层的失败而丢失数据。如果要启用高可靠机制,让数据零丢失,就必须启用Spark Streaming的预写日志机制(Write Ahead Log,WAL)。该机制会同步地将接收到的Kafka数据写入分布式文件系统(比如HDFS)上的预写日志中。所以,即使底层节点出现了失败,也可以使用预写日志中的数据进行恢复,但是效率会下降。
direct 这种方式会周期性地查询Kafka,来获得每个topic+partition的最新的offset,从而定义每个batch的offset的范围。当处理数据的job启动时,就会使用Kafka的简单consumer api来获取Kafka指定offset范围的数据。
这种方式有如下优点:
1、简化并行读取:如果要读取多个partition,不需要创建多个输入DStream然后对它们进行union操作。Spark会创建跟Kafka partition一样多的RDD partition,并且会并行从Kafka中读取数据。所以在Kafka partition和RDD partition之间,有一个一对一的映射关系。
2、高性能:如果要保证零数据丢失,在基于receiver的方式中,需要开启WAL机制。这种方式其实效率低下,因为数据实际上被复制了两份,Kafka自己本身就有高可靠的机制,会对数据复制一份,而这里又会复制一份到WAL中。而基于direct的方式,不依赖Receiver,不需要开启WAL机制,只要Kafka中作了数据的复制,那么就可以通过Kafka的副本进行恢复。
3、一次且仅一次的事务机制:
基于receiver的方式,是使用Kafka的高阶API来在ZooKeeper中保存消费过的offset的。这是消费Kafka数据的传统方式。这种方式配合着WAL机制可以保证数据零丢失的高可靠性,但是却无法保证数据被处理一次且仅一次,可能会处理两次。因为Spark和ZooKeeper之间可能是不同步的。
基于direct的方式,使用kafka的简单api,Spark Streaming自己就负责追踪消费的offset,并保存在checkpoint中。Spark自己一定是同步的,因此可以保证数据是消费一次且仅消费一次。
两者进行比较应用场景:
(1)Receiver:日志信息(基本数据类型+分隔符)
(2)Direct:复杂的实体类
一、Kafka配置
在这之前开启tomcat的web程序
./srart-all.sh
启动Kafka
一.kafka-server-start.sh -daemon $KAFKA_HOME/config/server-0.properties
创建Topic
kafka-topics.sh --create --zookeeper hh:2181 --replication-factor 1 --partitions 1 --topic product_topic
使用控制台生产脚本
kafka-console-producer.sh --broker-list hh:9092 --topic product_topic
flume的配置
# Name the components on this agent a1.sources = r1 a1.sinks = k1 a1.channels = c1
# Describe/configure the source a1.sources.r1.type = exec a1.sources.r1.command = tail -f /home/hadoop/data.log
# Describe the sink a1.sinks.k1.type = org.apache.flume.sink.kafka.KafkaSink a1.sinks.k1.kafka.bootstrap.servers= hh:9092 a1.sinks.k1.kafka.topic = product_topic
# Use a channel which buffers events in memory a1.channels.c1.type = memory
# Bind the source and sink to the channel a1.sources.r1.channels = c1 a1.sinks.k1.channel = c1 |
二.启动flume:
flume-ng agent --name a1 --conf $FLUME_HOME/conf --conf-file $FLUME_HOME/conf/example-Streaming.conf -Dflume.root.logger=INFO,console
|
启动一个消费者测试:
kafka-console-consumer.sh --zookeeper hh:2181 --topic product_topic
到此为止实现了,flum监控web的日志文件,kafka在flume中拉取数据
二、Receiver-based拉取进行计算
环境构建:libraryDependencies += "org.apache.spark" %% "spark-streaming-kafka" % "1.6.3"
import org.apache.spark.SparkConf
import org.apache.spark.streaming.kafka.KafkaUtils
import org.apache.spark.streaming.{Seconds, StreamingContext}
object KafkaReceiver {
def main(args: Array[String]): Unit = {
val sparkConf = new SparkConf().setMaster("local[2]").setAppName("Kafka")
val ssc = new StreamingContext(sparkConf,Seconds(3))
val Array(zookeeper,groupId,topicNames,topicPartition) = args
val topicMap = topicNames.split(",").map((_,topicPartition.toInt)).toMap
val kafkaStream = KafkaUtils.createStream(ssc,zookeeper,groupId,topicMap)
val products = kafkaStream.filter(data => "click".equals(data._2.split("-")(0))).flatMap(_._2.split("-")(1))
val result = products.map((_,1)).reduceByKey(_ + _)
result.print()
ssc.start()
ssc.awaitTermination()
}
}
三、启动程序此时完成了streaming的实时计算:
求wordcount的案例
package com.china.streaming
|
edit configrations: had01:2181 click streaming1,streaming2 1
三、Direct方式拉取数据进行计算
|
开启生产者:
kafka-console-producer.sh --broker-list hh:9092 --topic first_topic
启动idea程序:
生产者生产:
click-1
click-1
click-2
click-2
click-1
click-1
click-2
click-2
在web操作,点击按钮测试
十五.SparkStreaming整合Hbase
SparkStreaming整合Hbase本节任务教学目标教学内容一、Hbase安装和启动二、SparkStreaming程序
SparkStreaming整合HbaseSparkStreaming保存计算结果
一、Hbase安装和启动
解压缩
tar -zvxf tar -zvxf hbase-1.2.8-bin.tar.gz
环境变量
vi ~/.bash_profile
export HBASE_HOME=/home/bigdata/hbase-1.2.8
PATH=$PATH:$HBASE_HOME/bin
source ~/.bash_profile
hbase-env.sh
export JAVA_HOME=/home/bigdata/jdk1.8.0_171
export HBASE_MANAGES_ZK=false
hbase-site.xml
<configuration>
<property>
<name>hbase.rootdir</name>
<value>hdfs://bigdata:9000/hbase</value>
</property>
<property>
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>
<property>
<name>hbase.zookeeper.quorum</name>
<value>bigdata:2181</value>
</property>
<property>
<name>hbase.master.info.port</name>
<value>60010</value>
</property>
</configuration>
regionservers
bigdata
启动Hbase
start-hbase.sh
WEBUI
http://bigdata:60010/
创建表(hbase shell)
create 'product','info'
hbase可以对某个rowkey做增量操作
需求
场景:电商平台产生的商品被浏览数据
数据维度:商品Id,点击次数
分析过程:统计每种商品被点击的次数
结果保存:HBase
二、SparkStreaming程序
环境构建
libraryDependencies += "org.apache.spark" %% "spark-streaming-kafka" % "1.6.3" exclude("javax.servlet", "*")
libraryDependencies += "org.apache.hbase" % "hbase-common" % "1.2.8"
libraryDependencies += "org.apache.hbase" % "hbase-client" % "1.2.8"
libraryDependencies += "org.apache.hbase" % "hbase-server" % "1.2.8"
添加连接hbase的配置文件
在scala下建立config文件夹,在文件夹下添加hbase-site.xml文件,由于文件中各个属性都是以键值对的形式存在的,可以直接读取该文件获得配置信息。
在scala下添加properties配置文件
kafkaConsumer.properties
kafkaProducer.properties
log4j.properties
HBase工具类(新创建hbase的package)
连接测试:
import org.apache.hadoop.conf.Configuration |
在scala文件夹下创建conf文件夹
file---project structure----Modules----找到conf文件夹----resources---OK
实体类
/**
* 商品点击量
* @param productId 商品唯一标识
* @param count 商品被点击次数
*/
case class ProductClickCount(productId: String, count: Long)
HBase数据交互类
dao层
package com.qfedu.dao
|
实现类:
package com.qfedu.streaming
|
工具类
import org.apache.hadoop.conf.Configuration
|
启动主类和工具类即可完成实验
衍生程序单词计数:
文件中的单词------flume-----kafka------SparkStreaming---------Hbase-----读取控制台
flume的编写
#every name a1.sources = r1 a1.sinks = k1 a1.channels = c1 #the source a1.sources.r1.type = exec a1.sources.r1.command = tail -f /opt/mydata/ccc.txt #the sink a1.sinks.k1.type = org.apache.flume.sink.kafka.KafkaSink a1.sinks.k1.kafka.bootstrap.servers= had01:9092 a1.sinks.k1.kafka.topic = streaming1 #the channer a1.channels.c1.type = memory #bind the source and sink to the channel a1.sources.r1.channels = c1 a1.sinks.k1.channel = c1 |
执行语句:
bin/flume-ng agent --conf ./conf --name a1 --conf-file conf/kafka_streaming.conf -Dflume.root.logger=INFO,console
kafka创建两个browke
kafka-server-start.sh -daemon $KAFKA_HOME/config/server-0.properties
./kafka-topics.sh --create --zookeeper hh:2181 --replication-factor 1 --partitions 3 --topic first_topic
kafka-topics.sh --create --zookeeper hh:2181 --replication-factor 1 --partitions 1 --topic first_topic
kafka-topics.sh --list --zookeeper hh:2181
程序
name := "MySparkStremaing"
|
在scala下建立config文件夹,在文件夹下添加hbase-site.xml文件,由于文件中各个属性都是以键值对的形式存在的,可以直接读取该文件获得配置信息。
在scala下添加properties配置文件
kafkaConsumer.properties
kafkaProducer.properties
log4j.properties
创建bean类
package com.china.hbase.bean
|
创建向hbase表添加数据的类
mport scala.collection.mutable.ListBuffer
|
添加kafka-streaming类
package com.china.hbase.oprate
|
添加hbaseutil类
import org.apache.hadoop.conf.Configuration
|