spark bulkload hbase笔记
1. 现有的三方包不能完全支持
- 官方:hbase-spark,不能设置 timestamp
- unicredit/hbase-rdd:接口太复杂,不能同时支持多个 family
2. HFile 得是有序的,排序依据 KeyValue.KVComparator,于是我们自定义一个 Comparator,内部调用 KeyValue.KVComparator
3. 如果没有自定义 partitioner,极有可能出现以下异常
ERROR: "java.io.IOException: Retry attempted 10 times without completing, bailing out"
https://community.hortonworks.com/content/supportkb/150138/error-javaioioexception-retry-attempted-10-times-w.html
自定义的方法,参考了:https://github.com/unicredit/hbase-rdd/blob/master/src/main/scala/unicredit/spark/hbase/HFileSupport.scala
4. 很多博客中有以下代码,一开始理解为可以用来对 rdd 分区,实际没有用。这是 mapreduce 的 job 参数,spark中不生效
val job = Job.getInstance(hbaseConfig)
HFileOutputFormat2.configureIncrementalLoad(job, table.getTableDescriptor, regionLocator)
job.getConfiguration
其他知识点:
1. scala 中实现 serializable 接口
2. HFilePartitioner,使用 hbase 的 regionLocator.getStartKeys,将 rdd 中的 put,按 rowkey 分割成不同的 partition,每个 partition 会产生一个 hfile,对应于 hbase region 的分区
代码,以后整理:
object BulkloadHelper {
private val logger = Logger.getLogger(this.getClass)
def bulkloadWrite(rdd: RDD[Put], hbaseConfig: Configuration, thisTableName: TableName): Unit = {
val hbaseConnection = ConnectionFactory.createConnection(hbaseConfig)
val regionLocator = hbaseConnection.getRegionLocator(thisTableName)
val myPartitioner = HFilePartitioner.apply(hbaseConfig, regionLocator.getStartKeys, 1)
logger.info(s"regionLocator.getStartKeys.length = ${regionLocator.getStartKeys.length}")
regionLocator.getStartKeys.foreach(keys => logger.info("regionLocator.getStartKeys: " + new String(keys)))
val hFilePath = getHFilePath()
logger.info(s"bulkload, begin to write to hdfs path: $hFilePath")
/**
* HFile sort function -> KeyValue.KVComparator
* CellComparator
*/
rdd.flatMap(put => putToKeyValueList(put))
.map(c => (c, 1))
.repartitionAndSortWithinPartitions(myPartitioner) // repartition so each hfile can match the hbase region
.map(tuple => (new ImmutableBytesWritable(tuple._1.row), tuple._1.getKeyValue()))
.saveAsNewAPIHadoopFile(
hFilePath,
classOf[ImmutableBytesWritable],
classOf[KeyValue],
classOf[HFileOutputFormat2],
hbaseConfig)
// Bulk load Hfiles to Hbase
logger.info("bulkload, begin to load to hbase")
val bulkLoader = new LoadIncrementalHFiles(hbaseConfig)
bulkLoader.doBulkLoad(new Path(hFilePath), new HTable(hbaseConfig, thisTableName))
logger.info("bulkload, delete hdfs path")
val hadoopConf = new Configuration()
val fileSystem = FileSystem.get(hadoopConf)
fileSystem.delete(new Path(hFilePath), true)
hbaseConnection.close()
fileSystem.close()
logger.info("bulkload, done")
}
def getHFilePath():String = "hdfs:///user/hadoop/hbase/bulkload/hfile/" + LocalDate.now().toString + "-" + UUID.randomUUID().toString
/**
* select one keyvalue from put
* @param put
*/
def putToKeyValueList(put: Put): Seq[MyKeyValue] = {
put.getFamilyCellMap.asScala
.flatMap(_._2.asScala) // list cells
.map(cell => new MyKeyValue(put.getRow, cell.getFamily, cell.getQualifier, cell.getTimestamp, cell.getValue))
.toSeq
}
}
class MyKeyValue(var row: Array[Byte], var family: Array[Byte], var qualifier: Array[Byte], var timestamp: Long, var value: Array[Byte])
extends Serializable with Ordered[MyKeyValue] { import java.io.IOException
import java.io.ObjectInputStream
import java.io.ObjectOutputStream var keyValue: KeyValue = _ def getKeyValue(): KeyValue = {
if (keyValue == null) {
keyValue = new KeyValue(row, family, qualifier, timestamp, value)
}
keyValue
} @throws[IOException]
private def writeObject(out: ObjectOutputStream) {
keyValue = null
out.defaultWriteObject()
out.writeObject(this)
} @throws[IOException]
@throws[ClassNotFoundException]
private def readObject(in: ObjectInputStream) {
in.defaultReadObject()
val newKeyValue = in.readObject().asInstanceOf[MyKeyValue]
this.row = newKeyValue.row
this.family = newKeyValue.family
this.qualifier = newKeyValue.qualifier
this.timestamp = newKeyValue.timestamp
this.value = newKeyValue.value
getKeyValue()
} class MyComparator extends KeyValue.KVComparator with Serializable {}
val comparator = new MyComparator() override def compare(that: MyKeyValue): Int = {
comparator.compare(this.getKeyValue(), that.getKeyValue())
} override def toString: String = {
getKeyValue().toString
}
}
object HFilePartitionerHelper {
object HFilePartitioner {
def apply(conf: Configuration, splits: Array[Array[Byte]], numFilesPerRegionPerFamily: Int): HFilePartitioner = {
if (numFilesPerRegionPerFamily == 1)
new SingleHFilePartitioner(splits)
else {
val fraction = 1 max numFilesPerRegionPerFamily min conf.getInt(LoadIncrementalHFiles.MAX_FILES_PER_REGION_PER_FAMILY, 32)
new MultiHFilePartitioner(splits, fraction)
}
}
}
protected abstract class HFilePartitioner extends Partitioner {
def extractKey(n: Any): Array[Byte] = {
// println(s"n = $n")
n match {
case kv: MyKeyValue => kv.row
}
}
}
private class MultiHFilePartitioner(splits: Array[Array[Byte]], fraction: Int) extends HFilePartitioner {
override def getPartition(key: Any): Int = {
val k = extractKey(key)
val h = (k.hashCode() & Int.MaxValue) % fraction
for (i <- 1 until splits.length)
if (Bytes.compareTo(k, splits(i)) < 0) return (i - 1) * fraction + h
(splits.length - 1) * fraction + h
}
override def numPartitions: Int = splits.length * fraction
}
private class SingleHFilePartitioner(splits: Array[Array[Byte]]) extends HFilePartitioner {
override def getPartition(key: Any): Int = {
val p = selfGetPartition(key)
// println(s"p = $p")
p
}
def selfGetPartition(key: Any): Int = {
val k = extractKey(key)
for (i <- 1 until splits.length)
if (Bytes.compareTo(k, splits(i)) < 0) return i - 1
splits.length - 1
}
override def numPartitions: Int = splits.length
}
}
spark bulkload hbase笔记的更多相关文章
- Spark、BulkLoad Hbase、单列、多列
背景 之前的博客:Spark:DataFrame写HFile (Hbase)一个列族.一个列扩展一个列族.多个列 用spark 1.6.0 和 hbase 1.2.0 版本实现过spark BulkL ...
- Spark操作HBase问题:java.io.IOException: Non-increasing Bloom keys
1 问题描述 在使用Spark BulkLoad数据到HBase时遇到以下问题: 17/05/19 14:47:26 WARN scheduler.TaskSetManager: Lost task ...
- MapReduce和Spark写入Hbase多表总结
作者:Syn良子 出处:http://www.cnblogs.com/cssdongl 转载请注明出处 大家都知道用mapreduce或者spark写入已知的hbase中的表时,直接在mapreduc ...
- spark 操作hbase
HBase经过七年发展,终于在今年2月底,发布了 1.0.0 版本.这个版本提供了一些让人激动的功能,并且,在不牺牲稳定性的前提下,引入了新的API.虽然 1.0.0 兼容旧版本的 API,不过还是应 ...
- Spark操作hbase
于Spark它是一个计算框架,于Spark环境,不仅支持单个文件操作,HDFS档,同时也可以使用Spark对Hbase操作. 从企业的数据源HBase取出.这涉及阅读hbase数据,在本文中尽快为了尽 ...
- 大数据学习系列之九---- Hive整合Spark和HBase以及相关测试
前言 在之前的大数据学习系列之七 ----- Hadoop+Spark+Zookeeper+HBase+Hive集群搭建 中介绍了集群的环境搭建,但是在使用hive进行数据查询的时候会非常的慢,因为h ...
- Spark 基本函数学习笔记一
Spark 基本函数学习笔记一¶ spark的函数主要分两类,Transformations和Actions. Transformations为一些数据转换类函数,actions为一些行动类函数: ...
- Spark读Hbase优化 --手动划分region提高并行数
一. Hbase的region 我们先简单介绍下Hbase的架构和Hbase的region: 从物理集群的角度看,Hbase集群中,由一个Hmaster管理多个HRegionServer,其中每个HR ...
- spark读写hbase性能对比
一.spark写入hbase hbase client以put方式封装数据,并支持逐条或批量插入.spark中内置saveAsHadoopDataset和saveAsNewAPIHadoopDatas ...
随机推荐
- OGG在windows环境下字符集的配置
windows环境下不配置字符集(默认使用windows自己的字符集),从linux等系统同步过来的表中如果含有中文字符列将显示为乱码,被ogg误认为虚拟列,从而导致进程abend. 设置ogg进程在 ...
- provide 和 inject高阶使用
provide 在祖先里授权导出 inject在后代负责接收 foo可以是本组件的函数方法 或者 变量foo 也可以是祖先组件自己 祖先组件foo: this 后代组件 foo.$options.da ...
- 三星前有note7,现有GalaxyS10,爆炸原因外力?
编辑 | 于斌 出品 | 于见(mpyujian) 提到三星,不知道大家什么感觉,反正首先映入脑海的是在Note 7系列爆炸中,三星就让中国消费者欲哭无泪的画面.而也正是三星的态度,三星手机在这件事情 ...
- 关于GOM引擎启动时显示:windows socket error: 在其上下文中,该请求的地址无效。 (10049), on API 'bind'
GOM启动时网管登陆器显示:windows socket error: 在其上下文中,该请求的地址无效. (10049), on API 'bind'解决方法: 重新配置引擎控制台.在配置里取消双IP ...
- centos7一步一步搭建docker tomcat 及重点讲解
系统环境:centos7.7 (VMware中) image版本:tomcat:8-jdk8-openjdk (截止2020.01.10该系列版本) 安装步骤参考文章:https://www.jian ...
- Vue-footer始终置底
需求:当页面高度不足一屏时需要footer固定显示在页面底部,而页面内容超过一屏时需要footer紧跟在页面内容的最后. 思路:通过获取 网页可见区域高度:document.body.clientHe ...
- java月利率计算(等额本息贷款)
等额本息 每月还款计算公式: 每月本息金额 = (本金×月利率×(1+月利率)^还款月数)÷ ((1+月利率)^还款月数-1)) 反转求出 月利率 月利率 如果根据上面公式反转是算不出来的. 下面给出 ...
- python splash scrapy
python splash scrapy 1. 前言 slpash是一个渲染引擎,它有自己的api,可以直接访问splash服务的http接口,但也有对应的包python-splash方便调 ...
- Codeforces Round #592 (Div. 2)G(模拟)
#define HAVE_STRUCT_TIMESPEC#include<bits/stdc++.h>using namespace std;long long a[1000007],b[ ...
- centos7搭建hadoop2.10完全分布式
本篇介绍在centos7中大家hadoop2.10完全分布式,首先准备4台机器:1台nn(namenode);3台dn(datanode) IP hostname 进程 192.168.30.141 ...