如何基于 HBase 构建图片、视频数据的统一存储检索方案|学习笔记

简介: 快速学习如何基于 HBase 构建图片、视频数据的统一存储检索方案

开发者学堂课程【HBase 入门与实战如何基于 HBase 构建图片、视频数据的统一存储检索方案】学习笔记,与课程紧密联系,让用户快速学习知识。

课程地址https://developer.aliyun.com/learning/course/808/detail/13900


如何基于 HBase 构建图片、视频数据的统一存储检索方案


内容介绍

一、背景介绍    

二、图片视频统一存储检索系统设计

三、图片视频统一存储检索系统编码实践

四、总结


一.背景介绍

1、需求情景

老板提出一个紧急需求,下周交付:

.我有非常多的文件需要存储,以图片和短视频为主,以后还会有更多

.每一个图片或者视频都会有很多的标签信息,我需要通过标签能快速的找到我想要的文件,不需要其他的操作,很简单的。

.你需要尽量节省资源

相当于我们能提供的资源不是很多,老板提出需求我们并不知道他背后可能想要的更到。不得不与目标客户交流。

和目标客户交流

.小王最近接收了一个图片模型训练的项目,需要线上批量拉取某种标签的图片进行模型训练,比如涉黄、涉暴,图片大小20k~10M。

.小李是短视频推荐系统的研发,需要一个可以存储和通过标签检索短视屏的服务,短视频文件大小200k~200MB,rt不敏感,吞吐量要求tps100+,qps200+,保存数据2个月以上。

2、需求分析

了解需求后看用户到底想要什么?

图片、视频统一存储检索系统,提供图片、视频文件的存储、检索服务(需要注意的是我们往往会给图片或者视频打上很多的标签,比如:涉黄、涉暴等等,这里提及的检索是根据标签进行检索),数据大多都是小文件(80%大小在数MB以内),数据体量大,增长快速等特点。

根据这些需求可以抽离出系统的功能点

功能需求

1.图片或者视频数据作为单独的对象存储到一个大容器中

2.应用可以通过标签查询来获取每个单独的对象数据(图片或者视频)

3.支持海量数据,高性能,可扩展,高可用

这些需求很急,下周就要交付。


二、图片视频统一存储检索系统设计

基于我们所了解的需求如何构建图片视频统一存储检索系统设计

1、技术选型

HBase,我为你转身

HBase的优势

1.HBase 可以很好的支持非结构化的数据存储,且基 HDFS保证数据的可靠性

2.HBase 吞吐量非常高,足够支撑业务

3.HBase 基于 Hadoop 集群,不需要单独重新维护其他数据存储服务

HBase 有哪些不足之处

1.HBase 对小文件(小于10MB)支持很好,但是对于较大的文件无法满足需求

2.由于 HBase 的设计,HBase 会发生 compact 和 split操作,文件存储会频繁的触发此类的操作导致写放大等不良的影响。

3.HBase 不适合复杂的检索操作,此系统想要标签查询,功能上可能会有限制

那么我们该如何来弥补这些不足呢?

大文件存储方案

1.方案一:比较容易想到的,将大文件分片存储在HBase中。比如100M的文件,按照1M一片,也就是将100M的文件分成100个分片存储在 HBase表里,但对后期的实践查询审核一些复杂的设计来保证整个流程可行。

2.方案二:将大文件支持存储到 HDFS 中,HBase 中只存储图片或者视频的元数据以及标签信息。即避免了将一个文件拆分成多个,而且可以充分用底层的 HDFS 来保证整体的数据可靠性。第二个方案架构如下所示:

image.png

用户直接将数据写入统一文件服务,统一文件服务进行判断,如果当前文件大于10M将数据存储在 HDFS 中,其他文件标签信息统一存储在 HBase 中。如果针对小于10M的文件可以直接存储在 HBase 中。

如何解决复查查询支持

1.HBase 本身根据字典排查,我们可以将一些较为固定的标签设计在 Rowkey 中,以便满足我们常规查询的需要

2.如果系统需要支持更加灵活的检索功能,我们也可以引入 phoenix 来构建二级索引或者 ElasticSearch 来满足我们的检索功能

2、技术构架

方案二统一存储检索系统架构图

        image.png

该项目是一个 SpringBoot 的项目,提供两种接口类型一种Rest 第二种 SDK,接口支持以下:

1. Bucket 的创建,删除,查询等接口

2.上传文件,查询文件内容以及基本的信息

3.根据标签信息查询获取文件信息以及文件的具体内容

