hadoop19--hbase与mapreduce集成,rowkey热点,TSV,CSV

hbase与Mapreduce集成整合

在公司的实际开发中, 在多数情况下, 都是Mapreduce与Hbase联合使用, 在Hbase中对于Hbase来说, 就是读和写的操作

HBASE与hadoop内部已经做好了集成的封装, 对于用户来说只是调用即可

集成的模式

  1. 从HBASE中读取数据, HBASE中的数据可以作为map的输入, 输出可以进行任意的指定
  2. 将数据写入HBASE, 将HBASE作为reduce的输出
  3. 从HBASE读出, 再写入HBASE, 用作数据迁移

在HBASE中已经封装好了一个jar包, 该jar包的名为hbase-server-1.3.1.jar, 可以在hadoop中运行

在hadoop中运行jar包

在hadoop中运行hbase/lib /hbase-server-1.3.1.jar

bin/yarn jar /opt/app/hbase-1.3.1/lib/hbase-server-1.3.1.jar

在运行以上的命令出现了下面的错误

Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/hadoop/hbase/filter/Filter

如上的问题出现的主要原因是 在hadoop环境中运行了hbase中的jar包, 而该jar包在运行的过程中需要别的jar包的依赖

解决方案:

需要清楚的知道, 在运行该jar包的时候需要哪些jar包的支持, 如果将jar包全部拷贝过来, 有可能会产生jar包冲突, 通过如下命令, 可以查找到hadoop中需要支持的jar包

[hadoop@hadoop03 hbase-1.3.1]$ bin/hbase mapredcp.
---------------------------------------------------------------
2018-11-15 05:27:43,625 WARN  [main] util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
/opt/app/hbase-1.3.1/lib/hbase-hadoop-compat-1.3.1.jar:/opt/app/hbase-1.3.1/lib/hbase-common-1.3.1.jar:/opt/app/hbase-1.3.1/lib/htrace-core-3.1.0-incubating.jar:/opt/app/hbase-1.3.1/lib/hbase-client-1.3.1.jar:/opt/app/hbase-1.3.1/lib/zookeeper-3.4.5.jar:/opt/app/hbase-1.3.1/lib/netty-all-4.0.23.Final.jar:/opt/app/hbase-1.3.1/lib/protobuf-java-2.5.0.jar:/opt/app/hbase-1.3.1/lib/guava-12.0.1.jar:/opt/app/hbase-1.3.1/lib/metrics-core-2.2.0.jar:/opt/app/hbase-1.3.1/lib/hbase-prefix-tree-1.3.1.jar:/opt/app/hbase-1.3.1/lib/hbase-protocol-1.3.1.jar:/opt/app/hbase-1.3.1/lib/hbase-server-1.3.1.jar

把hadoop中需要运行的jar包放到hadoop的运行环境中, 两种方式

  1. 把jar包添加到hadoop的classpath中的hadoop-env.sh, 这种方式配置完成之后需要重启hadoop
  2. 把hadoop中需要运行的jar包放置到/etc/profile 全局变量中, source 刷新即可

这里采取第二种方式

​ (1)配置环境变量

vi /etc/profile
----------------------------------
#HBase And Mapreduce
export HBASE_HOME=/opt/app/hbase-1.3.1
export HADOOP_CLASSPATH=$HADOOP_CLASSPATH:`$HBASE_HOME/bin/hbase mapredcp`

​ (2)分发到其他机器

sudo scp  /etc/profile hadoop03:/etc/

​ (3)刷新(需要root用户)

source /etc/profile

​ (4)hadoop根目录下再次执行jar程序

[hadoop@hadoop01 hadoop-2.7.2]$ bin/yarn jar /opt/app/hbase-1.3.1/lib/hbase-server-1.3.1.jar
---------------------------------------------------------------
An example program must be given as the first argument.
Valid program names are:
  CellCounter: Count cells in HBase table.
  WALPlayer: Replay WAL files.
  completebulkload: Complete a bulk data load.
  copytable: Export a table from local cluster to peer cluster.
  export: Write table data to HDFS.
  exportsnapshot: Export the specific snapshot to a given FileSystem.
  import: Import data written by Export.
  importtsv: Import data in TSV format.
  rowcounter: Count rows in HBase table.
  verifyrep: Compare the data from tables in two different clusters. WARNING: It doesn't work for incrementColumnValues'd cells since the timestamp is changed after being appended to the log.

使用rowcounter

bin/yarn jar /opt/app/hbase-1.3.1/lib/hbase-server-1.3.1.jar rowcounter hadoop
--------------------------------------------------------------
... ...
                ROWS=5
        File Input Format Counters
                Bytes Read=0
        File Output Format Counters
                Bytes Written=0

小案例

把HBASE中的数据通过mapreduce读取出来, 之后再写入HBASE中

  1. 修改maven的配置文件
<!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-client -->
<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-client</artifactId>
    <version>2.7.2</version>
</dependency>
  1. 创建一张信息表
create 'stuinfo','f1','f2','f3'
  1. 添加测试数据
put 'stuinfo','1001','f1:name','zhangsan'
put 'stuinfo','1002','f1:name','lisi'
put 'stuinfo','1003','f1:name','wangwu'
  1. 创建要拷贝数据的空表
