Presto Connector连接Kairosdb时序性数据库

2022-04-24 00:00:00 数据 对象 定义 接口 方法

Presto Connector连接Kairosdb时序性数据库
Presto Connector连接Kairosdb时序性数据库
Kairosdb数据关系型化
Presto Connector接口
Presto 插件
ConnectorFactory
Connector
ConnectorMetadata
getSplitManager
getRecordSetProvider
Presto Connector连接Kairosdb时序性数据库
Presto我就不用多说了,既然能搜到这篇文章肯定对presto有所了解,这玩意支持跨库跨表查询,牛逼异常啊。某天Leader跟我说让我看看Kairosdb数据库,我冥冥之中感觉到我可能走到一个大坑里长时间出不来的那种,至于Kairosdb数据库网上的资料很少,没办法,本人只能看着可怜的资料去学习。等初步掌握了Kairosdb的部署与使用后,果不其然Leader让我把我们的项目跟Kairosdb连接起来。因为我们项目底层使用的Presto,所以言外之意就是让Presto支持Kairosdb。我叫苦不迭啊····网上Kairosdb数据库的资料那么少,Presto Connector的样例更是凤毛麟角,官网的example-http给不了多大的帮助。还好哥们扛得住,在零零散散的博客与官网还有源码的阅读下···终于杀出一条血路!搞定了prestoConnector。Talk is cheap, Show me the code,废话不多说,各位看官准备好茶水瓜子准备往下看。

Kairosdb数据关系型化
Kairosdb数据库是一个时序性数据库,而Presto是以关系型数据库来查询处理数据的。所以我们首先要规定Kairosdb中的数据转化为关系型数据库的格式,我称之为关系型化;既然这哥们是个时序性数据库,那么肯定少不了时序性数据库的那几个重要元素:Metric、Tags、Timestamp、Value;咱们一个一个说;

Metric:Metric,指标。可以看作是关系型数据库中的表名;
Tags:标签,一个Metric中可以有多个Tag。对应的,可以看作是多个关系型数据库中的列;
Timestamp:时间戳,这玩意我不用多说了吧。在关系型数据库中可以看作为一个列来处理;
Value:值,也可一当作关系型数据库中的列来处理;
好啦,目前Kairosdb数据格式就先介绍这么多,那么一个Kairosdb的表(Metric)转为关系型数据库中的表后长什么样子呢?


Presto Connector接口
好啦,Kairosdb 关系型数据表已经定义好啦,接下来我们来了解一下Presto Connector接口吧。
关于Presto Connector接口官网上的说明实在是抠门,好像非死不可的开源软件都是这么毛病,还好,搜到一篇国内易到写的Presto Hbase Connector相关文章给了我很大的帮助。接下来我将详细的刨析一下Presto Connector接口

Presto 插件
在动手之前我跟各位码农一样,搜索了一下 Presto Connector相关资料,首先映入眼帘的就是咬定青松老哥写的PrestoConnector原理,这老哥写的博客很不错,从源码上分析出了Presto加载插件与加载catalog的流程。强烈推荐各位看官去看一下。根据青松老哥的博客说明,Presto 连接任何数据源都是通过加载Connector插件来完成的,而定义插件则是需要编写一个相应的properties配置文件放在{presto-dir}/etc/catalog下,以Kaiosdb为例


要开发Presto Connector 首先你要实现com.facebook.presto.spi接口,以我的Kairosdb为例


至于为什么我只定义了getConnectorFactories,问这个问题的看官肯定没仔细阅读咬定青松老哥的博客。
另外Presto是根据SPI方式来加载各个插件的,所以要在代码的src/main/resource目录下创建META-INF文件夹,在其之下还要创建service文件夹,在service文件夹下创建以com.facebook.presto.spi.Plugin命名的文本文件,文本文件内要写实现Plugin接口的类路径名例如:


完成以上准备工作后,就可以开始着手写接口代码了!

ConnectorFactory
上一章说到,要编写Connector插件代码,就要实现com.facebook.presto.spi.Plugin接口,那么在其实现类中,getConnectorFactories方法中返回的ConnectorFactory同样也需要咱们去实现com.facebook.presto.spi.connector.ConnectorFactory接口来完成。


该接口有三个方法需要实现
getName():获取Presto连接的连接名称,注意,这里的命名需要与kairosdb.properties catalog中的配置文件里面保持一致


getHandleResolver:该方法需要返回一个ConnectorHandleResolver的实现对象,该对象定义了在Connector插件中各个连接的句柄等操作;


各位看官在开发其他组件过程中按照需要返回的接口定义相应的实现类即可。
create:该方法我不用多说了哈,返回一个连接。


该url就是kairosdb.properties配置文件中的url。到这里可能有看官问了,为什么你的样例跟官方提供的样例不一样,官方使用的是Guice,而你怎么没用?我的回答是:······我也想用,但是老子不会!就这么简单,别管黑猫白猫,抓到耗子就是好猫~!

Connector
上一章说了,在create方法中需要返回一个Connector的实现类,那么我们撸一下Connector;
首先定义一个实现com.facebook.presto.spi.connector.Connector接口的类,


该接口需要实现4个方法,beginTransaction,getMetadata,getSplitManager,getRecordSetProvider,咱们一个一个唠:

beginTransaction:该类需要定义一个枚举,我根据官方的例子同样写了一个


