数据源管理背景描述
大数据+AI是时代的必然走向,很多企业已经初步或较为完整的建立了数据仓库,数仓能力是数据驱动的必要能力。日渐庞大的数据量,要求企业必须能够有效地管理自己拥有的数据,那围绕这个领域,很多公司或开源组织都有所尝试,典型的如数据血缘,而今天讨论的内容也是这个问题的一个子集。
就一个企业而言,其使用的数据承载平台可能是多样化的。目前很多企业的数仓是以HDFS+Hive的技术栈来实现,并且其数据血缘关系也仅仅在Hive层面打通,这个局域的数据血缘图谱或许已经能够满足其80%以上的需求。但这仍然不够,对于跨系统之间的数据传输的数据血缘是无法得到的,这个问题在很多公司会变得比较棘手,规模越大的公司,这个问题会愈加尖锐,如google或Linkedin。google公司内部采用了很多存储平台,这些存储平台之间的数据集的交换会很频繁,系统之间的数据血缘的隔离,必然会导致数据使用非常的困难,针对这个问题,google通过收集不同系统之间的数据信息来解决这个问题,相关的实现可以参考google的goods论文,linkedin也是在该论文的基础之上做了一些完善。
很多企业规模不是那么大的公司或部门,对多系统之间的数据血缘也不是强依赖的,它可能仅在公技部门提供的数仓平台工具上建立了自己业务线的数仓,就像我们这里现在的情况一样。但不可避免的问题源数据据到数仓的链路的信息是相对比较缺失的,外部数据源的多样化特点决定了数据进入数仓可能会千差万别,给数据源的管理带来了很大的困难,尤其是中间再经过人事变动,会导致之后的源数据会丢失等等,因此我们想将数据源这块给监控起来,并能够将数据源到数仓这个链路的数据血缘弥补起来。
方案构想
这块内容涉猎的不多,仅做一些设想。
首先看下当前外部数据源导入的可能的主流方式:Sqoop,Datax,flume(其他待补充)。
是不是可以把问题等价于如何将这几种数据导入的方式监控起来?如果假设成立,那以什么样的方式来解决?
以前接触过Apache Atlas的,Apache Atlas通过Hook功能来解决不同系统之间数据传输的元数据采集,这给当下要解决的问题带来新思路。不知道是Sqoop给Atlas留的Hook的口子,还是Atlas利用了Sqoop,但这些都不重要,重要的是这种方案是可以重用的,其他的Hadoop生态体系下都有类似的Hook功能,如Storm,Hive,Impala, Hbase等,如果对这些数据导入的渠道有监控的需要,都可以重用,此处先感谢Atlas提供的思路以及其对这项工作的推进。Datax和flume也可以利用类似的方案,经过调研,Datax支持Hook功能,而flume支持Custom Reporting,如果能够将这些不同的数据导入的方式的元数据统一起来,进而做自己想做的事情,如数据源管理(至于管理要做什么事情,要看业务的需求),或绘制数据血缘。
元数据获取与元数据内容调研
1. Datax
元数据获取
Datax支持用户自定义Hook,对代码无入侵。Datax会扫描${DATAX_HOME}/hook
下所有一级子目录,每个子目录当作一个Hook的目录,加载里头的jar,使用ServiceLoader机制调用。对于每个子目录,必须符合ServiceLoader的标准目录格式,见http://docs.oracle.com/javase/6/docs/api/java/util/ServiceLoader.html。
Hook组件需要遵循ServiceLoader
元数据内容
Datax的Hook执行器在执行Hook时会将Job的conf信息以及Job执行完成后的统计信息作为上下文传入到Hook中,因此,收集Datax的元数据信息便可以从conf和统计信息入手。
- conf信息
Datax启动Job时会以一个json文件作为Job的配置文件。一个经典的配置文件如下,从中可以获取Job的源以及去向,这可以很好的解决数据从哪里来到哪里去的问题,要注意的是Datax支持多种reader插件和writer插件,每一种插件的parameter中的配置格式也是不同的,因此收集元数据信息时需要能够对不同的插件做适配:
{
"job": {
"content": [
{
"reader": {
"name": "mysqlreader",
"parameter": {
"column": ["id","qiye","diqu"],
"connection": [
{
"jdbcUrl": ["jdbc:mysql://[HOST_NAME]:PORT/[DATABASE_NAME]"],
"table": ["***"]
}
],
"password": "***",
"username": "***",
"where": ""
}
},
"writer": {
"name": "oraclewriter",
"parameter": {
"column": ["id","qiye","diqu"],
"connection": [
{
"jdbcUrl": "jdbc:oracle:thin:@[HOST_NAME]:PORT:[DATABASE_NAME]",
"table": ["***"]
}
],
"password": "***",
"preSql": ["delete from ceshi"],
"username": "***"
}
}
}
],
"setting": {
"speed": {
"channel": "1"
}
}
}
}
- 统计信息
每一个字段基本可以靠名称识别出来,在此不做详细说明。这些统计数据可以用于任务的执行状态的监控。
public static final String STAGE = "stage";
public static final String BYTE_SPEED = "byteSpeed";
public static final String RECORD_SPEED = "recordSpeed";
public static final String PERCENTAGE = "percentage";
public static final String READ_SUCCEED_RECORDS = "readSucceedRecords";
public static final String READ_SUCCEED_BYTES = "readSucceedBytes";
public static final String READ_FAILED_RECORDS = "readFailedRecords";
public static final String READ_FAILED_BYTES = "readFailedBytes";
public static final String WRITE_RECEIVED_RECORDS = "writeReceivedRecords";
public static final String WRITE_RECEIVED_BYTES = "writeReceivedBytes";
public static final String WRITE_FAILED_RECORDS = "writeFailedRecords";
public static final String WRITE_FAILED_BYTES = "writeFailedBytes";
public static final String TOTAL_READ_RECORDS = "totalReadRecords";
private static final String TOTAL_READ_BYTES = "totalReadBytes";
private static final String TOTAL_ERROR_RECORDS = "totalErrorRecords";
private static final String TOTAL_ERROR_BYTES = "totalErrorBytes";
private static final String WRITE_SUCCEED_RECORDS = "writeSucceedRecords";
private static final String WRITE_SUCCEED_BYTES = "writeSucceedBytes";
public static final String WAIT_WRITER_TIME = "waitWriterTime";
public static final String WAIT_READER_TIME = "waitReaderTime";
public static final String TRANSFORMER_USED_TIME = "totalTransformerUsedTime";
public static final String TRANSFORMER_SUCCEED_RECORDS = "totalTransformerSuccessRecords";
public static final String TRANSFORMER_FAILED_RECORDS = "totalTransformerFailedRecords";
public static final String TRANSFORMER_FILTER_RECORDS = "totalTransformerFilterRecords";
2. Sqoop
元数据获取
Sqoop原生支持Hook,因此可以通过实现Sqoop的Hook接口来获取想要的数据信息。
具体的方式可以通过以下步骤来完成(Sqoop1.4.7之前的版本):
- 将实现了Hook的jar拷贝到Sqoop的lib下
- 在sqoop的配置文件中增加配置:
<property> <name>sqoop.job.data.publish.class</name> <value>${your_sqoop_class_full_name}</value> </property>
元数据内容
一个经典的sqoop任务如:
sqoop import \
--connect jdbc:mysql://hadoop001:3306/sqoop \
--username root \
--password 123456 \
--table emp_etl \
-m 1 \
--hive-import \
--create-hive-table \
--hive-table emp_mysql
产生的元数据信息如下:
String operation; // sqoop的操作类型, 上面的例子是import
String user; // hadoop的用户信息
String storeType; // 连接类型,上面的例子是jdbc
String storeTable; // 源表,从 --table读取
String storeQuery; // 导入SQL“语句”,从--query读取
String hiveDB; // --hive-database <database-name>:在导入到hive时设置数据库名
String hiveTable; // --hive-table <table-name>:设置导入到hive时使用的表名
Properties commandLineOpts; // 更丰富的参数信息,非常的详细,包括column信息等。
long startTime;
long endTime;
String url; // 从--connect读取
3. Flume
元数据获取
Flume的监控支持多种方式:JMX Reporting、Ganglia Reporting、JSON Reporting、Custom Reporting。
元数据内容
除了Custom Reporting,其上报的信息只是一些统计相关的指标,如下:
-
SOURCE
SOURCE作为flume的数据源组件,所有收集日志的第一个到达的地方,它的监控信息非常重要。通过监控我们能够得到的监控数据有这些:OpenConnectionCount(打开的连接数) Type(组件类型) AppendBatchAcceptedCount(追加到channel中的批数量) AppendBatchReceivedCount(source端刚刚追加的批数量) EventAcceptedCount(成功放入channel的event数量) AppendReceivedCount(source追加目前收到的数量) StartTime(组件开始时间) StopTime(组件停止时间) EventReceivedCount(source端成功收到的event数量) AppendAcceptedCount(放入channel的event数量)等
-
CHANNEL
CHANNEL是flume的一个通道组件,对数据有一个缓存的作用。能够得到的数据:EventPutSuccessCount(成功放入channel的event数量) ChannelFillPercentage(通道使用比例)、Type(组件类型) EventPutAttemptCount(尝试放入将event放入channel的次数) ChannelSize(目前在channel中的event数量) StartTime(组件开始时间)、StopTime(组件停止时间) EventTakeSuccessCount(从channel中成功取走的event数量) ChannelCapacity(通道容量) EventTakeAttemptCount(尝试从channel中取走event的次数)等
-
SINK
SINK是数据即将离开flume的最后一个组件,它从channel中取走数据,然后发送到缓存系统或者持久化数据库。能得到数据:BatchCompleteCount(完成的批数量) ConnectionFailedCount(连接失败数) EventDrainAttemptCount(尝试提交的event数量) ConnectionCreatedCount(创建连接数) Type(组件类型) BatchEmptyCount(批量取空的数量) ConnectionClosedCount(关闭连接数量) EventDrainSuccessCount(成功发送event的数量) StartTime(组件开始时间) StopTime(组件停止时间) BatchUnderflowCount(正处于批量处理的batch数)等
不同的SINK、CHANNEL、SOURCE支持的指标程度是不一样的,详细说明可以参考:https://flume.apache.org/FlumeUserGuide.html#monitoring
根据我们的需求,我们需要能够获取到Sink、Source的配置信息以及Ip信息,这些信息可能需要通过Custom Reporting的方式来解决。