记一次Hbase查询速度优化经历

时间:2022-04-17 01:00:37

项目背景

  在这次影像系统中,我们利用大数据平台做的是文件(图片、视频等)批次的增删改查,每个批次都包含多个文件,上传完成以后要添加文件索引(文件信息及批次信息),由于在Hbase存储的过程中,每个文件都对应一个文件rowKey,一个批次就会有很多个RoweKey,查询的下载的时候就必须根据每个文件的rowkey找到对应的文件,如果一个批次有很多个文件的话,就需要查找很多次,这样是很浪费时间的,一开始没注意这么多,开发并且完成功能测试后,觉得一切OK,但是作为大数据后台,对效率的要求非常高,在压力测试的时候出现了问题,并发量上来之后,查询下载的速度非常慢,TPS总上不去,仔细分析代码后,发现了问题。

改进之前的部分代码如下:

public List<FileInfo> batchGetFileMeta (String systemType, String batchNo,

                         String fileName,String versionNo,BufferedOutputStream bw) {

                 List<FileInfo> fileInfoList = new ArrayList<FileInfo>();
FileStoreInfo fileStoreInfo = batchGetFileStoreInfo(systemType,batchNo, versionNo,bw);
if(fileStoreInfo == null){
return null;
}
List<String> fileNameList=batchGetFileNameByBathNO(systemType,batchNo, fileName,
versionNo,bw);
if(fileNameList == null || fileNameList.size()==0 ){
return null;
}
if(fileNameList.size()==1 && ("".equals(fileNameList.get(0)))){
fileInfoList.add(null);
return fileInfoList;
}
int hash = batchNo.hashCode();
String rowKey = "";
String fileNName = fileStoreInfo.getFile_N_Name();
String[] fileNNameArray = fileNName.split(Constants.SPLIT);
for(int i=0;i<fileNNameArray.length;i++){
for(int j=0;j<fileNameList.size();j++){
String[] fileNInfo = fileNNameArray[i].split(Constants.SPLITF);
if(fileNInfo[0].equals(fileNameList.get(j))){
String version = fileNInfo[1];
String versionNow = version;
if(versionNow != null && !versionNow.equals("")){
int length2 = versionNow.length();
for (int k=0 ;k<3-length2 ;k++) {
versionNow = "0"+versionNow;
}
}
rowKey = hash + "1" +batchNo + versionNow + fileNInfo[0];
FileInfo fileInfo = batchGetFileMetaByIndex(systemType, rowKey, bw);
if(fileInfo == null){
return null;
}
fileInfo.setFileVersionNO(version);
fileInfoList.add(fileInfo);
}
}
}
return fileInfoList;
}
public FileInfo batchGetFileMetaByIndex(String systemType, String rowKey,
BufferedOutputStream bw) {
Map<String,String> fileInfoMaps = new HashMap<String,String>();
fileInfoMaps = HbaseUtil.queryBykey(Constants.HBASE_TAB+systemType, rowKey,
Constants.HBASE_FAMILYY_CF1, Constants.HBASE_COLUMN_L);
if(fileInfoMaps == null ){
return null;
}
String fileInfoStr = fileInfoMaps.get("value");
FileInfo fileInfo = new FileInfo();
fileInfo = (FileInfo) Utils.jsonToObj(fileInfoStr,fileInfo);
if(fileInfo == null){
return null;
}
String userdefinede = getUserDefinedE(systemType, rowKey);
fileInfo.setUserDefined(userdefinede);
return fileInfo;
}
public Map<String,String > queryBykey(String tableName, String rowKey,String fam, String col) {
Map<String, String> result = new HashMap<String, String>();
HTable table=null;
try {
if(isExistTable(tableName)){
table = new HTable(conf, tableName);
Get scan = new Get(rowKey.getBytes());
Result r = table.get(scan);
byte[] bs = r.getValue(Bytes.toBytes(fam), Bytes.toBytes(col));
String value = Bytes.toString(bs);
result.put("value", value);
table.close();
return result;
}else{
return null;
}
} catch (IOException e) {
e.printStackTrace();
return null;
}

测试结果如下:

记一次Hbase查询速度优化经历

  虽然时间比较少,但是远远不能满足效率要求。仔细分析上面代码不难发现:由于业务需要查询数据的时候要校验文件信息,所以代码中出现了循环套循环的情况,如果某批次的文件数量特别多的话那么循环查询的次数的增长不是一个数量级的,相当大的一个数字,问题的原因在于拼接rowkey,然后拿着rowkey去查询,循环多少次就查多少次,虽然Hbase查询速度快,但这样也是在浪费时间,经过思考和研究HbaseAPI的时候发现,Hbase支持rowkey批量查询,思路大概是这样的:

1)  循环文件信息,循环之中得到拼接rowkey的信息

2)  把得到的rowkey放入list中

