数据测试功能(数据沙箱)

1 背景说明

数据沙箱功能,可生效在离线开发和自助分析两个子产品中,主要解决的是数据开发过程中的线上数据和开发数据隔离问题。

在目前常规的hive sql使用中,一般读写表都需要指定库表(不指定则操作的是default库)。如下方的示例:

insert overwrite table intern_new.dim_user_info_p
partition (ds='2021-07-25')
select id as user_id,
name as user_name,
province,
age 
from intern_new.ods_user_info
where ds='2021-07-25';

如果上述代码已经在一个线上调度的任务中,“intern_new.dim_user_info_p”表也已经被下游使用,则当该表的逻辑需要修改,或者增加字段等操作时,会有两类用户:

1)第一类用户,会选择新建一个临时表,并复制出现有代码,先进行测试验证。当验证通过时,再将该表更新,并更新代码,然后将任务提交上线。

2)第二类用户,会选择直接修改该表,并修改原有代码,修改完成后,将任务提交上线。

对于上述两种做法,第一类用户的做法更可靠,能保证所有操作不影响线上数据,也不影响下游,但是会多一些额外的工作;第二类用户,可以节约额外的创建临时表,以及代码反复拷贝修改的时间,但是容易影响线上数据,特别容易出纰漏。

因此,本平台研发了“数据沙箱”功能,引入了一种新的代码规则,可以实现同一份代码根据运行环境不同,自动进行部分参数替换,实现操作离线表或测试表的功能,以及操作默认HDFS文件或测试HDFS集群文件的功能。

2 功能说明

1)针对HiveSQL

回到前面提到的SQL语句,开启“数据沙箱”功能后,离线开发和自助分析中,支持执行如下带参数的sql:

insert overwrite table ${intern_new}.dim_user_info_p --修改点是intern_new 变成了 ${intern_new}
partition (ds='2021-07-25')
select id as user_id,
name as user_name,
province,
age 
from intern_new.ods_user_info
where ds='2021-07-25';

在离线开发的开发模式下,任务的线上调度、重跑、补数据等,以及自助分析(开启测试模式)下,运行上述sql,系统自动转换为如下sql,并且使用测试Yarn集群的资源(即使用测试Yarn队列,后文的案例中会有更多说明):

insert overwrite table intern_new_dev.dim_user_info_p 
partition (ds='2021-07-25')
select id as user_id,
name as user_name,
province,
age 
from intern_new.ods_user_info
where ds='2021-07-25';

即实现将“${xxx}”作为参数去匹配当前项目-集群下,“xxx”库对应的测试库(dev库)。在上面的例子中,也就是替换成“intern_new_dev”,从而实现操作测试库下的表。

如果上述代码,提交上线并设置定时调度,则运行时会实际执行如下sql,并且使用默认Yarn集群的资源(即项目的默认Yarn队列):

insert overwrite table intern_new.dim_user_info_p 
partition (ds='2021-07-25')
select id as user_id,
name as user_name,
province,
age 
from intern_new.ods_user_info
where ds='2021-07-25';

即实现将“${xxx}”作为参数去匹配当前项目-集群下的普通库。在上面的例子中,也就是替换成“intern_new”,从而实现操作普通库下的表。

上述参数的使用格式是原生hive和spark的格式,开启“数据沙箱”后,系统新增加了上述的处理逻辑。

注意:要使用上述自动库替换功能,需要先确保当前项目-集群下,您要操作的普通库已经存在对应的测试库,并且有您期望的表结构的同名表。对应测试库,可由项目的管理员进行申请,并给您授权。

2) 针对HDFS

离线开发中,支持使用Script、MR等节点,用户可在节点中自行指定hdfs相对路径。开启“数据沙箱”功能后,任务运行时,相对hdfs路径,也可以自动根据运行环境,补充不同的完成路径。离线开发的开发模式运行,会自动补充测试Hdfs集群前缀;离线开发的线上模式下,任务的线上调度、重跑、补数据等,会自动补充默认Hdfs集群前缀。

在前面的例子中,表“intern_new_dev.dim_user_info_p”,其hdfs存储路径为:“hdfs://cluster1/user/intern/hive_db/intern_new.db/dim_user_info_p”。表“intern_new.dim_user_info_p”,其hdfs存储路径为:”hdfs://dev4/user/intern/hive_db/intern_new.db/dim_user_info_p”。

这里的路径区别是,对于测试表,默认location的测试Hdfs集群是“cluster1”,这个是测试hdfs集群。对于离线表,默认location的默认Hdfs集群是“dev4”,这个是默认hdfs集群。而两个路径的后半部分地址相同,都是“user/intern/hive_db/intern_new.db/dim_user_info_p”。

