Skip to content

필사 모드: 数据工程与 AI 流水线完全指南:从 Spark 到 Kafka

中文
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.

目录

  1. 数据工程概述
  2. Apache Spark
  3. Apache Kafka
  4. Apache Airflow
  5. dbt (Data Build Tool)
  6. Delta Lake / Apache Iceberg
  7. 特征存储
  8. 数据质量与监控
  9. 云数据平台
  10. 测验

数据工程概述

数据工程是 AI/ML 系统的根基所在。设计并构建数据流水线,将数据以适合分析与模型训练的形式提供出来,是其核心角色。

角色对比:数据工程师 vs 数据科学家 vs ML 工程师

角色主要职责核心工具
数据工程师构建流水线、管理数据存储Spark, Kafka, Airflow, dbt
数据科学家数据分析、模型开发Python, Jupyter, Pandas, Scikit-learn
ML 工程师模型部署、服务基础设施MLflow, Kubeflow, TFX, Ray

现代数据栈架构

现代数据栈(Modern Data Stack)已经转向以云为中心重构:

  • 采集(Ingestion):Fivetran、Airbyte、Kafka
  • 存储(Storage):Snowflake、BigQuery、Redshift、Delta Lake
  • 转换(Transformation):dbt、Spark、Beam
  • 编排(Orchestration):Airflow、Prefect、Dagster
  • 可视化(Visualization):Tableau、Looker、Metabase

批处理 vs 流处理

批处理(Batch Processing)按周期处理大批量数据。用于数据仓库 ETL 作业、日报生成、模型再训练等场景。

流处理(Stream Processing)在数据生成的同时立即处理。适合实时欺诈检测、异常检测、推荐系统更新等场景。

Lambda 架构 vs Kappa 架构

Lambda 架构并行运行批处理层与速度层,将精确的批处理结果与实时流结果在服务层合并。复杂度较高,但能保证准确性。

Kappa 架构只用流处理层来简化架构。随着 Kafka Streams、Flink 等工具的发展,它已成为一个实用的选择。易于维护,也能保持代码库的一致性。


Apache Spark

Apache Spark 是面向大规模数据处理的统一分析引擎。凭借内存中处理,性能最高可达 Hadoop MapReduce 的 100 倍。

Spark 架构

Spark 集群由三个核心组件构成:

  • Driver:运行 SparkContext 并协调作业的主进程
  • Executor:实际执行数据处理的工作进程
  • Cluster Manager:YARN、Kubernetes、Mesos 或 Spark Standalone

RDD、DataFrame、Dataset API

RDD(Resilient Distributed Dataset)是 Spark 的基本数据结构,为分布式集合提供不可变操作。

DataFrame 是带 schema 的分布式集合,提供类似 SQL 的 API。借助 Catalyst 优化器自动优化查询。

Dataset 是 DataFrame 的类型安全版本,在 Scala/Java 中支持编译期类型检查。

用 PySpark 做 AI 特征工程

from pyspark.sql import SparkSession
from pyspark.sql.functions import col, count, avg, when
from pyspark.ml.feature import VectorAssembler
from pyspark.ml.classification import RandomForestClassifier

spark = SparkSession.builder \
    .appName("AI Feature Engineering") \
    .config("spark.sql.adaptive.enabled", "true") \
    .getOrCreate()

# 加载并转换数据
df = spark.read.parquet("s3://data-lake/features/")
df_clean = df.dropna() \
    .withColumn("age_group", when(col("age") < 30, "young")
                              .when(col("age") < 50, "middle")
                              .otherwise("senior"))

# 聚合统计
stats_df = df_clean.groupBy("category").agg(
    count("*").alias("cnt"),
    avg("score").alias("avg_score")
)

# 构建特征向量
assembler = VectorAssembler(
    inputCols=["age", "income", "score"],
    outputCol="features"
)
ml_df = assembler.transform(df_clean)

# 训练模型
rf = RandomForestClassifier(numTrees=100, featuresCol="features")
model = rf.fit(ml_df)

Spark SQL 优化技巧

  • 分区(Partitioning):按经常过滤的列做分区。
  • 广播 Join(Broadcast Join):小表使用广播 join。
  • 缓存(Caching):反复使用的 DataFrame 用 cache()persist() 保留在内存中。
  • AQE(Adaptive Query Execution):利用 Spark 3.0+ 的动态查询优化。

Apache Kafka

Apache Kafka 是一个高吞吐、具备容错能力的分布式事件流平台。由 LinkedIn 开发并开源,现已成为实时 AI 流水线的核心基础设施。