create 'stuinfocp' , 'info'
  1. map端代码
package com.wch.hbase2hbase;

import java.io.IOException;

import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.mapreduce.TableMapper;
import org.apache.hadoop.hbase.util.Bytes;

public class ToHbaseMap extends TableMapper<ImmutableBytesWritable, Put> {
	@Override
	protected void map(ImmutableBytesWritable key, Result value, Context context)
			throws IOException, InterruptedException {
		// TODO Auto-generated method stub
		super.map(key, value, context);

		Put put = new Put(key.get());

		Cell[] cells = value.rawCells();

		for (Cell cell : cells) {
			if ("info".equals(Bytes.toString(CellUtil.cloneFamily(cell)))) {
				if ("name".equals(Bytes.toString(CellUtil.cloneQualifier(cell)))) {
					put.add(cell);
				}
			}

		}

		context.write(key, put);
	}
}
  1. driver主函数代码
package com.wch.hbase2hbase;

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil;
import org.apache.hadoop.mapreduce.Job;

public class Driver {
	public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
		Configuration conf = HBaseConfiguration.create();

		Job job = Job.getInstance(conf);

		job.setJarByClass(Driver.class);

		Scan scan = new Scan();

		TableMapReduceUtil.initTableMapperJob("stuinfo", // input table
				scan, // Scan instance to control CF and attribute selection
				ToHbaseMap.class, // mapper class
				ImmutableBytesWritable.class, // mapper output key
				Put.class, // mapper output value
				job);
		TableMapReduceUtil.initTableReducerJob("stuinfocp", // output table
				null, // reducer class
				job);
		job.setNumReduceTasks(1);

		boolean b = job.waitForCompletion(true);
		System.exit(b?0:1);

	}
}
  1. 上传至Linux中
  2. 在hadoop根目录下运行
bin/yarn jar /data/HB2HB.jar
  1. 查看 stuinfocp 表
实参 'stuinfocp' 

hbase import TSV

TSV就是一个固定文件的导入工具, 将按照\t分割的文件导入到hbase中

  1. 创建一个表, 用来接收导入的数据
create 'importtsv','info','f1'
  1. 准备要准备的数据
vi importtsv.tsv
-------------------------------
123     zhangsan        henan   18
456     lisi    shanxi  20
789     wangwu  beijing 28
  1. 查看使用方式
bin/yarn jar /opt/app/hbase-1.3.1/lib/hbase-server-1.3.1.jar importtsv
  1. 上传至HDFS
bin/hdfs dfs -put /data/importtsv.tsv /importtsv.tsv
  1. 导入数据
bin/yarn jar /opt/app/hbase-1.3.1/lib/hbase-server-1.3.1.jar importtsv -Dimporttsv.columns=HBASE_ROW_KEY,info:name,f1:location,info:age importtsv /importtsv.tsv

​ HBASE_ROW_KEY : rowkey

​ 剩下的数据要和列簇一一对应, 给定一个

hbase import CSV

CSV格式的文件时按照 " , " 进行分割的

bin/yarn jar /opt/app/hbase-1.3.1/lib/hbase-server-1.3.1.jar importtsv '-Dimporttsv.sperator=,' -Dimporttsv.columns=HBASE_ROW_KEY,info:name,f1:location,info:age importtsv /importcsv

rowkey的热点与表的设计原则

热点原理

假设一个region最多存储2000条记录, 如果rowkey设置成自增长的话, 如果数据存满, 就会触发split操作, 那么0-2000的数据就会分成两个操作, 那么region1里边存放的就是0-1000, region2里边存放的是1001-2000, 继续想表中添加数据, 因为rowkey是自增长的, 所以新来的数据的rowkey是2001, 这条数据会直接存放在region2中, 直到再次触发split操作, 分成region2-1, region2-2, 这样一直执行的话, 前边的region就会闲下来, 造成了资源的浪费.

如果rowkey设计不当, 就会造成大量的region浪费, 这就是rowkey热点. 为了避免热点的情况, 数据应该被写到多个region中, 而不是一个region

rowkey长度限制

rowkey的长度限制, 二进制数据, 可以是任意字符, 最多给64kb, 建议10-100个字节, 但是越短越好, 最好不要超过16个字节. 有两个原因

  1. 数据都是存储到hbase中的, 按照keyvalue进行存储的, 如果rowkey过长, 超过了100个字节, 假设有1000万条那么1000万条数据中rowkey的字节=100*1000万≈1G, 这样的话, rowkey就占用了很大的空间, 极大浪费了HFile资源
  2. memstore 将缓存数据到内存总, 如果rowkey过大, 内存的利用率就会降低, 将无法缓存更多的数据
rowkey的设计原则
  1. 利用Hash散列将rowkey打乱
  2. UUID+时间戳的方式(联通采用的设计)
    • UUID : 手机号
    • 时间戳: 通话记录
    • 通过建立索引表, 然后将时间戳+UUID反过来
  3. 如果hbase就是作为海量存储的, 不是频繁查询的话, rowkey可以采用随机数的方式, 或者是MD5
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值