大数据-242 离线数仓 - DataX 实战:MySQL 全量/增量导入 HDFS + Hive 分区(离线数仓 ODS

TL;DR

  • 场景:电商离线数仓 ODS 层,MySQL 7 张表每日抽取到 HDFS 并按 dt 分区给 Hive 加载。
  • 结论:小表全量 + 大表按可分辨新增字段做增量;DataX channel=1 控小文件;HDFS 先建分区目录再跑作业。
  • 产出:可复用 DataX JSON 模板(mysqlreader→hdfswriter)+ 每日调度脚本骨架 + 分区加载命令。

数据导入

已经确定的事情:DataX、导出7张表的数据。 MySQL导出:全量导出、增量导出(导出前一天的数据)

业务数据保存在MySQL中,每日凌晨上一天的表数据:

  • 表数据量少,采用全量方式导出MySQL
  • 表数据量多,而且根据字段能区分出每天新增数据,采用增量的方式导出MySQL

3张增量表:

  • 订单表 wzk_trade_orders
  • 订单产品表 wzk_order_produce
  • 产品信息表 wzk_product_info

4张全量表:

  • 产品分量表 wzk_product_category
  • 商家店铺表 wzk_shops
  • 商家地域组织表 wzk_shop_admin_org
  • 支付方式表 wzk_payment

数据库导入

上述的内容中,可以先把表构建出来,然后生成一批数据,用于测试,我这里就导入生成好的数据了。

业务需求

电商系统业务中最关键的业务,电商的运营活动都是围绕这个主题展开。 选取的指标包括:订单数、商品数、支付金额,对这些指标按销售区域、商品类型分析。

在大数据的分析中,"电商核心交易"是指电商平台上所有与商品交易相关的核心行为和交易数据的集合。具体来说,核心交易涵盖了商品的浏览、加购物车、下单、支付、发货、收货等一系列行为,它们直接影响电商平台的运营效率、用户体验和商业价值。

需求板块

电商平台的核心交易可以分为以下几个主要环节,每个环节都涉及大量数据的收集、存储和分析:

  • 商品浏览:用户浏览商品的行为数据,例如用户查看了哪些商品、查看时长、是否点击了相关广告或推荐商品等。这些数据能够帮助平台了解用户的兴趣点,进而优化商品推荐和个性化营销策略。
  • 加入购物车:用户将商品添加到购物车中的行为。通过分析购物车中的商品,可以获取用户的购买意图和倾向,帮助商家调整商品定价、库存和促销策略。
  • 下单:用户在电商平台上完成的订单生成行为。包括订单的创建、订单内容、用户的收货地址、选择的支付方式等数据。订单数据是电商交易中的核心,通常涉及大量的数据信息,要求系统能够高效地处理和存储。
  • 支付:支付是交易中至关重要的环节,支付数据可以通过支付方式、支付成功与否、支付金额、支付时间等维度进行分析。这部分数据可以帮助平台评估不同支付方式的受欢迎程度,并进行相应的优化。
  • 发货:商品发货数据记录了商家发货的时间、物流公司、物流单号等信息。通过对发货数据的分析,可以判断出物流时效、发货效率等关键指标,进一步优化供应链和物流流程。
  • 收货和评价:用户收到商品后的评价、退换货行为等。评价数据不仅反映了商品的质量和用户满意度,还对后续的购买决策产生影响。此外,退换货数据也能够反映出商品质量问题和物流中的痛点。

全量数据导入

  • MySQL => HDFS => Hive
  • 每日加载全量数据,形成新的分区
  • MySQL Reader => HDFS Writer

产品分类表

shell 复制代码
vim /opt/wzk/datax/product_category.json

写入的内容如下所示:

  • 数据量小的表没有必要使用多个channel,使用多个channel会生成多个小文件
  • 执行命令之前要在HDFS上创建对应的目录:/user/data/trade.db/product_category/dt=yyyy-mm-dd
json 复制代码
{
  "job": {
    "setting": {
      "speed": {
        "channel": 1
      }
    },
    "content": [
      {
        "reader": {
          "name": "mysqlreader",
          "parameter": {
            "username": "hive",
            "password": "hive@wzk.icu",
            "column": [
              "catId", 
              "parentId", 
              "catName", 
              "isShow", 
              "sortNum", 
              "isDel", 
              "createTime", 
              "level"
            ],
            "connection": [
              {
                "table": [
                  "wzk_product_category"
                ],
                "jdbcUrl": [
                  "jdbc:mysql://h122.wzk.icu:3306/ebiz"
                ]
              }
            ]
          }
        },
        "writer": {
          "name": "hdfswriter",
          "parameter": {
            "defaultFS": "hdfs://h121.wzk.icu:9000",
            "fileType": "text",
            "path": "/user/data/trade.db/product_category/dt=$do_date",
            "fileName": "product_category_$do_date",
            "column": [
              {
                "name": "catId",
                "type": "INT"
              },
              {
                "name": "parentId",
                "type": "INT"
              },
              {
                "name": "catName",
                "type": "STRING"
              },
              {
                "name": "isShow",
                "type": "TINYINT"
              },
              {
                "name": "sortNum",
                "type": "INT"
              },
              {
                "name": "isDel",
                "type": "TINYINT"
              },
              {
                "name": "createTime",
                "type": "STRING"
              },
              {
                "name": "level",
                "type": "TINYINT"
              }
            ],
            "writeMode": "append",
            "fieldDelimiter": ","
          }
        }
      }
    ]
  }
}

写入的结果如下图:

加载数据的过程如下:

shell 复制代码
do_date='2020-07-01'
# 创建目录
hdfs dfs -mkdir -p /user/data/trade.db/product_category/dt=$do_date
# 数据迁移
python $DATAX_HOME/bin/datax.py -p "-Ddo_date=$do_date" /opt/wzk/datax/product_category.json
# 加载数据
# hive 还没有表,后续再执行
hive -e "alter table ods.ods_trade_product_category add partition(dt='$do_date')"

对应的截图如下所示: DataX将MySQL数据加载到HDFS上:

商家店铺表

wzk_shops => ods.ods_trade_shops

shell 复制代码
vim /opt/wzk/datax/shops.json

创建的内容:

json 复制代码
{
  "job": {
    "setting": {
      "speed": {
        "channel": 1
      },
      "errorLimit": {
        "record": 0
      }
    },
    "content": [
      {
        "reader": {
          "name": "mysqlreader",
          "parameter": {
            "username": "hive",
            "password": "hive@wzk.icu",
            "column": [
              "shopId",
              "userId",
              "areaId",
              "shopName",
              "shopLevel",
              "status",
              "createTime",
              "modifyTime"
            ],
            "connection": [
              {
                "table": [
                  "wzk_shops"
                ],
                "jdbcUrl": [
                  "jdbc:mysql://h122.wzk.icu:3306/ebiz"
                ]
              }
            ]
          }
        },
        "writer": {
          "name": "hdfswriter",
          "parameter": {
            "defaultFS": "hdfs://h121.wzk.icu:9000",
            "fileType": "text",
            "path": "/user/data/trade.db/shops/dt=$do_date",
            "fileName": "shops_$do_date",
            "column": [
              {
                "name": "shopId",
                "type": "INT"
              },
              {
                "name": "userId",
                "type": "INT"
              },
              {
                "name": "areaId",
                "type": "INT"
              },
              {
                "name": "shopName",
                "type": "STRING"
              },
              {
                "name": "shopLevel",
                "type": "TINYINT"
              },
              {
                "name": "status",
                "type": "TINYINT"
              },
              {
                "name": "createTime",
                "type": "STRING"
              },
              {
                "name": "modifyTime",
                "type": "STRING"
              }
            ],
            "writeMode": "append",
            "fieldDelimiter": ","
          }
        }
      }
    ]
  }
}

对应的截图如下所示:

数据加载执行如下指令:

shell 复制代码
do_date='2020-07-02'
# 创建目录
hdfs dfs -mkdir -p /user/data/trade.db/shops/dt=$do_date
# 数据迁移
python $DATAX_HOME/bin/datax.py -p "-Ddo_date=$do_date" /opt/wzk/datax/shops.json
# 加载数据
# hive中还没有表 后续再执行
hive -e "alter table ods.ods_trade_shops add
partition(dt='$do_date')"

DataX 数据库数据导入到 HDFS 结果如下:

商家地域组织表

wzk_shop_admin_org => ods.ods_trade_shop_admin_org

shell 复制代码
vim /opt/wzk/datax/shop_org.json

编写的内容如下所示:

json 复制代码
{
  "job": {
    "setting": {
      "speed": {
        "channel": 1
      },
      "errorLimit": {
        "record": 0
      }
    },
    "content": [
      {
        "reader": {
          "name": "mysqlreader",
          "parameter": {
            "username": "hive",
            "password": "hive@wzk.icu",
            "column": [
              "id",
              "parentId",
              "orgName",
              "orgLevel",
              "isDelete",
              "createTime",
              "updateTime",
              "isShow",
              "orgType"
            ],
            "connection": [
              {
                "table": [
                  "wzk_shop_admin_org"
                ],
                "jdbcUrl": [
                  "jdbc:mysql://h122.wzk.icu:3306/ebiz"
                ]
              }
            ]
          }
        },
        "writer": {
          "name": "hdfswriter",
          "parameter": {
            "defaultFS": "hdfs://h121.wzk.icu:9000",
            "fileType": "text",
            "path": "/user/data/trade.db/shop_org/dt=$do_date",
            "fileName": "shop_admin_org_$do_date.dat",
            "column": [
              {
                "name": "id",
                "type": "INT"
              },
              {
                "name": "parentId",
                "type": "INT"
              },
              {
                "name": "orgName",
                "type": "STRING"
              },
              {
                "name": "orgLevel",
                "type": "TINYINT"
              },
              {
                "name": "isDelete",
                "type": "TINYINT"
              },
              {
                "name": "createTime",
                "type": "STRING"
              },
              {
                "name": "updateTime",
                "type": "STRING"
              },
              {
                "name": "isShow",
                "type": "TINYINT"
              },
              {
                "name": "orgType",
                "type": "TINYINT"
              }
            ],
            "writeMode": "append",
            "fieldDelimiter": ","
          }
        }
      }
    ]
  }
}

对应的截图如下所示: 数据加载脚本:

shell 复制代码
do_date='2020-07-01'
# 创建目录
hdfs dfs -mkdir -p /user/data/trade.db/shop_org/dt=$do_date
# 数据迁移
python $DATAX_HOME/bin/datax.py -p "-Ddo_date=$do_date" /opt/wzk/datax/shop_org.json
# 加载数据
# hive中还没有表 后续再执行
hive -e "alter table ods.ods_trade_shop_admin_org add
partition(dt='$do_date')"

写入的内容如下所示,从数据库将数据加载到HDFS中:

支付方式表

wzk_payments => ods.ods_trade_payments

shell 复制代码
vim /opt/wzk/datax/payments.json

对应的内容如下:

json 复制代码
{
  "job": {
    "setting": {
      "speed": {
        "channel": 1
      },
      "errorLimit": {
        "record": 0
      }
    },
    "content": [
      {
        "reader": {
          "name": "mysqlreader",
          "parameter": {
            "username": "hive",
            "password": "hive@wzk.icu",
            "column": [
              "id",
              "payMethod",
              "payName",
              "description",
              "payOrder",
              "online"
            ],
            "connection": [
              {
                "table": [
                  "wzk_payments"
                ],
                "jdbcUrl": [
                  "jdbc:mysql://h122.wzk.icu:3306/ebiz"
                ]
              }
            ]
          }
        },
        "writer": {
          "name": "hdfswriter",
          "parameter": {
            "defaultFS": "hdfs://h121.wzk.icu:9000",
            "fileType": "text",
            "path": "/user/data/trade.db/payments/dt=$do_date",
            "fileName": "payments_$do_date.dat",
            "column": [
              {
                "name": "id",
                "type": "INT"
              },
              {
                "name": "payMethod",
                "type": "STRING"
              },
              {
                "name": "payName",
                "type": "STRING"
              },
              {
                "name": "description",
                "type": "STRING"
              },
              {
                "name": "payOrder",
                "type": "INT"
              },
              {
                "name": "online",
                "type": "TINYINT"
              }
            ],
            "writeMode": "append",
            "fieldDelimiter": ","
          }
        }
      }
    ]
  }
}

对应的截图如下:

数据导入的过程如下:

shell 复制代码
do_date='2020-07-01'
# 创建目录
hdfs dfs -mkdir -p /user/data/trade.db/payments/dt=$do_date
# 数据迁移
python $DATAX_HOME/bin/datax.py -p "-Ddo_date=$do_date" /opt/wzk/datax/payments.json
# 加载数据
# hive还没有表 后续再执行
hive -e "alter table ods.ods_trade_payments add
partition(dt='$do_date')"

从MySQL中将数据加载到HDFS中:

错误速查

症状 根因定位 修复
DataX 写入失败:HDFS No such file or directory / Path does not exist 分区目录未提前创建(你当前依赖手工 hdfs dfs -mkdir -p) 看 DataX Job 日志中 hdfswriter 异常;同时 hdfs dfs -ls /user/data/trade.db/.../dt=...运行前统一创建目录;把"mkdir + datax + add partition"封装成同一个日调脚本
Hive add partition 报错:table not found / database not found ODS 表尚未创建(你多处写了"hive 还没有表 后续再执行") hive -e "show tables in ods" / describe formatted ods.xxx先建库建表(含 dt 分区字段),再执行 add partition;或改为 MSCK REPAIR TABLE(前提是分区目录规范)
每日跑完 HDFS 出现大量小文件 channel>1 或多次 append 叠加;并行写导致文件碎片 hdfs dfs -count -q -h 看文件数;NameNode 压力迹象小表固定 channel=1;大表控制并行与切分;必要时落地后做合并(如 Hive insert overwrite/compaction 思路)
字段错位/解析失败(CSV 逗号冲突) fieldDelimiter: "," 但字段内容包含逗号、换行或未转义 抽查 HDFS 文件;对比 MySQL 源字段是否有文本类含逗号更换分隔符(如 \001);或输出为更稳定格式(如 ORC/Parquet,需引入对应 writer/落库方式)
增量表重复/漏数 "导出前一天数据"口径依赖时间字段;时区/延迟写入/更新覆盖导致边界问题 对比 MySQL where 条件与 Hive 分区 dt;抽样核对昨日数据是否全覆盖增量用闭开区间(>=start and <end);引入延迟窗口(T-1/T-2 补拉);对更新型表增加 upsert 处理策略
数据类型不匹配导致 Hive 查询异常 DataX writer 中 type 仅用于写文件,Hive 表类型与文件内容不一致(尤其时间/字符串/数值) describe formatted 对比 Hive schema;抽查 HDFS 文件实际值统一"文件字段顺序 + Hive 列类型 + 分隔符";时间字段明确格式(yyyy-MM-dd HH:mm:ss 等)
MySQL 读取慢/锁表风险 全量抽取对大表压力大;未做分片/条件过滤 MySQL 慢查询/负载;DataX reader 吞吐低大表走增量;reader 增加条件与切分;在业务低峰跑;必要时走从库或快照机制
HDFS 文件名冲突或追加混乱 writeMode: append + 固定 fileName,重复跑会叠加数据 同一 dt 目录下 hdfs dfs -ls 出现多次同名前缀文件约束重跑策略:重跑前清理分区目录;或按时间戳/批次号生成 fileName;或改覆盖写并确保幂等

其他系列

🚀 AI篇持续更新中(长期更新)

AI炼丹日志-29 - 字节跳动 DeerFlow 深度研究框斜体样式架 私有部署 测试上手 架构研究 ,持续打造实用AI工具指南! AI研究-132 Java 生态前沿 2025:Spring、Quarkus、GraalVM、CRaC 与云原生落地

💻 Java篇持续更新中(长期更新)

Java-218 RocketMQ Java API 实战:同步/异步 Producer 与 Pull/Push Consumer MyBatis 已完结,Spring 已完结,Nginx已完结,Tomcat已完结,分布式服务已完结,Dubbo已完结,MySQL已完结,MongoDB已完结,Neo4j已完结,FastDFS 已完结,OSS已完结,GuavaCache已完结,EVCache已完结,RabbitMQ已完结,RocketMQ正在更新... 深入浅出助你打牢基础!

📊 大数据板块已完成多项干货更新(300篇):

包括 Hadoop、Hive、Kafka、Flink、ClickHouse、Elasticsearch 等二十余项核心组件,覆盖离线+实时数仓全栈! 大数据-278 Spark MLib - 基础介绍 机器学习算法 梯度提升树 GBDT案例 详解

相关推荐
砍材农夫2 小时前
TCP和UDP区别
后端
千寻girling3 小时前
一份不可多得的 《 Django 》 零基础入门教程
后端·python·面试
千寻girling3 小时前
Python 是用来做 AI 人工智能 的 , 不适合开发 Web 网站 | 《Web框架》
人工智能·后端·算法
贾铭3 小时前
如何实现一个网页版的剪映(三)使用fabric.js绘制时间轴
前端·后端
xiaoye20183 小时前
Spring 自定义 Redis 超时:TTL、TTI 与 Pipeline 实战
后端
程序员爱钓鱼6 小时前
GoHTML解析利器:github.com/PuerkitoBio/goquery实战指南
后端·google·go
golang学习记6 小时前
从“大泥球“到模块化单体:Spring Modulith + IntelliJ IDEA 拯救你的代码
后端·intellij idea
颜酱6 小时前
一步步实现字符串计算器:从「转整数」到「带括号与优化」
javascript·后端·算法
离开地球表面_996 小时前
金三银四程序员跳槽指南:从简历到面试再到 Offer 的全流程准备
前端·后端·面试