Kafka 架构

  • Broker:存储并转发消息的服务器。集群由多个 Broker 组成。
  • Topic:消息发布所在的分类/信息流名称
  • Partition:将 Topic 切分以实现并行处理。每个分区保证顺序。
  • Consumer Group:共享同一 Topic 的消费者集合,提供负载均衡。
  • Offset:分区内消息的唯一位置标识符

生产者/消费者模式

from kafka import KafkaProducer, KafkaConsumer
import json
import numpy as np

# 生产者:发送实时特征数据
producer = KafkaProducer(
    bootstrap_servers=['localhost:9092'],
    value_serializer=lambda v: json.dumps(v).encode('utf-8')
)

def send_feature(data):
    producer.send('ml-features', value={
        'timestamp': data['ts'],
        'features': data['features'].tolist(),
        'user_id': data['user_id']
    })

# 消费者:实时 AI 推理
consumer = KafkaConsumer(
    'ml-features',
    bootstrap_servers=['localhost:9092'],
    value_deserializer=lambda m: json.loads(m.decode('utf-8'))
)

import onnxruntime as ort
session = ort.InferenceSession('model.onnx')

for msg in consumer:
    features = np.array(msg.value['features']).reshape(1, -1)
    prediction = session.run(None, {'input': features.astype(np.float32)})[0]
    print(f"User {msg.value['user_id']}: {prediction}")

Kafka Streams 与 ksqlDB

Kafka Streams 是一个 Java/Scala 库,支持从 Kafka Topic 读取、转换后再写回 Kafka 的流处理。ksqlDB 是一个事件流数据库,让你能用 SQL 编写流式查询。

Kafka 在实时 AI 流水线中的角色:

  1. 事件源(用户行为、传感器数据等)
  2. 传递特征工程结果
  3. 发布模型预测结果
  4. 收集 A/B 测试结果

Apache Airflow

Apache Airflow 是一个以编程方式定义、调度、监控流水线的工作流管理平台。

DAG(有向无环图)概念

DAG 是有方向且无环的图,是 Airflow 中表示工作流的方式。每个节点是一个 Task,边表示依赖关系(执行顺序)。

Operator 类型

  • PythonOperator:执行 Python 函数
  • BashOperator:执行 shell 命令
  • SQLExecuteQueryOperator:执行 SQL 查询
  • KubernetesPodOperator:运行 Kubernetes Pod
  • SparkSubmitOperator:提交 Spark 作业

用 TaskFlow API 构建 ML 流水线

from airflow.decorators import dag, task
from datetime import datetime

@dag(schedule='@daily', start_date=datetime(2026, 1, 1))
def ml_training_pipeline():

    @task
    def extract_data():
        # 提取数据
        return {'rows': 10000, 'path': '/tmp/data.parquet'}

    @task
    def preprocess(info: dict):
        # 预处理
        import pandas as pd
        df = pd.read_parquet(info['path'])
        df_clean = df.dropna()
        return df_clean.to_dict()

    @task
    def train_model(data: dict):
        # 模型训练
        from sklearn.ensemble import GradientBoostingClassifier
        import mlflow

        with mlflow.start_run():
            model = GradientBoostingClassifier()
            # training logic here
            mlflow.sklearn.log_model(model, "model")
        return "model_trained"

    @task
    def validate_model(status: str):
        # 模型验证
        if status == "model_trained":
            return {"accuracy": 0.92, "passed": True}
        return {"passed": False}

    raw = extract_data()
    processed = preprocess(raw)
    result = train_model(processed)
    validate_model(result)

dag_instance = ml_training_pipeline()

Airflow 最佳实践

  • 幂等性(Idempotency):同一个 DAG 无论运行多少次,结果都应保持一致。
  • 原子性(Atomicity):Task 要么完全成功,要么完全失败。
  • 减少 XCom 使用:大数据量应使用外部存储,而不是 XCom。
  • 设置 SLA:为关键流水线设置 SLA(Service Level Agreement)。

dbt (Data Build Tool)

dbt 让分析工程师能够用 SQL 编写数据转换逻辑,并内置版本管理、测试与文档化能力。

dbt 的角色与 ELT 模式

与传统的 ETL(Extract-Transform-Load)不同,dbt 采用 ELT(Extract-Load-Transform)模式。先把原始数据加载进数据仓库,再在仓库内部用 SQL 完成转换。

模型分层结构

models/
├── staging/          # 清洗原始源数据
│   ├── stg_orders.sql
│   └── stg_customers.sql
├── intermediate/     # 业务逻辑的中间转换
│   └── int_order_items.sql
└── marts/           # 面向最终业务的表
    ├── fct_orders.sql
    └── dim_customers.sql

Jinja 模板与 ref() 函数

dbt 使用 Jinja 模板引擎,为 SQL 添加动态能力:

