MRS HBase文件存储 HFS介绍
简介
HBase文件存储模块(HBase FileStream,简称HFS)是HBase的独立模块,它作为对HBase与HDFS接口的封装,应用在MRS的上层应用,为上层应用提供文件的存储、读取、删除等功能。
在Hadoop生态系统中,无论是HDFS,还是HBase,在面对海量文件存储的时候,在某些场景下,都会存在一些很难解决的问题:
- 如果把海量小文件直接保存在HDFS中,会给NameNode带来极大的压力。
- 由于HBase接口以及内部机制的原因,一些较大的文件也不适合直接保存到HBase中。
HFS的出现,就是为了解决需要在Hadoop中存储海量小文件,同时也要存储一些大文件的混合场景。简单来说,就是在HBase表中,需要存放大量的小文件(10MB以下),同时又需要存放一些比较大的文件(10MB以上)。
HFS为以上场景提供了统一的操作接口,这些操作接口与HBase的函数接口类似。必须在HBase的配置参数“hbase.coprocessor.master.classes”中增加一个值:“org.apache.hadoop.hbase.filestream.coprocessor.FileStreamMasterObserver”。
注意事项
- 如果只有小文件,确定不会有大文件的场景下,建议使用HBase的原始接口进行操作。
- HFS接口需要同时对HBase和HDFS进行操作,所以客户端用户需要同时拥有这两个组件的操作权限。
- HBase权限:用户需要用户对应表的读、写权限。另外,如果用户需要创建表,还需要有HBase的建表权限。具体的授权操作请参考《组件操作指南》中“创建HBase角色”章节。
- HDFS权限:用户需要具有HFS文件存储目录的读、写以及创建子目录的权限,具体的HFS文件存储目录可以通过FusionInsight Manager页面搜索对应HBase实例的服务配置参数“hbase.filestream.rootdir”来确认。
- 直接存放在HDFS中的大文件,HFS在存储时会加入一些元数据信息,所以存储的文件不是直接等于原文件的。不能直接从HDFS中移动出来使用,而需要用HFS的接口进行读取。
- 使用HFS接口存储在HDFS中的数据,暂不支持备份与容灾。
- 如果当前组件使用了Ranger进行权限控制,须基于Ranger配置相关策略进行权限管理,具体操作可参考《组件操作指南》中“添加HBase的Ranger访问权限策略”章节。
操作步骤
- 登录MRS Manager。
- 单击“集群 > 待操作集群的名称 > 服务 > HBase > 配置”,单击“全部配置”,然后在左边窗口选择 。
- 在“hbase.coprocessor.master.classes”配置项中增加值“org.apache.hadoop.hbase.filestream.coprocessor.FileStreamMasterObserver”。
- 单击“保存”在“保存配置”中单击“确定”,保存完成后重启HBase服务及其他受影响的服务或实例。
功能简介
一般都通过调用org.apache.hadoop.hbase.filestream.client.FSTableDescriptor创建HFS的table,通过org.apache.hadoop.hbase.filestream.client.FSHColumnDescriptor来指定哪个列簇是存储文件。
代码样例
以下代码片段在com.huawei.bigdata.hbase.examples包的“HFSSample”类的createTable方法中。
/** * Create HFS table. */ public void createTable() throws IOException { try (Admin admin = conn.getAdmin()) { LOG.info("Start to create table."); FSTableDescriptor tableDescriptor = new FSTableDescriptor(tableName); HColumnDescriptor normalCd = new HColumnDescriptor("I"); FSHColumnDescriptor largeCd = new FSHColumnDescriptor(Bytes.toBytes("F")); largeCd.setFileColumn(); largeCd.setFileThreshold(5 * 1024 * 1024); tableDescriptor.addFamily(normalCd); tableDescriptor.addFamily(largeCd); admin.createTable(tableDescriptor); LOG.info("Create table successfully."); } catch (IOException e) { throw new IOException("Create table failed!", e); } } /** * Delete HFS table. */ private void cleanup() throws IOException { try (Admin admin = conn.getAdmin()) { admin.disableTable(tableName); admin.deleteTable(tableName); } catch (IOException e) { throw new IOException("Delete table failed!", e); } }
解释
(1)创建HFS_TABLE表,其中创建列簇F为FSHColumnDescriptor,支持小文件和大文件存取。
(2)FSHColumnDescriptor.setFileColumn()设置了F列簇支持MOB和大文件存取;其中默认MOB的threshold是1K。
(3)FSHColumnDescriptor.setFileThreshold(5 * 1024 * 1024)设置大文件的threshold,默认是10M。
注意事项
- 必须在HBase的配置参数“hbase.coprocessor.master.classes”中增加一个值:“org.apache.hadoop.hbase.filestream.coprocessor.FileStreamMasterObserver”。
- 一张表中只允许有一个FSHColumnDescriptor存储小文件和大文件。
写HFS表
功能简介
一般都通过调用org.apache.hadoop.hbase.filestream.client.FSTable读写数据,通过org.apache.hadoop.hbase.filestream.client.FSPut封装客户端每条数据。
代码样例
以下代码片段在com.huawei.bigdata.hbase.examples包的“HFSSample”类的putFiles方法中。
/** * Put files to HBase. */ public void putFiles() throws IOException { FSTable fsTable = null; InputStream is = null; try { LOG.info("Start to put file to HBase."); fsTable = new FSTable(conf, "HFS_TABLE"); is = new FileInputStream(INPUTFILE); FSPut fsPut = new FSPut(Bytes.toBytes("FILE_ID_1")); fsPut.addFile("I", is); fsTable.put(fsPut); LOG.info("Put file to HBase successfully."); } catch (IOException e) { throw new IOException("Put file failed!", e); } finally { if (fsTable != null) { try { fsTable.close(); } catch (IOException e) { e.printStackTrace(); } } if(is != null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } }
读HFS表
功能简介
一般都通过调用org.apache.hadoop.hbase.filestream.client.FSTable读写数据,通过org.apache.hadoop.hbase.filestream.client.FSGet读取一个。
代码样例
以下代码片段在com.huawei.bigdata.hbase.examples包的“HFSSample”类的getFiles方法中。
/**
* Get files from HBase.
*/
public void getFiles() throws IOException {
FSTable fsTable = null;
try {
fsTable = new FSTable(conf, "HFS_TABLE");
// get FSFile
FSGet fsGet = new FSGet(Bytes.toBytes("FILE_ID_1"));
fsGet.addFile("I");
FSResult fsResult = fsTable.get(fsGet);
FSFile fsFile = fsResult.getFile("I");
if (fsFile == null) {
throw new IOException("File isn't exits : " + "FILE_ID_1");
}
InputStream is = fsFile.createInputStream();
} catch (IOException e) {
throw new IOException("Get file failed!", e);
} finally {
if (fsTable != null) {
try {
fsTable.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
- 点赞
- 收藏
- 关注作者
评论(0)