在数据存储上,每一个 Bucket 对应 HBase 的一张表,对于小文件(我们将所有小于2MB的文件定义为小文件,而大于2M的文件者称为较大文件)直接存储在 HBase 的表中,而大于2MB文件我们存储在 HDFS 中,并且将文件的 Meta 信息存储在HBase的表中。

额外说明:

1.在下面的实践项目中,我们只是简单的实现其中的部分功能,针对于服务本身的高可用和 SDK 等功能并不加以实现。

2.对于检索功能而言也只是实现一些简单的检索功能。


三、图片视频统一存储检索系统编码实践

1、准备工作

购买HBase集群

·购买云HBase增强版服务

·用户密码在控制台->集群详情->账号管理页面链接串在数据库连接页面

配置集群

.开通公网服务

.获取连接配置

.将本机公网IP添加至白名单

.修改本机hosts配置,绑定 hdfs 的域名

配置开发环境

.下载并安装Idea开发环境

.在Spring模版生成器中生成项目模版,地址

https://start.spring.iol

.将生成好的项目导入Idea

购买 HBase 增强版服务,在用户控制台详情获取链接信息。配置集群公网、连接、本机的白名单。开发环境 Idea、Spring boot,本身此部分用 Spring boot 来构建。

表结构设计

2、HBase 表结构设计image.png

说明

1.设计 HBase 表格为了能够支持检索功能,在 RowKey 的设计上采用 BucketName+标签+key的方式,通过这种方式,可以使用 HBase前缀扫描的方式找到在一个特定 bucket 下标签为tag_1的数据。数据存储,文件的大小、过期时间、创建时间、bucket 名称。最后 content,针对相对小的文件直接将数据本身存储在 HBase 中,针对大文件在 content 里直接 hdfs 路径。

2.虽然这种设计可以满足我们检索的功能,但是这种设计在 RowKey 里,只能应用在一些标签相对比较固定的场景,而且会存在数据的热点问题。Bucket 插入数据较多本身有可能数据热点。

3.该设计对于删除操作不友好,在 RowKey 前面加了其它信息,所以用户删除只需要获取完整的信息包括标签信息,进行数据串的拼接,拼接完成后删除。单考虑到删除操作并不多,所以该设计在一定程度上还是可以满足我们的需求

3、项目目录介绍

common 目录

·公用层,包括工具类和基础的 bean 类

.controller 层,堆外提供的 api 接口

·Service 层,核心处理逻辑,包括对 HBase 和 HDFS 操作的封装类等

