本文适用有入门spark基础的同窗,一些最基础知识再也不赘述数据库
经过阅读本文便可掌握使用Spark跨集群同步Hive数据的技巧!app
众所周知,业界比较成熟的同步数据工具是Sqoop,它是链接关系型数据库和Hadoop的桥梁框架
比较经常使用的场景是从MySQL等RDB同步到Hive、Hbase或者将Hive、Hbase的数据导出到MySQL工具
可是在公司项目技术选型时选用了用Spark来从一个集群同步数据到另外一个集群oop
下面来比较一下这两种方式:学习
①Sqoop使用配置化,Spark须要代码开发spa
学习成本上使用Spark稍微高一些,可是同步数据复杂一些Sqoop的配置也不见得很简单日志
②Sqoop在同步数据进行存储时仍须要启动MapReduce任务,Spark使用自身框架进行内存计算对象
在效率上Spark比Sqoop要高生命周期
③Sqoop1和Sqoop2不能彻底兼容,且网上在不一样集群的Hive间同步数据的资料也比较少,出现问题时不保证能解决
因此选用了Spark做为天池的数据同步方式
其实当时选用Spark最重要的缘由是本人使用Spark比较熟!
下面就来介绍如何使用Spark进行数据同步
1. 抽取数据文件
1.1 建立Spark入口对象指定源数据的Hive元数据服务
扩展:在远程链接Hive时Hive有两种服务Hive Metastore Server和HiveServer2
HiveServer2是JDBC链接,使用这种方式会占用数据本地集群的计算资源(经常使用默认端口10000的那种)
Spark链接Hive可使用Hive Metastore Server,这样只需链接Hive的元数据,经过元数据记录的数据路径拉取数据使用Spark对数据进行计算(经常使用默认端口9083的那种)
在建立SparkSession对象时动态传参传入源数据集群的Hive Metastore Server地址
1.2 将Spark的hadoopConfiguration对象切换到源数据集群
链接了数据源集群的Hive Metastore Server元数据服务,Spark会根据里面记录的元数据信息去拉取数据,而其它集群记录的是其它HDFS集群的路径
默认根据配置文件本集群跑Spark程序时链接的是本集群的HDFS地址,因此根据元数据获取的数据路径会找不到
而MetaServer元数据服务地址属于在Spark建立时指定的,在这个对象生命周期内没法被改变,可是Hadoop相关配置是能够在运行时切换的
因此须要在取数时切换Hadoop配置
1.3 经过SQL指定须要获取的数据将数据加载到目标集群的HDFS文件中
上例中是抽取APP埋点日志表,这个表中源数据是根据site和year, month, day进行分区的
咱们须要天天同步每日的增量数据,Spark在拉取数据时会根据分区去拉取对应的数据而不是全量数据
同时在SQL中能够看到我在同步过来数据时将year, month, day字段拼成dt字段做为日期新字段,且原表数据中字段比这里多得多,只取了须要的字段以节省时间空间
而且在写出成HDFS文件的时候经过.partitionBy("site", "dt")也指定了目标表的分区
写出的文件路径就是这种格式的:/tianchi/data/ods_app_burial_log/site=zz/dt=2019-06-11
另外$HDFS_ADDR是经过API动态获取的目标集群active nameNode的ip:port
防止写死后NN主备切换
因为这里是链接spark本地集群的hadoop集群,只须要建立Configuration对象读取集群默认配置,若是是获取其它集群的还须要把链接信息赋入
2.将导入的数据文件加载到本集群的Hive表中
因为上面说过的缘由,链接的MetaServer没法在运行时改变,因此抽取数据文件和加载数据进目标集群的Hive表没法放在同一个任务中进行,要另起一个任务进行加载
2.1 新的任务中建立SparkSession对象指定本集群的Hive Metastore Server元数据服务地址
2.2 使用HiveSQL的语法加载数据LOAD DATA INPATH '/datapath/' OVERWRITE INTO TABLE tableName PARTITION (par='xxx')