3)  循环完毕,用List去查Hbase,将得到的信息放入Map返回

4)  获取Map中的信息

下面是改进之后的代码:

改进后:

public List<FileInfo> batchGetFileMetaByBathNo(String systemType, String batchNo,
String fileName,String versionNo,BufferedOutputStream bw) {
List<FileInfo> fileInfoList = new ArrayList<FileInfo>();
FileStoreInfo fileStoreInfo =batchGetFileStoreInfo(systemType, batchNo, versionNo,bw);
if(fileStoreInfo == null){
return null;
}
List<String>fileNameList=batchGetFileNameByBathNO(systemType, batchNo, fileName,
versionNo,bw);
if(fileNameList == null || fileNameList.size()==0 ){
return null;
}
if(fileNameList.size()==1 && ("".equals(fileNameList.get(0)))){
fileInfoList.add(null);
return fileInfoList;
}
String rowKey = "";
List<String> rowkeylist=new ArrayList<>(); String fileNName = fileStoreInfo.getFile_N_Name();
String[] fileNNameArray = fileNName.split(Constants.SPLIT);
for(int i=0;i<fileNNameArray.length;i++){
for(int j=0;j<fileNameList.size();j++){
String[] fileNInfo = fileNNameArray[i].split(Constants.SPLITF);
if(fileNInfo[0].equals(fileNameList.get(j))){
String version = fileNInfo[1];
String versionNow = version;
if(versionNow != null && !versionNow.equals("")){
versionNow=PublicMethod.chengeVerNo(versionNow);
}
rowKey = batchNo.hashCode()+"1"+batchNo+ versionNow + fileNInfo[0];
rowkeylist.add(rowKey);
}
}
}
fileInfoList = batchGetFileMetaByIndex(systemType, rowkeylist, bw);
return fileInfoList;
} public List<FileInfo> batchGetFileMetaByIndex(String systemType, List<String> rowKey,
BufferedOutputStream bw) {
List<FileInfo> fileInfoList=new ArrayList<>();
List<Map<String,String>>list=HbaseUtil.queryByList(Constants.HBASE_TAB+systemType,
rowKey);
if(list.size()==0){
return null;
}
for(Map<String,String> resultMap:list){
FileInfo fileInfo = new FileInfo();
String LValue = resultMap.get(Constants.HBASE_COLUMN_L);
String EValue=resultMap.get(Constants.HBASE_COLUMN_E);
if(!"".equals(LValue)&&null!=LValue){
fileInfo = (FileInfo) Utils.jsonToObj(LValue,fileInfo);
}
if(!"".equals(EValue)&&null!=EValue&&fileInfo!=null){
fileInfo.setUserDefined(EValue);
}
fileInfoList.add(fileInfo);
}
return fileInfoList;
} public List<Map<String, String>> queryByList(String tableName,List<String> rowKeyList){ Connection connection=null;
List<Map<String, String>> list=new ArrayList<>();
List<Get> getList=new ArrayList<Get>();
try {
connection=ConnectionFactory.createConnection(conf);
Table table=connection.getTable(TableName.valueOf(tableName));
for(String rowKey:rowKeyList){
Get get=new Get(Bytes.toBytes(rowKey));
get.addFamily(Bytes.toBytes(Constants.HBASE_FAMILYY_CF1));
getList.add(get);
} Result[]results=table.get(getList);
for (Result result:results) {
Map<String, String> listMap=new HashMap<>();
for(Cell kv:result.rawCells()){
if(Bytes.toString(kv.getQualifier()).equals(Constants.HBASE_COLUMN_E)){
listMap.put(Constants.HBASE_COLUMN_E,
Bytes.toString(CellUtil.cloneValue(kv)));
}else{
listMap.put(Constants.HBASE_COLUMN_L,
Bytes.toString(CellUtil.cloneValue(kv)));
}
}
list.add(listMap);
}
} catch (IOException e) {
e.fillInStackTrace();
}finally{
try {
if(connection!=null&&!connection.isClosed()){
connection.close();
}
} catch (IOException e) {
e.fillInStackTrace();
}
}
return list;
}

  Hbase是支持批量查询的,经过改进之后,从代码中就可以看出,效率提升了很多,我们对10000条数据进行了测试,发现提升的效率非常明显,下面是测试图:

记一次Hbase查询速度优化经历

  进过优化后,从时间上,我们可以看到,提升的效率非常明显,这就告诉我们在做项目写代码的时候,不要只局限于功能的实现,还要考虑效率上的可行性,从一开始就要做好铺垫,否则到后期再改是非常麻烦的。