4、Service 层private void saveObject(TmobObject object, String bucket, String key, long size) throws I0Exception {

try {

String table = hbaseService.decorateTable(bucket);

HTablehTable=(HTable)hbaseService.getConn().getTable(TableName.valueof(table));

Put p=new Put(Bytes.toBytes(key));

if (size <mobFileThreshold) {

p.addColumn(Bytes.toBytes(TmobUtil.COLUMN_FAMILY_DEFAULT),Bytes.toBytes(TmobUtil.OBJ_CONTENT)

object.getData));

if(lp.isEmpty()){

hTable.put(p);

logger.info("put hbase " + bucket + " " + key);

}

}else {Pathpath=newPath(String.format(“/%s/%s"hdfsService.getRootPath(),bucket));

FileSystem fileSystem=hdfsService.getFileSystem() ;

if(lfileSystem.exists(path)){

fileSystem.mkdirs(path);

}

FSDataOutputStream fsDataOutputStream=fileSysten.create(newPath(String.format(“/%s/%s/%s”,hdfsService.getRootPath(), bucket,key)), overwrite: true);

try { fsDataOutputStream.write(object.getData()); fsDateOutputStream.flush();

} finally {

fsDataOutputStream.close();

}

p.addColumn(Bytes.toBytes(TmobUtil.COLUMN_FAMILY_DEFAULT),Bytes.toBytes(TmobUtil.OBJ_CONTENT)Bytes.toBytes(String.format(/%s/%s/%s”,hdfsService.getRootPath(),bucket,key)));

if(!p.isEmpty()){

hTable.put(p);

}

}

} catch (Exception e){

.服务端收到图片或者是视频文件的时候,首先会存储meta信息,接着判断文件的大小是否超过长度限制:

.如果没有超过那么我们会将文件的内容直接存储在HBase表中的fc: content

·如果长度超过了限制,那么我们先将文件写入到HDFS的特定的文件夹中,接着将文件的路径存储在fc:content

当用户上传文件,服务端的处理流程,服务端将文件 meta 信息存储在 HBase 表中,数据做以下判断

如果判断数据的长度,长度超过设置的限制,将数据写入 HDFS 中,文件的路径存储在 content 字段。如果长度没有超过限制,数据本身存储到 HBase 中。public List<Tmobobject> queryobject(String bucket, String tag) throws I0Exception {

List<TmobObject> objects =now ArrayList<();

try {

String table=hbaseService.decorateTable(bucket);

HTablehTable=(HTable)hbaseService.getConn().getTableTableName.valueOf(table)); String prefixString = String.format("%s_%s",bucket,tag); Scan scan=new Scan();scan.setRowPrefixFilter(Bytes.toBytes(prefixString)); scan.setCaching(18);

ResultScannerrs=hTable.getScanner(scan)

for(Resultr:rs){

TmobObjectMeta objectMeta=getObjectMeta(r);

Tmobobject tmobObject=newTmobobject();

tmobObject.setMeta(objectMeta);objectMeta.setStoreType(TmobType.HBASE.name()); tmobObject.setMeta(objectMeta);

tmobObject.setKey(Bytes.toHex(r.getRow());

if(objectMeta.getSize()<mobFileThreshold){tmobObject.setData(r.getValue(Bytes.toBytes(TmobUtil.COLUMN_FAMILY DEFAULT),

Bytes.toBytes(TnobUtil.OBJ_CONTENT)));

} else {

FileSystem fileSystem=hdfsServicegetFileSystem():String filePath=Bytes.toString(r.getValue(Bytes.toBytes(TmobUtil.COLUMN_FAMILY_DEFAULT)

Bytes.toBytos(TnobUtil.OBJ_CONTENT)));if (filePath ==null I I!fileSystem.exists(new Path(filePath))) {

continue;

}

objectMeta.setStoreType(TmobType.HDFS.name(());FSDataInputStreamInputStream=fileSystem.open(newPath(filePath));byte[]content=newbyte[inputStream.available()]:

inputStream.readFully(content);

tmobObiect.setData(content);

数据存储后用户通过某个标签查询时具体流程

服务端根据容器名称和标签组合进行模糊查询,获取文件的 Mate 信息,接着根据文件的长度进行判断:

.如果长度小于存放 HBase 的阈值,者说明文件是存储在 HBase 中的,直接从 HBase 中获取,整合数据之后返回给用

.如果长度大于存储 HBase 的阈值,者说明文件是存储在 HDFS 中,需要根据cf: content 中存储的文件路径从 HDFS 中获取文件信息,组装完成之后返回给用户。

5、效果显示

整个编码核心逻辑,最主要的核心在

HbaseObjectServiceimpl

在保存时进行判断,如果值小于在系统中配置的阈值

If(size<mobFileThreshold{

那么数据会存储在 HBase 中

p.addColumn(Bytes.toBytes(TmobUtil.COLUMN_FAMILY_DEFAULT),Bytes.toBytes(TmobUtil.OBJ_CONTENT)

object.getData());

if(lp.isEmpty()){

hTable.put(p);

logger.info("put hbase "+ bucket +""+ key);

如果大于在系统中配置的阈值,通过 HTTP 访问方式,创建容器,取名为 test_2

image.png

代表 bucket 创建成功

先上传一个较小的图片,如果小于10M的数据直接存储在 HBase。按照系统的设计256KB照片应该存储在 HBase,可以通过查询检查。

标记存储类型存储在 HBase 中,下面的数据是具体文件的数据。

image.png

再上传一个较大的文件,文件大约20多M,将大文件进行上传,用 bucket tag 进行查询

image.png

可以看到文件本身存储到 HDFS 中。

之前演示的效果图如下:

image.png


四、总结

虽然我们基本已经完成了老板交给待的任务,项目也正常上线了,但是从设计上我们依旧遗留两个问题

.RowKey 的热点问题,因为我们是将容器名称和标签作为前缀,那么势必当存储的文件达到一定程度之后会导致热点,影响 HBase 的稳定性。

.无法支持复杂的查询,并且由于用于查询条件的标签是开始就固定的 RowKey 当中的,所以对于之后如果想扩展标签的维度势必会照常困难。

那么正对上面的两个问题,我们应该如何解决呢?

.其实上面的两个问题,都是由于我们将 RowKey 作为查询的依据而产生的问题,那么我们是否可以将查询所使用到的字段不存储在RowKey 上呢?这样我们就可以使用一个随机的 RowKey 避免热点问题。答案是特定的。

.方案一:使用 HBase+phoenix 的方案,创建容器名称和标签的二级缩影,查询通过 phoenix 二级索引进行加速,支持更多字段的查询,后期扩展时只需要添加更多的二级索引,可以通过更多标签查询。

方案二:使用 HBase+ElasticSearch 方案,索引信息通过 hbase-indexer 服务同步到 ES 中,同步相当于标签信息,查询的时候先查询 ES 获取 RowKey 再从 HBase 中获取明细数据,通过 ES 可以支持更多复杂的查询条件。

是否有更好的方案?

image.png

阿里巴巴引动多能引擎,集成了宽表、时序、搜索、文件、键值,完全可以支持统一的存储,通过收纳的功能提供更复杂的查询来满足需求。

相关实践学习
lindorm多模间数据无缝流转
展现了Lindorm多模融合能力——用kafka API写入,无缝流转在各引擎内进行数据存储和计算的实验。
云数据库HBase版使用教程
&nbsp; 相关的阿里云产品:云数据库 HBase 版 面向大数据领域的一站式NoSQL服务,100%兼容开源HBase并深度扩展,支持海量数据下的实时存储、高并发吞吐、轻SQL分析、全文检索、时序时空查询等能力,是风控、推荐、广告、物联网、车联网、Feeds流、数据大屏等场景首选数据库,是为淘宝、支付宝、菜鸟等众多阿里核心业务提供关键支撑的数据库。 了解产品详情:&nbsp;https://cn.aliyun.com/product/hbase &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
1月前
|
缓存 监控 Shell
如何使用 HBase Shell 进行数据的实时监控和备份?
如何使用 HBase Shell 进行数据的实时监控和备份?
|
1月前
|
Shell 分布式数据库 Hbase
如何使用 HBase Shell 进行数据的批量导入和导出?
如何使用 HBase Shell 进行数据的批量导入和导出?
|
5月前
|
存储 分布式数据库 数据库
Hbase学习二:Hbase数据特点和架构特点
Hbase学习二:Hbase数据特点和架构特点
91 0
|
2月前
|
存储 监控 分布式数据库
百亿级存储架构: ElasticSearch+HBase 海量存储架构与实现
本文介绍了百亿级数据存储架构的设计与实现,重点探讨了ElasticSearch和HBase的结合使用。通过ElasticSearch实现快速检索,HBase实现海量数据存储,解决了大规模数据的高效存储与查询问题。文章详细讲解了数据统一接入、元数据管理、数据一致性及平台监控等关键模块的设计思路和技术细节,帮助读者理解和掌握构建高性能数据存储系统的方法。
百亿级存储架构: ElasticSearch+HBase 海量存储架构与实现
|
3月前
|
存储 分布式计算 分布式数据库
深入理解Apache HBase:构建大数据时代的基石
在大数据时代,数据的存储和管理成为了企业面临的一大挑战。随着数据量的急剧增长和数据结构的多样化,传统的关系型数据库(如RDBMS)逐渐显现出局限性。
518 12
|
5月前
|
缓存 监控 Shell
使用 HBase Shell 进行数据的实时监控和备份
使用 HBase Shell 进行数据的实时监控和备份
|
5月前
|
Shell 分布式数据库 Hbase
使用 HBase Shell 进行数据的批量导入和导出
使用 HBase Shell 进行数据的批量导入和导出
650 6
|
4月前
|
存储 分布式计算 分布式数据库
《HBase MapReduce之旅:我的学习笔记与心得》——跟随我的步伐,一同探索HBase世界,揭开MapReduce的神秘面纱,分享那些挑战与收获,让你在数据的海洋里畅游无阻!
【8月更文挑战第17天】HBase是Apache顶级项目,作为Bigtable的开源版,它是一个非关系型、分布式数据库,具备高可扩展性和性能。结合HDFS存储和MapReduce计算框架,以及Zookeeper协同服务,HBase支持海量数据高效管理。MapReduce通过将任务拆解并在集群上并行执行,极大提升处理速度。学习HBase MapReduce涉及理解其数据模型、编程模型及应用实践,虽然充满挑战,但收获颇丰,对职业发展大有裨益。
52 0
|
3月前
|
分布式计算 Java Hadoop
java使用hbase、hadoop报错举例
java使用hbase、hadoop报错举例
121 4
|
2月前
|
分布式计算 Hadoop Shell
Hadoop-35 HBase 集群配置和启动 3节点云服务器 集群效果测试 Shell测试
Hadoop-35 HBase 集群配置和启动 3节点云服务器 集群效果测试 Shell测试
80 4
下一篇
DataWorks