一、概述

  在实时应用之中,难免会遇到往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的更多相关文章

  1. Spark Streaming接收Kafka数据存储到Hbase

    Spark Streaming接收Kafka数据存储到Hbase fly spark hbase kafka 主要参考了这篇文章https://yq.aliyun.com/articles/60712 ...

  2. 【转】Spark Streaming 实时计算在甜橙金融监控系统中的应用及优化

    系统架构介绍 整个实时监控系统的架构是先由 Flume 收集服务器产生的日志 Log 和前端埋点数据, 然后实时把这些信息发送到 Kafka 分布式发布订阅消息系统,接着由 Spark Streami ...

  3. 【慕课网实战】Spark Streaming实时流处理项目实战笔记十之铭文升级版

    铭文一级: 第八章:Spark Streaming进阶与案例实战 updateStateByKey算子需求:统计到目前为止累积出现的单词的个数(需要保持住以前的状态) java.lang.Illega ...

  4. Spark练习之通过Spark Streaming实时计算wordcount程序

    Spark练习之通过Spark Streaming实时计算wordcount程序 Java版本 Scala版本 pom.xml Java版本 import org.apache.spark.Spark ...

  5. Spark Streaming实时计算框架介绍

    随着大数据的发展,人们对大数据的处理要求也越来越高,原有的批处理框架MapReduce适合离线计算,却无法满足实时性要求较高的业务,如实时推荐.用户行为分析等. Spark Streaming是建立在 ...

  6. 【Streaming】30分钟概览Spark Streaming 实时计算

    本文主要介绍四个问题: 什么是Spark Streaming实时计算? Spark实时计算原理流程是什么? Spark 2.X下一代实时计算框架Structured Streaming Spark S ...

  7. Spark Streaming揭秘 Day16 数据清理机制

    Spark Streaming揭秘 Day16 数据清理机制 今天主要来讲下Spark的数据清理机制,我们都知道,Spark是运行在jvm上的,虽然jvm本身就有对象的自动回收工作,但是,如果自己不进 ...

  8. 新闻网大数据实时分析可视化系统项目——19、Spark Streaming实时数据分析

    1.Spark Streaming功能介绍 1)定义 Spark Streaming is an extension of the core Spark API that enables scalab ...

  9. 通过Spark Streaming处理交易数据

    Apache Spark 是加州大学伯克利分校的 AMPLabs 开发的开源分布式轻量级通用计算框架. 由于 Spark 基于内存设计,使得它拥有比 Hadoop 更高的性能(极端情况下可以达到 10 ...

随机推荐

  1. python----mysql链接汉字编码的问题

    解决python连接mysql,UTF-8乱码问题 1.  Python文件设置编码 utf-8 (文件前面加上 #encoding=UTF-8)     2. MySQL数据库charset=utf ...

  2. laravel5 数据库连接问题

    [PDOException] SQLSTATE[28000] [1045] Access denied for user ‘homestead’@’localhost’ (using password ...

  3. 为什么无线信号(RSSI)是负值(转)

    源:为什么无线信号(RSSI)是负值 为什么无线信号(RSSI)是负值 答:其实归根到底为什么接收的无线信号是负值,这样子是不是容易理解多了.因为无线信号多为mW级别,所以对它进行了极化,转化为dBm ...

  4. IdTCP的C++Builder2010示例(转)

    源:IdTCP的C++Builder2010示例 IdTCP的C++Builder2010示例 这个是服务端的: void __fastcall TTCPDataServer::TCPServerEx ...

  5. 在 WindowMobile 上的模拟LED 显示屏插件(转)

    源:在 WindowMobile 上的模拟LED 显示屏插件 我在给一个对话框上的控件查找翻看合适的图标时,无形中看到了一个LED显示屏的图标,这里所说的LED显示屏是指由很多LED灯密集排列组成的点 ...

  6. DownloadManager 版本更新,出现 No Activity found to handle Intent 的解决办法

    项目中,进行版本更新的时候,用的是自己写的下载方案,最近看到了使用系统服务 DownloadManager 进行版本更新,自己也试试. 在下载完成以后,安装更新的时候,出现了一个 crash,抓取的 ...

  7. IOS 实现TXT文本自动识别编码的方法

    from :http://kyoworkios.blog.51cto.com/878347/1344013 TXT识别编码是个复杂的问题.幸好有c/c++的一个库能识别. 库的叫uchardet,可以 ...

  8. eclipse安装maketplace插件

    对于默认eclipse是没有marketplace插件的,但是marketplace确实是非常好用的,可以在上面下载各种插件. 1.Help-->Install new Software 2.输 ...

  9. PHP读取Excel文件(PHPExcel)

    /*     * 读取Excel文件     * */    require_once (dirname(dirname(dirname(__FILE__))).'/PHPExcel/PHPExcel ...

  10. 4)Javascript设计模式:Decorator模式

    function MacBook() { this.cost = function() { return 997; } } var macbook = new MacBook(); function ...