数据工程实战课程 · 数据存储阶段
数据湖以原始格式存储大量结构化和非结构化数据,采用Schema-on-Read模式。
# 数据湖存储引擎
import json, hashlib, time, random
from datetime import datetime
from collections import defaultdict
from dataclasses import dataclass, field
@dataclass
class LakeTable:
name: str; zone: str; format: str; schema: dict = field(default_factory=dict)
partitions: list = field(default_factory=list); record_count: int = 0; size_bytes: int = 0
created_at: str = ""; updated_at: str = ""
class DataLakeEngine:
def __init__(self, name):
self.name = name
self.zones = {'raw':{'tables':{}},'silver':{'tables':{}},'gold':{'tables':{}}}
self.catalog = {}
def register_table(self, zone, name, fmt, schema=None, partitions=None):
t = LakeTable(name, zone, fmt, schema or {}, partitions or [], created_at=datetime.now().isoformat(), updated_at=datetime.now().isoformat())
self.zones[zone]['tables'][name] = t; self.catalog[name] = t; return t
def write_data(self, name, records):
if name not in self.catalog: raise ValueError(f"表{name}未注册")
t = self.catalog[name]
t.record_count += len(records)
t.size_bytes += len(json.dumps(records, default=str).encode())
t.updated_at = datetime.now().isoformat()
return {'table':name, 'written':len(records)}
def discover(self, zone=None):
results = []
for z, data in self.zones.items():
if zone and z != zone: continue
for name, t in data['tables'].items(): results.append(t)
return results
def stats(self):
return {z:{'tables':len(d['tables']),'records':sum(t.record_count for t in d['tables'].values()),'size_mb':round(sum(t.size_bytes for t in d['tables'].values())/1024/1024,2)} for z,d in self.zones.items()}
lake = DataLakeEngine("enterprise-lake")
lake.register_table('raw','raw_orders','json',{'order_id':'int','amount':'float'},['date'])
lake.register_table('raw','raw_clicks','json',{'session_id':'str','page':'str'},['date'])
lake.register_table('silver','clean_orders','parquet',{'order_id':'int','region':'str'},['date','region'])
lake.register_table('gold','daily_sales','parquet',{'date':'str','total':'float'},['date'])
for _ in range(10):
lake.write_data('raw_orders', [{'order_id':random.randint(1,1000),'amount':round(random.uniform(10,5000),2)} for _ in range(random.randint(50,200))])
lake.write_data('raw_clicks', [{'session_id':f'S_{random.randint(1,10000)}','page':f'/p/{random.randint(1,100)}'} for _ in range(random.randint(100,500))])
lake.write_data('clean_orders', [{'order_id':i,'region':random.choice(['华东','华南'])} for i in range(500)])
lake.write_data('daily_sales', [{'date':'2024-01-15','total':15000}])
print(f"数据湖: {lake.name}")
for zone, info in lake.stats().items():
print(f" {zone}: {info['tables']}表, {info['records']}条, {info['size_mb']}MB")
print("发现(raw):")
for t in lake.discover('raw'):
print(f" {t.name}({t.format}): {t.record_count}条")
print("✅ 验证通过 - 数据湖引擎运行正常")
🎁 下一课预告:Parquet与Avro!
| 策略 | 原理 | 节省比例 |
|---|---|---|
| 分层存储 | 热SSD/温HDD/冷对象存储 | 50-80% |
| 数据压缩 | 列式存储高压缩比 | 60-90% |
| 生命周期 | 自动归档删除 | 30-60% |
| 降采样 | 历史数据低精度 | 70-95% |
在生产环境中,我们经常遇到教科书不会告诉你的问题。以下是常见的实战经验和解决方案:
| 指标 | 告警阈值 | 监控方式 |
|---|---|---|
| 管道延迟 | 超过SLA 120% | 端到端时间戳追踪 |
| 数据量偏差 | 日均偏差超过30% | 与历史同期对比 |
| 错误率 | 超过0.1% | 错误计数/总记录数 |
| 数据新鲜度 | 超过SLA 150% | 最新数据时间戳 |
| 资源利用率 | CPU持续>80% | 系统监控 |
A: 根据业务延迟要求决定:秒级用流处理、分钟级用微批、小时级用批处理。大部分场景批处理足够,流处理用于实时业务场景(风控、监控、推荐)。
A: 不会完全取代,但边界在模糊。湖仓一体(如Iceberg/Delta Lake)正在融合两者优势。未来趋势是统一存储+多引擎计算。
A: 先用云原生服务(BigQuery/Snowflake + Fivetran + dbt + Looker),验证业务后再考虑自建。过早优化是万恶之源。
A: 用钱说话:数据质量问题的直接经济损失(错误决策、合规罚款、重复劳动)远大于治理投入。量化问题是第一步。
| 角色 | 职责 | 交付物 |
|---|---|---|
| 数据工程师 | 管道开发与维护 | 数据管道、基础设施 |
| 数据分析师 | 数据分析与报表 | SQL查询、BI报表 |
| 数据科学家 | 模型与实验 | ML模型、实验报告 |
| 数据产品经理 | 需求与优先级 | PRD、数据产品规划 |
| 数据管家 | 数据质量与治理 | 质量规则、数据字典 |