大数据架构 | 数据湖与数据仓库的区别,90%的人都理解错了
引言:从“数据爆炸”到“架构选择焦虑”
深夜11点,某电商公司的数据工程师小张盯着屏幕上的报警邮件发呆——业务部门要求明天早上给出“618大促用户行为分析报告”,但他手头的用户行为日志(JSON格式)、订单数据(CSV格式)、**商品图片(JPG)**散落在5个不同的存储系统里,根本无法快速整合分析。
这不是小张一个人的困境。随着企业数字化转型的深入,数据正以每两年翻一番的速度增长(IDC数据),但大部分企业都面临同一个问题:如何高效存储、管理和利用这些“多类型、高增长、非结构化”的数据?
这时,两个高频词汇总会被提及——数据湖(Data Lake)和数据仓库(Data Warehouse)。但很多人对它们的理解停留在“数据湖存原始数据,数据仓库存处理后的数据”这种表面认知,甚至有人认为“数据湖会取代数据仓库”。
今天,我们就从定义、架构、核心区别、实战案例四个维度,彻底讲清楚数据湖与数据仓库的本质差异,帮你告别“架构选择焦虑”。
一、先搞懂基础:什么是数据湖?什么是数据仓库?
在对比之前,我们需要先明确两个概念的官方定义和核心特征——这是避免误解的关键。
1.1 数据湖:“容纳所有数据的水库”
定义(Gartner)
数据湖是一个集中式存储库,允许以原生格式存储结构化、半结构化、非结构化数据(比如日志、图片、视频、JSON),支持从** dashboards 到机器学习**的所有分析类型。
核心特征
- 全类型存储:支持几乎所有数据格式(文本、二进制、流数据);
- schema-on-read:写数据时不强制 schema(结构),读数据时才定义结构;
- 低成本存储:依赖对象存储(如S3、HDFS),存储成本仅为传统数据库的1/10;
- 灵活处理:支持批处理(Spark)、流处理(Flink)、机器学习(TensorFlow)等多种计算引擎。
数据湖的典型架构(Mermaid流程图)
#mermaid-svg-HdKQYpwQj5fldDg6{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-HdKQYpwQj5fldDg6 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-HdKQYpwQj5fldDg6 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-HdKQYpwQj5fldDg6 .error-icon{fill:#552222;}#mermaid-svg-HdKQYpwQj5fldDg6 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-HdKQYpwQj5fldDg6 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-HdKQYpwQj5fldDg6 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-HdKQYpwQj5fldDg6 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-HdKQYpwQj5fldDg6 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-HdKQYpwQj5fldDg6 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-HdKQYpwQj5fldDg6 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-HdKQYpwQj5fldDg6 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-HdKQYpwQj5fldDg6 .marker.cross{stroke:#333333;}#mermaid-svg-HdKQYpwQj5fldDg6 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-HdKQYpwQj5fldDg6 p{margin:0;}#mermaid-svg-HdKQYpwQj5fldDg6 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-HdKQYpwQj5fldDg6 .cluster-label text{fill:#333;}#mermaid-svg-HdKQYpwQj5fldDg6 .cluster-label span{color:#333;}#mermaid-svg-HdKQYpwQj5fldDg6 .cluster-label span p{background-color:transparent;}#mermaid-svg-HdKQYpwQj5fldDg6 .label text,#mermaid-svg-HdKQYpwQj5fldDg6 span{fill:#333;color:#333;}#mermaid-svg-HdKQYpwQj5fldDg6 .node rect,#mermaid-svg-HdKQYpwQj5fldDg6 .node circle,#mermaid-svg-HdKQYpwQj5fldDg6 .node ellipse,#mermaid-svg-HdKQYpwQj5fldDg6 .node polygon,#mermaid-svg-HdKQYpwQj5fldDg6 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-HdKQYpwQj5fldDg6 .rough-node .label text,#mermaid-svg-HdKQYpwQj5fldDg6 .node .label text,#mermaid-svg-HdKQYpwQj5fldDg6 .image-shape .label,#mermaid-svg-HdKQYpwQj5fldDg6 .icon-shape .label{text-anchor:middle;}#mermaid-svg-HdKQYpwQj5fldDg6 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-HdKQYpwQj5fldDg6 .rough-node .label,#mermaid-svg-HdKQYpwQj5fldDg6 .node .label,#mermaid-svg-HdKQYpwQj5fldDg6 .image-shape .label,#mermaid-svg-HdKQYpwQj5fldDg6 .icon-shape .label{text-align:center;}#mermaid-svg-HdKQYpwQj5fldDg6 .node.clickable{cursor:pointer;}#mermaid-svg-HdKQYpwQj5fldDg6 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-HdKQYpwQj5fldDg6 .arrowheadPath{fill:#333333;}#mermaid-svg-HdKQYpwQj5fldDg6 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-HdKQYpwQj5fldDg6 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-HdKQYpwQj5fldDg6 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HdKQYpwQj5fldDg6 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-HdKQYpwQj5fldDg6 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HdKQYpwQj5fldDg6 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-HdKQYpwQj5fldDg6 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-HdKQYpwQj5fldDg6 .cluster text{fill:#333;}#mermaid-svg-HdKQYpwQj5fldDg6 .cluster span{color:#333;}#mermaid-svg-HdKQYpwQj5fldDg6 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-HdKQYpwQj5fldDg6 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-HdKQYpwQj5fldDg6 rect.text{fill:none;stroke-width:0;}#mermaid-svg-HdKQYpwQj5fldDg6 .icon-shape,#mermaid-svg-HdKQYpwQj5fldDg6 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HdKQYpwQj5fldDg6 .icon-shape p,#mermaid-svg-HdKQYpwQj5fldDg6 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-HdKQYpwQj5fldDg6 .icon-shape rect,#mermaid-svg-HdKQYpwQj5fldDg6 .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HdKQYpwQj5fldDg6 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-HdKQYpwQj5fldDg6 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-HdKQYpwQj5fldDg6 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
源数据:日志/图片/流数据
提取:Kinesis/Flink
存储:S3/HDFS(原生格式)
元数据管理:Glue Catalog/Atlas
处理:Spark/Flink/MLlib
应用:推荐系统/实时Dashboard
1.2 数据仓库:“预处理好的纯净水厂”
定义(Inmon,数据仓库之父)
数据仓库是一个面向主题、集成、非易失、随时间变化的数据集合,用于支持管理决策。
核心特征
- 结构化优先:主要存储结构化数据(如订单、用户信息);
- schema-on-write:写数据前必须定义严格的 schema(比如Hive表的字段类型);
- ETL流程:先提取(Extract)→转换(Transform)→加载(Load),确保数据一致性;
- 高性能查询:采用列式存储(Parquet)、MPP架构(Redshift),适合复杂聚合查询。
数据仓库的典型架构(Mermaid流程图)
#mermaid-svg-jzze5WMGPGBx0yvQ{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-jzze5WMGPGBx0yvQ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-jzze5WMGPGBx0yvQ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-jzze5WMGPGBx0yvQ .error-icon{fill:#552222;}#mermaid-svg-jzze5WMGPGBx0yvQ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-jzze5WMGPGBx0yvQ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-jzze5WMGPGBx0yvQ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-jzze5WMGPGBx0yvQ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-jzze5WMGPGBx0yvQ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-jzze5WMGPGBx0yvQ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-jzze5WMGPGBx0yvQ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-jzze5WMGPGBx0yvQ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-jzze5WMGPGBx0yvQ .marker.cross{stroke:#333333;}#mermaid-svg-jzze5WMGPGBx0yvQ svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-jzze5WMGPGBx0yvQ p{margin:0;}#mermaid-svg-jzze5WMGPGBx0yvQ .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-jzze5WMGPGBx0yvQ .cluster-label text{fill:#333;}#mermaid-svg-jzze5WMGPGBx0yvQ .cluster-label span{color:#333;}#mermaid-svg-jzze5WMGPGBx0yvQ .cluster-label span p{background-color:transparent;}#mermaid-svg-jzze5WMGPGBx0yvQ .label text,#mermaid-svg-jzze5WMGPGBx0yvQ span{fill:#333;color:#333;}#mermaid-svg-jzze5WMGPGBx0yvQ .node rect,#mermaid-svg-jzze5WMGPGBx0yvQ .node circle,#mermaid-svg-jzze5WMGPGBx0yvQ .node ellipse,#mermaid-svg-jzze5WMGPGBx0yvQ .node polygon,#mermaid-svg-jzze5WMGPGBx0yvQ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-jzze5WMGPGBx0yvQ .rough-node .label text,#mermaid-svg-jzze5WMGPGBx0yvQ .node .label text,#mermaid-svg-jzze5WMGPGBx0yvQ .image-shape .label,#mermaid-svg-jzze5WMGPGBx0yvQ .icon-shape .label{text-anchor:middle;}#mermaid-svg-jzze5WMGPGBx0yvQ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-jzze5WMGPGBx0yvQ .rough-node .label,#mermaid-svg-jzze5WMGPGBx0yvQ .node .label,#mermaid-svg-jzze5WMGPGBx0yvQ .image-shape .label,#mermaid-svg-jzze5WMGPGBx0yvQ .icon-shape .label{text-align:center;}#mermaid-svg-jzze5WMGPGBx0yvQ .node.clickable{cursor:pointer;}#mermaid-svg-jzze5WMGPGBx0yvQ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-jzze5WMGPGBx0yvQ .arrowheadPath{fill:#333333;}#mermaid-svg-jzze5WMGPGBx0yvQ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-jzze5WMGPGBx0yvQ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-jzze5WMGPGBx0yvQ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jzze5WMGPGBx0yvQ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-jzze5WMGPGBx0yvQ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jzze5WMGPGBx0yvQ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-jzze5WMGPGBx0yvQ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-jzze5WMGPGBx0yvQ .cluster text{fill:#333;}#mermaid-svg-jzze5WMGPGBx0yvQ .cluster span{color:#333;}#mermaid-svg-jzze5WMGPGBx0yvQ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-jzze5WMGPGBx0yvQ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-jzze5WMGPGBx0yvQ rect.text{fill:none;stroke-width:0;}#mermaid-svg-jzze5WMGPGBx0yvQ .icon-shape,#mermaid-svg-jzze5WMGPGBx0yvQ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jzze5WMGPGBx0yvQ .icon-shape p,#mermaid-svg-jzze5WMGPGBx0yvQ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-jzze5WMGPGBx0yvQ .icon-shape rect,#mermaid-svg-jzze5WMGPGBx0yvQ .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jzze5WMGPGBx0yvQ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-jzze5WMGPGBx0yvQ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-jzze5WMGPGBx0yvQ :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
源系统:RDS/ERP/CSV
ETL工具:Airflow/Glue
转换:清洗/聚合/维度建模
存储:Redshift/BigQuery(结构化)
BI工具:Tableau/Power BI
决策:管理层KPI报表
二、核心区别:10个维度彻底说透
很多人对数据湖和数据仓库的误解,本质是没有从“设计目标”出发看差异。下面我们从10个关键维度对比,帮你建立“底层认知框架”。
2.1 维度1:数据类型——“什么数据能存?”
| 支持类型 | 结构化(CSV)、半结构化(JSON)、非结构化(图片/视频) | 主要是结构化数据(数据库表) |
| 典型例子 | 用户行为日志、商品图片、IoT传感器数据 | 订单表、用户维度表、销售汇总表 |
关键结论:数据湖是“全能存储”,数据仓库是“结构化专家”。
2.2 维度2:存储模式——“怎么存?”
数据湖用对象存储(Object Storage),比如AWS S3、HDFS;数据仓库用列式存储(Columnar Storage),比如Redshift、BigQuery。
为什么有这个差异?
- 对象存储:按“键-值”存储,适合非结构化数据,成本低(S3标准存储$0.023/GB/月);
- 列式存储:按列存储数据,压缩率高(Parquet比CSV小70%),查询时只扫描需要的列,适合聚合分析。
举例:存储1TB的用户行为日志,数据湖用S3只需$23/月,数据仓库用Redshift需要$160/月(Redshift存储成本$0.16/GB/月)。
2.3 维度3:处理流程——“ETL vs ELT”
这是最核心的差异,直接决定了两者的使用场景。
ETL(数据仓库):先转换,再加载
流程:Extract(从源系统取数据)→ Transform(清洗、聚合、去重)→ Load(加载到数据仓库)。
核心逻辑:数据仓库存储成本高,所以先“瘦身”,只存有用的数据。
ELT(数据湖):先加载,再转换
流程:Extract(取数据)→ Load(存到数据湖)→ Transform(按需处理)。
核心逻辑:数据湖存储成本低,先存所有原始数据,后期有新需求时再重新处理。
举例:
- 数据仓库:从RDS取订单数据→清洗掉重复订单→加载到Redshift;
- 数据湖:从Kinesis取用户行为日志→直接存到S3→需要分析“购买行为”时,再用Spark过滤出购买日志。
2.4 维度4:Schema设计——“写时定义vs读时定义”
| 定义时机 | 读取数据时才定义结构 | 写入数据前必须定义结构 |
| 灵活性 | 支持动态schema(比如JSON新增字段) | schema固定,修改需重建表 |
| 错误容忍度 | 允许数据格式不一致(读时过滤) | 数据不符合schema直接报错 |
举例:
- 数据湖:读取JSON日志时,用Spark的StructType定义schema,即使某些日志少字段也能处理;
- 数据仓库:Hive表创建时定义user_id INT, name STRING,插入字符串类型的user_id会直接失败。
2.5 维度5:适用场景——“解决什么问题?”
| 探索性分析 | ✅ 数据科学家找规律(比如用户行为模式) | ❌ 固定schema限制探索 |
| 机器学习 | ✅ 需要原始特征(比如图片像素、日志详情) | ❌ 处理后的数据丢失原始信息 |
| BI报表 | ❌ 查询速度慢(非结构化数据) | ✅ 适合固定KPI查询(比如月销售额) |
| 实时分析 | ✅ 流数据直接存湖(比如Flink→S3) | ❌ 实时ETL成本高 |
关键结论:数据湖是“创新引擎”(支持机器学习、探索性分析),数据仓库是“决策引擎”(支持BI报表、固定查询)。
2.6 维度6:用户角色——“谁在用户?”
- 数据湖的用户:数据科学家、数据工程师(需要处理原始数据,做模型训练);
- 数据仓库的用户:业务分析师、管理层(需要看结构化的聚合数据,做决策)。
举例:
- 数据科学家:用数据湖中的用户行为日志训练推荐模型;
- 业务分析师:用数据仓库中的订单汇总表做“618销售额Top10商品”报表。
2.7 维度7:数据治理——“如何管理混乱?”
数据湖的最大挑战是数据沼泽(Data Swamp)——大量原始数据堆积,没人知道“数据在哪、是什么、怎么来的”。
| 元数据管理 | 需要额外工具(Glue Catalog/Atlas) | 内置元数据(比如Redshift的系统表) |
| 数据 lineage | 需要手动跟踪(比如Spark的lineage) | 自动记录(ETL工具内置 lineage) |
| 权限控制 | 依赖存储层(S3 IAM/ HDFS ACL) | 内置细粒度权限(比如Redshift角色) |
解决方法:数据湖需要元数据管理工具(如Apache Atlas)和数据目录(如AWS Glue Catalog),否则会变成“数据沼泽”。
2.8 维度8:性能——“查询速度谁更快?”
数据仓库的查询性能远高于数据湖,原因有三个:
举例:查询“2023年Q2月销售额”,数据仓库用Redshift需要10秒,数据湖用Spark需要1分钟。
2.9 维度9:成本——“谁更便宜?”
成本对比需要看总拥有成本(TCO),包括存储成本和计算成本:
- 数据湖:存储成本低($0.023/GB/月),但计算成本高(Spark集群按小时收费);
- 数据仓库:存储成本高($0.16/GB/月),但计算成本低(查询优化好,用更少资源)。
结论:如果数据以“存储为主,偶尔查询”,选数据湖;如果“频繁查询,实时分析”,选数据仓库。
2.10 维度10:灵活性vs一致性——“鱼和熊掌?”
- 数据湖:灵活性高(支持所有数据类型、任意处理逻辑),但一致性低(数据格式可能不一致);
- 数据仓库:一致性高(严格schema、ETL清洗),但灵活性低(无法处理非结构化数据)。
三、纠正3个最常见的误解
误解1:“数据湖只存原始数据,数据仓库只存处理后的数据”
错误:数据湖可以存处理后的数据(比如Spark处理后的Parquet文件),数据仓库也可以存原始数据(比如Redshift存储原始订单表)。两者的差异是处理时机,不是“存储内容”。
误解2:“数据湖不需要schema”
错误:数据湖需要schema-on-read(读时schema),只是不在写的时候强制。比如用Spark读取JSON文件时,必须定义schema(手动或自动推断),否则无法解析数据。
误解3:“数据湖会取代数据仓库”
错误:两者是互补关系,不是替代关系。比如:
- 数据湖存原始用户行为日志,用于训练推荐模型;
- 数据仓库存聚合后的订单数据,用于生成BI报表。
未来趋势:数据湖仓一体化(Lakehouse),结合两者的优势(比如Databricks的Delta Lake)。
四、实战案例:构建电商数据分析系统
为了让你更直观理解两者的差异,我们以电商数据分析系统为例,展示数据湖和数据仓库的协同工作流程。
4.1 需求背景
某电商公司需要:
4.2 架构设计
- 数据湖:用AWS S3存储原始数据,AWS Glue做元数据管理,Spark做ELT处理;
- 数据仓库:用AWS Redshift存储结构化数据,Tableau做BI报表。
4.3 具体流程(附代码示例)
步骤1:收集数据到数据湖
用Python写Kinesis Producer,将用户行为日志发送到Kinesis Data Streams,再写入S3:
import boto3
import json
from datetime import datetime
# 初始化Kinesis客户端
kinesis = boto3.client('kinesis', region_name='us-east-1')
# 模拟用户行为日志
def generate_log():
return {
"user_id": 123,
"item_id": 456,
"behavior_type": "click",
"timestamp": datetime.now().isoformat()
}
# 发送日志到Kinesis
for _ in range(100):
log = generate_log()
response = kinesis.put_record(
StreamName='user-behavior-stream',
Data=json.dumps(log),
PartitionKey=str(log["user_id"])
)
print(f"发送日志成功:{response['SequenceNumber']}")
步骤2:ELT处理数据湖中的日志
用Spark读取S3中的JSON日志,过滤出购买行为,按天聚合:
from pyspark.sql import SparkSession
from pyspark.sql.types import StructType, StructField, IntegerType, StringType, TimestampType
# 初始化SparkSession
spark = SparkSession.builder \\
.appName("UserBehaviorELT") \\
.config("spark.hadoop.fs.s3a.access.key", "YOUR_ACCESS_KEY") \\
.config("spark.hadoop.fs.s3a.secret.key", "YOUR_SECRET_KEY") \\
.getOrCreate()
# 定义schema(读时schema)
schema = StructType([
StructField("user_id", IntegerType(), True),
StructField("item_id", IntegerType(), True),
StructField("behavior_type", StringType(), True),
StructField("timestamp", TimestampType(), True)
])
# 读取S3中的JSON日志
df = spark.read.schema(schema).json("s3a://your-bucket/user-behavior-logs/*")
# 转换:过滤购买行为,按天聚合
purchase_df = df.filter(df.behavior_type == "purchase") \\
.withColumn("date", df.timestamp.cast("date")) \\
.groupBy("date") \\
.count() \\
.withColumnRenamed("count", "daily_purchases")
# 写入S3(Parquet格式)
purchase_df.write.mode("overwrite").parquet("s3a://your-bucket/processed/purchase-stats/")
spark.stop()
步骤3:ETL导入数据到数据仓库
用Python和boto3将S3中的订单CSV文件导入Redshift:
import psycopg2
import boto3
# 配置参数
s3_bucket = "your-bucket"
s3_key = "orders/orders.csv"
redshift_host = "your-redshift-cluster.us-east-1.redshift.amazonaws.com"
redshift_db = "ecommerce_db"
redshift_user = "admin"
redshift_password = "YourPassword123"
redshift_table = "orders"
# 连接Redshift
conn = psycopg2.connect(
host=redshift_host,
port=5439,
dbname=redshift_db,
user=redshift_user,
password=redshift_password
)
cur = conn.cursor()
# 执行COPY命令(ETL:先转换CSV,再导入)
copy_cmd = f"""
COPY {redshift_table}
FROM 's3://{s3_bucket}/{s3_key}'
IAM_ROLE 'arn:aws:iam::123456789012:role/RedshiftS3AccessRole'
CSV
DELIMITER ','
IGNOREHEADER 1;
"""
cur.execute(copy_cmd)
conn.commit()
# 验证导入结果
cur.execute(f"SELECT COUNT(*) FROM {redshift_table}")
print(f"导入订单数:{cur.fetchone()[0]}")
cur.close()
conn.close()
步骤4:业务应用
- 数据科学家:用Spark读取S3中的purchase-stats数据,训练推荐模型;
- 业务分析师:用Tableau连接Redshift,生成“每日销售额报表”。
五、开发环境搭建:用Docker快速部署数据湖+数据仓库
如果你想本地测试数据湖和数据仓库,可以用Docker Compose快速搭建Hadoop(数据湖)+ Hive(数据仓库)环境。
5.1 安装依赖
- Docker:https://docs.docker.com/get-docker/
- Docker Compose:https://docs.docker.com/compose/install/
5.2 编写docker-compose.yml
version: "3"
services:
namenode:
image: bde2020/hadoop–namenode:2.0.0–hadoop3.2.1–java8
container_name: namenode
ports:
– 9870:9870
– 9000:9000
volumes:
– hadoop_namenode:/hadoop/dfs/name
environment:
– CLUSTER_NAME=test
env_file:
– ./hadoop.env
datanode:
image: bde2020/hadoop–datanode:2.0.0–hadoop3.2.1–java8
container_name: datanode
ports:
– 9864:9864
volumes:
– hadoop_datanode:/hadoop/dfs/data
environment:
SERVICE_PRECONDITION: "namenode:9870"
env_file:
– ./hadoop.env
hive-server:
image: bde2020/hive:2.3.2–postgresql–metastore
container_name: hive–server
ports:
– 10000:10000
environment:
HIVE_CORE_CONF_javax_jdo_option_ConnectionURL: "jdbc:postgresql://hive-metastore/metastore"
SERVICE_PRECONDITION: "hive-metastore:9083"
env_file:
– ./hadoop.env
hive-metastore:
image: bde2020/hive:2.3.2–postgresql–metastore
container_name: hive–metastore
ports:
– 9083:9083
env_file:
– ./hadoop.env
command: /opt/hive/bin/hive ––service metastore
volumes:
hadoop_namenode:
hadoop_datanode:
5.3 启动环境
# 下载hadoop.env文件
wget https://raw.githubusercontent.com/big-data-europe/docker-hadoop/master/hadoop.env
# 启动容器
docker-compose up -d
5.4 测试
order_id INT,
user_id INT,
amount DECIMAL(10,2),
order_date DATE
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
STORED AS TEXTFILE;
docker exec -it namenode hdfs dfs -put /tmp/orders.csv /user/hive/warehouse/orders/
六、未来趋势:数据湖仓一体化(Lakehouse)
随着企业对“灵活存储+高性能查询”的需求增加,**数据湖仓一体化(Lakehouse)**成为大数据架构的未来趋势。
6.1 Lakehouse的定义(Databricks)
Lakehouse是一种新架构,结合了:
- 数据湖的低成本存储和全类型支持;
- 数据仓库的ACID事务、高性能查询和数据治理。
6.2 Lakehouse的核心技术
- 事务层:Delta Lake、Apache Iceberg(支持ACID事务、time travel);
- 查询引擎:Spark、Presto、Redshift Spectrum(支持SQL查询);
- 数据治理:Apache Atlas、AWS Glue Catalog(元数据管理)。
6.3 Lakehouse的优势
6.4 挑战与应对
- 性能优化:用列式存储(Parquet)、分区(Partition)、Z-order索引;
- 数据治理:用元数据工具(Atlas)和数据目录(Glue Catalog);
- 兼容性:确保现有工具(如Tableau、Spark)能对接Lakehouse。
七、工具与资源推荐
7.1 数据湖工具
- 存储:AWS S3、Azure Data Lake Storage、Google Cloud Storage、HDFS;
- 处理:Apache Spark、Apache Flink、Databricks;
- 元数据:AWS Glue Catalog、Apache Atlas、Alation。
7.2 数据仓库工具
- 云原生:AWS Redshift、Azure Synapse Analytics、Google BigQuery、Snowflake;
- 开源:Apache Hive、Apache Impala、Presto。
7.3 ETL/ELT工具
- 开源:Apache Airflow、Apache Nifi;
- 云服务:AWS Glue、Fivetran、Stitch。
7.4 学习资源
- 书籍:《数据仓库工具箱》(Inmon)、《大数据湖》(Lenny Liebmann);
- 博客:Databricks Blog、AWS Big Data Blog;
- 课程:Coursera《大数据专项课程》、Udemy《数据湖与数据仓库实战》。
八、总结:选择数据湖还是数据仓库?
回到最初的问题:企业该选数据湖还是数据仓库?
答案是:根据业务需求选择,或采用Lakehouse一体化架构。
- 如果你需要处理非结构化数据、做机器学习:选数据湖;
- 如果你需要做BI报表、支持决策:选数据仓库;
- 如果你需要两者兼顾:选Lakehouse(比如Databricks Delta Lake、Snowflake Unistore)。
最后记住:技术是为业务服务的,不要为了“赶潮流”而选择不适合的架构。数据湖和数据仓库不是“非此即彼”,而是“协同工作”——它们共同构成了企业大数据生态的“双引擎”。
延伸思考:你的企业现在用的数据架构是什么?有没有遇到“数据沼泽”或“查询性能差”的问题?欢迎在评论区留言讨论。
作者:资深大数据架构师,15年行业经验,专注于数据湖、数据仓库、Lakehouse架构设计。
公众号:大数据架构师笔记(定期分享实战案例和技术干货)。
知乎:@大数据架构师(回答数据架构相关问题)。