-- models/marts/fct_orders.sql
SELECT
    o.order_id,
    o.customer_id,
    c.customer_name,
    o.total_amount,
    o.created_at
FROM {{ ref('stg_orders') }} o
LEFT JOIN {{ ref('dim_customers') }} c
    ON o.customer_id = c.customer_id
WHERE o.status = 'completed'

ref() 函数会自动推断模型间的依赖关系,并按正确的顺序执行。

数据测试与文档化

# schema.yml
models:
  - name: fct_orders
    description: '已完成订单事实表'
    columns:
      - name: order_id
        description: '订单唯一 ID'
        tests:
          - unique
          - not_null
      - name: total_amount
        tests:
          - not_null
          - dbt_utils.accepted_range:
              min_value: 0

Delta Lake / Apache Iceberg

Delta Lake 与 Apache Iceberg 是为数据湖带来 ACID 事务能力的开放表格式。

核心功能

  • ACID 事务:在并发读写下保证数据一致性
  • 时间旅行(Time Travel):可以查询特定时间点的数据快照
  • 模式演进(Schema Evolution):在不破坏既有数据的前提下变更 schema
  • 数据版本管理:追踪变更历史并支持回滚

Delta Lake 的 Merge/Upsert 操作

from delta.tables import DeltaTable
from pyspark.sql import SparkSession

spark = SparkSession.builder \
    .config("spark.sql.extensions", "io.delta.sql.DeltaSparkSessionExtension") \
    .config("spark.sql.catalog.spark_catalog",
            "org.apache.spark.sql.delta.catalog.DeltaCatalog") \
    .getOrCreate()

# Upsert (Merge) 操作
delta_table = DeltaTable.forPath(spark, "/delta/users")
updates_df = spark.read.parquet("/tmp/updates/")

delta_table.alias("target").merge(
    updates_df.alias("source"),
    "target.user_id = source.user_id"
).whenMatchedUpdateAll() \
 .whenNotMatchedInsertAll() \
 .execute()

# 时间旅行:查询昨天的数据
df_yesterday = spark.read.format("delta") \
    .option("timestampAsOf", "2026-03-16") \
    .load("/delta/users")

# 按版本查询
df_v1 = spark.read.format("delta") \
    .option("versionAsOf", 1) \
    .load("/delta/users")

# 查看变更历史
delta_table.history().show()

Z-Order 聚簇

Z-Order 把相关数据放在同一批文件中,以此提升查询性能:

spark.sql("""
    OPTIMIZE delta.`/delta/events`
    ZORDER BY (user_id, event_date)
""")

特征存储

特征存储是集中管理 ML 特征的存储系统,用于保证特征的复用性、一致性与治理。

在线 vs 离线特征存储

离线特征存储保存用于模型训练的大规模历史特征,以 Parquet、Delta Lake 格式存放在数据湖中。

在线特征存储以低延迟提供用于实时推理的最新特征,存放在 Redis、DynamoDB、Cassandra 等内存/NoSQL 数据库中。

Feast(开源特征存储)

from feast import FeatureStore, Entity, FeatureView, Field
from feast.types import Float32, Int64

# 定义特征
user_stats = FeatureView(
    name="user_stats",
    entities=["user_id"],
    schema=[
        Field(name="avg_purchase_amount", dtype=Float32),
        Field(name="purchase_count_30d", dtype=Int64),
    ],
    ttl=timedelta(days=30),
)

# 在线特征查询(实时推理)
store = FeatureStore(repo_path=".")
features = store.get_online_features(
    features=["user_stats:avg_purchase_amount", "user_stats:purchase_count_30d"],
    entity_rows=[{"user_id": 1001}],
).to_dict()

托管式特征存储

  • Tecton:企业级特征平台,支持实时转换
  • Vertex AI Feature Store:GCP 集成托管服务
  • SageMaker Feature Store:AWS 集成托管服务
  • Databricks Feature Store:基于 Delta Lake 的特征管理

数据质量与监控

数据质量决定了 AI 系统的可靠性。"Garbage in, garbage out" 在 ML 中尤其重要。

用 Great Expectations 做数据校验

Great Expectations 是一个为数据流水线添加自动化数据校验的工具:

import great_expectations as gx

context = gx.get_context()
datasource = context.sources.add_pandas("my_datasource")

# 定义期望(Expectation)
suite = context.add_expectation_suite("orders_suite")
validator = context.get_validator(
    batch_request=batch_request,
    expectation_suite_name="orders_suite"
)

validator.expect_column_values_to_not_be_null("order_id")
validator.expect_column_values_to_be_between("total_amount", min_value=0, max_value=100000)
validator.expect_column_values_to_be_unique("order_id")
validator.save_expectation_suite()

