如何使用Jenkins构建和滚动存储库中表的元数据模型工件的工件

一切始于这样一个事实,即我们面临着快速,正确地形成EDWEX,JSON,DDL结构,然后将它们滚动到关系数据库的不同轮廓上的需求。 轮廓是指大家都知道的缩写-DEV,TST,UAT,PRD。



当时,我们几乎手动完成了所有工作:我们生成了DDL,并基于Oracle数据库中的元数据收集了edwex和json。 输入参数很多。 如果您错过一个,您将错误地形成一个实体。 而且由于整个形成过程是一致且连续的,因此错误只会在最后发现。 关于我们所有人如何自动化并克服错误,请仔细阅读。

关于基础架构的一些知识


在将数据填充到关系数据库表中之前,我们需要从源接受它们-以任何格式,例如在Excel中。 使用内部机制将来自源的数据传输到Hadoop(Data Lake)。 Hive已安装了Hive插件-借助它的帮助,我们可以使用类似SQL的语法查看文件的内容。

为了以表格的形式在Data Lake中传输数据,我们需要基于元数据形成的json。 要以Excel格式解析数据,我们需要创建EDWEX文件。 EDWEX(EDW_EXTRACTOR)文件是一组工件,其中包含具有名称的表集以及每个表的字段集,这些表集是基于元数据形成的。 根据模型版本和源ID,字段集会有所不同。 DDL的形成对于在Hive数据库中的操作数据级别和Greenplum数据库中的详细和汇总数据级别创建表本身是必要的。 也就是说,数据主要传输到Hive,必要时进行过滤并传输到Greenplum,以进行后续数据操作并基于该数据创建店面。

Edwex工件示例
包-包含一组表
数据-包含一组字段

pack.edwex:

1 Table_1 User Table_1 bid between to_char($fromdt,'yyyymm') and to_char($actualdt,'yyyymm') 2 Table_2 User Table_2 curbid between to_char($fromdt,'yyyymm') and to_char($actualdt,'yyyymm') 3 Table_3 User Table_3 bid between to_char($fromdt,'yyyymm') and to_char($actualdt,'yyyymm') 


data.edwex:

 1 1 CHARGE_ID NUMBER 38 0 1 2 SVC_ID NUMBER 38 0 1 3 VND_ID NUMBER 38 0 1 4 PRICE NUMBER 38 5 1 5 QUANTITY NUMBER 38 5 1 6 BASE NUMBER 38 5 1 7 TAX NUMBER 38 5 1 8 TOTAL NUMBER 38 5 1 9 TAX_RATE NUMBER 38 5 1 10 TAX_IN VARCHAR 1 1 11 CHARGE_KIND VARCHAR 3 1 12 PRIVILEGE_ID NUMBER 38 0 1 13 CHARGE_REF_ID NUMBER 38 0 1 14 EBID NUMBER 38 0 1 15 INVOICE_ID NUMBER 38 0 1 16 ZERO_STATE_ID NUMBER 38 0 1 17 USER_ID NUMBER 38 0 1 18 BID NUMBER 38 0 1 19 QUANTITY_REAL NUMBER 38 5 2 1 CURBID NUMBER 38 0 2 2 USER_ID NUMBER 38 0 2 3 VND_ID NUMBER 38 0 2 4 APPBID NUMBER 38 0 2 5 SVC_ID NUMBER 38 0 2 6 DEBT NUMBER 38 5 2 7 INSTDEBT NUMBER 38 5 3 1 INVOICE_ID NUMBER 38 0 3 2 INVOICE_DATE DATE 3 3 INVOICE_NUM VARCHAR 64 3 4 INVOICE_NUM_N NUMBER 38 5 3 5 BASE NUMBER 38 5 3 6 TAX NUMBER 38 5 3 7 TOTAL NUMBER 38 5 3 8 PREPAID VARCHAR 1 3 9 EXPLICIT VARCHAR 1 3 10 VND_ID NUMBER 38 0 3 11 ADV_PAYMENT_ID NUMBER 38 0 3 12 MDBID NUMBER 38 0 3 13 BID NUMBER 38 0 3 14 USER_ID NUMBER 38 0 3 15 ZERO_STATE_ID NUMBER 38 0 3 16 ACTIVE_SUM NUMBER 38 5 3 17 SPLIT_VND NUMBER 38 5 3 18 PRECREATED VARCHAR 1 


