Spark Streaming实时写入数据到HBase
一、概述
在实时应用之中,难免会遇到往NoSql数据如HBase中写入数据的情景。题主在工作中遇到如下情景,需要实时查询某个设备ID对应的账号ID数量。踩过的坑也挺多,举其中之一,如一开始选择使用NEO4J图数据库存储设备和账号的关系,当然也有其他的数据,最终构成一个复杂的图关系,但是这个图数据库免费版是单机安装(集群要收费),在实时写入和查询关系的时候,导致我们一台服务器内存和cpu损耗严重,为了保证Hadoop集群的稳定性,只好替换掉这个数据库,采用流行的HBase。本文就HBase的使用心得做如下记录。
二、解决方案
1.rowkey设计:设备id是32位字母、数字组成的串,考虑到HBase长表扫描的查询最快,所以rowkey的设计方式为,设备ID+账号ID拼接而成,这样在扫描某个设备ID时会很快计算出条数。
2.HBase表设计:在创建表的时候采用预分区建表,因为这样的,如果知道hbase数据表的rowkey的分布情况,就可以在建表的时候对hbase进行region的预分区,这样做的好处是防止大数据量插入的热点问题,提高数据插入的效率。rowkey是字母或者数字开头,所以建表语句如下(数据量再大的时候还可以在细分分区):
create 'T_TEST', 'data', SPLITS => ['0', '1','2', '3','4', '5','6','7','8','9','a', 'b', 'c', 'd', 'e', 'f', 'g']
此处入坑:创建表的时候将HBase表映射到Hive外部表,语句如下。这样做是为了方便导入历史数据,但是Hive跑批将历史数据导入之后,从HBase查询已经导入的某一数据的时候,无法查询导数据,也无法通过API写入到HBase,这个问题很诡异,后来想了下Hive导入的数据编码和HBase的不同,于是重新将表删除,不采用映射表,直接使用Spark将历史数据导入,问题解决。
CREATE external TABLE tmp.H_T_TEST(key string ,num string)
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES ("hbase.columns.mapping" = ":key,data:num")
TBLPROPERTIES ("hbase.table.name" = "T_TEST");
3.设计好rowkey和表之后,我们就开始写Spark代码了。
此处入坑,我把HBase的连接池写在了和Spark的同一位置,这样会遇到一个问题,Spark程序运行的时候报HBaseConnection没有序列化,按照网上的做法,将对象加上 @transient注解,虽然不报错误,还是无法将数据写入到Hba之中。后来经过查找,找到了解决办法,将HBase的连接放到消息的循环之内,即一个分区建立一个HBase连接,代码如下。
def main(args: Array[String]): Unit = {
val sc: SparkContext = SparkUtil.createSparkContext(this.getClass.getSimpleName)
val ssc: StreamingContext = new StreamingContext(sc, Seconds(10))
val messages = SparkUtil.createDStreamFromKafka(
"T_TEST",
topicSet,
ssc)//创建消息接收器
messages.foreachRDD(rdd => {
rdd.foreachPartition(partitionRecords => {//循环分区
try {
val connection = HBaseUtil.getHbaseConn //获取HBase连接,分区创建一个连接,分区不跨节点,不需要序列化
partitionRecords.foreach(s => {
val data = JSON.parseObject(s._2)//将数据转化成JSON格式
val tableName = TableName.valueOf("T_TEST")
val table = connection.getTable(tableName)//获取表连接
val put = new Put(Bytes.toBytes(data.getString("id1") + "_" + data.getString("id2")))
put.addColumn(Bytes.toBytes("data"), Bytes.toBytes("num"), Bytes.toBytes("1"))
Try(table.put(put)).getOrElse(table.close())//将数据写入HBase,若出错关闭table
table.close()//分区数据写入HBase后关闭连接
})
} catch {
case e: Exception => logger.error("写入HBase失败,{}", e.getMessage)
}
})
})
ssc.start()
ssc.awaitTermination()
}
至此问题解决,数据正常,还没出现过问题,等待时间验证吧。
4.历史数据导入,在导入历史数据的时候,由于数据放在了Hive的两个不同表之中,一开始想要一次性读入,使用Spark SQL的dataframe,创建一个hivecontext,写HiveSQL将两个表结果执行union all操作,但是Spark程序报rpc错误。将两个表的结果分别查出,使用dataframe 的union all操作,也是不行,也是rpc错误,查了很多资料,还是没解决,莫名其妙的错误,后来两个表分开执行导入历史数据,问题不再出现,可能Spark还是不够成熟,总是遇到莫名其妙的问题。
三、总结
在使用Hbase的时候要预分区。不要为了方便使用Hive外部映射表。HBase的连接池要放在分区循环开始的地方,不然创建很多的连接,会导致HBase垮掉。
Spark Streaming实时写入数据到HBase的更多相关文章
- Spark Streaming接收Kafka数据存储到Hbase
Spark Streaming接收Kafka数据存储到Hbase fly spark hbase kafka 主要参考了这篇文章https://yq.aliyun.com/articles/60712 ...
- 【转】Spark Streaming 实时计算在甜橙金融监控系统中的应用及优化
系统架构介绍 整个实时监控系统的架构是先由 Flume 收集服务器产生的日志 Log 和前端埋点数据, 然后实时把这些信息发送到 Kafka 分布式发布订阅消息系统,接着由 Spark Streami ...
- 【慕课网实战】Spark Streaming实时流处理项目实战笔记十之铭文升级版
铭文一级: 第八章:Spark Streaming进阶与案例实战 updateStateByKey算子需求:统计到目前为止累积出现的单词的个数(需要保持住以前的状态) java.lang.Illega ...
- Spark练习之通过Spark Streaming实时计算wordcount程序
Spark练习之通过Spark Streaming实时计算wordcount程序 Java版本 Scala版本 pom.xml Java版本 import org.apache.spark.Spark ...
- Spark Streaming实时计算框架介绍
随着大数据的发展,人们对大数据的处理要求也越来越高,原有的批处理框架MapReduce适合离线计算,却无法满足实时性要求较高的业务,如实时推荐.用户行为分析等. Spark Streaming是建立在 ...
- 【Streaming】30分钟概览Spark Streaming 实时计算
本文主要介绍四个问题: 什么是Spark Streaming实时计算? Spark实时计算原理流程是什么? Spark 2.X下一代实时计算框架Structured Streaming Spark S ...
- Spark Streaming揭秘 Day16 数据清理机制
Spark Streaming揭秘 Day16 数据清理机制 今天主要来讲下Spark的数据清理机制,我们都知道,Spark是运行在jvm上的,虽然jvm本身就有对象的自动回收工作,但是,如果自己不进 ...
- 新闻网大数据实时分析可视化系统项目——19、Spark Streaming实时数据分析
1.Spark Streaming功能介绍 1)定义 Spark Streaming is an extension of the core Spark API that enables scalab ...
- 通过Spark Streaming处理交易数据
Apache Spark 是加州大学伯克利分校的 AMPLabs 开发的开源分布式轻量级通用计算框架. 由于 Spark 基于内存设计,使得它拥有比 Hadoop 更高的性能(极端情况下可以达到 10 ...
随机推荐
- ASP.NET AJAX注册命名空间
AJAX库支持命名空间的概念. 类可以分组到不同的命名空间.AJAX库会自动创建在此层次中不存在的任何级别的命名空间. <%@ Page Language="C#" Auto ...
- jvm 配置,看看
http://my.oschina.net/qiangzigege/blog/661757
- 解决在某些IE浏览器下字符乱码的问题
习惯上我们写字符声明都是 <meta charset="utf-8"> 在绝大多数浏览器都没有问题,但是在操蛋的IE上有时候会出现编码错误!! 解决方案: <me ...
- CABasicAnimation 基本动画
几个可以用来实现热门APP应用PATH中menu效果的几个方法 +(CABasicAnimation *)opacityForever_Animation:(float)time //永久闪烁的动画 ...
- new sun.misc.BASE64Encoder()报错找不到jar包
解决方案1(推荐): 只需要在project build path中先移除JRE System Library,再添加库JRE System Library,重新编译后就一切正常了. 解决方案2: W ...
- sql数据库中查询第几条到第几条的数据
通用方法: select top 500 * from (select top 1000 * from UserSearchDatas order by ID) a order by ID desc ...
- innodb系统表空间维护
环境说明: 有一个在运行中的mysql环境,由于之前的配置文件设置的过于简单(没有配置innodb_data_file_path变更):造成现在系统表空间已经满了 如果innodb_data_file ...
- 【转】C/CPP之static
静态变量作用范围在一个文件内,程序开始时分配空间,结束时释放空间,默认初始化为0,使用时可以改变其值. 静态变量或静态函数只有本文件内的代码才能访问它,它的名字在其它文件中不可见.用法1:函数内部声明 ...
- jquery遍历二维数组
function eachTowArray() { var ar = [[1,2,3],[4,5,6],[7,8,9]]; var result=""; //结果存放变量 ...
- 【ural1297】 Palindrome
http://acm.timus.ru/problem.aspx?space=1&num=1297 (题目链接) 题意 求最长回文子串 Solution 后缀数组论文题 穷举每一位,然后计算以 ...