记一次Hbase查询速度优化经历的更多相关文章

  1. mysql索引原理及查询速度优化

    一 介绍 为何要有索引? 一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题,在生产环境中,我们遇到最多的,也是最容易出问题的,还是一些复杂的查询操作,因此对查询语句 ...

  2. HBase查询速度慢原因排查

    问题:通过HBase访问服务在HBase中查询 ASSET_NORMAL 表速度很慢 如下,查询一条数据需要2.970s时间: 如下,统计总条数需要14.675s时间: HBase访问服务部署了3个节 ...

  3. SAP内表查询速度优化实例-OPEN SQL

    一.FOR ALL ENTRIES IN 案例 今天碰到工单报工统计分析表查询速度特别慢 经查看源代码: SELECT afpo~dwerk afko~aufnr afpo~matnr AS plnb ...

  4. 记一次真实的webpack优化经历

    前言 公司目前现有的一款产品是使用vue v2.0框架实现的,配套的打包工具为webpack v3.0.整个项目大概有80多个vue文件,也算不上什么大型项目. 只不过每次头疼的就是打包所耗费的时间平 ...

  5. 记一次有惊无险的 JVM 优化经历

    转载:https://my.oschina.net/u/3627055/blog/2995973 背景 生产环境有二台阿里云服务器,均为同一时期购买的,CPU.内存.硬盘等配置相同.具体配置如下: 节 ...

  6. 提高查询速度:SQL Server数据库优化方案

    查询速度慢的原因很多,常见如下几种: 1.没有索引或者没有用到索引(这是查询慢最常见的问题,是程序设计的缺陷) 2.I/O吞吐量小,形成了瓶颈效应. 3.没有创建计算列导致查询不优化. 4.内存不足 ...

  7. 优化SQLServer数据库加快查询速度

    查询速度慢的原因很多,常见如下几种: 1.没有索引或者没有用到索引(这是查询慢最常见的问题,是程序设计的缺陷) 2.I/O吞吐量小,形成了瓶颈效应. 3.没有创建计算列导致查询不优化. 4.内存不足 ...

  8. SQL Server数据库 优化查询速度

    查询速度慢的原因很多,常见如下几种: 1.没有索引或者没有用到索引(这是查询慢最常见的问题,是程序设计的缺陷) 2.I/O吞吐量小,形成了瓶颈效应. 3.没有创建计算列导致查询不优化. 4.内存不足 ...

  9. Sql server2005 优化查询速度50个方法小结

    Sql server2005 优化查询速度50个方法小结   Sql server2005优化查询速度51法查询速度慢的原因很多,常见如下几种,大家可以参考下.   I/O吞吐量小,形成了瓶颈效应.  ...

随机推荐

  1. Unity 序列化 总结

    查找了 Script Serialization http://docs.unity3d.com/Manual/script-Serialization.html 自定义序列化及例子: http:// ...

  2. 使用 expect 命令执行自动分发系统

    一.命令 except 实例详解 1. 介绍 expect 使用场景 expect可以让我们实现自动登录远程机器,并且可以实现自动远程执行命令.当然若是使用不带密码的密钥验证同样可以实现自动登录和自动 ...

  3. vs&period;net 2005 C&num; WinForm GroupBOX 的BUG?尝试读取或写入受保护的内存。这通常指示其他内存已损坏

    其实很久没有写程序了,国庆难得有空闲,写了个游戏辅助机器人,程序写好能用后本想把UI控件放到GroupBox里归下分类,美化下界面,结果一运行报“尝试读取或写入受保护的内存.这通常指示其他内存已损坏” ...

  4. centos 服务器操作

     CENTOS下创建FTP登录用户 yum install vsftpd2.启动/重启/关闭vsftpd服务器[root@localhost ftp]# /sbin/service vsftpd re ...

  5. webpack打包后该如何访问项目?

    一.问题描述 开发环境,页面浏览都OK,产出文件后,直接打开产出目录的index.html,页面空白. 二.预期结果 能正常看到页面. 三.问题分析 你可能会在编译的最后看到如下一句话: Tip: b ...

  6. 038 lock wait timeout exceeded&semi;try restarting transaction

    场景:有两个会话,其中会话1在事务操作,会话2在等待这个事务操作完成,然后会有这个报错产生. 通过查询资料,在这里整理一下. 一:总结timeout参数的作用 1.操作 2.具体解释 1)connec ...

  7. 网易新网 spider

    # -*- coding: utf-8 -*- import os import sys import urllib.request import requests import re from lx ...

  8. sagas

    http://mp.weixin.qq.com/s?src=3&timestamp=1503011877&ver=1&signature=cngvQj8-8qYsYcHR-5A ...

  9. ADAMS与外部程序通信(Adams Command Server)

    The Adams Command Server is an Adams View (or Adams Car) component that manages communication betwee ...

  10. django官方文档--对静态文件的管理

    一.入门级理解: 在django中对静态文件的管理和模板(template)的思路是一样的.在模板的管理中django是把app用到 到的模板都保存到app目录下的templates子目录中. 静态文 ...