数据迁移心得

  前几天出差,去客户现场帮忙迁移数据,通过几天的奋战,终于将迁移数据自动化起来,而且能够日跑批操做,这里小编就跟你们分享下,这其中踩过的坑(也多是实战经验不丰富致使)。
  首先,荣小编我抱怨一下,不是本身熟悉的开发环境真的有些难过,给一台电脑,咱不说没有IDE,就连java都没有安装,链接数据库的工具也没有,惟一值得庆幸的是有xshell,可是彻底不符合我的快捷键的喜爱,没办法,想要开发高效,本身动手配置吧。单单是配置这些开发环境就整整牺牲了小编一上午的时间,还好后期开发有明显的提速。中午吃个饭,下午进入正题。
  下午拿到迁移任务,发现一个库中有不少表,其中表有大有小,当时我沉默了几秒钟,感受这个星期是交代在这里了。这里小编在那几秒钟的沉默中也把这个迁移流程想了一下,首先数据是存在关系型数据库中的,而后咱们要经过sqoop将数据上传到HDFS中,而后用hive的外表去映射这些数据,最终创建有索引的内表来存储一份完整的数据。内表通常都是分区,分桶,且有索引的orc表,查询速度明显比外表快不少。那么接下来小编就将这其中的步骤,一点点的分析下。java

前期准备:

   拿到一个库的数据时,咱们首先分析下这里有哪些表比较大,哪些表比较小,将大表和小表分开,使用不一样的迁移方法,通常都是客户提供每张表的数据条数,若是没有的话,只能selecct count(*) from table; 将这些表的数据查出来,不只便于区分大小表,并且对后期数据核对有较大的帮助。shell

1. 从关系型数据库将数据迁移到HDFS中

  这里迁移数据小编是用的sqoop,虽然sqoop比较慢,可是学习成本相对较低,并且便于批量的生成语句,对开发要求没那么高。首先先测试一个sqoop是否能够成功的迁移数据,而后编写脚本批量的生成sqoop语句,最后调用这些语句,后台并行的迁移数据。这里小编先说说使用sqoop的几个小窍门:数据库

  • 若是集群的资源比较充分,通常新集群是没有什么生产任务的,咱们的sqoop语句中能够加入:
    -m 这个参数能够设置为>1 ,表示并行多个map去抽取数据。
    --split-by 固然-m 参数设置大于后,要同时设置这个参数,表示以表中的哪个字段去分map并行。

    这里选取--split-by 尽可能使用表中比较分散的字段,保证每个map任务抽取的数据量都大体相同。app

  • 若是表的数据量比较大,好比超过亿条,咱们这里就须要将这个表分红多个sqoop去抽取:ide

    --query : 指定where后的条件,抽取部分数据
       这样的好处是:若是只有一个sqoop任务,抽取了90%的数据后,发现sqoop任务挂了,那么本次抽取失败,不只耗时,并且数据没有抽取到。分多个sqoop任务,不只可并行,并且每一个任务的数据量也不大,若是有任务挂了,只须要抽象抽取那个where条件下的数据即,而且对于找错也有极大的帮助。
       分区字段的选取也一样重要,这里通常都是使用日期做为where的后的条件,保证每一个sqoop任务分的的数据量相差无几。工具

    • sqoop抽取数据的目录规划
      #小表目录规划
      /tmp/库名/表名
      #大表的目录规划
      /tmp/库名/表名/分区名
  • query语句:在sqoop命令中,咱们编写查询语句去抽取数据时,切记不要:oop

    -- ×
    select * from table;
    -- √
    select 字段1,字段2.... from table;
    否则可能会致使sqoop抽取速度变慢,甚至可能致使没有抽取到数据。
       当咱们注意了以上的内容后,就能够编写脚本批量的生成每张表的sqoop语句了,根据库名.表名,获取关系型数据库中表的元数据,最后将sqoop组装起来。最后在编写任务脚本,定时执行这些sqoop语句。
    实际数据分享:
       这里小编测试过,数据量比较大时,多sqoop和单sqoop的耗时:
    以600G数据为例:
       - 多sqoop 并行抽取数据耗时:3~4小时。
       - 单sqoop 抽取数据耗时:12小时以上。
       - 单sqoop && (-m 1)抽取5千万条数据,大概是27分钟。学习

2. 创建外表映射

   说白了就是将抽取到的数据,在hive中经过外表的方式映射出来,其实这里没什么难的,主要是看客户若是要求,多是外表单独一个库,或者外表的名称统一是:表名_ext。可是切记,不要手动的去编写建表语句,若是表有百张以上,心态容易炸,这里可使用关系型数据库的元数据 ,生成hive的建表语句的,这里咱们与MySQL为例:测试

