Skip to content

Commit

Permalink
增加使用ClientSideRegionScanner的查询方式
Browse files Browse the repository at this point in the history
  • Loading branch information
Crossoverrr committed May 31, 2019
1 parent 86bb95e commit ce0da37
Showing 1 changed file with 165 additions and 33 deletions.
198 changes: 165 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,28 @@

## 性能对比

| 环境 | 明细 |
| ------ | ------------------------- |
| 数据量 | 事件表500万条数据,90个字段 |
| 节点数 | 3 |
| 硬件 | 16逻辑核64G内存4T*2硬盘。给HBase分配了16G内存,读写各占40% |
| 环境 | 明细 |
| ------ | ------------------------------------------------------------ |
| 数据量 | 事件表500万条数据,90个字段 |
| 节点数 | 3 |
| 硬件 | 16逻辑核 64G内存(其中Presto和RegionServer各占16G内存) 4T*2硬盘 |

![analysys-hb-performance.png](https://github.com/analysys/presto-hbase-connector/blob/master/imgs/analysys-hb-performance.png?raw=true)

详细测试结果参见:https://github.com/analysys/public-docs/blob/master/Attachment5(Presto-HBase-Connector-PerformanceTesting).xlsx

## 功能点对比

| 功能点 | 易观 | 其他 |
| ------------------- | ------------ | ------ |
| 加盐查询 | 支持 | 不支持 |
| 拼接StartKey/EndKey | 支持 | 不支持 |
| 批量Get查询 | 支持 | 不支持 |
| 谓词下推(Filter) | 支持 | 不支持 |
| ClientSideScan | 商业版已实现 | 不支持 |
| Insert | 后续支持 | 支持 |
| Delete | 后续支持 | 支持 |
| 建表语句 | 后续支持 | 支持 |
| 功能点 | 易观 | 其他 |
| ------------------- | -------- | ------ |
| 加盐查询 | 支持 | 不支持 |
| 拼接StartKey/EndKey | 支持 | 不支持 |
| 批量Get查询 | 支持 | 不支持 |
| 谓词下推(Filter) | 支持 | 不支持 |
| ClientSideScan | 支持 | 支持 |
| Insert | 后续支持 | 支持 |
| Delete | 后续支持 | 支持 |
| 建表语句 | 后续支持 | 支持 |



Expand Down Expand Up @@ -64,41 +64,41 @@ meta-dir=/etc/presto/chbase

* connector.name

该配置固定设置为hbase
该配置固定设置为hbase

* zookeeper-quorum

相当于HBase API的hbase.zookeeper.quorum参数
相当于HBase API的hbase.zookeeper.quorum参数

* zookeeper-client-port

相当于HBase API的hbase.zookeeper.property.clientPort参数
相当于HBase API的hbase.zookeeper.property.clientPort参数

* hbase-cluster-distributed

相当于HBase API的hbase.cluster.distributed参数
相当于HBase API的hbase.cluster.distributed参数

* presto-workers-name

presto worker的hostname,以英文逗号间隔。

如果split-remotely-accessible配置为false,则该参数可以不设置。
presto worker的hostname,以英文逗号间隔。
如果split-remotely-accessible配置为false,则该参数可以不设置。

* presto-server-port

与{Presto_Config_Dir}/config.properties配置文件的http-server.http.port参数
与{Presto_Config_Dir}/config.properties配置文件的http-server.http.port参数

* random-schedule-redundant-split

Presto默认采用按可用Worker的顺序,依次分配Split的方式调度Split。

这样容易导致多表查询时,第余数个Split集中调度到可用Worker列表开头的几台机器上。

将这个参数设置为true可以改为将第余数个Split随机调度到一个Worker上执行。
Presto默认采用按可用Worker的顺序,依次分配Split的方式调度Split。
这样容易导致多表查询时,第余数个Split集中调度到可用Worker列表开头的几台机器上。
将这个参数设置为true可以改为将第余数个Split随机调度到一个Worker上执行。

* meta-dir

存放HBase表元数据信息的目录。
存放HBase表元数据信息的目录。

##### 2.配置namespace

Expand Down Expand Up @@ -215,7 +215,7 @@ mvn clean package
在组件中使用盐值需要在json文件中设置以下两个属性:
* rowKeySaltUpperAndLower

该属性用来定义盐值的数值范围,如果设置为"0,29",则会从00到29依次生成30对startKey和endKey,每一对startKey和endKey会交给一个split去做数据扫描。如下:
该属性用来定义盐值的数值范围,如果设置为"0,29",则会从00到29依次生成30对startKey和endKey,每一对startKey和endKey会交给一个split去做数据扫描。如下:

```
(00, 00|)
Expand All @@ -229,7 +229,7 @@ mvn clean package

* rowKeySeparator

RowKey的不同组成部分之间的分隔符,默认是\001
RowKey的不同组成部分之间的分隔符,默认是\001

##### 2.根据RowKey的组成拼接StartKey和EndKey

Expand Down Expand Up @@ -258,11 +258,11 @@ select xwhat, xwho, date, xwhen from t_event_test where xwhat='login' and xwho i

* rowKeyFormat

定义RowKey是由哪些字段有序组成。以刚才的例子来说,该参数应该配置为"xwhat,xwho"
定义RowKey是由哪些字段有序组成。以刚才的例子来说,该参数应该配置为"xwhat,xwho"

* rowKeySeparator

RowKey的不同组成部分之间的分隔符,默认是\001
RowKey的不同组成部分之间的分隔符,默认是\001

如果想查看sql具体切分出了哪些split,可以将日志级别设置为info,在server.log中查看。

Expand All @@ -281,3 +281,135 @@ select * from t_event_test where rk in ('rk1', 'rk2', 'rk3');
使用这个查询模式,要求必须在表的json文件中通过isRowKey指定RowKey字段。

注意:因为我们定义的RowKey字段是虚拟字段,所以对它做除等值查询之外的其他类型的查询都是没有逻辑意义的。

##### 4.ClientSideRegionScanner

ClientSideRegionScanner是HBase在0.96版本新增的Scanner,他可以在Client端直接扫描HDFS上的数据文件,不需要发送请求给RegionServer,再由RegionServer扫描HDFS上的文件。
这样减少了RegionServer的负担,并且即使RegionServer处于不可用状态也不影响查询。同时,因为是直接读取HDFS,所以在负载较为均衡的集群中,可以基本实现本地读策略,避免了很多网络负载。

下图是ClientSideRegionScanner与普通RegionScanner的性能对比,通过比较可以得出,大部分查询都有了30%以上的提升,尤其是接近全表扫描的查询性能提升更为明显:

![ClientSide&NormalScanner.png](https://github.com/analysys/presto-hbase-connector/blob/dev_0.1.1/imgs/ClientSide-NormalScanner.png?raw=true)

详细测试结果参见:https://github.com/analysys/public-docs/blob/master/Attachment6(Presto-HBase-Connector-PerformanceTesting-ClientSide).xlsx

使用ClientSide查询需要设置以下三个参数:

* hbase-rootdir

这个参数与hbase-site.xml的hbase.rootdir保持一致即可。

* enable-clientSide-scan

是否开启ClientSide查询模式。

* clientside-querymode-tablenames

定义哪些表需要使用ClientSide查询,表名之间用英文','间隔,例如:

```
namespace_a:table_a,namespace_a:table_b,namespace_b:table_c
```

如果所有表都要使用ClientSide查询,可以配置成*

除以上三个参数之外,打包时还需要将运行环境中hadoop的core-site.xml和hdfs-site.xml两个配置文件拷贝到project的src/main/resources目录下

需要注意的是,ClientSideRegionScanner的查询是依赖Snapshot的,所以为了查询能获取到最新的数据,每次查询时都会自动创建一个命名规则如下的Snapshot:

```
"ss-" + schemaName + "." + tableName + "-" + System.nanoTime()
```

HBase最大可支持的Snapshot数为65536个,所以在使用ClientSideRegionScanner时最好能够做到定时清理过期Snapshot。

## 问题解决

##### 1.如何让ClientSideRegionScanner可以查询Snappy压缩格式的HBase表?

你需要解决以下几个问题:

###### 1) SnappyCodec找不到的问题

这是因为在Presto的classPath中缺少hadoop-common-2.7.3.jar这个jar包。因为我们是基于ambari搭建的presto,所以需要将这个jar包拷贝到/usr/lib/presto/lib目录下。

###### 2) SnappyCodec无法转换为CompressionCodec的问题

经过定位发现Presto加载插件的类是采用自定义的PluginClassLoader,而SnappyCodec是采用AppClassLoader加载的。二者classLoader不同导致父类和子类不具备父子继承关系。

修改hbase-common-1.1.2.jar中代码,将SnappyCodec使用PluginClassLoader的方式加载解决了这个问题。需要修改的代码为hbase-common模块的org.apache.hadoop.hbase.io.compress.Compression类,修改方法如下:

```
/**
* Returns the classloader to load the Codec class from.
*/
private static ClassLoader getClassLoaderForCodec() {
/*修改前:
ClassLoader cl = Thread.currentThread().getContextClassLoader();
if (cl == null) {
cl = Compression.class.getClassLoader();
}*/
// 修改后:
ClassLoader cl = Compression.class.getClassLoader();
if (cl == null) {
cl = Thread.currentThread().getContextClassLoader();
}
if (cl == null) {
cl = ClassLoader.getSystemClassLoader();
}
if (cl == null) {
throw new RuntimeException("A ClassLoader to load the Codec could not be determined");
}
```

用修改后的代码重新install maven仓库,再重新打组件jar包即可。

###### 3) java.lang.UnsatisfiedLinkError: org.apache.hadoop.util.NativeCodeLoader.buildSupportsSnappy()Z

这是需要在jvm中增加hadoop的native snappy库。可以在presto的jvm.config中,增加如下配置:

```
-Djava.library.path={path to hadoop native lib}
```

###### 4) java.io.IOException: java.lang.NoSuchMethodError: com.google.common.base.Objects.toStringHelper(Ljava/lang/Object;)Lcom/google/common/base/Objects$ToStringHelper;

这是因为guava在v20.0以上的版本去掉了com.google.common.base.Objects中实现的内部类ToStringHelper,以及几个toStringHelper的方法。

可以从低版本中将这些删除的代码增加到高版本的guava源码中,重新编译更新maven库中的guava-24.1-jre.jar之后,再重新构建presto-hbase.jar包。

并将guava-24.1-jre.jar上传到PrestoWorker的lib目录中。

或者使用maven的shade插件来解决这类jar包冲突的问题。

###### 5) Stopwatch的构造函数找不到

将guava的com.google.common.base.Stopwatch类中的构造函数改为public即可。

或者使用shade来解决这类jar包冲突的问题。

###### 6)Caused by: org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.security.AccessControlException): Permission denied: user=presto, access=WRITE, inode="/apps/hbase/data/data/db_moredatatest/multifamily_90cq_7cf_500w_snappy2/dee9b34c5cd8ee34f74ff5fc5446432a/.tmp":hbase:hdfs:drwxr-xr-x
权限不足,因为hbase对自身的数据文件权限都是hbase用户之下,而我们通过presto查询使用的是presto用户,需要给presto用户授予读取权限。

##### 2.如何在Idea中debug开发ClientSideRegionScanner查询以Snappy格式进行压缩的HBase表?

你需要解决以下几个问题:

###### 1) 找不到类CanUnbuff

在presto-hbase-connector模块中增加如下dependency:

```
<dependency>
<groupId>com.facebook.presto.hadoop</groupId>
<artifactId>hadoop-apache2</artifactId>
<version>2.7.4-1</version>
</dependency>
```

###### 2) 使用hbase-shaded-client和hbase-shaded-server依赖

###### 3) 参考“SnappyCodec无法转换为CompressionCodec的问题”部分,修改hbase-common模块的代码,并重新编译更新maven库。其中hbase-shade-client、hbase-shade-server和hbase-common这三个模块必须重新编译。

###### 4) 在idea的run->Edit Configuration中配置-Djava.library.path到PrestoServer的VM options中。java.library.path就是hadoop的native snappy库路径。

0 comments on commit ce0da37

Please sign in to comment.