Json神器示例
 Table.json: { "metadata": [ { "colOrder":"1", "name":"charge_id", "dataType":"DECIMAL", "precision":"0", "requied":"true", "keyFile":"" }, { "colOrder":"2", "name":"svc_id", "dataType":"DECIMAL", "precision":"0", "requied":"false", "keyFile":"" }, { "colOrder":"3", "name":"vnd_id", "dataType":"DECIMAL", "precision":"0", "requied":"false", "keyFile":"" }, { "colOrder":"4", "name":"price", "dataType":"DECIMAL", "precision":"0", "requied":"false", "keyFile":"" }, { "colOrder":"5", "name":"quantity", "dataType":"DECIMAL", "precision":"0", "requied":"false", "keyFile":"" }, { "colOrder":"6", "name":"base", "dataType":"DECIMAL", "precision":"0", "requied":"false", "keyFile":"" }, { "colOrder":"7", "name":"tax", "dataType":"DECIMAL", "precision":"0", "requied":"false", "keyFile":"" }, { "colOrder":"8", "name":"total", "dataType":"DECIMAL", "precision":"0", "requied":"false", "keyFile":"" }, { "colOrder":"9", "name":"tax_rate", "dataType":"DECIMAL", "precision":"0", "requied":"false", "keyFile":"" }, { "colOrder":"10", "name":"tax_in", "dataType":"STRING", "precision":"0", "requied":"false", "keyFile":"" }, { "colOrder":"11", "name":"charge_kind", "dataType":"STRING", "precision":"0", "requied":"false", "keyFile":"" }, { "colOrder":"12", "name":"privilege_id", "dataType":"DECIMAL", "precision":"0", "requied":"false", "keyFile":"" }, { "colOrder":"13", "name":"charge_ref_id", "dataType":"DECIMAL", "precision":"0", "requied":"false", "keyFile":"" }, { "colOrder":"14", "name":"ebid", "dataType":"DECIMAL", "precision":"0", "requied":"false", "keyFile":"" }, { "colOrder":"15", "name":"invoice_id", "dataType":"DECIMAL", "precision":"0", "requied":"false", "keyFile":"" }, { "colOrder":"16", "name":"zero_state_id", "dataType":"DECIMAL", "precision":"0", "requied":"false", "keyFile":"" }, { "colOrder":"17", "name":"user_id", "dataType":"DECIMAL", "precision":"0", "requied":"false", "keyFile":"" }, { "colOrder":"18", "name":"bid", "dataType":"DECIMAL", "precision":"0", "requied":"false", "keyFile":"" }, { "colOrder":"19", "name":"quantity_real", "dataType":"DECIMAL", "precision":"0", "requied":"false", "keyFile":"" } ], "ctlPath":"  ctl", "errPath":"    ", "inPath":"    hdfs", "outSchema":" ", "outTable":" ", "isPartitioned":" ", "sourceId":"id  " } 


示例DDL工件
GP_000001_TABLE重命名为Z_GP_000001_TABLE_20180807;
创建表方案。GP_000001_TABLE


`charge_id` DECIMAL(38.0),
svc_id DECIMAL(38.0),
`vnd_id` DECIMAL(38.0),
价格DECIMAL(38.5),
数量DECIMAL(38.5),
`base` DECIMAL(38.5),
`tax`十进制(38.5),
总十进制(38.5),
`tax_rate` DECIMAL(38.5),
`tax_in` STRING,
`charge_kind` STRING,
`privilege_id` DECIMAL(38.0),
`charge_ref_id`十进制(38.0),
`ebid` DECIMAL(38.0),
`invoice_id` DECIMAL(38.0),
`zero_state_id` DECIMAL(38,0),
`user_id` DECIMAL(38.0),
`bid` DECIMAL(38.0),
`quantity_real` DECIMAL(38.5),
`load_dttm` TIMESTAMP,
`src_id` SMALLINT,
`package_id` BIGINT,
wf_run_id BIGINT,
`md5` STRING

