<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>ETL从入门到精通 on 老张开工了</title>
    <link>/etl%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E7%B2%BE%E9%80%9A/</link>
    <description>Recent content in ETL从入门到精通 on 老张开工了</description>
    <generator>Hugo</generator>
    <language>zh-cn</language>
    <lastBuildDate>Wed, 29 Apr 2026 00:00:00 +0000</lastBuildDate>
    <atom:link href="/etl%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E7%B2%BE%E9%80%9A/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>实战：构建完整 ETL 数据管道</title>
      <link>/posts/2026/04/etl-project/</link>
      <pubDate>Wed, 29 Apr 2026 00:00:00 +0000</pubDate>
      <guid>/posts/2026/04/etl-project/</guid>
      <description>项目概述 经过前面 14 篇文章的学习，你已经掌握了 ETL 的各个核心环节：数据抽取、转换、加载、SQL 技巧、Python 开发、现代工具链和工作流编排。现在是时候把它们全部串联起来了。&#xA;本章是一个端到端的实战项目。我们将为一个电商平台构建完整的数据管道，从原始数据采集到业务指标计算，全部自动化运行。&#xA;场景设定 假设你在一家中型电商公司工作。公司有以下几个数据源：&#xA;MySQL 业务数据库：存储订单、用户、商品信息 CSV 文件：存储在 S3 上的每日营销费用数据 REST API：第三方物流服务商的运单状态接口 你的任务是把这些数据汇集到 PostgreSQL 数据仓库中，清洗转换后生成业务报表，并每天自动运行。&#xA;技术栈 环节 工具 用途 数据抽取 Python + SQLAlchemy + requests 从数据库、API、文件抽取数据 数据加载 Python + PostgreSQL 加载到数据仓库 数据转换 dbt 在仓库内完成转换 工作流编排 Airflow 调度整个流程 数据质量 dbt test + Great Expectations 数据验证 监控告警 Airflow + Slack 失败通知 第一步：项目结构 ecommerce-etl/ ├── dags/ # Airflow DAG 定义 │ └── ecommerce_pipeline.py ├── dbt_project/ # dbt 项目 │ ├── dbt_project.</description>
    </item>
    <item>
      <title>工作流编排：Apache Airflow</title>
      <link>/posts/2026/04/etl-airflow/</link>
      <pubDate>Mon, 27 Apr 2026 00:00:00 +0000</pubDate>
      <guid>/posts/2026/04/etl-airflow/</guid>
      <description>为什么需要工作流编排？ 上一章我们介绍了 Airbyte 和 dbt，它们各自负责 ETL 的不同环节。但一个完整的生产环境数据管道包含多个步骤：Airbyte 同步、dbt 运行、数据质量检查、异常告警、失败重试。这些步骤需要按特定顺序执行，并且要每天自动运行。这就是工作流编排工具的职责。&#xA;没有编排工具时，你可能用 cron 脚本把一堆命令串起来：&#xA;# cron 方案，很脆弱 0 2 * * * /usr/bin/airbyte sync-orders &amp;amp;&amp;amp; /usr/bin/dbt run &amp;amp;&amp;amp; /usr/bin/python check_quality.py [/code] 这种方案的问题很明显：没有任务依赖管理，失败无法自动重试，没有可视化的执行状态，难以扩展。当你有几十个数据管道时，cron 脚本很快就会变成一团乱麻。 Apache Airflow 就是为了解决这些问题而生的。 ## Apache Airflow 核心概念 ### DAG（有向无环图） DAG 是 Airflow 中最核心的概念。一个 DAG 定义了一个完整的工作流，包含所有任务以及它们之间的依赖关系。&amp;#34;有向无环&amp;#34;意味着任务之间有方向性的依赖，且不能形成循环依赖。 一个最简单的 DAG from airflow import DAG from airflow.operators.python import PythonOperator from datetime import datetime&#xA;def extract(): print(&amp;ldquo;抽取数据&amp;hellip;&amp;rdquo;)&#xA;def transform(): print(&amp;ldquo;转换数据&amp;hellip;&amp;rdquo;)&#xA;def load(): print(&amp;ldquo;加载数据&amp;hellip;&amp;rdquo;)&#xA;with DAG( dag_id=&amp;ldquo;simple_etl&amp;rdquo;, start_date=datetime(2026, 1, 1), schedule=&amp;quot;@daily&amp;quot;, catchup=False ) as dag: extract_task = PythonOperator( task_id=&amp;ldquo;extract&amp;rdquo;, python_callable=extract ) transform_task = PythonOperator( task_id=&amp;ldquo;transform&amp;rdquo;, python_callable=transform ) load_task = PythonOperator( task_id=&amp;ldquo;load&amp;rdquo;, python_callable=load )</description>
    </item>
    <item>
      <title>开源 ETL 工具链：Airbyte 与 dbt</title>
      <link>/posts/2026/04/etl-tools/</link>
      <pubDate>Sat, 25 Apr 2026 00:00:00 +0000</pubDate>
      <guid>/posts/2026/04/etl-tools/</guid>
      <description>现代开源 ETL 生态 如果你在 2015 年问一个数据工程师用什么做 ETL，答案很可能是 Informatica 或 DataStage。到了 2026 年，答案已经完全不同。开源工具链的成熟让数据团队可以用更低的成本搭建媲美商业产品的数据管道。&#xA;现代开源 ETL 栈的核心是两个工具：Airbyte 负责 Extract 和 Load，dbt 负责 Transform。这个组合被称为&amp;quot;ELT 模式&amp;quot;——先把原始数据加载到目标仓库，再在仓库内部完成转换。相比传统 ETL，ELT 利用数据仓库的计算能力做转换，避免了大量数据传输。&#xA;Airbyte：数据集成层 什么是 Airbyte？ Airbyte 是一个开源的数据集成平台，提供从各种数据源到目标存储的连接器。它的核心理念是&amp;quot;连接器优先&amp;quot;——社区已经贡献了 300 多个预建连接器，覆盖数据库、API、文件存储、SaaS 应用等常见数据源。&#xA;核心概念 Source（源）：数据从哪里来。可以是 PostgreSQL、MySQL、MongoDB 等数据库，也可以是 Stripe、Salesforce、Google Analytics 等 SaaS 服务，还可以是 S3、GCS 等文件存储。&#xA;Destination（目标）：数据到哪里去。常见的目标包括 Snowflake、BigQuery、Redshift、PostgreSQL、S3 等。&#xA;Connection（连接）：定义 Source 和 Destination 之间的数据流。一个连接包含同步频率、同步模式、流的选择等配置。&#xA;Sync Mode（同步模式）：Airbyte 支持多种同步策略：&#xA;模式 说明 适用场景 Full Refresh - Replace 每次全量覆盖 小表、字典表 Full Refresh - Append 每次全量追加 不可变日志 Incremental - Append 增量追加新数据 事件表、日志表 Incremental - Deduped 增量追加并去重 订单表、用户表 部署 Airbyte # 使用 Docker Compose 快速部署 mkdir airbyte &amp;amp;&amp;amp; cd airbyte wget https://raw.</description>
    </item>
    <item>
      <title>SQL 在 ETL 中的应用</title>
      <link>/posts/2026/04/etl-sql/</link>
      <pubDate>Thu, 23 Apr 2026 00:00:00 +0000</pubDate>
      <guid>/posts/2026/04/etl-sql/</guid>
      <description>SQL 在 ETL 中的角色 很多人一提到 ETL 就想到 Python 或 Spark，但 SQL 才是 ETL 领域最基础也最强大的工具。无论你用什么框架，最终的数据操作大多会落到 SQL 上。dbt 用 SQL 做转换，Spark SQL 用 SQL 做分析，甚至 Pandas 的 DataFrame 操作在概念上也和 SQL 的 SELECT、GROUP BY、JOIN 一一对应。&#xA;SQL 的优势在于声明式：你告诉数据库&amp;quot;要什么&amp;quot;，而不是&amp;quot;怎么做&amp;quot;。数据库优化器会帮你决定最佳的执行路径。对于数据量在千万级以下的 ETL 任务，纯 SQL 方案往往比 Python 方案更简洁、更高效。&#xA;CTE：构建可读的 ETL 管道 公用表表达式（CTE）是 SQL ETL 中最有用的语法之一。它让你能把复杂的转换拆成多个逻辑步骤，每个步骤清晰独立，就像管道中的一个个节点。&#xA;`sql &amp;ndash; 一个典型的 ETL 管道，用 CTE 分步实现 WITH &amp;ndash; 步骤 1：抽取原始数据 raw_orders AS ( SELECT * FROM orders WHERE order_date &amp;gt;= &amp;lsquo;2026-01-01&amp;rsquo; ),</description>
    </item>
    <item>
      <title>Python ETL 实践</title>
      <link>/posts/2026/04/etl-python/</link>
      <pubDate>Tue, 21 Apr 2026 00:00:00 +0000</pubDate>
      <guid>/posts/2026/04/etl-python/</guid>
      <description>为什么用 Python 做 ETL？ Python 是数据工程领域最受欢迎的语言之一。原因很简单：语法简洁、生态丰富、社区庞大。对于 ETL 开发来说，Python 的优势尤其明显。&#xA;Python 拥有几乎所有数据源对应的库。连接数据库有 SQLAlchemy 和 psycopg2，处理文件有 Pandas 和 PyArrow，调用 API 有 requests 和 httpx，操作云存储有 boto3 和 google-cloud-storage。你几乎不需要从零开始写任何底层代码。&#xA;另一个关键优势是灵活性。SQL 擅长做声明式的数据转换，但遇到复杂的业务逻辑、条件分支、循环处理时，Python 的表达力远超 SQL。ETL 流程中那些脏活累活——数据清洗、异常处理、重试机制、日志记录——用 Python 写起来得心应手。&#xA;核心库速览 Pandas：数据转换的主力 Pandas 是 Python ETL 中最核心的库。它提供了 DataFrame 数据结构，可以理解为一个内存中的表格，支持各种数据操作：过滤、聚合、关联、透视、窗口函数等。&#xA;`python import pandas as pd&#xA;从 CSV 读取数据 df = pd.read_csv(&amp;ldquo;sales.csv&amp;rdquo;)&#xA;数据清洗 df = df.dropna(subset=[&amp;ldquo;amount&amp;rdquo;]) df[&amp;ldquo;amount&amp;rdquo;] = df[&amp;ldquo;amount&amp;rdquo;].clip(lower=0) # 过滤负值&#xA;数据转换 df[&amp;ldquo;order_month&amp;rdquo;] = pd.to_datetime(df[&amp;ldquo;order_date&amp;rdquo;]).dt.to_period(&amp;ldquo;M&amp;rdquo;) df[&amp;ldquo;total_price&amp;rdquo;] = df[&amp;ldquo;quantity&amp;rdquo;] * df[&amp;ldquo;unit_price&amp;rdquo;]</description>
    </item>
    <item>
      <title>元数据管理与数据血缘</title>
      <link>/posts/2026/04/etl-metadata/</link>
      <pubDate>Sun, 19 Apr 2026 00:00:00 +0000</pubDate>
      <guid>/posts/2026/04/etl-metadata/</guid>
      <description>元数据到底是什么 元数据就是&amp;quot;关于数据的数据&amp;quot;。听起来像绕口令，但道理很简单：你的 ETL 管道每天处理几百张表、几千个字段、几十个任务。当有人问&amp;quot;这张表的数据从哪来的&amp;quot;或者&amp;quot;这个字段的转换规则是什么&amp;quot;时，你需要一个系统来回答这些问题。这个系统就是元数据管理。&#xA;元数据分为三个层次：&#xA;技术元数据 技术元数据描述数据处理的技术细节：&#xA;数据库连接信息 表的 schema（字段名、类型、约束） 分区和文件路径 ETL 任务的调度配置 数据量和大小 # 典型的表级技术元数据 table_metadata = { &amp;#34;table_name&amp;#34;: &amp;#34;fact_orders&amp;#34;, &amp;#34;database&amp;#34;: &amp;#34;dw_prod&amp;#34;, &amp;#34;schema&amp;#34;: &amp;#34;public&amp;#34;, &amp;#34;columns&amp;#34;: [ {&amp;#34;name&amp;#34;: &amp;#34;order_id&amp;#34;, &amp;#34;type&amp;#34;: &amp;#34;BIGINT&amp;#34;, &amp;#34;nullable&amp;#34;: False, &amp;#34;pk&amp;#34;: True}, {&amp;#34;name&amp;#34;: &amp;#34;user_id&amp;#34;, &amp;#34;type&amp;#34;: &amp;#34;BIGINT&amp;#34;, &amp;#34;nullable&amp;#34;: False, &amp;#34;fk&amp;#34;: &amp;#34;dim_users&amp;#34;}, {&amp;#34;name&amp;#34;: &amp;#34;amount&amp;#34;, &amp;#34;type&amp;#34;: &amp;#34;DECIMAL(12,2)&amp;#34;, &amp;#34;nullable&amp;#34;: False}, {&amp;#34;name&amp;#34;: &amp;#34;status&amp;#34;, &amp;#34;type&amp;#34;: &amp;#34;VARCHAR(20)&amp;#34;, &amp;#34;nullable&amp;#34;: False}, {&amp;#34;name&amp;#34;: &amp;#34;created_at&amp;#34;, &amp;#34;type&amp;#34;: &amp;#34;TIMESTAMP&amp;#34;, &amp;#34;nullable&amp;#34;: False}, ], &amp;#34;partitions&amp;#34;: [&amp;#34;dt&amp;#34;], &amp;#34;format&amp;#34;: &amp;#34;parquet&amp;#34;, &amp;#34;location&amp;#34;: &amp;#34;s3://dw-prod/orders/&amp;#34;, &amp;#34;row_count&amp;#34;: 50000000, &amp;#34;last_refreshed&amp;#34;: &amp;#34;2026-04-19 03:15:00&amp;#34;, } 业务元数据 业务元数据回答&amp;quot;这是什么意思&amp;quot;的问题：</description>
    </item>
    <item>
      <title>ETL 性能优化技巧</title>
      <link>/posts/2026/04/etl-performance/</link>
      <pubDate>Fri, 17 Apr 2026 00:00:00 +0000</pubDate>
      <guid>/posts/2026/04/etl-performance/</guid>
      <description>瓶颈在哪里 ETL 性能优化最忌讳的事就是一上来到处调参数。没有找到真正的瓶颈之前，所有的优化都是瞎蒙。&#xA;先搞清楚一个基本事实：ETL 管道中最慢的环节决定了整体速度。这个瓶颈可能出现在抽取阶段（网络带宽限制）、转换阶段（CPU 算力不足）、或者加载阶段（数据库写入太慢）。&#xA;定位瓶颈的基本方法是用监控工具观察每个阶段的耗时和资源消耗。一个简单的做法是在管道中埋点记录时间：&#xA;import time from contextlib import contextmanager @contextmanager def measure_stage(stage_name, logger=None): &amp;#34;&amp;#34;&amp;#34;记录每个阶段的耗时&amp;#34;&amp;#34;&amp;#34; start = time.time() start_mem = get_memory_usage() try: yield finally: elapsed = time.time() - start end_mem = get_memory_usage() print(f&amp;#34;[{stage_name}] 耗时: {elapsed:.2f}s, &amp;#34; f&amp;#34;内存: {start_mem:.0f}MB → {end_mem:.0f}MB &amp;#34; f&amp;#34;(增量: {end_mem - start_mem:.0f}MB)&amp;#34;) 在实际案例中，我曾见过一个团队花了两周优化 SQL 查询，把转换阶段从 2 小时降到 20 分钟，但整体 ETL 仍然跑了 3 小时——因为他们没发现瓶颈其实在加载阶段，数据库写入速度跟不上。&#xA;并行处理 并行是加速 ETL 最直接的手段。可以把一个大任务拆分成多个小任务同时执行。&#xA;数据分区并行 把数据按某个维度分成多个分区，每个分区独立处理。分区方式包括：&#xA;按时间分区：每天的数据一个分区，多天的数据可以并行处理 按范围分区：按 ID 范围拆分，比如 1-100 万、100 万-200 万 按业务维度：按地区、产品类别等业务字段拆分 import concurrent.</description>
    </item>
    <item>
      <title>数据质量监控与异常处理</title>
      <link>/posts/2026/04/etl-data-quality/</link>
      <pubDate>Wed, 15 Apr 2026 00:00:00 +0000</pubDate>
      <guid>/posts/2026/04/etl-data-quality/</guid>
      <description>数据质量为什么是 ETL 的生命线 先讲一个真实的故事。某电商公司每天凌晨跑 ETL，把前一天的订单数据导入分析系统。数据团队每天早上的第一件事就是检查报表。有一天，市场部开会时发现 GMV（总成交额）比前一天跌了 80%。大家慌了——不是运营出了问题，而是 ETL 任务在凌晨 2 点因为源库连接超时失败了，但没有人发现。整个上午的决策都基于错误的数据。&#xA;这种情况在数据工程领域太常见了。数据管道的输出质量直接影响着下游的报表、分析和机器学习模型。没有质量监控的 ETL 管道，就像没有质检的生产线——你不知道产品里有没有混入次品，甚至不知道生产线是不是还在运转。&#xA;数据质量的六个维度 在建立数据质量监控之前，先要明确&amp;quot;质量好&amp;quot;到底是什么意思。业界通常用这六个维度来衡量：&#xA;准确性（Accuracy） 数据是否真实反映了现实世界的情况？一个用户的年龄写的是 200 岁，这不准确。一笔订单金额是负数，这也是不准确。&#xA;完整性（Completeness） 是否有缺失的数据？订单表里必须有订单号，如果订单号字段为空，就违反了完整性要求。在 ETL 场景中，完整性还指目标表的数据行数是否和源表一致。&#xA;一致性（Consistency） 数据在不同系统之间是否一致？用户表里姓名字段在数据库 A 中是 UTF-8 编码，在数据库 B 中是 GBK 编码，同一用户在两个系统中的姓名可能不一致。&#xA;时效性（Timeliness） 数据是否在预期的时间内可用？每日报表要求在早上 8 点前准备好，如果 ETL 任务跑到了中午 12 点，数据就是&amp;quot;过期&amp;quot;的。&#xA;唯一性（Uniqueness） 数据是否有重复？主键是否唯一？在 ETL 过程中，如果同一个订单被抽取了两次，就会破坏唯一性约束。&#xA;有效性（Validity） 数据是否满足定义的格式和规则？邮件地址必须包含 @，手机号必须是 11 位数字，枚举字段必须在定义的值范围内。&#xA;在 ETL 管道中嵌入质量检查 质量检查不应该在数据入仓之后再去做，而应该嵌入在 ETL 管道的每一个环节。&#xA;抽取阶段：源端检查 在抽取数据之前，先对源数据做基本检查：&#xA;def validate_source(source_config): &amp;#34;&amp;#34;&amp;#34;源端数据验证&amp;#34;&amp;#34;&amp;#34; checks = { &amp;#34;table_exists&amp;#34;: check_table_exists(source_config), &amp;#34;row_count_reasonable&amp;#34;: check_row_count(source_config), &amp;#34;freshness&amp;#34;: check_data_freshness(source_config), &amp;#34;schema_match&amp;#34;: check_schema(source_config), } failed = [name for name, passed in checks.</description>
    </item>
    <item>
      <title>增量抽取与变更数据捕获（CDC）</title>
      <link>/posts/2026/04/etl-cdc/</link>
      <pubDate>Mon, 13 Apr 2026 00:00:00 +0000</pubDate>
      <guid>/posts/2026/04/etl-cdc/</guid>
      <description>为什么全量刷新不够用 在 ETL 入门阶段，全量刷新听起来很省事：每次把源表的所有数据删掉，重新拉一遍。对于小数据量表，这没什么问题。但当数据量增长到百万、千万甚至亿级时，全量刷新就成了一场噩梦。&#xA;来看几个数字。假设你有一个订单表，每天新增 5 万条记录，总计 2000 万行。全量读取 2000 万行可能耗费 30 分钟，但实际发生变化的数据只有 5 万行，占总量的 0.25%。这意味着你浪费了 99.75% 的传输量和计算量。&#xA;全量刷新还有几个更棘手的问题：&#xA;窗口时间不够：数据量越大，刷新窗口越长。如果每天只有 2 小时的维护窗口，全量同步 10 亿条数据根本跑不完 对源库压力大：全表扫描会对业务数据库造成巨大压力，影响在线交易 浪费存储和带宽：每次传输全部数据，压缩、网络、磁盘 IO 的成本成倍增加 增量抽取就是为了解决这些问题而生的。&#xA;增量抽取的三种主要策略 增量抽取的核心是回答一个问题：&amp;ldquo;上次处理完之后，哪些数据发生了变化？&amp;rdquo; 针对不同的数据源和业务场景，有三种主流策略。&#xA;时间戳增量 时间戳策略是最简单、应用最广泛的增量抽取方式。原理是：源表里有一个时间字段（如 updated_at、modified_date），记录每条数据最后修改的时间。每次抽取时，只取时间大于上次抽取时间的记录。&#xA;-- 最后一次抽取的时间是 2026-04-12 03:00:00 -- 只抽取此后修改的数据 SELECT * FROM orders WHERE updated_at &amp;gt; &amp;#39;2026-04-12 03:00:00&amp;#39; AND updated_at &amp;lt;= &amp;#39;2026-04-13 03:00:00&amp;#39;; 时间戳策略的优点是实现简单，对源库改造小。但缺点也很明显：&#xA;需要源表有时间戳字段，且业务代码正确维护该字段 物理删除的数据无法被捕获（删除不更新时间戳） 时间精度不够时可能漏数据（如果两行在同一毫秒内修改） 批量更新时间戳的情况可能导致重复或遗漏 增量文件/日志 有些系统会主动生成包含变更的文件或日志。例如：&#xA;应用日志：业务系统把每次增删改操作输出到日志文件 增量文件：ERP 系统每天生成变更文件，记录当天修改的记录 ID Binlog：MySQL 的二进制日志记录了所有数据变更 增量文件的方式对源系统侵入最小，但依赖应用配合生成这些文件。&#xA;基于日志的 CDC（Change Data Capture） CDC 是增量抽取的终极方案。它的原理是直接读取数据库的事务日志（如 MySQL 的 binlog、PostgreSQL 的 WAL），从中解析出所有数据变更事件。</description>
    </item>
    <item>
      <title>批量处理与调度策略</title>
      <link>/posts/2026/04/etl-batch-scheduling/</link>
      <pubDate>Sat, 11 Apr 2026 00:00:00 +0000</pubDate>
      <guid>/posts/2026/04/etl-batch-scheduling/</guid>
      <description>为什么需要批量处理 ETL 的本质是数据的搬移和转换。当数据量达到一定规模后，逐条处理就不再可行。不管是每天几百万条订单记录，还是每小时数 GB 的日志文件，批量处理都是数据工程的基础操作方式。&#xA;批量处理的核心思路很简单：把数据分成一个个批次，每个批次作为一个整体来处理。这样做的好处很明显：&#xA;吞吐量高：一次处理一批数据，而不是一条一条来 资源利用好：可以集中分配计算和存储资源 可恢复性强：一个批次失败不会影响其他批次 成本可控：按批处理，容易预估时间和开销 举一个实际的例子。假设你每天凌晨需要把前一天的所有订单从业务数据库同步到数据仓库。如果逐条同步一百万条订单，每条都在 10 毫秒，总耗时超过 2.5 小时；但如果用批量方式，每次插入一万条，网络往返次数从一百万次减少到一百次，整个流程可能十几分钟就完成了。&#xA;调度策略的三种模式 调度就是决定&amp;quot;什么时候跑哪个任务&amp;quot;。在 ETL 场景中，调度策略主要分三种。&#xA;时间驱动调度 最简单也最常用的方式。规定好时间，到点就执行。常见的形式有：&#xA;固定间隔：每 5 分钟跑一次增量抽取 定时执行：每天凌晨 3 点跑全量刷新 日历触发：每月 1 号跑月度汇总 时间驱动的优点是实现简单，依赖少。缺点是不够灵活——你无法感知上游数据是否准备好，如果上游系统故障导致数据延迟到达，定时任务可能跑了个空。&#xA;事件驱动调度 不是看时间，而是看条件。当某个事件发生时触发执行。事件可以是：&#xA;文件到达：监控某个 FTP 目录，新文件出现就触发处理 消息通知：上游系统发送一条 Kafka 消息，通知数据已就绪 API 回调：第三方系统通过 Webhook 通知数据变更 数据库变更：CDC 工具捕获到变更后触发后续流程 事件驱动的优势是反应迅速，不会浪费计算资源跑空任务。缺点是引入事件中间件会增加系统复杂度，而且事件丢失后需要有补偿机制。&#xA;依赖驱动调度 任务之间有关系。B 必须在 A 完成后才能跑，C 必须等 A 和 B 都完成。这种&amp;quot;先做这个，再做那个&amp;quot;的编排方式就是依赖驱动调度。&#xA;依赖驱动的典型实现是 DAG（有向无环图）。每个任务是一个节点，任务之间的依赖关系是边。调度引擎按照 DAG 的拓扑顺序执行任务，保证每个任务只在其所有前置依赖完成后才启动。&#xA;Cron 表达式与定时任务 Cron 是 Linux 世界最经典的定时任务工具。几乎所有调度框架都兼容 cron 表达式。来看一个基本的 cron 格式：</description>
    </item>
    <item>
      <title>ETL 架构模式与 ELT 对比</title>
      <link>/posts/2026/04/etl-architecture/</link>
      <pubDate>Thu, 09 Apr 2026 00:00:00 +0000</pubDate>
      <guid>/posts/2026/04/etl-architecture/</guid>
      <description>从 ETL 到架构思维 前面三篇文章我们分别深入了 ETL 的抽取、转换和加载三个环节。沿着这条路径，我们掌握了&amp;quot;怎么做&amp;quot;ETL。但当你从实现单个流程转向设计整个系统时，就需要切换到架构思维——考虑的不再是一条数据怎么跑，而是整个数据平台怎么搭。&#xA;数据架构的选择决定了系统的扩展性、维护成本和团队效率。选择一个不适合的架构，可能在数据量增长时遭遇性能瓶颈，或者在业务需求变化时难以调整。本文将从架构层面讨论 ETL 的各种模式，并与 ELT 进行深入对比。&#xA;传统 ETL 三層架构 传统 ETL 采用严格的三层架构，数据按照&amp;quot;源系统 → staging 区 → 数据仓库 → 数据集市&amp;quot;的顺序流动。&#xA;┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ 源系统 │ → │ Staging │ → │ 数据仓库 │ → │ 数据集市 │ │ (OLTP) │ │ (原始层) │ │ (明细层) │ │ (汇总层) │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ ↓ ┌──────────┐ │ 转换引擎 │ │ (ETL 层) │ └──────────┘ Staging 区 Staging 层是数据进入数据仓库的第一站。在此阶段，数据保持与源系统几乎一致的结构，不做任何转换。它的主要作用是隔离——避免直接从源系统拉数据时对业务产生影响。</description>
    </item>
    <item>
      <title>数据加载（Load）：目标存储与写入</title>
      <link>/posts/2026/04/etl-load/</link>
      <pubDate>Tue, 07 Apr 2026 00:00:00 +0000</pubDate>
      <guid>/posts/2026/04/etl-load/</guid>
      <description>数据加载概述 数据加载是 ETL 流程的最后一公里。经过抽取和转换的数据，最终需要写入目标存储系统，供分析师、数据科学家和业务系统使用。&#xA;加载环节看似简单——不就是把数据写进去吗？但实际上，加载策略的选择直接影响数据的一致性和可用性。是全量刷新还是增量更新？用 INSERT 还是 COPY？数据量大时如何保证写入性能？加载过程中出错了怎么办？这些问题都必须在设计阶段想清楚。&#xA;加载策略 全量加载 全量加载每次都将整个数据集写入目标表。它最简单直接，适合数据量不大或者需要完全重建分析视图的场景。&#xA;-- 全量加载：先清空目标表，再写入全部数据 TRUNCATE TABLE dwd_sales_daily; INSERT INTO dwd_sales_daily SELECT * FROM clean_sales_data; 优点：逻辑简单、数据完全一致、不需要处理变更追踪。&#xA;缺点：数据量大时耗时很长、消耗大量资源、加载期间数据不可用。&#xA;增量加载 增量加载只写入自上次加载以来发生变化的数据。它高效但实现复杂，需要可靠的变更追踪机制。&#xA;import psycopg2 import pandas as pd from datetime import datetime, timedelta def incremental_load(source_conn_str, target_conn_str, table_name, date_column): &amp;#34;&amp;#34;&amp;#34;增量加载：只加载最近一天的数据&amp;#34;&amp;#34;&amp;#34; yesterday = (datetime.now() - timedelta(days=1)).strftime(&amp;#34;%Y-%m-%d&amp;#34;) # 从源系统抽取增量数据 source_conn = psycopg2.connect(source_conn_str) query = f&amp;#34;SELECT * FROM {table_name} WHERE {date_column} &amp;gt;= &amp;#39;{yesterday}&amp;#39;&amp;#34; df = pd.read_sql(query, source_conn) source_conn.close() print(f&amp;#34;抽取到 {len(df)} 条增量记录&amp;#34;) if df.</description>
    </item>
    <item>
      <title>数据转换（Transform）：清洗与加工</title>
      <link>/posts/2026/04/etl-transform/</link>
      <pubDate>Sun, 05 Apr 2026 00:00:00 +0000</pubDate>
      <guid>/posts/2026/04/etl-transform/</guid>
      <description>Transform：ETL 的核心环节 如果说抽取是&amp;quot;采购食材&amp;quot;，加载是&amp;quot;摆盘上桌&amp;quot;，那么转换就是整个 ETL 流程中的&amp;quot;烹饪&amp;quot;环节。这也是数据工程师投入精力最多、代码量最大的部分。&#xA;原始数据通常充满了各种问题：字段缺失、格式不统一、存在重复记录、数值异常等等。转换环节的目标就是把这些&amp;quot;脏数据&amp;quot;变成干净、一致、可分析的高质量数据。毫不夸张地说，一个 ETL 流程的质量高低，几乎完全取决于转换环节做得怎么样。&#xA;常见的数据质量问题 在实际项目中，我们经常遇到以下几类数据质量问题：&#xA;缺失值 数据集中某些字段为空，这是最常见的问题。缺失的原因可能是源系统没有采集到、传输过程中丢失、或者该字段本身就不适用。&#xA;重复记录 同一行数据在数据集中出现了多次，通常是因为源系统没有正确的唯一约束、多次导入未去重、或者数据合并时出现了重复。&#xA;异常值 数据值明显超出正常范围。例如，年龄字段出现 200 岁、订单金额为负数、温度字段出现 9999 等。异常值可能是录入错误，也可能是正常但罕见的业务场景。&#xA;格式不一致 同一类型的数据使用了不同的表示方式。例如日期字段有的用&amp;quot;2026-04-05&amp;quot;，有的用&amp;quot;2026/04/05&amp;quot;，还有的用&amp;quot;05/04/2026&amp;quot;；电话号码有的带国家区号，有的不带。&#xA;问题类型 示例 原因 影响 缺失值 email 列为 NULL 未采集、未必填 统计分析偏差 重复记录 同一订单出现 2 次 重复导入 汇总数据翻倍 异常值 年龄=500 录入错误 平均值失真 格式不一致 日期格式混杂 多源合并 解析失败 逻辑矛盾 下单日期 &amp;gt; 发货日期 业务约束违反 数据不可信 使用 Pandas 进行数据清洗 Pandas 是 Python 生态中最强大的数据处理库，也是 ETL 转换环节的首选工具。&#xA;缺失值处理 import pandas as pd import numpy as np # 加载原始数据 df = pd.</description>
    </item>
    <item>
      <title>数据抽取（Extract）：数据源与连接</title>
      <link>/posts/2026/04/etl-extract/</link>
      <pubDate>Fri, 03 Apr 2026 00:00:00 +0000</pubDate>
      <guid>/posts/2026/04/etl-extract/</guid>
      <description>数据抽取概述 数据抽取是 ETL 流程的第一个环节，也是后续所有工作的基础。如果把 ETL 比作烹饪，抽取就是&amp;quot;采购食材&amp;quot;——食材的质量和新鲜度直接决定了最终菜品的好坏。&#xA;在实际工作中，数据抽取面临的挑战往往比想象中大：源系统的类型五花八门、数据量可能非常庞大、抽取过程不能影响业务系统的正常运行、网络不稳定导致连接中断等。因此，设计一个健壮的数据抽取方案是整个 ETL 工程的起点。&#xA;数据源的类型 现代数据架构中的数据源可以大致归为以下几类：&#xA;关系型数据库 关系型数据库是最常见的数据源。企业核心业务数据通常存储在 MySQL、PostgreSQL、Oracle、SQL Server 等系统中。从关系型数据库抽取数据通常有几种方式：直接执行 SELECT 查询、使用数据库的导出工具、通过日志复制（CDC）等。&#xA;文件系统 文件是另一种常见的数据载体。CSV 和 JSON 是最通用的交换格式，几乎任何系统都能读写。在大数据生态中，Parquet 和 Avro 这类列式存储格式越来越流行，它们具有更好的压缩率和查询性能。&#xA;API 接口 许多 SaaS 平台（如 Salesforce、HubSpot、Google Analytics）只通过 API 暴露数据。RESTful API 是目前的主流协议，GraphQL 也在逐渐普及。API 抽取通常需要考虑认证、限流、分页等问题。&#xA;消息队列和流数据 Kafka、RabbitMQ、AWS Kinesis 等消息系统承载着实时数据流。从这类系统抽取数据时，通常使用消费者模式持续订阅数据。这类场景往往偏向实时或准实时处理。&#xA;数据源类型 典型例子 抽取方式 常见挑战 关系型数据库 MySQL, PostgreSQL, Oracle JDBC/ODBC 查询、导出 dump 大表全量扫描影响性能 文件 CSV, JSON, Parquet, Avro 文件读取、FTP/S3 下载 文件编码、格式不一致 API REST, GraphQL, SOAP HTTP 请求 限流、认证、分页 消息队列 Kafka, RabbitMQ, Kinesis Consumer 订阅 消息顺序、重复消费 从关系型数据库抽取数据 JDBC 方式（Python 示例） JDBC（Java Database Connectivity）是连接数据库的标准接口。在 Python 中，我们可以使用数据库驱动库来实现类似的功能。</description>
    </item>
    <item>
      <title>ETL 从入门到精通</title>
      <link>/posts/2026/04/etl-course/</link>
      <pubDate>Wed, 01 Apr 2026 00:00:00 +0000</pubDate>
      <guid>/posts/2026/04/etl-course/</guid>
      <description>ETL（Extract, Transform, Load）是数据工程领域最核心的技能之一。无论你是数据工程师、数据分析师还是数据科学家，掌握 ETL 都是在实际工作中处理数据的必备能力。&#xA;本系列教程将从零开始，系统地带你掌握 ETL 的核心知识和实战技能。从基础概念到高级架构，从传统工具到云原生方案，涵盖理论、工具与实战，帮助你构建完整的数据工程知识体系。&#xA;课程大纲 基础篇 ETL 概述与数据工程基础 数据抽取（Extract）：数据源与连接 数据转换（Transform）：清洗与加工 数据加载（Load）：目标存储与写入 ETL 架构模式与 ELT 对比 进阶篇 批量处理与调度策略 增量抽取与变更数据捕获（CDC） 数据质量监控与异常处理 ETL 性能优化技巧 元数据管理与数据血缘 工具与实战篇 Python ETL 实践 SQL 在 ETL 中的应用 开源 ETL 工具链：Airbyte 与 dbt 工作流编排：Apache Airflow 实战：构建完整 ETL 数据管道 本系列文章中的代码示例主要使用 Python 和 SQL，你可以在本地或任何 Notebook 环境中运行体验。</description>
    </item>
    <item>
      <title>ETL 概述与数据工程基础</title>
      <link>/posts/2026/04/etl-overview/</link>
      <pubDate>Wed, 01 Apr 2026 00:00:00 +0000</pubDate>
      <guid>/posts/2026/04/etl-overview/</guid>
      <description>什么是 ETL？ ETL 是 Extract（抽取）、Transform（转换）、Load（加载）三个英文单词的首字母缩写。它描述了一个经典的数据集成过程：从源系统中抽取数据，经过清洗和转换，最终加载到目标存储系统中。&#xA;用一个简单的类比来理解：假设你要把散落在几个仓库里的书籍搬到一个新图书馆。你需要先去各个仓库把书搬出来（Extract），按照图书馆的分类体系给书贴上标签、整理排序（Transform），最后摆放到对应的书架上（Load）。ETL 做的就是这件事，只不过处理的对象是数据。&#xA;ETL 的三个核心步骤 抽取（Extract）：从各类数据源读取数据。数据源可以是关系型数据库、文件（CSV、JSON、Parquet）、API 接口、消息队列等。这一步的关键是高效地获取数据，尽可能减少对源系统的压力。&#xA;转换（Transform）：对原始数据进行清洗、加工和重组。这是 ETL 流程中最复杂、最核心的环节。具体操作包括：处理缺失值和异常值、统一数据格式、执行业务规则计算、数据聚合和关联等。&#xA;加载（Load）：将处理后的数据写入目标系统。目标通常是数据仓库、数据湖或者分析型数据库。加载策略分为全量加载和增量加载，选择哪种方案取决于业务需求和数据量级。&#xA;ETL 的起源与演进 数据仓库时代（1990s） ETL 概念最早在 1990 年代随着数据仓库的兴起而出现。当时企业开始意识到，将分散在各个业务系统中的数据汇集到一个统一的分析平台，能够带来巨大的商业价值。&#xA;Bill Inmon 和 Ralph Kimball 两位数据仓库大师分别提出了不同的数据仓库方法论，但两者的实现都离不开 ETL 这一核心流程。早期的 ETL 工具以商业软件为主，如 Informatica PowerCenter、IBM DataStage、Oracle Data Integrator 等。&#xA;Hadoop 时代（2000s-2010s） Hadoop 的出现打破了传统数据仓库的格局。分布式存储和计算框架使得处理海量数据成为可能，ETL 的概念也发生了变化。在这个阶段，Sqoop 用于在 Hadoop 和关系型数据库之间传输数据，Hive 和 Pig 用于数据转换，Flume 用于日志采集。&#xA;云原生时代（2010s 至今） 云计算的普及彻底改变了 ETL 的面貌。现代数据栈（Modern Data Stack）的兴起带来了几个重要变化：&#xA;ELT 模式成为主流：先把原始数据加载到数据湖，再利用目标系统（如 Snowflake、BigQuery）的强大计算能力进行转换 工具链更加丰富：dbt、Airbyte、Fivetran、Stitch 等新一代工具大幅降低了 ETL 的开发门槛 实时化趋势：从批处理向流处理演进，Kafka、Flink 等工具使得准实时和实时 ETL 成为可能 下面这张表格展示了 ETL 工具在三个时代的典型代表：</description>
    </item>
  </channel>
</rss>
