引言
即使在支持连续事件流的架构中,batch processing 仍然是数据工程中的基础模式。许多核心业务功能,例如 financial reporting、regulatory reconciliation、large-scale aggregations、historical trend analysis 和 periodic data warehouse refreshes,本质上都是按时间间隔驱动的。这些 workloads 优先考虑 completeness、consistency 和 cost efficiency,而不是 immediacy。
因此,本章不会把 batch processing 看作一种遗留技术,而是将其作为一种有意选择的架构方案来考察。我们将探索 Apache Spark 和 Hadoop MapReduce 等 distributed processing frameworks 如何让大型 datasets 被 partition,并在 clusters 上并行处理。不过,本章重点不只停留在 frameworks 本身,还会深入定义稳健 batch systems 的 operational realities。
可靠的 batch pipelines 必须考虑 retries、failure recovery 和 idempotent design,以确保可以安全重新执行,而不会造成 data corruption。它们必须处理 late-arriving data,并定义对 historical partitions 进行 reprocessing 的 policies。因此,schema evolution 必须被谨慎管理,以防止 downstream breakage。Cost 和 time-based service level expectations 会影响 jobs 运行频率、资源如何分配,以及 intermediate data 如何保留。
Batch processing 用 low-latency responsiveness 换取 stability、auditability 和 predictable cost control。不同于持续处理 events 的 streaming systems,batch systems 处理的是有边界的 datasets,并具有清晰的 execution windows。这一区别简化了某些 guarantees。不过,它也带来 scheduling、dependency management 和 resource allocation 方面的约束。
因此,本章将考察塑造有效 batch systems 的架构决策。这包括理解如何组织 transformations、如何设计 recoverability、如何管理 partitioning strategies,以及如何在规模化下优化 compute usage。因此,目标不仅是理解 batch frameworks 如何执行 workloads,更是理解如何设计随着 data volumes 和 business requirements 增长仍然可靠、可扩展且具备运营纪律的 batch pipelines。
结构
本章将覆盖以下主题:
- Introduction to Batch Processing
- Apache Spark for Batch Processing
- Hadoop MapReduce for Batch Processing
- Workflow Orchestration for Batch Processing
- Optimizing Batch Processing Workloads
- Real-World Applications of Batch Processing
Apache Spark for Batch Processing
Apache Spark 被广泛用于 large-scale batch workloads,因为它可以在 clusters 上分布式执行计算,并通过 DataFrames 和 Spark SQL 提供结构化 APIs。不过,使用 Spark 进行有效 batch processing,更多取决于它如何被配置和运营,而不只是 framework 本身。
Schema management 应该显式定义,而不是依赖推断。定义 schemas 可以避免错误的 type inference,尽早检测 drift,并确保 downstream processing 的一致性。因此,data typecasting 必须被有意处理,尤其是 timestamps 和 numeric fields,以避免 aggregations 或 joins 中出现 silent errors。
当写入 S3 等 object storage 时,配置非常重要。Spark 必须针对正确 connector usage、multipart uploads 和 retry handling 进行调优。由于 object storage 不是传统 file system,过多 small files 和大量 metadata operations 可能降低性能。因此,output file sizing 和 partition planning 是关键考虑因素。
此外,partitioning strategy 会直接影响 performance 和 cost。因此,它们应与常见 query filters 对齐,例如 date,避免 high-cardinality keys,并防止 data skew。糟糕的 partition design 会导致 workload 不均衡和 queries 低效。
Failure handling 和 idempotency 是 batch systems 中的基本要求。因此,jobs 必须支持 safe retries,避免 partial writes,并使用 overwrite 或 merge strategies 防止 duplication。Atomic write patterns 和 checkpointing 有助于确保 recoverability。
最后,batch frequency 和 resource allocation 会决定 cost-latency trade-offs。更频繁的 runs 可以提升 freshness,但会增加 compute costs。因此,cluster sizing 必须在 execution time、budget 和 SLA requirements 之间取得平衡。
Spark 支持 distributed execution,但 production-grade batch processing 依赖 disciplined schema control、storage layout design、partition strategy、failure safety 和 cost management。
Apache Spark 的关键特性
In-Memory Computation:Spark 通过在内存中处理数据来最小化 disk I/O,从而提升 iterative algorithms 和 large-scale transformations 的性能。
Unified Processing Engine:Spark 提供单一平台,支持 batch processing、stream processing、通过 MLlib 支持 Machine Learning(ML),以及通过 Spark SQL 支持 structured querying,因此它是 data engineers 和 scientists 的多功能选择。
Developer-Friendly APIs:Spark 支持多种编程语言,包括 Scala、Python(PySpark)、Java 和 R,允许团队根据自己的 expertise 选择语言。
High-Level Abstractions:Spark 的 DataFrame 和 Dataset APIs 简化数据操作,同时支持表达力强且 type-safe 的 queries。这些 abstractions 还利用 Catalyst 和 Tungsten,也就是 Spark 的 query optimizer 和 execution engine,实现高效执行。
Scalability and Fault Tolerance:Spark 构建在 distributed architecture 之上,支持 horizontal scalability 和 resilience。它可以运行在多种 cluster managers 上,例如 YARN、Mesos、Kubernetes,也可以使用自己的 standalone mode。
Batch Processing 中的常见 Use Cases
ETL(Extract、Transform、Load)Pipelines:Spark 被广泛用于按计划清洗、转换并加载大量 raw data 到 data lakes 或 warehouses 中。
Log and Clickstream Analysis:组织使用 Spark 处理 web servers 和 applications 生成的大规模 logs,以提取洞察并监控系统行为。
Data Warehousing and Aggregation:Spark SQL 支持对大型 datasets 进行 batch aggregation,用于 reporting 和 business intelligence。
ML Preprocessing:在许多 pipelines 中,Spark 用于 batch feature engineering、data balancing 和 transformation,然后再进入 training workflows。
Data Migration and Synchronization:Spark 常用于在 systems 之间迁移大型 datasets,或在多个 platforms 之间同步数据。
从高层看,Apache Spark 会接收你的代码,这些代码可能用 Python、Scala、Java 或 R 编写,然后将其转换为一系列可以分发到 cluster 中多台机器上的 tasks。因此,当你提交一个 Spark job 时,它会基于 transformations,例如 filtering 或 grouping data,创建一个 Directed Acyclic Graph(DAG)of tasks。这些 tasks 会被调度,并在 cluster 上并行执行。
Apache Spark 通过在可能情况下将 intermediate results 缓存在内存中来优化性能,这相比 Hadoop MapReduce 减少了重复 disk I/O,尽管它仍可能根据 memory availability 和 shuffle behavior spill to disk。这使它在 large-scale computations 中快得多,尤其是当数据需要在多个 stages 中复用时。
Spark jobs 通常使用 Resilient Distributed Datasets(RDDs)或 DataFrames,它们是处理 distributed data 的 abstractions。你可以从 HDFS、S3 或 local file 等各种 sources 加载数据,使用内置 functions 转换数据,然后保存 output 或用于进一步分析。
要使用 Spark,可以在 Python(PySpark)中启动 Spark session,如下:
from pyspark.sql import SparkSession
spark = SparkSession.builder \
.appName("BatchProcessingExample") \
.getOrCreate()
df = spark.read.csv("s3://data-bucket/sales.csv", header=True, inferSchema=True)
transformed_df = df.groupBy("region").sum("revenue")
transformed_df.write.parquet("s3://data-bucket/output/region_revenue")
这个简单 job 会读取存储在 Amazon S3 中的 CSV sales data,按 region 计算 total revenue,然后将结果以 Parquet file 的形式写回。所有这些过程都会由 Spark 分布式并行执行。
Use Case
想象一家零售公司从全国数千家门店收集 sales data。每天晚上,他们都会收到包含各分支 transactions 的大型 files。使用 Apache Spark,他们构建了一个 batch pipeline,用于摄入 raw data、过滤 invalid entries、按 product category 和 region 计算 daily totals,并将结果写入 reporting database。
Spark 在幕后处理复杂性:它会把数据拆分到多个 worker nodes 上并行处理,并将 intermediate results 缓存在内存中以缩短处理时间。因此,到第二天早上,dashboards 已经完成更新,业务方可以获得准确洞察来支持 decision-making。
因此,我们的目标是从 Amazon S3 摄入 daily sales CSV files,清洗和转换数据,按 product category 和 region 计算 total revenue,然后将结果存储为 Parquet files,供 downstream analytics 使用。
设置 Apache Spark Environment
为了易用性,你可以使用 PySpark。可以本地安装,也可以在 cluster 上运行,例如 EMR、Databricks 或 Spark standalone。
pip install pyspark
然后初始化 Spark session:
from pyspark.sql import SparkSession
spark = SparkSession.builder \
.appName("RetailSalesBatchJob") \
.getOrCreate()
从 S3 加载数据
假设你的 sales data 以 CSV 形式存储在 S3 bucket 中,我们将这样实现:
sales_df = spark.read.csv("s3://retail-bucket/daily_sales/*.csv", header=True, inferSchema=True)
Data Cleaning
删除 null entries 和 invalid rows,如下:
clean_df = sales_df.dropna(subset=["region", "product_category", "revenue"]) \
.filter("revenue > 0")
Data Transformation(Aggregation)
按 region 和 product_category 对数据分组,并计算 total revenue:
agg_df = clean_df.groupBy("region", "product_category") \
.sum("revenue") \
.withColumnRenamed("sum(revenue)", "total_revenue")
将 Output 以 Parquet Format 写入 S3
agg_df.write.mode("overwrite") \
.parquet("s3://retail-bucket/processed/daily_summary/")
这会将 aggregated results 存储为高度优化的 Parquet format。
此外,你可以使用以下工具将该 job 调度为每晚运行:
- Apache Airflow
- AWS Step Functions
- crontab,用于 local / dev testing
Hadoop MapReduce for Batch Processing
Hadoop MapReduce 是最早、也最有影响力的大规模 distributed data processing frameworks 之一。它构成了 Apache Hadoop ecosystem 的核心,因为它为 Big Data architectures 中面向 batch 的 data workflows 奠定了基础。虽然 Apache Spark 等新框架已经更受欢迎,但 Hadoop MapReduce 在 legacy systems 中仍然相关,也适用于那些需要可靠 disk-based processing 的特定 use cases。
Hadoop MapReduce 基于两阶段 programming model:map phase 和 reduce phase。
Map Phase:Input data 被拆分为 chunks,并在 cluster 中并行处理。Mapper 会逐行读取 input,然后发出 key-value pairs。
Shuffle and Sort:Framework 会自动按 key 对 mapper outputs 进行分组和排序。
Reduce Phase:Reducers 会聚合每个 key 的 values,然后生成 final result。
底层,Hadoop 将数据存储在 HDFS(Hadoop Distributed File System)中。MapReduce engine 随后通过将 tasks 分发给 worker nodes 来执行 jobs,并通过 JobTracker,也就是较新版本中的 YARN,协调它们,同时自动处理 fault tolerance、retries 和 progress tracking。
因此,要编写 MapReduce job,通常需要:
- 定义一个 Mapper class,用于处理 input records 并发出 intermediate key-value pairs。
- 定义一个 Reducer class,用于聚合每个 key 的 values。
- 通过
hadoop jarcommand 将 job 打包并提交到 Hadoop cluster。
Use Case
假设一家 telecom company 每天在 HDFS 中存储 TB 级 call records。每天结束时,它们希望计算每位 customer 使用的总分钟数,以检测 over-usage,然后据此应用 charges。
使用 MapReduce,job 会从 HDFS 读取 log files,将每条 call record 映射为 (customer_id, duration),然后按 customer 汇总 duration。Output 会作为 report 写回 HDFS,并输入 billing system。
虽然这种方法大量依赖 disk,比 in-memory systems 更慢,但它 highly scalable 且 reliable,因此非常适合 data volume 巨大、并且 cost-effective fault tolerance 很关键的场景。
因此,我们的目标是处理存储在 HDFS 中的 daily call logs,并使用 Hadoop MapReduce 计算每个 customer 的 total duration of calls。
Input Data Format(存储在 HDFS 中)
假设 input file,也就是 call logs,每一行如下:
customer_id,call_timestamp,duration_seconds
C101,2025-04-11T08:32:00,240
C102,2025-04-11T09:15:30,180
C101,2025-04-11T10:45:10,300
Mapper Class(Java)
这个 class 会解析每一行,并发出 (customer_id, duration)。
import org.apache.hadoop.io.*;
import org.apache.hadoop.mapreduce.Mapper;
import java.io.IOException;
public class CallDurationMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
private Text customerId = new Text();
private IntWritable duration = new IntWritable();
public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
String[] fields = value.toString().split(",");
if (fields.length == 3) {
try {
customerId.set(fields[0]);
duration.set(Integer.parseInt(fields[2]));
context.write(customerId, duration);
} catch (NumberFormatException e) {
// Skip bad records
}
}
}
}
Reducer Class(Java)
这个 class 会按 customer 聚合 durations。
import org.apache.hadoop.io.*;
import org.apache.hadoop.mapreduce.Reducer;
import java.io.IOException;
public class CallDurationReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
private IntWritable totalDuration = new IntWritable();
public void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
int sum = 0;
for (IntWritable val : values) {
sum += val.get();
}
totalDuration.set(sum);
context.write(key, totalDuration);
}
}
Driver Class(Java)
这是用于配置和运行 job 的 main class。
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.*;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
public class CallDurationJob {
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
Job job = Job.getInstance(conf, "Call Duration Aggregation");
job.setJarByClass(CallDurationJob.class);
job.setMapperClass(CallDurationMapper.class);
job.setReducerClass(CallDurationReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
FileInputFormat.addInputPath(job, new Path(args[0])); // Input path
FileOutputFormat.setOutputPath(job, new Path(args[1])); // Output path
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}
Compile and Package
使用 Maven 或手动编译:
javac -classpath $(hadoop classpath) -d call_duration_classes *.java
jar -cvf call_duration.jar -C call_duration_classes/ .
在 Hadoop 上运行 Job
通过以下命令将 input file 上传到 HDFS:
hdfs dfs -put call_logs.csv /input/call_logs.csv
运行 job:
hadoop jar call_duration.jar CallDurationJob /input /output
查看结果:
hdfs dfs -cat /output/part-r-00000
Sample output 如下:
C101 540
C102 180
因此,这个 job 成功地并行处理了大量 call logs,并使用 Hadoop 的 MapReduce framework 聚合出每位 customer 的 total call duration。它 reliable、scalable,非常适合 telecom 和类似行业中基于 batch 的 high-volume data workflows。
Workflow Orchestration for Batch Processing
随着 batch data pipelines 变得更复杂,经常包含 ingestion、transformation、aggregation 和 storage 等多个相互依赖的 tasks,就需要一个 workflow orchestrator,以可靠、透明且高效的方式管理端到端 pipeline。因此,workflow orchestration tools 为跨不同系统自动化、调度、监控和管理 batch processing jobs 提供了骨干能力。
Workflow orchestration 指的是 data workflows 的自动化管理,同时确保 tasks 按正确顺序执行,并具备适当的 retries、failure handling 和 alerting mechanisms。Orchestrator 会跟踪 tasks 之间的 dependencies,处理 job failures,并提供 workflow execution 的可见性。
因此,与编写 ad-hoc scripts 和 cron jobs 相比,orchestrators 提供了结构化、可复现的 pipelines,更容易 monitor、debug 和 scale。
Popular Workflow Orchestration Tools
为了支持 data engineering teams 日益增长的需求,出现了多种 orchestration tools。下面看其中一些:
Apache Airflow:Airflow 是一个被广泛采用的 open-source scheduler,它使用 Python code 将 workflows 定义为 Directed Acyclic Graphs(DAGs)。它支持 scheduling、retries、alerts,并拥有面向 Spark、Hadoop、SQL 和 cloud services 的大量 operator libraries。
Prefect:Prefect 是一种现代 orchestration tool,聚焦 observability 和 dynamic workflows。它提供 Pythonic API、无缝 cloud integration,以及每个 task 的 fine-grained state handling。
Luigi:Luigi 最初由 Spotify 开发,允许 users 构建带 dependencies 的复杂 pipelines,适合 Python-heavy environments。
Dagster、Argo Workflows and Others:Dagster 强调 development-friendly pipelines,支持 testing 和 type-checking。Argo 是 Kubernetes-native,因此非常适合编排 container-based batch jobs。
一个典型 orchestrator 的工作方式如下:
Define Tasks:每个 work unit,例如 Spark job、Python script、SQL query,被定义为一个 task。
Specify Dependencies:Tasks 被组织起来,使 downstream tasks 只有在 upstream tasks 成功后才会运行。
Schedule Execution:Pipelines 可以基于固定 schedule 触发,例如每天午夜,也可以基于 events 触发,例如 file arrival。
Monitor and Alert:Orchestrator 提供 UI 或 logs,用于跟踪 progress,并为 failures 或 delays 发出 alerts。
Use Case Implementation:Airflow 中的 Daily Risk Reporting DAG
下面展示如何使用 Apache Airflow 和 Python 实现 daily risk report pipeline。
安装带所需 extras 的 Airflow:
pip install apache-airflow
初始化并启动 Airflow,如果尚未完成:
airflow db init
airflow users create --username admin --password admin --role Admin --email admin@example.com
airflow webserver --port 8080
airflow scheduler
创建 DAG
在 Airflow 的 dags/ 目录中创建 Python 文件:
dags/daily_risk_report_dag.py
from airflow import DAG
from airflow.operators.bash import BashOperator
from airflow.utils.dates import days_ago
from datetime import timedelta
default_args = {
'owner': 'data_engineering',
'depends_on_past': False,
'email': ['alerts@company.com'],
'email_on_failure': True,
'email_on_retry': False,
'retries': 3,
'retry_delay': timedelta(minutes=5),
}
with DAG(
dag_id='daily_risk_report_pipeline',
default_args=default_args,
description='Daily pipeline for risk reporting using Spark and BI tools',
schedule_interval='0 1 * * *', # 1 AM daily
start_date=days_ago(1),
catchup=False,
tags=['risk', 'batch', 'reporting'],
) as dag:
# Step 1: Load the data from the data lake (assume S3 as example).
load_data = BashOperator(
task_id='load_data',
bash_command='python3 /opt/airflow/scripts/load_data.py'
)
# Step 2: Run data validation checks.
validate_data = BashOperator(
task_id='validate_data',
bash_command='python3 /opt/airflow/scripts/validate_data.py'
)
# Step 3: Feature engineering using Spark.
feature_engineering = BashOperator(
task_id='feature_engineering',
bash_command='spark-submit /opt/airflow/scripts/feature_engineering.py'
)
# Step 4: Train/update risk models.
train_model = BashOperator(
task_id='train_model',
bash_command='python3 /opt/airflow/scripts/train_model.py'
)
# Step 5: Generate the reports and push to the BI dashboard.
generate_report = BashOperator(
task_id='generate_report',
bash_command='python3 /opt/airflow/scripts/generate_report.py'
)
# DAG Dependencies
load_data >> validate_data >> feature_engineering >> train_model >> generate_report
创建 Scripts
在 scripts/ folder 中创建每个 task 使用的 Python 或 Spark scripts,如下:
load_data.py:从 S3 / data lake 拉取数据,并存储到本地或 warehouse。
validate_data.py:运行 schema 或 null checks,如果无效则抛出 errors。
feature_engineering.py:Spark transformations,保存 processed features。
train_model.py:加载 engineered features,并训练 ML models。
generate_report.py:将 output 推送到 BI tool,例如 Tableau、Superset。
每个 script 如果失败,都应以 non-zero code 退出,使 Airflow 能捕获失败并 retry。
Monitoring and Alerts
Airflow UI(http://localhost:8080)将展示:
- Task Status(Success / Failure)
- 每个 Task 的 Logs
- Retry History
- 基于 Failure 的 Email Alerts
Optimizing Batch Processing Workloads
高效 batch processing 不只是写出能运行的代码,而是写出能够良好扩展、按时完成,并充分利用可用资源的 pipelines。因此,随着 data volumes 增长和 workflows 变复杂,optimization 对维持性能、降低成本,以及确保及时交付结果变得至关重要。
Resource-Aware Partitioning
Partitioning 是将大型 datasets 拆分为更小、可管理 chunks 以进行并行处理。一个最优 partitioning strategy 应该:
- 平衡 nodes 之间的 workload,避免 data skew。
- 最小化 partitions 数量,因为太多 partitions 会增加 overhead。
- 与可用 CPU cores 和 executors 数量对齐。
在 Spark 中,可以根据你想增加还是减少 partition counts,使用 .repartition() 或 .coalesce() 显式控制。
Data Locality Optimization
在 cluster 上处理数据时,让 computation 靠近 data 可以减少 network traffic 并加快执行。因此,Hadoop 和 Spark 等系统会尝试将 tasks 调度到已经持有相关 data blocks 的 nodes 上,也就是 data locality。
为了利用这一点:
- 使用 HDFS 或 S3 等 distributed storage systems,并尽可能让 compute 与 data 协同部署。
- 避免 transformations 中过多 shuffles 或 wide dependencies。
Lazy Evaluation and Pipeline Fusion
在 Spark 中,transformations 是 lazily evaluated 的,这意味着它们不会执行,直到 action,例如 collect() 或 write() 被触发。这允许 Spark 优化 DAG(Directed Acyclic Graph)execution plan。
将 filter、select 和 map 等 transformations 链接起来,允许 Spark 将 operations 融合到一个 stage 中,并减少 I/O overhead。因此,打断这个链条或过早使用 actions 可能降低性能。
Caching and Persisting Intermediate Data
当 intermediate results 会在多个 stages 或 iterations 中复用时,例如 ML workflows,将这些数据用 .cache() 或 .persist() 缓存在 memory 中,可以显著提升性能。
应通过以下方式谨慎使用:
- 只缓存会被复用的 datasets。
- 监控 memory usage,避免 eviction 或 spilling to disk。
Tuning Execution Parameters
精细调优 execution parameters,例如 memory allocation、number of executors 和 shuffle partitions,可以带来显著性能收益,例如:
Spark 中:
spark.executor.memoryspark.sql.shuffle.partitionsspark.default.parallelism
Hadoop 中:
mapreduce.task.io.sort.mbmapreduce.reduce.shuffle.parallelcopies
因此,Spark UI 或 Hadoop 的 JobTracker 等 profiling tools,可以帮助识别 bottlenecks,并指导 tuning decisions。
Reducing Shuffle and Joins
Shuffles 指 partitions 或 nodes 之间的数据传输,是昂贵操作。为了减少 shuffles:
- 当其中一张 table 很小时,使用 broadcast joins。
- 避免
groupByKey等 wide transformations;优先使用reduceByKey或aggregateByKey。 - 在 join 前尽可能预先 partition data。
优化 batch processing workloads 需要同时关注 data layout 和 execution strategy。因此,通过调优 partitioning、最小化 shuffles、谨慎使用 caching,并利用 system-level parameters,data engineers 可以构建不仅正确,而且快速、可扩展、成本高效的 pipelines。
高效 batch processing 主要依赖 partition sizing、skew management,以及监控正确 metrics。因此,你必须注意以下内容:
Partition Sizing:目标是 balanced task sizes,而不是任意 partition counts。一个实用规则是,对于大多数 workloads,每个 task 目标处理约 100–300 MB 数据。确保 total partitions 至少是 total executor cores 的 2–4 倍,以保持 parallelism。在 heavy joins 或 aggregations 前使用 repartition() 增加 parallelism,在写 output 前使用 coalesce(),避免生成过多 small files。最后,根据 data size 和 cluster capacity 调整 shuffle partitions(spark.sql.shuffle.partitions)。
Detecting Skew:当少数 tasks 因 key distribution 不均而运行时间显著长于其他 tasks 时,就会出现 skew。指标包括 long-running straggler tasks、uneven shuffle read sizes,以及 executors 空闲等待少数 tasks 完成。
Mitigating Skew:按正确 join 或 aggregation key 对数据重新 partition。如果某些 keys 占比过高,使用 key salting 将 heavy keys 分布到多个 partitions 中。当一个 dataset 足够小时,使用 broadcast joins 避免大规模 shuffles。Join 前预先 aggregation 也可以减少 shuffle volume 和 skew impact。
Key Metrics to Monitor:关注 stage duration variance、executor CPU utilization、shuffle read / write size、shuffle spills 和 output file counts。大量 spills 表示 memory pressure;过多 small output files 表示 partition planning 不佳。因此,应始终跟踪 runtime 是否满足 SLA,以及消耗了多少 cluster-hours,以平衡 performance 和 cost。
Real-World Applications of Batch Processing
从 banking 到 e-commerce,从 telecom 到 healthcare,batch jobs 常常在幕后默默驱动 insights、reports、audits 等流程。因此,我们来看几个真实场景,说明 batch processing 如何创造巨大价值,并帮助组织以受控、可靠且成本高效的方式理解大型 datasets。
Banking:Overnight Transaction Reconciliation
每个 business day 结束时,银行必须在 accounts、branches 和 payment channels 之间对 transactions 进行 reconciliation。考虑一个客户从 savings account 向 mutual fund 转账 ₹10,000。该 transaction 可能触及多个内部系统,例如 core banking platform、payment gateway、fund management system,以及客户的 mobile app。
银行不会实时执行所有 validations 和 adjustments,而是将许多动作排入 daily reconciliation batch job。该 job 会拉取数百万 transactions,验证 debits 和 credits,检查 mismatches,调整 ledgers,并生成 audit reports。因此,到第二天,所有账目都会被核对清楚,确保 financial integrity 和 compliance。
E-Commerce:Daily Sales Summary and Inventory Update
像 Flipkart 或 Amazon 这样的 e-commerce company 每天处理数百万 orders、returns 和 payments。白天,系统专注于快速 real-time updates,例如哪些商品有库存、delivery statuses 等。不过,在高峰结束后,batch jobs 就会启动。
Nightly batch pipeline 会汇总 order data,按 category 计算 net revenue,更新各 warehouses 的 inventory levels,标记 out-of-stock items,并在早上之前将结果推送到 internal dashboard。这些 batch jobs 帮助 category managers 理解 performance、发现 supply chain issues,并在第二天开始前规划 restocking efforts。
Telecom:Usage-Based Billing and Plan Recommendations
Jio 和 Airtel 等 telecom companies 每天收集数十亿条 Call Detail Records(CDRs)、data usage logs 和 SMS records。在这种规模下,real-time billing 很难实现;因此,telecoms 高度依赖 batch jobs。
每天晚上,一个 CDR aggregation batch job 会计算每个 user 的 total minutes used、data consumed 和 overages。另一个 job 可能会根据 usage trends 对 users 分群,例如每晚 streaming YouTube 的用户,或者只在城市内通话的用户,并生成 personalized plan recommendations。这些 insights 随后会在第二天输入 customer outreach campaigns。
Healthcare:Medical Record Consolidation and Reporting
在大型 hospital networks 中,patient data 分散在 labs、doctor visits、pharmacy systems 和 insurance platforms 中。由于 regulatory 和 system constraints,real-time consolidation 并不总是可行。
因此,batch ETL pipeline 每晚运行,从不同 systems 中 extract records,清洗并合并它们,生成 unified patient histories。随后,这些数据用于向 insurance partners reporting、compliance audits 和 medical research analysis。Batch processing 确保 care 虽然实时发生,但 data reconciliation 和 insights 会可靠跟进,且不会产生延迟或冲突。
Public Sector:Social Scheme Eligibility Checks
政府 welfare programs 经常需要大规模运行 eligibility 和 compliance checks。这包括记录数百万人领取 food、education 或 housing subsidies 的详细信息。由于这是一个密集领域,在这里执行 real-time checks 在技术和财务上都不可行。
因此,机构会运行 monthly 或 quarterly batch jobs,拉取 Aadhaar-linked records,将其与 income tax data、bank account activity 和 school attendance 交叉比对,并标记 discrepancies。这可以确保福利及时发放,同时通过系统化 batch processing 捕捉不符合资格或重复的 entries。
因此,在所有这些示例中,batch processing 不只是关乎速度,而是关乎 scale、dependability 和 structure。这些 jobs 按 predictable schedules 运行,并内置 retries 和 monitoring,帮助组织:
- 交付准确 reports。
- 满足 regulatory timelines。
- 在下一个 business day 做出 informed decisions。
Batch pipelines 并不炫目,但它们是现代数据系统中的 workhorses,默默驱动着我们每天依赖的 apps、dashboards 和 decisions。
结论
本章探索了 batch processing 背后的基础原则和实践模式。Batch processing 是处理大规模、周期性 data transformations 的最广泛使用的数据工程技术之一。我们首先理解了 batch systems 的关键特征,以及它们在 architecture 和 execution flow 方面如何不同于 real-time processing。
我们考察了两个主流 frameworks:Apache Spark 和 Hadoop MapReduce,并理解它们如何管理 distributed computation、data locality 和 fault tolerance。Spark 的 in-memory engine 和丰富 APIs 使其成为现代 batch pipelines 的首选,而 MapReduce 在需要大规模 disk-based processing 的 legacy systems 中仍然相关。
本章也介绍了 workflow orchestration 在管理复杂 pipelines 中的重要性。此外,我们学习了 Apache Airflow 和 Prefect 等工具,它们让团队能够可靠地自动化、监控并恢复 multi-step workflows。
随后,我们讨论了 batch workload optimization techniques,例如 partition tuning、data locality improvements、caching strategies 和 resource configuration。这些技术都在降低 latency 和 cost 方面发挥关键作用。最后,我们通过真实世界 use cases 理解这些概念,并强调 banking、telecom、e-commerce 和 healthcare 等行业如何利用 batch processing 提升 operational 和 analytical efficiency。
虽然 batch processing 很强大,但对 real-time insights 和 responsiveness 的需求推动了 stream processing systems 的兴起。因此,在下一章中,我们将把重点转向 stream processing patterns,也就是在数据到达时处理数据,通常以毫秒级完成。
你将探索 Apache Flink、Spark Streaming 和 Kafka Streams 等工具,它们驱动现代 event-driven applications。此外,我们还将学习 event time 和 processing time、stateful computation,以及 exactly-once semantics 等概念,这些将帮助你构建稳健且可扩展的 streaming data pipelines。