SELECT CONCAT('create table ', TABLE_NAME, '(', substring(column_info, 1, length(column_info) - 1), ')', ' comment ', '"', TABLE_COMMENT, '"', ';')
FROM (SELECT TABLE_NAME, TABLE_COMMENT, group_concat(CONCAT(COLUMN_NAME, ' ', DATA_TYPE, ' comment ', '"', COLUMN_COMMENT, '"')) AS column_info
FROM (SELECT t1.TABLE_NAME, CASE WHEN t2.TABLE_COMMENT = NULL THEN t1.TABLE_NAME ELSE t2.TABLE_COMMENT END AS TABLE_COMMENT, COLUMN_NAME, CASE WHEN DATA_TYPE = 'varchar' THEN 'string' WHEN DATA_TYPE = 'int' THEN 'int' WHEN DATA_TYPE = 'tinyint' THEN 'tinyint' WHEN DATA_TYPE = 'decimal' THEN 'double' WHEN DATA_TYPE = 'datetime' THEN 'string' WHEN DATA_TYPE = 'timestamp' THEN 'string' WHEN DATA_TYPE = 'float' THEN 'double' WHEN DATA_TYPE = 'double' THEN 'double' WHEN DATA_TYPE = 'bigint' THEN 'bigint' END AS DATA_TYPE, CASE WHEN COLUMN_COMMENT = NULL THEN COLUMN_NAME ELSE COLUMN_COMMENT END AS COLUMN_COMMENT
FROM COLUMNS t1 JOIN TABLES t2 ON t1.TABLE_NAME = t2.TABLE_NAME
WHERE t1.TABLE_NAME = 't_app_equipment_status'
) t3
GROUP BY TABLE_NAME, TABLE_COMMENT
) t4;

网上这样的例子不少,这里小编就不在介绍。当外表创建好以后,最好核对一下数据量的大小,对比下关系型数据库中表的数据和hive中的数据是否相同,这样验证了sqoop这一环节是否有数据丢失的状况。
遇到的坑:
  当大表咱们在分区抽取时,是没法直接映射成为外表的,咱们须要创建范围分区表,将表的分区目录映射到各个分区上。优化

3. 创建高效的内表

   其实这一步就是将,外表的数据,insert到一张和外表字段相同的通过优化的内表中,这张内表通常都是分区分桶,创建索引,或者基于闪存的表,反正就是查询的速度大大提升的一张表,也叫作业务表。
   小编这里用的是一种基于闪存的高效查询的,企业内部开发的一种表结构。小编这里介绍一下如何肯定分桶字段:分桶的好处是
   (1)得到更高的查询处理效率。桶为表加上了额外的结构,Hive 在处理有些查询时能利用这个结构。具体而言,链接两个在(包含链接列的)相同列上划分了桶的表,可使用 Map 端链接 (Map-side join)高效的实现。好比JOIN操做。对于JOIN操做两个表有一个相同的列,若是对这两个表都进行了桶操做。那么将保存相同列值的桶进行JOIN操做就能够,能够大大较少JOIN的数据量。
   (2)使取样(sampling)更高效。在处理大规模数据集时,在开发和修改查询的阶段,若是能在数据集的一小部分数据上试运行查询,会带来不少方便。
   那么若是肯定分桶字段呢,通常的若是有主键的表就使用主键做为分桶字段,若是没有主键的表,找几个比较分散的字段使用:

select count(distinct feild) from table;

找出数据最大的那个字段做为分桶字段。具体的分桶数,这里建议是一个质数,由于若是是一个非质数,那么可能致使分桶不均匀,由于若是分桶数是9的话,那么字段值若是为1八、27都会分到一个桶中,可能会致使桶“热点”。

4. 外表insert 到 内表中

   这个过程是耗时仅次于sqoop的过程,因为咱们的内表创建的分区,那么在这个步骤中咱们须要使用hive的动态分区插入,插入语句通常都是:

insert into table_1 partition(par_field) select field1.field2...from table_2 ;

这里须要注意的是select 最后一个字段必定要是分区字段。
   当咱们insert 后,须要核对下是否全部的数据所有insert成功,此时:外表数据量=内表数据量=关系型数据库数据量

5. 日增量数据的处理

   当咱们完成数据迁移后,其实外表至关于一个中转站,仅仅是将数据中转到内表中,若是咱们确保了内表中有一份完整的数据,此时能够将外表的数据清空,这也是为何咱们将外表的location 设置为/tmp下 的缘由,清空外表数据后,将日增数据抽取到外表的location地址上,而后全量的将外表数据insert到内表中,就保证了日增量数据的成功导入到hive。

相关文章
相关标签/搜索