注意,你定义的枚举类要与ConnectorFactory实现类中定义的getHandleResolver方法中返回的HandleResolver中getTransactionHandleClass方法中定义。(说句题外话,这个地方起初是没有实现的····所以我掉坑了,找了好久发现没有定义transactionHandleClass)

getMetadata:这个方法返回一个实现com.facebook.presto.spi.connector.ConnectorMetadata接口的对象;该对象定义了需要连接的数据源所有信息(schema,tables,table,column,columnType等)该接口下面再说

getSplitManager:该接口返回一个实现com.facebook.presto.spi.connector.ConnectorSplitManager接口的对象,该对象定义了数据源的切片split,如果你所需要连接的数据源不支持split,比如Kairosdb,那么我的做法是一个表就是一个split。

getRecordSetProvider:该接口返回一个实现com.facebook.presto.spi.connector.ConnectorRecordSetProvider接口的对象,该对象是实际读取数据源的对象,所有数据读的操作到这在里面。

ConnectorMetadata
该接口是Presto Connector 插件中的重中之重,这哥们定义了数据元的表,schema,column等元数据信息。来看看实现该接口需要哪些方法。

listSchemaNames:该方法对应Presto show schemas命令,用来展示Connector下有哪些数据库。方法实现也很简单,因为Kairosdb没有数据库的概念,所以直接写死Kairosdb即可。简单粗暴!


getTableHandle:获取指定表名的表句柄,实现非常简单,只需要定义一个com.facebook.presto.spi.ConnectorTableHandle的实现类即可,可以看到该接口没有任何需要实现的方法,咱们本着走前人的路的原则仿照官网的样例开发。


注意,该类其实是一个Bean类,presto用来组装json,需要序列化与反序列化,所以在其构造器上需要使用@JsonCreator注释,并在其每个属性都要使用@JsonProperty注释,并注意构建get方法。

getTableLayouts:该方法是返回一个表布局约束,老规矩根据官网的例子照抄即可。但是这里需要定义一个实现com.facebook.presto.spi.ConnectorTableLayoutHandle该接口的类代码如下:


listTables:查看给定schema下所有的表;对应presto show tables命令,实现方法如下:


这里KairosdbUtil.getTableName()是我自己开发的一个工具类,内部是使用Kairosdb内置的API来查询所有的Metric,因为Kairosdb有很多元数据Metric,万幸这些Metric都是以Kairosdb开头,所以只需要过滤即可。

getTableLayout:该方法获取指定表的layout,根据官网的例子直接使用内置的ConnectorTableLayout即可。


getTableMetadata:该方法顾名思义,获取给定表的元数据信息,所以该方法非常重要,首先要想知道kairosdb某一个Metric(表),需要你使用kairosdb的API设定开始时间1,查询当前Metric所有的Tags然后把这些Tag分别封装ColumnMetadata对象,该对象很简单,只需要定义column名与其类型即可,Tag建议定义varchar类型,代码如下:


如上代码所示,除了各个Tag,Kairosdb还有重要的两个列,TimeStamp与value,我们将其一起放入列的列表中去;
所以该接口实现代码如下:


getColumnHandles:该方法是获取给定table的每个列的handles。在该方法中要创建一个实现com.facebook.presto.spi.ColumnHandle的Bean类。注意,既然是Bean类,以Presto的套路来讲就是需要序列化与反序列化,所以···对你想的没错,需要使用jackjasn的注释。


该Bean类的属性分别为column的名称,类型,下标位置与连接ID(友情提示,别忘是定get方法);所以该方法的实现如下:


listTableColumns:没什么可说的,获取所有的表与其column的映射关系,废话不多说直接上代码:


getColumnMetadata:该方法获取某一列的元数据,实现非常简单直接调用KairosdbColumnHandle内部的实现方法


以上实现查询的ConnectorMetadata接口就已经完成。

getSplitManager
该方法获取切片的主要实现内容,需要定义一个实现com.facebook.presto.spi.connector.ConnectorSplitManager接口的类;
其中主要的为getSplits方法。该方法顶一个获取的切片方式。因Kairosdb不支持切片所以一个Metric就为一个切片(后续可优化为一天的数据一个切片)


getRecordSetProvider
该方法定义了真正读取数据源的逻辑。实现com.facebook.presto.spi.connector.ConnectorRecordSetProvider接口后发现只有一个方法getRecordSet。该方法返回一个RecordSet对象,那么好,咱么那就生成一个该对象,没错,同样的需要实现该接口com.facebook.presto.spi.RecordSet;
该接口需要实体化两个方法
getColumn*:该方法获取一行数据中所有的列的类型
cursor:该方法需要返回一个RecordCursor的实体对象。该对象中定义读取数据的逻辑;


RecordCursor对象需要实现以上方法,虽然多但不要慌,咱们一个一个看;
在该对象的构造器中获取一个split的所有数据,并赋值给一个迭代器:


advanceNextPosition:该方法判断是否还有下一行数据,实现很简单,使用迭代器的hasNext方法判断即可;
close:读取结束后关闭连接或者流的方法,Kairosdb的交互使用http协议,所以该方法可pass
getBoolean/getDouble/getLong/getSlice:这些方法都是获取相应类型的数据
isNull:判断数据是否为null
getType:获取某一个下表位置的列的类型

以上整个Connector插件开发完成
链接: 项目代码.

如有任何问题欢迎留言,咱们一起探讨~!

相关文章