# 执行校验
checkpoint = context.add_or_update_checkpoint(
    name="orders_checkpoint",
    validations=[{"batch_request": batch_request, "expectation_suite_name": "orders_suite"}],
)
result = checkpoint.run()

数据漂移检测

数据漂移(Data Drift)是生产数据的统计特性偏离训练数据的现象。可以用 Evidently AI、WhyLogs、Nannyml 等工具检测:

from evidently.report import Report
from evidently.metric_preset import DataDriftPreset

report = Report(metrics=[DataDriftPreset()])
report.run(reference_data=train_df, current_data=prod_df)
report.show(mode='inline')

数据血缘(Data Lineage)追踪

数据血缘追踪数据从源头到消费的完整旅程。常用工具包括 Apache Atlas、OpenLineage、Marquez。


云数据平台

AWS 数据栈

  • Amazon S3:对象存储,是数据湖的基础
  • AWS Glue:无服务器 ETL 服务、数据目录
  • Amazon Athena:用 SQL 分析 S3 数据
  • Amazon Redshift:云数据仓库
  • Amazon EMR:托管 Hadoop/Spark 集群

GCP 数据栈

  • Google BigQuery:内置 ML 能力的无服务器数据仓库
  • Cloud Dataflow:基于 Apache Beam 的数据处理
  • Cloud Pub/Sub:实时消息服务(Kafka 的替代方案)
  • Vertex AI:统一 ML 平台

Azure 数据栈

  • Azure Data Lake Storage (ADLS):分层命名空间存储
  • Azure Synapse Analytics:集成分析服务
  • Azure Event Hub:大规模事件流(与 Kafka 兼容)
  • Azure Databricks:基于 Spark 的分析平台

Snowflake 数据平台

Snowflake 是一个多云数据平台,其特点是把存储与计算分离的架构:

  • 虚拟仓库(Virtual Warehouse):可独立扩展的计算集群
  • 数据共享:组织间的安全数据共享
  • Snowpipe:自动化的持续数据摄取
  • Cortex:内置 AI/ML 能力

测验

Q1. Lambda 架构与 Kappa 架构的核心区别是什么?

答案:Lambda 架构同时维护批处理层与速度层,而 Kappa 架构只使用流处理层来简化架构。

说明:Lambda 架构能同时提供准确性(批处理)与实时性(流处理),但要分别维护两个层,复杂度较高。随着 Kafka Streams、Apache Flink 等工具的发展,仅靠流处理也能提供足够的准确性,这使得 Kappa 架构成为了现实可行的选择。

Q2. Apache Spark 中 DataFrame 与 RDD 的主要区别是什么?

答案:DataFrame 表示带 schema 的结构化数据,并通过 Catalyst 优化器实现自动查询优化。RDD 是无类型的低层级 API,能提供更精细的控制,但优化需要用户自己完成。

说明:大多数情况下推荐使用 DataFrame 或 Dataset API。只有在需要自定义序列化或底层控制时才使用 RDD。Spark 3.0+ 还通过 Adaptive Query Execution(AQE)支持运行时优化。

Q3. Kafka 中 Consumer Group 的作用是什么?

答案:Consumer Group 是订阅同一个 Topic 的消费者集合,通过把分区分配给各个消费者来实现并行处理与负载均衡。

说明:同一个 Partition 只能被同一个 Consumer Group 内的一个消费者读取。即使把消费者数量增加到超过分区数,多出来的消费者也会处于空闲状态。不同的 Consumer Group 可以独立读取同一个 Topic,因此同一个事件流可以用于多种目的。

Q4. dbt 中 ref() 函数的作用是什么?

答案:ref() 函数用于引用其他 dbt 模型,能自动推断模型间的依赖关系,并决定正确的执行顺序。

说明:使用 ref() 后,dbt 会构建 DAG(依赖关系图),并根据环境(开发/生产)自动解析出正确的数据库 schema 与表名。这大幅提升了代码的复用性与可维护性。

Q5. 特征存储中在线存储与离线存储的区别是什么?

答案:离线存储保存用于模型训练的大规模历史数据(Delta Lake、Parquet),在线存储则以低延迟提供用于实时推理的最新特征(Redis、DynamoDB)。

说明:两种存储之所以要分开,是因为它们的需求不同。训练需要批量处理数十亿行数据的高吞吐量,而推理需要毫秒级的低延迟。Feast 这类特征存储还承担着在两种存储之间保证特征一致性的角色。


参考资料

현재 단락 (1/288)

1. [数据工程概述](#数据工程概述)

작성 글자: 0원문 글자: 10,947작성 단락: 0/288