关键组件说明:
基于CDC的实时捕获方案:
# 使用Debezium实现MySQL CDC
from debezium import Connect
conn = Connect(host='mysql-server',
port=3306,
user='etl_user',
password='securepass')
for change in conn.stream('inventory.orders'):
process_change(change) # 处理变更事件
write_to_kafka('ods_orders', change) # 写入消息队列
增量策略对比:
策略 | 实现方式 | 适用场景 |
---|---|---|
Timestamp | 更新时间戳过滤 | OLTP系统,有时间字段 |
CDC | 数据库日志解析 | 实时数据捕获 |
Hash Diff | 全字段MD5比对 | 无时间戳的小表 |
Type 2实现模板:
-- 当前有效记录标记
ALTER TABLE dim_customer
ADD COLUMN is_current BOOLEAN DEFAULT TRUE;
-- SCD2处理存储过程
CREATE PROCEDURE scd_type2_update()
BEGIN
-- 失效旧记录
UPDATE dim_customer
SET is_current = FALSE,
end_date = CURRENT_DATE
WHERE customer_id IN (SELECT customer_id FROM stage_customer)
AND is_current = TRUE;
-- 插入新记录
INSERT INTO dim_customer
SELECT NULL, customer_id, name, address,
CURRENT_DATE AS start_date,
NULL AS end_date,
TRUE AS is_current
FROM stage_customer;
END;
# 使用Spark进行分布式清洗
from pyspark.sql import SparkSession
spark = SparkSession.builder \
.appName("DataCleaning") \
.config("spark.executor.memory", "8g") \
.getOrCreate()
raw_df = spark.read.parquet("s3://raw-data/orders")
cleaned_df = raw_df.dropDuplicates(["order_id"]) \
.filter("amount > 0") \
.withColumn("phone",
regexp_replace(col("phone"), "[^0-9]", ""))
cleaned_df.write.parquet("s3://cleaned-data/orders")
数据分区策略:
-- 按日期分区的Hive表
CREATE TABLE dw_sales (
order_id BIGINT,
sale_date DATE,
amount DECIMAL(10,2)
)
PARTITIONED BY (sale_year INT, sale_month INT)
STORED AS ORC;
加载性能优化矩阵:
技术手段 | 实施方法 | 效果预估 |
---|---|---|
批量提交 | 每1000条提交一次事务 | 提升30%写入速度 |
索引预创建 | 加载前禁用,完成后重建 | 缩短50%加载时间 |
列式存储 | 使用ORC/Parquet格式 | 减少70%存储空间 |
错误隔离设计:
class ETLPipeline:
def run(self):
try:
self.extract()
self.transform()
self.load()
except DataQualityError as e:
self.log_error(e)
self.move_to_quarantine(e.record)
self.send_alert(e)
finally:
self.update_metadata()
def move_to_quarantine(self, record):
with self.error_db.connect() as conn:
conn.execute("""
INSERT INTO error_queue
VALUES (?, ?, ?)""",
(datetime.now(), record, traceback.format_exc()))
// Spark Streaming实时处理
val kafkaStream = KafkaUtils.createDirectStream[String, String](
ssc, Locations(kafkaBrokers), TopicsSet("orders"))
kafkaStream.foreachRDD { rdd =>
rdd.map(parseOrder)
.filter(validateOrder)
.foreachPartition { orders =>
CassandraConnector.writeToCassandra(orders)
}
}
// 批处理层补偿
spark.read.parquet("s3://batch-data/orders")
.createOrReplaceTempView("batch_orders")
spark.sql("""
SELECT user_id, SUM(amount)
FROM batch_orders
GROUP BY user_id""")
架构类型 | 延迟 | 准确性 | 典型工具链 |
---|---|---|---|
Lambda | 秒级 | 最终一致 | Kafka+Spark+HDFS |
Kappa | 毫秒级 | 精确一次 | Flink+Pravega |
混合架构 | 分级处理 | 平衡方案 | Spark Structured Streaming |
挑战:
技术方案:
-- 时区统一转换
CREATE VIEW unified_transactions AS
SELECT
transaction_id,
CONVERT_TZ(transaction_time,
bank_timezone,
'UTC') AS utc_time,
amount,
CASE bank_id
WHEN 'CITI' THEN DECRYPT(account_number)
ELSE account_number
END AS unified_account
FROM raw_transactions
WHERE amount <= compliance_limit;
流水线设计:
传感器数据 → Kafka → Flink实时过滤 →
↓ ↓
HDFS冷存储 ← Spark批处理 ← 异常检测
Q1:如何选择批处理与流处理架构?
✅ 决策树:
数据延迟要求 < 1分钟 → 流处理
数据量 > 1TB/天 → 批处理
需要精确一次语义 → 选择Flink
Q2:维度表如何应对高频更新?
✅ 解决方案:
下期预告:《大数据分析》
互动话题:你在学习遇到过哪些坑?欢迎评论区留言讨论!
️温馨提示:我是[随缘而动,随遇而安], 一个喜欢用生活案例讲技术的开发者。如果觉得有帮助,点赞关注不迷路