行格式以'\ t'终止的字段
存储为INPUTFORMAT'org.apache.hadoop.mapred.TextInputFormat'OUTPUTFORMAT'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
位置“在HDFS中形成的方式”
TBLPROPERTIES('auto.purge'='true','transient_lastDlastDdlTime'='1489060201');
插入scheme.GP_000001_TABLE(`charge_id`,
`svc_id`,
`vnd_id`,
价格,
数量
`base`,
`税`,
总计,
`tax_rate`,
`tax_in`,
`charge_kind`,
`privilege_id`,
`charge_ref_id`,
`ebid`,
`invoice_id`,
`zero_state_id`,
`user_id`,
竞标
`quantity_real`,
`load_dttm`,
`src_id`,
package_id
`wf_run_id`,
md5)

选择“ charge_id”,
`svc_id`,
`vnd_id`,
价格,
数量
`base`,
`税`,
总计,
`tax_rate`,
`tax_in`,
`charge_kind`,
`privilege_id`,
`charge_ref_id`,
`ebid`,
`invoice_id`,
`zero_state_id`,
`user_id`,
竞标
`quantity_real`,
load_dttm,
src_id
package_id,
wf_run_id,
来自scheme.Z_GP_000001_TABLE_20180807的md5;

GP_000001_TABLE重命名为Z_GP_000001_TABLE_20180807;
创建表方案。GP_000001_TABLE


`charge_id` DECIMAL(38.0),
svc_id DECIMAL(38.0),
`vnd_id` DECIMAL(38.0),
价格DECIMAL(38.5),
数量DECIMAL(38.5),
`base` DECIMAL(38.5),
`tax`十进制(38.5),
总十进制(38.5),
`tax_rate` DECIMAL(38.5),
`tax_in` STRING,
`charge_kind` STRING,
`privilege_id` DECIMAL(38.0),
`charge_ref_id`十进制(38.0),
`ebid` DECIMAL(38.0),
`invoice_id` DECIMAL(38.0),
`zero_state_id` DECIMAL(38,0),
`user_id` DECIMAL(38.0),
`bid` DECIMAL(38.0),
`quantity_real` DECIMAL(38.5),
`load_dttm` TIMESTAMP,
`src_id` SMALLINT,
`package_id` BIGINT,
wf_run_id BIGINT,
`md5` STRING

行格式以'\ t'终止的字段
存储为INPUTFORMAT'org.apache.hadoop.mapred.TextInputFormat'OUTPUTFORMAT'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
位置“在HDFS中形成的方式”
TBLPROPERTIES('auto.purge'='true','transient_lastDlastDdlTime'='1489060201');
插入scheme.GP_000001_CPA_CHARGE(`charge_id`,
`svc_id`,
`vnd_id`,
价格,
数量
`base`,
`税`,
总计,
`tax_rate`,
`tax_in`,
`charge_kind`,
`privilege_id`,
`charge_ref_id`,
`ebid`,
`invoice_id`,
`zero_state_id`,
`user_id`,
竞标
`quantity_real`,
`load_dttm`,
`src_id`,
package_id
`wf_run_id`,
md5)

选择“ charge_id”,
`svc_id`,
`vnd_id`,
价格,
数量
`base`,
`税`,
总计,
`tax_rate`,
`tax_in`,
`charge_kind`,
`privilege_id`,
`charge_ref_id`,
`ebid`,
`invoice_id`,
`zero_state_id`,
`user_id`,
竞标
`quantity_real`,
load_dttm,
src_id
package_id,
wf_run_id,
来自scheme.Z_GP_000001_TABLE_20180807的md5;

如何自动化


为了解决这个问题,我们使用了:

  • Jenkins-作为实施CI流程的乐队和工具。
  • Python-它实现功能和单元测试。
  • SQL-访问元数据数据库。
  • Shell脚本-用于在目录之间复制工件并在Jenkins服务器上运行的多作业项目中创建脚本。