3 功能开启准备

项目如果要开启“数据沙箱”功能,首先需要平台部署了测试Hdfs集群和测试Yarn集群,并安装了相关服务,具体需要联系本平台的运维人员。

4 开启测试功能

目前,有3种方式来开启测试功能(“数据沙箱”功能目前在产品上叫“测试功能”)。

4.1 新建项目

申请新建项目时,可申请开通测试功能。这里仅对开启测试功能的部分做说明,其它新建项目的说明,请前往对应章节查看。

在新建项目时,如果选择的集群支持开启“测试功能”,则选择集群后,页面后面会增加显示“测试功能”区块。

如下图,为新建项目页面:

数据测试功能(数据沙箱) - 图1 2021-07-26-21-05-27.png

如下图,为选择支持开启“测试功能”的集群后,页面后面显示的“测试功能”配置区块:

数据测试功能(数据沙箱) - 图3 2021-07-26-21-04-53.png

下面,说明配置区块中几个比较重要的项:

1)“测试存储配额”:这个是后续测试库表可存放测试数据的空间大小,取决于当前平台的测试Hdfs集群的空间,具体可联系平台运维人员确定。

2)“测试Hive库”:新建的项目,默认会按照项目名称创建一个同名的Hive离线库。开通测试功能的,也会自动创建一个对应的测试库。比如项目名叫“my_dwd”,则测试Hive库就叫“my_dwd_dev”。

3)“测试资源配置”:新建的项目,需要指定一个Yarn队列的名称。开通测试功能的,也会自动在测试Yarn集群上创建一个同名队列。比如默认Yarn队列名叫“my_queue”,则测试Yarn队列也叫“my_queue”。

4.2 已有项目在新集群开通

已有项目,申请在新集群开通时,可同时申请开通测试功能。需要配置的内容基本和新建项目的相同。

数据测试功能(数据沙箱) - 图5 2021-07-26-22-25-37.png

4.3 已有项目在已开通集群上开通

已有项目,可在已开通的集群上,申请开通测试功能。

数据测试功能(数据沙箱) - 图7 2021-07-26-22-30-13.png

数据测试功能(数据沙箱) - 图9 2021-07-26-22-30-46.png

下面,说明配置区块中几个比较重要的项:

1)“测试存储配额”:这个是后续测试库表可存放测试数据的空间大小,取决于当前平台的测试Hdfs集群的空间,具体可联系平台运维人员确定。

2)“Hive库选择”:在申请开通时,有需要选择一个已有离线库作为当前项目-集群的主库。系统会在申请通过后,自动创建一个名为“{主库}_dev”的测试库。

3)“测试资源配置”:对于已有项目,会存在一些Yarn队列。在申请开通测试功能后,系统会自动在测试Yarn集群上新建相同数量的同名Yarn队列,默认会设置一个资源。后续管理员可在“项目中心”-“资源管理”中,申请修改队列的测试队列的资源。

5 典型使用案例

下面,通过一个实际的例子,说明测试功能的用法。案例主线是,基于一个ods源头表,加工一个dim维表,后续ods表增加一个字段,dim维表做更新。在这过程中,使用了2次测试功能,并使用了离线开发的“离线表新增字段”和“表克隆”功能。

场景1:基于ods源头表加工dim维表

1)ods表的ddl

假设ods源头表为一张用户信息表:

CREATE TABLE `intern_new_dev`.`ods_user_info`(
  `id` string COMMENT 'id', 
  `name` string COMMENT '姓名', 
  `province` string COMMENT '省份', 
  `age` string COMMENT '年龄'
  )
COMMENT '用户信息表'
PARTITIONED BY ( 
  `ds` string COMMENT '时间分区')
ROW FORMAT SERDE 
  'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe' 
STORED AS INPUTFORMAT 
  'org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat' 
OUTPUTFORMAT 
  'org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat';

2)在测试库设计表

离线库为“intern_new”,测试库为“intern_new_dev”,设计的dim维表ddl如下:

CREATE TABLE `intern_new_dev`.`dim_user_info_p`(
  `user_id` string COMMENT 'id', 
  `user_name` string COMMENT '姓名', 
  `province` string COMMENT '省份', 
  `age` string COMMENT '年龄'
  )
COMMENT '用户全量维表'
PARTITIONED BY ( 
  `ds` string COMMENT '时间分区')
ROW FORMAT SERDE 
  'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe' 
STORED AS INPUTFORMAT 
  'org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat' 
OUTPUTFORMAT 
  'org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat';