首先,我们最初使用大量源,因此,使用Shell脚本作为开始参数,我们将源ID传递给SQL函数以标识它们。 生成的SQL函数随后将在元数据数据库中自动执行。 根据可用的元数据,这些函数形成一个文件,其中包含每个源表的新SQL函数的列表,以便我们随后可以在可执行程序中对其进行调用。 执行生成的函数的结果是将DDL,JSON或EDWEX值传输到输出参数。

这是Python连接的地方,并编写了所有可执行功能和单元测试。 在使用单元测试启动任何用于滚动工件的模块之前,请检查正确的参数传输以运行python脚本。 测试不仅检查输入参数的正确性,还检查它们在元数据模块中的存在性,创建的文件的大小以及创建日期。 测试还监视创建的新工件的数量和现有工件的数量。 因此,我们优化了服务器资源的使用,因为我们只使用新文件进行滚动,而不会再次重新安装现有模型。

只有成功通过所有检查后,才会执行python程序,该程序创建必要的工件并将结果分解到服务器上的必要项目文件夹中。 Python不仅将生成的json文件定向到目录中,而且将结构形成到Data Lake中,以便正确加载数据。 生成DDL工件时,它们不仅被保存以供以后分析和重复使用,而且还可以使用元数据模块中指定的新模型和结构立即安装在数据库中。 这使您可以在短时间内创建数百个表,而无需进行人工操作。

詹金斯在哪里?


当需要使用界面直观地管理所有这些过程时,Jenkins进入。

选择该工具的原因是:

  • 完全满足组装和安装自动化的需求
  • 允许您设计一种机制,以通过自检过程的实现来组装工件
  • 使您可以轻松地管理工作启动并监视远离编程人员的执行情况
  • 允许您配置日志记录机制,以使团队中的任何人都可以理解执行的结果。 组装中的问题将得到明确指示,或者过程将成功完成。

为了解决任务,我们创建了几个多任务项目。 之所以使用这种类型的项目,是因为它可以与其他作业同时启动。 每个作业都负责其功能块的实现。 因此,我们用自主并行工件代替了获取工件的顺序过程。 一切都是分开开始的:EDWEX,JSON,DDL的形成,HPE中结构的形成,数据库中表结构的安装。 我们在伪像形成的不同阶段分析结果,如果成功,则着手启动后续操作。

Jenkins部分的实现没有太多技巧。 将StringRun参数发送到输入以启动python代码。 String参数是一个窗口,用于在启动之前输入str类型的值。 可以将运行参数即时转移到另一个作业中执行,因为这足以表明需要从哪个项目中获取接收到的变量。 同样,将节点作为单独的参数传递来执行。 此处仅实现了在DEV,TST,UAT,PRD上划分为运行时的功能。 为了能够跟踪已更改结构的版本,使用了一个单独的作业将接收到的EDWEX文件与修订号一起传输到SVN。

Jenkins中的示例界面:



作业执行的结果是必要工件的创建和安装,将它们转移到SVN以及形成HTML报告的结果,该报告显示了通过单元测试的成功以及工件的组装和安装结果。 先前已建立执行链的作业可以手动操作或以自动模式运行。


组装和安装机制架构

总结一下


为了自动化工件的形成,已经做了很多工作。 以前,您必须手动爬到服务器上,运行shell脚本,然后长时间动手研究和编辑数据。 现在只需单击开始按钮,指定源系统ID,型号和执行循环。 在詹金斯的帮助下,有可能将工件的整个组装和安装机制进行结构化和分解成独立的阶段。 在开始生成工件及其集成之前,添加了必要的检查。 接收到的工件会自动传输到SVN,从而简化了与系统分析师和数据建模人员的相关团队的合作。 执行检查以避免伪造物形成的空转并确认其正确性。

结果,我们将组装和安装模型工件的耗时过程从几个小时减少到了几分钟。 最重要的是,它们消除了由于人为因素导致的错误的发生,而错误是不可避免地在复杂的常规过程中出现的。

Source: https://habr.com/ru/post/zh-CN428101/


All Articles