3)在离线开发新建任务,并拖入SQL节点

SQL节点的代码如下(其中’${azkaban.flow.1.days.ago}’表示azkaban调度系统的系统参数,表示昨天):

insert overwrite table ${intern_new}.dim_user_info_p
partition (ds='${azkaban.flow.1.days.ago}')
select id as user_id,
name as user_name,
province,
age 
from intern_new.ods_user_info
where ds='${azkaban.flow.1.days.ago}';

开发模式,运行SQL节点,在“运行设置”弹框中,保持“测试模式”开关打开。运行后,数据实际插入到的是“intern_new_dev.dim_user_info_p”中。确认测试库的表的数据没有问题后,可进入下一步。

数据测试功能(数据沙箱) - 图11 2021-07-26-17-41-37.png

4)通过“表克隆”功能将测试库表克隆到离线库

入口:离线开发左上角的“辅助功能区”。

数据测试功能(数据沙箱) - 图13 2021-07-26-22-59-42.png

在“表克隆”的弹框中,设置待克隆表为“intern_new_dev.dim_user_info_p”,目标库为“intern_new”.

如下图,为克隆检验,检验通过,则可进入下一步:

数据测试功能(数据沙箱) - 图15 2021-07-26-19-28-13.png

如下图,为执行克隆页面,系统会自动生成建表语句:

数据测试功能(数据沙箱) - 图17 2021-07-26-19-28-43.png

5)将任务提交上线并编辑调度

最后,将任务提交上线,编辑调度。在线上调度的任务,实际执行时,就会执行如下代码,将数据插入到“intern_new.dim_user_info_p”表中:

insert overwrite table intern_new.dim_user_info_p
partition (ds='${azkaban.flow.1.days.ago}')
select id as user_id,
name as user_name,
province,
age 
from intern_new.ods_user_info
where ds='${azkaban.flow.1.days.ago}';

场景2:dim维表增加字段

1)ods源头表增加了性别字段

ods源头表新的ddl如下:

CREATE TABLE `intern_new_dev`.`ods_user_info`(
  `id` string COMMENT 'id', 
  `name` string COMMENT '姓名', 
  `province` string COMMENT '省份', 
  `age` string COMMENT '年龄',
  `sex` string COMMENT '性别' --新增的字段
  )
COMMENT '用户信息表'
PARTITIONED BY ( 
  `ds` string COMMENT '时间分区')
ROW FORMAT SERDE 
  'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe' 
STORED AS INPUTFORMAT 
  'org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat' 
OUTPUTFORMAT 
  'org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat';

2)对测试dim维表表新增字段

使用离线开发的“离线表新增字段”功能,给测试维表“intern_new_dev.dim_user_info_p”增加一个性别字段。

如下图,为“离线表新增字段”的入口:

数据测试功能(数据沙箱) - 图19 2021-07-26-19-25-13.png

如下图,为新增性别字段:

数据测试功能(数据沙箱) - 图21 2021-07-26-19-26-37.png

3)修改原SQL节点代码

新的SQL节点代码如下:

insert overwrite table ${intern_new}.dim_user_info_p
partition (ds='${azkaban.flow.1.days.ago}')
select id as user_id,
name as user_name,
province,
age,
sex --为新增加的代码
from intern_new.ods_user_info
where ds='${azkaban.flow.1.days.ago}';

修改后,开发模式,运行SQL节点,在“运行设置”弹框中,保持“测试模式”开关打开。运行后,数据实际插入到的是“intern_new_dev.dim_user_info_p”中。确认测试库的表的数据没有问题后,可进入下一步。

4)通过“表克隆”功能将测试库表更新到离线库

如下图,为“表克隆”的弹框中,设置“待克隆表”为“intern_new_dev.dim_user_info_p”,目标库为“intern_new”。经过“克隆检验”,发现待克隆表比目标库的表多一个字段,且可以进行更新。

数据测试功能(数据沙箱) - 图23 2021-07-26-19-29-36.png

如下图,为克隆执行语句,实际为对“intern_new.dim_user_info_p”表执行加字段操作。

数据测试功能(数据沙箱) - 图25 2021-07-26-19-30-28.png

5)将任务提交上线

最后,将任务提交上线。在线上调度的任务,实际执行时,就会执行如下代码,将数据插入到“intern_new.dim_user_info_p”表中:

insert overwrite table intern_new.dim_user_info_p
partition (ds='${azkaban.flow.1.days.ago}')
select id as user_id,
name as user_name,
province,
age,
sex
from intern_new.ods_user_info
where ds='${azkaban.flow.1.days.ago}';