DLAI-数据工程导论笔记-全-
DLAI 数据工程导论笔记(全)
001:欢迎来到数据工程 🚀

在本节课中,我们将学*数据工程的基本概念、其重要性以及本系列课程的整体结构。数据工程是构建和管理数据基础设施的关键学科,它支撑着现代企业的数据分析、机器学*和人工智能应用。
概述
过去十年,几乎所有行业都实现了数字化。数字通信无处不在,数字数据正在取代纸质文件,成为医疗保健、金融、制造、教育、科技等几乎所有行业存储信息的主要机制。
然而,这股数据浪潮也带来了风险,以及如何存储和处理所有这些数据以创造价值的新挑战。无论您的组织是希望改善客户服务,还是在竞争中脱颖而出,拥有良好的数据管道都变得越来越关键。这也是数据工程师需求激增的原因。

认识你的讲师
我们很高兴欢迎乔·雷斯(Joe Reis)作为本专业课程的讲师。乔是一位拥有数十年经验的数据工程师和数据架构师,曾为多家公司提供数据服务。他还是一位教授、播客主播,并且是这本写得很好的畅销书《数据工程基础》的合著者。
乔曾将自己描述为一位“正在康复的数据科学家”。这个昵称源于2010年代中期,当时数据科学变得非常热门和流行。乔的背景是机器学*和分析,他注意到许多公司在招聘数据科学家时,并没有为他们提供成功所需的适当支持和基础架构。数据科学家常常没有数据来进行“科学研究”。
反复看到这种情况后,乔开始意识到,帮助数据科学取得成功同样重要的是数据工程。数据工程是关于构建基础架构、确保数据质量,并为数据科学家提供成功手段的学科。因此,虽然乔从数据科学起步,但他转向了数据工程,以帮助数据科学家解决这些问题。
数据工程的价值
当数据工程到位时,数据科学家提出一个问题并得到答案的时间可以从一周或一个月缩短到五分钟或一小时。这带来了巨大的效率差异,有时甚至决定了快速开发能否得到支持。
*年来,随着公司将数据视为宝贵的资产,他们开始投资构建基础部分,以将价值实现时间从几天、几周、几个月缩短到几小时、几分钟,有时甚至是几秒钟。
当你的数据只是笔记本电脑上的一个小CSV文件时,问题还不大。但一旦超出这个小数据集,构建和管理数据管道的工程复杂性就会产生巨大影响。
以数据为中心的AI
随着当今AI的兴起,采取以数据为中心的方法比以往任何时候都更加重要。以数据为中心的AI是一门系统化地设计数据以构建成功AI系统的学科。
对于数据工程师而言,这意味着无论数据规模大小——从笔记本电脑上的小CSV文件到存储在数据仓库中的海量数据集,甚至是如今用数万亿标记训练的大型语言模型——设计数据以使AI和机器学*算法获得成功所需的数据,都是一个令人兴奋且快速发展的领域。
本课程的学*内容
数据工程师的工作非常重要,也是一项专业技能。本课程旨在传授框架和原则,让你学会像数据工程师一样思考。
我们很高兴与亚马逊云科技(AWS)合作,在本课程中提供实践练*,帮助你在云上开发构建数据系统的技能。如今,大多数数据工程师都在云上构建系统,而AWS是目前使用最广泛的公有云。熟悉在AWS上构建系统将成为你作为数据工程师的一项宝贵资产。
本课程将数据工程的基础原则(与平台无关)与实践动手练*相结合。
课程适合人群
- 如果你是一名有抱负的数据工程师,那么本课程适合你。
- 如果你已经是一名数据工程师,并希望进一步提升技能,本课程也适合你。
- 如果你在与数据工程相关的领域工作,例如数据科学、机器学*、软件工程、分析或其他数据相关角色,本课程同样对你有益。
先修要求
唯一的先决条件是你需要有使用数据和Python的工作经验。如果你有一些SQL和云工具的经验会更好,但这并非必需。我们将向你展示需要了解的内容,并提供建议的学*资源。
课程结构
本专业课程包含四门课程:
- 第一门课程:我们将纵览全局,形成数据工程的心理框架,并启动一些云数据管道。
- 第二门课程:我们将专注于从源系统摄取数据、数据运维以及数据管道的编排。
- 第三门课程:全部关于云中的数据存储,以及存储如何成为数据工程生命周期所有阶段的重要组成部分。
- 第四门课程:关于为最终用例进行数据建模、转换和服务。
有很多内容需要涵盖,我们期待与你分享这一切。
总结
本节课我们一起学*了数据工程的兴起背景及其在数字化时代的关键作用。我们认识了讲师乔·雷斯,了解了他从数据科学转向数据工程的历程,以及数据工程在支持数据科学和以数据为中心的AI方面的重要性。最后,我们概述了本系列课程的结构、目标受众和先修要求,为后续深入学*做好了准备。


让我们继续观看下一个视频,正式开始学*。
002:数据工程导论(第1课)📊
在本课程中,我们将学*数据工程的基本概念、核心原则以及如何从宏观角度思考数据系统的构建。我们将首先了解数据工程师的角色、数据工程生命周期,并探讨如何将业务需求转化为系统设计。课程强调先建立正确的思维框架,再深入技术实现。
课程背景与目标 🎯
想象你刚被一家电子商务公司聘为数据工程师。首先,祝贺你获得这份新工作。
这家公司最初雇佣了数据科学家,希望进行数据分析以了解客户兴趣、行为和购买*惯,并希望利用大语言模型开发机器学*工具来自动化客户支持的各个环节。
然而,当数据科学家开始工作时,他们发现完成分析或机器学*任务所需的数据基础设施根本不存在。他们开始研究数据架构和系统以帮助构建所需的基础设施,同时也向管理层解释,构建数据基础设施并非他们的专长。为了确保成功,公司还应雇佣一名数据工程师。于是,你加入了公司。
这个故事听起来可能有些夸张,但在现实生活中,我亲眼目睹过无数次完全相同的场景。
事实上,我曾是故事中描述的那种数据科学家。我发现自己陷入了一种境地,需要快速学*如何构建数据基础设施的各个方面,以便将公司的数据和系统调整到可以开始进行我被雇佣来做的数据科学项目的状态。那是很多年前的事了,当时数据工程师这个角色甚至还不存在。
因此,也许雇佣我作为数据科学家的公司不知道他们真正需要什么,是可以被原谅的。当我深入设计和构建数据系统时,我对所学到的东西既感到不知所措,又感到兴奋。
我发现,无论你试图完成何种下游任务(例如数据科学、机器学*,或在应用程序中为用户提供嵌入式分析等),构建健壮数据基础设施所需的核心技能集在很大程度上是相同的。随着时间的推移,这套核心技能集被称为数据工程。
数据工程师的角色与职责 👨💻
回到我们的场景。你刚被聘为数据工程师,你的公司希望你构建能够实现其目标的数据系统。
为了实现这一目标,你需要能够将公司利益相关者的需求转化为系统需求,然后选择正确的工具和技术集来构建该系统。
这听起来可能相对简单,但我经常看到数据工程师在深入理解他们的系统将如何为组织创造价值之前,就直接投入到系统的实施中,选择工具和技术。采取这种方法可能导致灾难性后果,例如浪费公司的时间和资源,甚至可能让你丢掉工作。
因此,在这些课程中,特别是在第一门课程中,我们将花大量时间从宏观角度审视问题。
我们将讨论一套适用于你所有数据工程项目的原则,以构建成功数据系统的思维框架。
别担心,我们也会深入实践层面。在这些课程的实验练*中,你将使用前沿工具和技术在 AWS 云上构建数据系统。
第一周课程计划 📅
以下是第一周材料的学*计划。
我们将从高层次审视数据工程领域。我们将从数据工程生命周期和一点历史开始,并探讨数据工程师在公司其他角色和利益相关者背景下的定位。
之后,我们将探讨作为数据工程师如何为业务增加价值,然后讨论如何收集利益相关者的需求并将其转化为数据系统的需求。这个主题将在整个课程中反复讨论。
现在,我想暂停一下,在我们开始第一周学*时,非常明确地告诉你:本周你不会编写任何代码,也不会使用任何云工具。
相反,本周的重点是如何像数据工程师一样思考。这可能与你报名参加此类课程的预期感觉有些不同。
但请相信我,能够像数据工程师一样思考,是在这个领域取得成功的第一步。这就是为什么它是第一周材料的重点。
有了足够的高层次知识和正确的心态,成功数据工程的其他所有方面才有可能实现。没有它,任何技术知识或编码技能都无法拯救你。
正如我之前所说,在整个专项课程中,我们肯定也会深入技术层面。所以别担心,这将在本课程的第二周到来。
后续课程展望 🔮
在第二周,我们将深入探讨数据工程生命周期的每个阶段。第二周的材料也包含大量理论和数据工程领域的高层次导向。因此,你将在第一周“像数据工程师一样思考”的知识基础上继续学*。
然后,你将在周末的实验中,在 AWS 上动手实践云数据管道。
在第三周,我们将专注于良好数据架构的原则。
在第四周,我们将把所有内容整合起来,根据利益相关者的需求,设计和构建一个能够交付价值的数据架构。
总结 ✨


在本节课中,我们一起学*了数据工程师的角色起源、核心职责以及从宏观视角规划数据系统的重要性。我们明确了在深入技术细节之前,建立正确的思维框架和业务理解是成功的第一步。第一周的重点是培养“像数据工程师一样思考”的能力,为后续的技术实践和系统构建打下坚实的基础。在接下来的视频中,我们将开始深入了解数据工程生命周期。
003:数据工程定义 📘

在本节课中,我们将学*数据工程的定义及其核心概念。我们将探讨数据工程如何从软件工程的一个分支演变为一个独立的、至关重要的职能领域,并理解数据工程生命周期及其关键组成部分。
数据工程的演变
我见证了数据工程领域随着时间而发生的变化。
最初的数据工程师是软件工程师,他们的主要工作是构建组织所需的软件应用程序。
不久之前,由软件应用程序生成的数据大多被视为一种副产品或“废气”。我的意思是,假设你有一个像这样的软件应用程序在运行,它会将应用程序内的各种事件记录到日志中。
那么,记录在日志中的数据可能被认为对故障排除或监控应用程序健康状况等事情有用,但它本身并没有被认为具有多少内在价值。

因此,我画了一个从应用程序延伸出来的小排气管,然后数据就会像汽车的废气一样被生成,或者仅仅是应用程序的副产品。
然而,随着时间的推移,随着组织开始认识到数据的内在价值,以及由软件应用程序生成的数据量(由用户上传或通过各种记录的数字化创建)持续增长,同样的软件工程师越来越专注于构建专门用于摄取、存储、转换和为各种用例提供数据的系统。
随着数据工程在许多处理数据的组织中成为一项基本职能,数据工程师的角色便诞生了。
数据工程的定义
在我的合著者 Matt Hausley 与我合著的《数据工程基础》一书中,我们提出了以下数据工程的定义:
数据工程是开发、实施和维护相关系统和流程,这些系统和流程接收原始数据,并产生高质量、一致的信息,以支持下游用例,如分析和机器学*。


数据工程是安全、数据管理、数据运维、数据架构、编排和软件工程的交叉领域。
在课程的这一点上,我意识到这个定义可能有点令人困惑,或者至少听起来需要进一步解释这里出现的术语。
不过不用担心,在本课程中,我们将深入探讨这个定义中所有内容的细节,以便你理解其含义以及在实践中是如何体现的。
数据工程生命周期
除了数据工程的定义,为了可视化数据工程的生命周期,我们在书中整理了这个图表。在整个课程中你会经常看到这个图表,所以我想花点时间介绍一下它。
你可以将数据工程生命周期视为由一系列阶段组成。
在左边这里,你有数据生成和源系统。这些源系统可能是任何类型的软件应用程序、用户生成的数据、传感器测量数据或其他东西。无论如何,生命周期始于数据生成。
然后在中间这里,你有摄取、转换、存储和提供。我用一个方框框住了这些阶段,以表明这些是作为数据工程师你将重点关注的生命周期阶段。
你会注意到,存储位于摄取、转换和提供之下,并横跨整个方框的宽度。这是为了表明数据存储是上述每个阶段不可或缺的一部分。
在实践中,你构建的数据系统可能不像生命周期图表看起来那么简单,但根据我的经验,在可视化任何数据系统的共同元素时,以这种方式思考生命周期是有帮助的。
在图表的右侧,你有最终用例。这些是你的组织中的利益相关者实际从数据中获取价值的方式。这些包括分析、机器学*,或者称为反向ETL的东西(基本上是将转换或处理后的数据发送回源系统,为使用这些系统的组织内个人提供额外价值)。
数据管道
在本课程中,我将频繁使用术语数据管道,来统称数据从源系统生成到最终用例所经历的各种步骤。


你可以将数据管道视为架构、系统和流程的组合,它们推动数据经历数据工程生命周期的各个阶段。
作为数据工程师,你将管理数据工程生命周期,从从源系统获取数据开始,到为分析和机器学*等用例提供数据结束。
简单来说,数据工程师的工作就是从某个地方获取原始数据,将其转化为有用的东西,然后使其可用于下游用例。
数据工程的底层要素
在数据工程的定义中,我说数据工程处于安全、数据管理、数据运维、数据架构、编排和软件工程的交叉领域。
在《数据工程基础》一书中,我们将数据工程的这六个组成部分称为数据工程生命周期的底层要素。

因此,在这个数据工程生命周期图旁边,我喜欢把这些底层要素写在下面。这些底层要素不是像上面那样的生命周期阶段,而是贯穿整个生命周期。
所以现在解读这个图表的方式是:上面是数据工程生命周期的各个阶段,包括数据生成、摄取、存储、转换和提供;下面是你的底层要素,包括安全、数据管理、数据运维、数据架构、编排和软件工程。现在,这些底层要素中的每一个都与上面的所有生命周期阶段相关。
在本课程的第二周,我们将放大这里显示的每个阶段和底层要素,让你清楚地了解所有这些部分是如何组合在一起的。
整体视角的重要性
正如我在上一个视频中提到的,作为数据工程师,很容易直接跳入实施阶段,并尝试不同的工具和技术。这样做很容易忽视你工作的更高层次目标,以及你究竟打算如何为你的组织提供价值。
在整个课程中,我们将探讨如何整体地思考整个数据工程生命周期及其底层要素,以便你能成功地将利益相关者的需求转化为系统要求,并为你的业务提供真正的价值。

在我们继续前进之前,我认为有必要简要回顾一下数据和数据工程的历史,以了解我们是如何走到今天的。
话虽如此,下一个视频是可选的。你不需要记住任何这段历史也能在这些课程中取得成功。所以,如果你更愿意直接开始学*如何作为一名数据工程师开展工作,那么你可以跳过它。
否则,请加入下一个视频,快速了解数据和数据工程的历史。
总结
本节课中,我们一起学*了数据工程的核心定义及其演变过程。我们明确了数据工程是开发、实施和维护系统与流程,将原始数据转化为高质量信息以支持下游分析、机器学*等用例的学科。我们引入了数据工程生命周期模型,它涵盖了从数据生成、摄取、存储、转换到提供服务的各个阶段,并强调了贯穿始终的数据管道概念。最后,我们了解了构成数据工程基础的六大底层要素:安全、数据管理、数据运维、数据架构、编排和软件工程。理解这些整体框架是后续深入学*具体技术和实践的基础。
004:数据工程简史 📜 | 吴恩达《数据工程》课程 第1.3课

在本节课中,我们将回顾数据工程领域的发展历程,了解数字数据如何从早期计算机系统演变为今天复杂而强大的生态系统。理解这段历史有助于我们把握数据工程的核心任务与价值。
概述:无处不在的数据
首先需要明确一点:数据无处不在。数据构成了信息的基本单元,其形式可以是文字、数字,或是更为短暂的现象,例如来自遥远恒星的光子,或是拂面的微风。这些不同形式的数据可以被记录下来,例如作为大脑中的记忆、纸上的文字,或是数字形式——就像我正在为你录制的这段视频。从某种意义上说,数据自时间伊始就以某种形式存在了。
然而,在这些课程中,当我谈论“数据”时,我指的是数字记录的数据,即可以存储在计算机中或通过互联网传输的数据。
数字数据的开端:1960s-1990s
上一节我们明确了数据的定义,本节中我们来看看数字数据的早期发展。




数字数据的故事真正始于20世纪60年代,随着计算机的出现。那时,第一批计算机化数据库被引入。随后在70年代,关系型数据库兴起,这促使IBM的工程师开发了结构化查询语言,简称 SQL。
到了80年代,我的朋友Bill Inman开发了第一个数据仓库,目的是将数据转换为能够支持分析决策的形式。90年代,随着数据系统的增长,企业需要专门的工具和数据管道来进行报告和商业智能。正是在这种背景下,Ralph Kimball和Bill Inman分别开发了他们用于分析的数据建模方法。
90年代中期,互联网成为主流,催生了亚马逊等全新的“网络优先”公司。随后的互联网热潮导致了网络应用的快速增长,以及支持它们的后端系统(即服务器数据库和存储解决方案)的出现。
大数据时代的来临:2000s
互联网热潮之后,泡沫破裂,留下了雅虎、谷歌和亚马逊等少数幸存者,它们成长为强大的科技公司。起初,这些公司继续依赖90年代传统的关系型数据库和数据仓库,但这些系统无法处理它们当时面临的爆炸性数据增长。由此,大数据时代开始了。
《牛津词典》将大数据定义为“可能通过计算分析以揭示模式、趋势和关联的极大数据集,特别是与人类行为和互动相关的”。另一个著名而简洁的描述是数据的 3V 特性:速度、多样性和体量。这意味着大数据以高速度、广多样性、大体量的形式涌现。
2004年,谷歌发表了一篇关于MapReduce的论文,这是一种超大规模的数据处理范式。这篇论文的发表构成了数据技术以及我们今天所知的数据工程文化根源的“大爆炸”时刻。
谷歌的MapReduce论文及相关出版物启发了雅虎的工程师,他们在2006年开发并随后开源了Apache Hadoop。Hadoop的影响怎么强调都不为过。对大规模数据问题感兴趣的工程师被这个新的开源技术生态系统的可能性所吸引。随着各种规模和类型的公司的数据增长到许多TB甚至PB级别,大数据工程师的时代诞生了。
大约在同一时期,亚马逊为了跟上自身爆炸式增长的数据需求,创建了一个可扩展且灵活的计算环境,即亚马逊弹性云计算,简称 EC2。他们还创建了无限可扩展的存储系统,包括亚马逊简单存储服务,即 S3。他们也开发了高度可扩展的NoSQL数据库——亚马逊DynamoDB。
亚马逊决定通过亚马逊网络服务将这些核心数据构建模块提供给内部和外部使用,AWS也因此成为第一个流行的公共云。AWS发展成为一个极其灵活、按需付费的资源市场。现在,开发者无需为数据中心购买硬件,只需从AWS租用计算和存储资源。
随着AWS成为亚马逊高利润的增长引擎,其他公共云也很快跟进,包括谷歌云平台和微软Azure。公共云作为构建数据系统的媒介,可以说是21世纪最重要的创新之一,并引发了一场软件和数据应用开发与部署方式的革命。早期的大数据工具和公共云为今天的数据生态系统奠定了基础。没有这些创新,就不会有我们今天所知的数据格局和数据工程。

数据工程的普及与演变:2010s至今
在2000年代末和2010年代初,小型初创公司首次能够使用与顶级科技公司相同的尖端数据工具。
与此同时,另一场革命发生了:从批处理计算(即以块或批次的形式处理和分析数据)向事件流处理的过渡。这使得将数据作为连续的单事件流进行处理成为可能。伴随着这一转变,一个大型实时数据的新时代到来了。
尽管“大数据”一词曾广受欢迎,但作为一个概念,它已经失去了势头。即使拥有强大而复杂的开源大数据工具,管理它们也是一项繁重的工作,需要持续的关注。公司通常需要雇佣整个大数据工程师团队,花费数百万美元来“照看”这些系统。大数据工程师常常花费过多时间维护复杂的工具,而用于交付业务洞察和价值的时间可能相对较少。
如今,数据流动速度比以往任何时候都快,体量也越来越大,但大数据处理已经变得如此普及,以至于不再需要一个单独的术语。每家公司都致力于处理其数据并从中获取价值,无论实际数据体量大小。换句话说,大数据工程师现在就是数据工程师。
2010年代见证了云优先、开源和第三方产品的出现。这使得大规模处理数据比大数据时代简单得多。与此同时,数据源和数据格式在多样性和体量上持续增长。数据工程日益成为一门关于互操作和连接各种技术(就像乐高积木一样)以实现最终业务目标的学科。

这把我们带到了今天。如今,数据工程师的角色在价值链上的位置比以往任何时候都更高,并且还在继续上升。我的意思是,作为今天的数据工程师,你有机会站在巨人的肩膀上,使用前人开发的工具和技术构建强大、可扩展的数据系统。你也有机会为这些工具和技术的开发做出贡献,并构建未来的数据解决方案。
构建稳健的数据系统现在已成为各行各业商业战略的核心。因此,作为一名数据工程师,你可以直接参与实现业务目标,为你的组织创造价值。
总结与展望
本节课中,我们一起学*了数据工程从早期计算机数据库到现代云生态系统的演变历程。我们看到了数据如何从简单的记录演变为驱动商业决策的核心资产,以及数据工程师角色如何随之演变并变得日益重要。
在接下来的视频中,我们将开始探讨这在实践中是如何体现的,例如数据工程在组织中如何与其他角色和利益相关者协同,如何识别最终用户及其需求,这如何与业务价值相关联,以及如何将利益相关者的需求转化为系统要求。请加入下一节视频,一起看看数据工程如何融入你组织的其他部分。
005:🤝 数据工程师与其他利益相关者


在本节课中,我们将要学*数据工程师在工作中需要与哪些关键角色进行协作。你将了解到,数据工程师的工作并非孤立进行,而是需要深入理解上游数据提供者和下游数据使用者的需求,才能成功地将原始数据转化为有价值的信息。
正如之前所述,数据工程师的职责是从某处获取原始数据,将其转化为有用的内容,并使其可用于下游用例。但这无法在真空中完成。为了准确地将原始数据转化为对下游消费者有用的内容,你必须深入理解他们的需求。如果你能成为一名成功的数据工程师,你将以一种为下游用户增加价值并帮助他们实现目标的方式提供数据。
我们已经提到了一些潜在的下游用例,即分析和机器学*。在这些用例中,下游数据消费者可能是分析师、数据科学家、机器学*工程师,或是你组织中需要做出数据驱动决策的其他人员,例如销售人员、产品或营销专业人员或高管。
理解下游利益相关者


上一节我们介绍了数据工程师的核心职责,本节中我们来看看如何与下游数据消费者进行有效协作。
例如,假设你的下游数据消费者是一位业务分析师,他们需要能够对数据库运行SQL查询,以便为各种类型的分析生成数据。他们将使用这些数据来制作仪表板、分析趋势并预测某些指标的方向。
为了成功地为这位分析师服务,你需要与他们讨论以下事项:
- 他们需要多频繁地查询数据库以刷新仪表板?
- 每次查询需要检索哪些信息?基于此,你可以考虑是否需要在数据表之间进行某些连接(
JOIN)或执行其他聚合操作,以便在他们的查询之前预先运行,从而加快查询速度。 - 他们能容忍的指标延迟是多少?例如,查看过时一天的数据是否可以接受,还是他们需要接*实时的数据?
除了这些要求,你还需要确保你与这位分析师就他们工作所需数据的定义达成一致。例如,如果他们正在寻找“给定一天内的总销售额美元金额”,这听起来很直接。但假设你在一家为全球客户服务的公司,与你的分析师就使用哪个时区以及确切使用什么开始和结束时间来界定每一天达成一致,就非常重要。
这只是一个例子,但正如你所想象的,根据你的最终用户及其用例,你需要考虑的因素可能会有很大差异。
作为数据工程师,积极参与理解公司的整体战略非常重要,这样你才能更好地理解从你提供的数据中可以提取哪些商业价值,以及哪些业务指标是下游利益相关者所关心的。
理解上游利益相关者
在了解了如何服务下游用户之后,我们还需要考虑数据的来源。除了下游利益相关者,你还需要考虑上游利益相关者。
上游利益相关者是那些负责你摄取原始数据的源系统的开发和维护的人员。你的上游利益相关者通常是构建你所使用的源系统的软件工程师。这些可能是你公司内部的软件工程师,也可能是负责你正在摄取数据的第三方源的开发人员。
现在情况发生了转变,你成为了数据消费者,而源系统所有者为你提供服务,就像你在为业务分析师服务的例子中看到的那样。
在这种情况下,你需要与源系统所有者沟通,以了解在生成数据的数量、频率和格式方面可以期待什么,以及任何其他会影响数据工程生命周期的事项,例如数据安全和法规遵从性。
如果你能与这些源系统所有者建立正确的关系,通常你可以与他们合作,影响原始数据如何从这些源系统提供给你。通过开放的沟通渠道,他们还可以提前让你知道何时可能出现数据流中断或其他变化,例如数据中的模式(schema)变更。

在某些情况下,源系统可能位于你的组织外部,基本上不受你控制。即便如此,如果你能与这些系统的所有者建立联系,你可以更好地理解生成你所消费数据的应用程序。
课程总结
本节课中我们一起学*了数据工程师在将原始数据转化为有用信息并服务于用例的过程中,需要与所构建系统的上下游利益相关者进行协作。
回顾一下,以下是关键要点:
- 与上游源系统所有者沟通:花时间与他们联系,以更好地理解你正在摄取的数据,以及任何可能中断你数据管道的事项,例如服务中断或数据变更。
- 与下游利益相关者沟通:花时间理解你所提供的数据如何为你的组织增加价值,以及这与你所服务的利益相关者的个人目标有何关联。
谈到商业价值,这实际上是一个有点模糊的概念。因此,在我们开始为你的系统收集需求之前,我想就商业价值及其与你作为数据工程师角色的关系再多说几句。就像我之前提供的简短历史课一样,下一个视频是可选的,所以如果你更愿意直接开始为你的系统收集需求,可以随时跳过。
006:商业价值 💰

在本节课中,我们将探讨数据工程师如何为组织创造商业价值,以及理解这一概念为何对你的职业成功至关重要。
我创建这些课程的目标,是为你作为一名数据工程师在工作中的成功奠定基础。因此,让我们稍作停顿,设想一下成功是什么样子。任何公司雇用你担任数据工程师,都是因为他们相信你能为组织增加价值,这与其他任何员工并无不同。
最*,我与我的朋友比尔·英蒙进行了交谈,他是数据领域的意见领袖和知识最渊博的人士之一。当我询问他对于刚进入这个行业的人有何建议时,他强调了寻找并交付商业价值的重要性。以下是比尔所说的话:
“我给他们的建议,就像给银行劫匪的建议一样:去有钱的地方。如果你想在我们的行业中获得长期巨大的成功,就去寻找商业价值。不要纠结于每一个新出现的技术、每一个新奇的事物。去有商业价值的地方,因为在一天结束时,商业价值驱动着我们在技术领域所做的一切。我们很容易迷失并纠结于技术,技术本身并没有错,我自己也是一名技术人员,我热爱技术。但你现在需要考虑的首要事情是……如果你不在乎成功,只想去做一些看起来有趣的、花哨的事情,那就尽管去做吧,但不要期望从中获得任何巨大的回报。就像威利·萨顿在解释为何抢劫银行时说的:‘因为那里有钱。’所以,你做技术,就要寻找商业价值。”
因此,作为一名数据工程师,你需要寻找商业价值。但是,作为一名数据工程师,增加价值究竟意味着什么呢?根据我的经验,商业价值在某种程度上可以说是“因人而异”的。我的意思是,例如,假设你的组织希望你的数据工程师工作能帮助实现收入增长。在这种情况下,如果你的经理或领导层认为你的工作有助于公司收入增长,那么恭喜你,你很可能会被认为为组织增加了价值。另一方面,如果你的数据工程师工作被认为只是花费了大量资金,而投资回报很少或没有,那么你可能需要开始寻找另一份工作了。
但在许多情况下,商业价值并不仅仅是简单的盈亏,它可以有多种不同的形式,正如我们在上一个视频中看到的那样。在你的数据工程师工作中,你将与各种利益相关者互动。通常,正是这些利益相关者自行决定你是否在增加价值。一般来说,这意味着他们是否认为你在帮助他们实现目标。请注意,在所有这些例子中,我谈论的是你的工作如何被感知,而不是你实际做了什么。你为业务和利益相关者提供的价值量,将由你为之提供价值的对象来决定。因此,一般来说,当你满足利益相关者的需求时,你就是在为他们提供价值,无论这种价值是以收入增加、成本节约、工作效率提高的形式出现,还是以帮助产品成功发布等其他形式出现。

在成功识别了组织中所有利益相关者的数据需求之后,一个常见的情况是发现他们的集体需求远远超出了你创建解决方案的能力或资源。因此,你需要确定优先级,弄清楚哪些项目更可行,以及实施它们可能需要多长时间,等等。
现实地讲,我认为弄清楚作为一名数据工程师应该专注于什么以及如何最好地分配时间,这本身就可以成为另一门完整的课程主题。因此,我们不会在这里深入细节。但如果你好奇,可以在本周课程结束时的资源部分查看一个链接,那是马特·豪斯利和我与我们的朋友索·拉希蒂做的一个播客,她作为一名数据高管,就商业价值的真正含义提供了见解和观点。

现在,我们将继续前进,假设你已经想好了要构建什么样的系统。下一步就是确定该系统的需求。请加入下一个视频,我们一起探讨如何收集系统需求。
本节课总结
在本节课中,我们一起学*了商业价值对数据工程师的重要性。我们了解到,成功的关键在于为组织和利益相关者创造可感知的价值,而不仅仅是掌握技术。价值可以表现为收入增长、成本节约或效率提升等多种形式。同时,我们也认识到资源总是有限的,因此必须学会优先处理那些能带来最大商业价值的项目。理解并聚焦于商业价值,将指引你在数据工程领域取得长期的成功。
007:理解系统需求

在本节课中,我们将学*如何为数据工程项目定义系统需求。这是任何数据工程工作的第一步,确保我们构建的系统能够真正为利益相关者创造价值。
概述:什么是系统需求?
确保为利益相关者交付价值的方法是:首先理解他们的需求,然后将这些需求转化为你所构建系统的要求。
因此,在我们开始编写任何代码或在云端启动资源之前,需要花时间讨论为你的系统收集需求意味着什么。
首先,“需求”这个词在商业和工程背景下可以有许多不同的含义。例如,你可以有定义业务高层目标的业务需求。业务需求可能广泛地包括增加收入或扩大用户群等事项。
另一方面,利益相关者需求是组织内个人的需求,即他们为了做好工作所需要的东西。
当涉及到数据工程或一般的软件开发时,工程师需要定义系统需求,以描述系统需要能够做什么,以满足业务和利益相关者的需求。

系统需求通常分为两类:功能性需求和非功能性需求。你可以将它们分别粗略地理解为系统的“做什么”和“如何做”的要求。
功能性需求与非功能性需求
上一节我们介绍了需求的基本分类,本节中我们来看看这两类需求的具体含义。
功能性需求,即“做什么”,指的是系统需要能够完成的事情。在数据工程的背景下,这些可能包括:为服务于分析仪表板的数据库提供定期更新,或在数据出现异常时向用户发出警报。
相比之下,非功能性需求可以被视为你的系统将“如何”完成它需要做的事情。这可能包括技术规范,例如你计划在数据管道中使用的编排或存储,以满足最终用户的需求。
因此,要构建任何数据系统,你需要从该系统的需求集开始。这些需求可以涵盖从高层次的业务和利益相关者需求,到要提供的数据产品的特性和属性,再到你的计算和数据库资源所需的内存和存储容量。

你还需要考虑成本约束以及安全和法规要求。因此,任何数据工程项目的第一步,也是最重要的一步,就是收集系统需求。
如何收集需求?
理解了需求的类型后,我们来看看这些需求从何而来,以及如何收集它们。
通常,这些需求将来自你的下游利益相关者,即那些希望通过你的工作实现目标的人。问题在于,你的利益相关者通常不会以具体的系统需求形式与你沟通。相反,他们考虑的是业务目标,而你的工作就是弄清楚如何将他们与业务目标相关的需求转化为你的系统需求。
你构建的每个系统,需求收集过程看起来都会有些不同,但这个过程总是从与你的利益相关者对话开始。进行这些对话的方式将根据利益相关者在数据和数据系统方面的技术水平以及他们在组织中的角色而有所不同。

与不同利益相关者沟通
在下一段视频中,我将向你介绍我的朋友So Shiti,她在许多大公司担任过数据高管的角色。她将为新的数据工程师提供一些建议,关于如何与具有不同技术背景的不同利益相关者沟通。
然后,你将听到Jordan Morrow的分享,他被称为数据素养教父,建立了世界上最早的数据素养项目之一。他将就与不同利益相关者交谈时如何进行需求收集提供一些建议。
这两段视频都是可选的,你不会被评估这些对话的内容。所以,如果你愿意,可以自由地跳到后面的视频,在那里我们将看看在本周开始时为你设定的场景中,需求收集可能是什么样子:你是一家电子商务公司的新数据工程师,数据科学家需要你的帮助。
总结

本节课中我们一起学*了系统需求在数据工程中的核心地位。我们明确了业务需求、利益相关者需求和系统需求的区别,并重点剖析了系统需求中的功能性需求(系统“做什么”)与非功能性需求(系统“如何做”)。我们了解到,需求收集是与利益相关者对话的起点,并且沟通方式需因人而异。这是确保项目成功交付价值的关键第一步。
008:与数据高管的对话 🎙️

在本节课中,我们将学*如何与组织内的领导层进行有效沟通。通过与首席数据官索尔·拉希迪的对话,我们将了解数据工程师在商业环境中的重要性,以及如何根据沟通对象的背景调整沟通策略。
背景介绍
首席数据官(CDO)是商业世界中一个相对较新的职位。随着数据成为关键商业资产,许多公司正在围绕数据管理和价值挖掘建立专门的组织。索尔·拉希迪在2016年担任皇家加勒比的首席数据与人工智能官,是最早担任C级数据高管职位的人之一。在过去的十年里,她曾在索尼音乐、默克制药和埃斯特·劳尔等大型跨国公司领导数据和分析团队,并获得多项荣誉。
进入数据与AI领域的经历
索尔进入数据与AI领域完全出于偶然。她大学主修化学,但毕业后并不想从事化学相关工作。她决定追随自己的爱好,在大学期间参加体育运动,并在毕业后继续打橄榄球。随着年龄增长,身体恢复速度变慢,她不得不退役。她当时想找一份没人愿意做、能立刻获得的工作,结果恰好是数据工程师的职位。
她发现自己非常适合这个领域,但六个月后,团队禁止她再接触任何代码,因为她提交到生产环境的代码质量不佳。尽管如此,她仍然留在这个领域,因为她找到了自己的“部落”和社区。她发现,优秀的数据工程师虽然技术精湛,但有时无法将他们的工作转化为商业术语。索尔对商业语言、指标和财务报表一直很感兴趣,因此她成为了业务与技术之间的“翻译官”。
她的职业生涯由此展开,她担任过各种职位,最大的转折点是成为SAP白金级NDM顾问,后来晋升为企业数据管理负责人,并最终在IBM沃森团队负责数据相关工作。
成为C级高管的路径
索尔从未等待许可或被赋予机会,她总是主动识别目标并明确表达自己的追求。她曾担任安永的合伙人,负责管理最大客户的技术和数据。2015年,她建议客户聘请一位CDO,结果四个月后,客户邀请她加入领导团队,担任首席数据与人工智能官。
与数据工程师共事的经验
索尔认为数据工程师非常出色,是公司一切运作的支柱。这是一个常常不被感谢但至关重要的职位。所有业务运营,无论是营销活动、消费者细分还是产品发布,最终都依赖于信息和数据流。数据工程师掌握着这座“城堡”的钥匙,他们的工作是分析和构建管道,以确保在需要时能获取所需数据。
- 数据工程师非常出色。
- 他们是一个未被充分重视的群体,需要更多关注。
- 没有业务运营可以在没有他们的情况下运行,他们确实是每家公司的支柱。
我们需要更好地保护、鼓励他们,并让他们知道他们的工作非常重要。
给 aspiring 数据工程师的建议
如果你渴望成为一名数据工程师:
- 你需要有“脊梁骨”,而不是“许愿骨”。这个职位需要一定的韧性。
- 你掌握着城堡的钥匙。你所了解的信息及其在生态系统中的流动方式非常强大,是艺术与科学的结合。
- 不要害怕要求成为前台职能部门。数据工程师有时可能被视为后台职能部门,但如果你有进入管理或领导层的抱负,请主动争取。
- 提升沟通技巧。如果你不满足于只在办公室或隔间里写代码,请走到前台中心。
- 理解商业语言和背景。对于数据工程师来说,上下文就是一切。没有上下文,业务部门可能会立即质疑数据的有效性。
请记住,你的职能对每个业务职能都至关重要,无论他们是否认可你。确保你理解他们的语言和重点,沟通是关键。
与领导层沟通的策略
在课程中,我们正在讨论需求收集的过程。其中一个关键部分是了解业务的整体目标,而最好的方式可能就是与领导层交谈。
当索尔担任首席数据官时,她经常与数据工程师、架构师、分析师和科学家互动。她最喜欢做的事情之一就是白板会议,共同解决问题。她强调,与业务高管或任何类型的领导者交谈时,必须了解你的听众。
- 如果对方是职能型领导(不懂技术语言),切勿谈论语义层、管道构建等技术细节,否则会立刻失去他们。
- 如果对方是技术职能型领导,可以适当使用一些行话,但不要过度。
- 如果对方是技术型高管,则可以充分展示你的专业技能。
关键在于,在接触业务高管之前,了解他们使用的语言,并与之对齐。
如何判断沟通对象的类型
那么,作为数据工程师,如何判断应该与利益相关者进行多深的技术交流呢?
- 初创或小型公司:运营非常精简。要么你周围都是技术人员(CEO可能曾是技术个体贡献者),这时可以使用正常的技术语言;要么CEO是出色的营销人员,周围是销售和市场人员,这时你必须使用职能型语言。
- 中型和大型企业:查看对方的头衔和汇报线。除非他们在CIO或CDO办公室,否则通常可以假设他们是职能型的。如果对方领导一个品牌、标签、职能或服务,他们很可能是职能型的。
在对话中,可以先试探他们对技术领域的了解,再决定深入的程度。一个建议是:查看头衔和汇报线,通常先假设对方是职能型的,以职能型语言开始对话,除非他们将话题引向技术方向。
总结

本节课中,我们一起学*了与组织内领导层沟通的重要性与策略。索尔·拉希迪的分享告诉我们,数据工程师是公司的支柱,有效的沟通需要根据听众的背景调整语言。关键在于了解你的听众是职能型、技术型还是介于两者之间,并使用他们能理解的语言进行交流。这一建议不仅适用于与领导层的对话,也适用于与其他利益相关者的沟通。接下来,我们将听取乔丹·莫罗的建议,学*如何与不同的利益相关者进行需求收集对话。
009:与乔丹·莫罗的对话 🎙️

在本节课中,我们将与数据素养领域的专家乔丹·莫罗进行对话,探讨数据素养的定义、重要性,以及数据工程师如何更好地理解业务需求与受众。
什么是数据素养?📊
乔丹·莫罗被广泛认为是数据素养领域的奠基人之一。他首先阐述了数据素养的核心概念。
数据素养是使用数据的舒适度和信心。其定义为:阅读、处理、分析和交流数据的能力。其核心目标是帮助所有人,而不仅仅是数据分析专业人士,都能在使用数据时感到自如。这样,当数据被民主化或在工作中使用时,人们能更从容地应对。
数据素养为何重要?🤔
上一节我们定义了数据素养,本节中我们来看看为什么它如此关键。
组织长期以来一直试图从数据中获取价值。但如果你在构建数据产品或人工智能产品,你需要人们去采纳它们。如果用户对此感到不舒适或缺乏相关技能,就会阻碍数据工作和数据战略的真正成功。
组织投资数据工具和技术时,不能只是把它们摆在人们面前。这就像不能把一个没有经过任何训练的人直接放在一面高难度的攀岩墙前。数据也是如此,不能只是把仪表盘放在人们面前,就要求他们去发现洞察。我们需要让用户有能力驾驭优秀数据工作的成果,以确保产品被有效采纳和使用。此外,避免出现“不想碰数据”的文化问题也至关重要。
如何收集需求与理解业务目标?🎯
数据工程的一大核心部分是沟通业务、确定需求。以下是乔丹对此的建议。
在为目标和需求收集过程中,一个可能被忽视的关键点是理解你的受众。首先要做的是真正理解公司的业务目标,这来自于沟通、阅读和人际网络。但需求收集的下一步是关注你为之构建产品的人:他们需要什么?不仅仅是业务需要什么。无论是首席营销官、首席风险官还是销售团队,了解什么能驱动他们,这样在产品完成并推广时,你不仅能满足业务目标,还能将你的故事与他们的需求联系起来,从而获得他们更深层次的认同。
因此,需求收集也应包含对受众的理解。
理解不同的受众角色 👥
上一节强调了理解受众,本节我们进一步探讨受众角色的多样性。
与不同高管沟通时,他们的关注点截然不同。例如:
- 首席销售官关注销售目标。
- 首席营销官关注如何改进营销。
- 首席财务官关注现金流。
根据你构建的产品,你可能需要同时满足所有这些角色,这使得任务更具挑战性,因为你需要与每个人的需求都联系起来。这是一个很好的练*,能有效提升你的人际交往能力。
给 aspiring 数据工程师的建议 💡
对于有志于成为数据工程师的人,乔丹提供了以下核心建议。
我建议他们真正擅长的是理解业务如何运作。这可以称为“业务素养”。其目的不是把数据工程师变成业务人员,而是让他们在保持专业本色的同时,深刻理解业务运营。这样,在进行数据工程构建时,就能朝着支持业务运营的方向努力;在沟通时,也能使用业务语言。
所以,给 aspiring 数据工程师的建议是:不必强迫自己成为下一个销售或业务专家,但要努力成为一名优秀的数据工程师,并精通业务层面的知识。
总结 📝
本节课中,我们一起学*了与乔丹·莫罗的对话。我们探讨了数据素养的定义及其对数据产品成功采纳的重要性,强调了在需求收集中理解业务目标和不同受众角色的关键作用。最后,我们了解到,对于数据工程师而言,在深耕技术的同时,培养对业务运作的深刻理解是通往成功的重要路径。
010:需求收集对话示例 🗣️

在本节课中,我们将通过一个模拟对话,学*数据工程师如何与数据科学家等关键利益相关者进行需求收集。这是任何数据工程项目的第一步,旨在理解业务需求和数据挑战。
概述
上一节我们介绍了数据工程项目的第一步是需求收集。本节中,我们来看看一个具体的模拟对话示例,展示数据工程师如何与扮演数据科学家角色的利益相关者进行初步沟通,以理解其数据需求和当前痛点。
模拟对话:数据工程师与数据科学家
数据工程师(Joe): 你好,我是Joe,本周刚加入公司,是一名新的数据工程师。我非常期待能与你合作数据项目。我想我们可以讨论一下你正在做的工作,看看我能如何帮助你。
数据科学家(Colleen): 当然可以。很高兴认识你,欢迎加入公司。实际上,我几个月前才作为数据科学家加入这里,可以说工作一直非常忙乱。
数据工程师(Joe): 忙乱?请详细说说。
数据科学家(Colleen): 我们的营销团队要求对产品销售额进行按地区的实时分析。他们希望查看诸如客户购买了哪些产品、客户所在地等信息。目前,我们所有的产品销售信息和数据都位于销售平台的生产数据库中。软件工程团队不希望给我直接访问权限,因为他们担心我可能会破坏某些东西。因此,他们每天给我一次数据转储,我需要手动拉取。
数据工程师(Joe): 我明白了。所以你得到了需要的信息,但因为需要手动下载,所以有点麻烦。
数据科学家(Colleen): 嗯,可以说我得到了需要的信息,但也得到了很多不需要的东西。我花了大量时间筛选这些数据,大约90%的内容我都不需要。数据存储在各种CSV和JSON文件中,我需要运行一系列处理步骤,从每个文件中提取所需内容,进行清理、聚合,然后保存成我实际可以用来构建仪表板的格式。
数据工程师(Joe): 所以听起来你在能够将数据用于分析之前,需要花费相当多的时间来处理数据,对吗?
数据科学家(Colleen): 是的,没错。我可能花了大约80%的时间来清理和处理数据。我的处理脚本经常崩溃,因为文件中存在异常或意外的条目。有几次,软件团队实际上改变了他们发送给我的数据格式,而我只是在处理脚本全部无法运行时才发现。我不得不重构这些脚本来适应新格式。我花一整天时间将数据转换成仪表板可用的格式并不少见。与此同时,正如我所说,营销团队希望获得实时的区域销售分析。而通常当我推送更新时,信息已经过去两天了。
数据工程师(Joe): 这听起来是个相当痛苦的过程。我能理解你为什么觉得忙乱了。为了能够更快地交付结果,听起来一个问题是你每天只获得一次数据转储,而且数据清理和处理步骤既繁琐又有点不可预测,这可能增加了你的工作时间,对吗?
数据科学家(Colleen): 对。在目前情况下,我觉得很难更快地交付结果。但营销团队确实想要当前的指标,而不是两天前的数据。我希望你能帮忙解决这个问题。
数据工程师(Joe): 当然可以。你提到他们想要实时更新,他们希望用这些信息做什么?
数据科学家(Colleen): 根据我们目前所做的工作,他们一直专注于更好地理解营销活动的效果,以及观察产品销售的短期和长期趋势,以便更好地安排活动时间。我们还在为网站开发一个推荐引擎,在客户浏览或购买时向他们推荐产品。
数据工程师(Joe): 有趣。听起来那里可能有几个不同的用例。那么,目前你正在为他们提供仪表板和一个满足部分需求的推荐引擎。
数据科学家(Colleen): 嗯,可以说是,也可以说不是。在顶层,我提供的仪表板显示了过去30天按类别和地区汇总的产品销售额,包括30天总计以及显示每日数字的时间线图。这是应要求提供的,以便他们能够广泛地了解各地区正在发生什么样的趋势。他们还可以双击进入任何特定区域,查看按单个产品或更精细时间节奏(如每小时而非每天)的细分。但正如我所说,数据通常至少是两天前的,所以它显示的不是当前数字。至于推荐器,我只是做一些分析来确定过去一周左右最受欢迎的产品,然后将这些产品列表传递给软件团队,以便他们可以向浏览网站的每个人推荐一些热门产品。所以它还没有真正针对单个客户进行定制,只是显示热门产品。我目前一直在训练一个模型,使用内容过滤方法进行个性化推荐,但还没有部署任何东西。
数据工程师(Joe): 所以听起来对于产品推荐系统,你可能需要更多数据用于训练。一旦你有了一个实际准备好部署的模型,你将需要某种系统,将销售平台的用户活动数据提供给模型,然后将输出的产品推荐传递回平台,在用户浏览时展示给他们,对吗?
数据科学家(Colleen): 是的,计划就是这样。就像你在任何电子商务网站或应用上可能看到的那样,当用户浏览或结账购买时,他们会看到根据他们查看的内容或放入购物车的商品推荐的其他产品。
数据工程师(Joe): 这说得通。那么,对于你提供给营销部门的仪表板,你说他们想要当前数据,而不是两天前的数据。你是否了解营销部门希望基于当前数据采取什么行动,而这些行动是他们用两天前或更旧的数据无法做到的?
数据科学家(Colleen): 他们谈到能够基于当前数据定位广告活动。我想这可能意味着查看客户目前在购买或销售平台上的其他活动方面在做什么。但我不确定这是否意味着他们需要知道客户当前这一秒在做什么,还是过去一小时内,或者更笼统地说是今天而不是昨天。
数据工程师(Joe): 没关系。我会看看是否能与营销团队的人员跟进,更好地了解他们的期望。如果我能弄清楚他们计划基于数据采取什么行动,那将帮助我准确确定数据需要如何提供,以及系统可以容忍多少延迟。
数据科学家(Colleen): 有道理。如果有什么其他我能帮忙的,请告诉我。
数据工程师(Joe): 好的,太好了。嗯,这次谈话真的很有帮助。如果我理解正确的话,听起来真正能帮助你的方法是,如果我们能找到一种更直接、更及时地从记录销售的数据库摄取数据的方式,然后如果我们能找到一种更好的方法来自动化和编排数据的转换及服务,使其成为你的仪表板和推荐器所需的格式,那么我们就走对了方向,对吗?
数据科学家(Colleen): 是的,绝对是的。如果数据的摄取和处理能够自动处理,并以我需要的格式存储,那将对我有巨大的帮助,让我的生活轻松很多,并帮助我专注于我擅长的事情,即分析数据。
数据工程师(Joe): 好的,太好了。谢谢Colleen。我认为一个好的下一步是与营销团队的人员沟通,以更好地了解他们的需求。
数据科学家(Colleen): 是的,听起来很棒。谢谢你,Joe。
数据工程师(Joe): 好的,谢谢。
对话要点总结
以上是一个初始需求收集对话的示例。当然,在现实世界中,这样的对话可能不会如此简短或直接,而且每种情况都是独特的。除此之外,还会有更多的对话需要进行。
从这次对话中,我们可以开始思考以下关键要点:
以下是数据工程师从对话中提取出的核心需求和痛点:
- 数据获取延迟: 数据科学家每天仅获得一次手动数据转储,导致分析结果滞后至少两天。
- 数据处理负担重: 数据科学家花费约80%的时间进行数据清洗、格式转换和聚合,流程繁琐且易出错。
- 数据源不稳定: 源数据格式可能在不通知的情况下变更,导致处理脚本崩溃,需要额外时间修复。
- 业务需求不明确: 营销团队要求的“实时”分析具体指代的时间粒度(秒级、小时级或日级)尚不清晰,需要进一步确认。
- 系统自动化需求: 迫切需要将数据摄取、处理和转换为可用格式的流程自动化。
基于这些信息,数据工程师可以开始规划系统需求,例如设计自动化的数据管道、确定合适的数据存储和查询方案,并安排与营销团队的进一步沟通以明确“实时”的具体定义。
总结
本节课中,我们一起学*了一个模拟的需求收集对话。通过这个例子,我们看到了数据工程师如何通过提问来理解数据科学家的日常工作流程、当前数据挑战以及业务团队的最终目标。有效提取这些信息是设计一个能够真正解决问题、创造价值的数据系统的关键第一步。在下一课中,我们将深入分析这次对话,学*如何从中提取出构建数据系统的具体需求。
011:将利益相关者需求转化为具体要求 📋

在本节课中,我们将学*如何与利益相关者(例如数据科学家)进行有效沟通,并将其需求转化为清晰、具体的数据系统要求。我们将通过分析一个示例对话,拆解出需求收集的关键步骤和核心要素。
概述:需求收集的核心要素
上一节我们介绍了与数据科学家进行初步需求收集对话的示例。本节中,我们将详细分析对话中的每一部分,并提炼出一个系统化的方法,用于从类似对话中提取数据系统需求,并识别需要沟通的其他利益相关者。
任何需求收集工作的关键要素如下:
- 了解现状与痛点:学*当前用于交付数据的现有系统或解决方案,以及这些系统存在的问题。
- 明确行动与目标:了解利益相关者计划基于你提供的数据采取什么行动。
- 确认与复述:将你理解的内容复述给利益相关者,以确认信息准确无误。
- 识别其他相关方:如果对现有系统或计划行动的信息仍有缺失,识别其他需要沟通的利益相关者。

接下来,我们看看这些关键要素是如何在与数据科学家的对话中体现的。
分析现有系统与痛点
对话开始时,数据科学家提到:“营销团队需要按地区实时分析产品销售数据,但他们目前只能从软件团队获得每日数据转储,以避免影响生产数据库。”
这显然不是一个理想的解决方案。但事实上,不将生产数据库用于分析或其他项目通常被认为是良好实践。这是因为,如果在向数据库写入新客户活动信息的同时,对其运行复杂查询,可能导致整个系统崩溃,这非常不利。
数据科学家还提到,他们有时会因为数据模式变更或其他数据异常而遇到问题。对于源系统的模式变更或其他中断,你可以考虑如何建立数据摄入的自动检查机制,以确保数据符合预期。但更理想的情况是,你能在这些变更或中断发生前就知晓。你应该直接与提供数据的源系统所有者沟通。
因此,在确认了关于现有解决方案和痛点的信息后,你也识别出了需要进行进一步沟通的利益相关者。具体来说,你需要与维护源系统和数据库的软件工程师进行对话。在这些对话中,你的目标是理解比每日数据转储更好的数据摄入解决方案可能是什么样子,以及可能遇到哪些中断或变更,并探讨如何提前获知这些变更。
明确功能与非功能需求
数据科学家关心的下一个问题是数据清洗和处理的繁琐性。从某种意义上说,利益相关者的需求从一开始就很明确:需要有人(也就是你,数据工程师)来自动化数据的摄入和转换,将其变为所需的格式。
在这种情况下,你识别出了一个功能需求:系统需要摄入、转换并以数据科学家所需的格式提供数据。与此相关的系统非功能需求可能包括延迟要求,即数据在源系统中记录后,需要多快可用。
这引出了对话中出现的另一个关键信息:数据科学家多次提到“营销团队需要实时数据”。在现实世界中,你会发现人们使用“实时”这类术语相当宽泛。我曾遇到过声称需要“实时”信息的客户,但实际上他们只需要月度报告。在其他情况下,“实时”可能意味着每日、每小时或系统实际的亚秒级延迟。
因此,我想强调需求收集中的一个关键策略:询问你的利益相关者,他们计划基于你提供的数据采取什么行动。需要指出的是,询问“计划采取什么行动”与询问“需要什么”并不相同。利益相关者通常会倾向于直接告诉你他们需要什么,有时他们已经将自己的需求转化为系统的功能需求。他们可能做得很好,识别出了正确的功能需求。但关键在于,你必须首先准确理解利益相关者希望用你提供的数据产品做什么。然后,你可以将他们的计划映射到他们的需求上。在许多情况下,一旦你理解了他们的需求,你会发现存在他们尚未识别的不同或额外的功能需求,而下一步就是就此达成一致。
通过“行动”澄清“需求”
在这个案例中,询问营销团队计划采取什么行动,有助于明确最终用例:基于分析仪表板做出营销活动决策,以及为平台中的推荐系统提供产品推荐。很明显,产品推荐需要以*实时(可能几秒或更短)的方式提供给浏览平台的客户。因此,你可以开始思考该系统的功能和非功能需求。
另一方面,对于仪表板,营销团队计划采取的具体行动尚不明确。因此,需要与营销团队沟通,了解更多他们希望实现的目标,以明确“实时”对他们而言在那种情况下的具体含义。

总结与后续步骤
那段与数据科学家的简短对话包含了大量信息。至此,你已经了解了现有解决方案和痛点,开始识别一些系统需求,并确定了需要沟通的其他利益相关者,包括营销团队和软件工程团队。
总结一下,任何需求收集对话的关键要素是:识别现有系统和痛点、询问利益相关者计划用数据采取什么行动、确认你的理解,并识别需要沟通的其他利益相关者。
在本课程的第四周也是最后一周,当我们与其他利益相关者进行后续对话时,你将看到需求收集每个方面的更多示例。一旦你掌握了所有需求,就是时候选择能够满足这些需求的工具和技术了。在下一个视频中,我将详细介绍如何在一个框架内将这些部分整合起来,这个框架可以用于你处理的任何数据工程项目。
012:像数据工程师一样思考 🧠
在本节课中,我们将学*一个系统化的思考框架,帮助您像数据工程师一样规划、设计和实施数据项目。这个框架涵盖了从需求收集到系统部署与迭代的全过程。
在之前的视频中,我们走查了一个需求收集对话的示例,并总结了从该对话中得出的关于数据系统的功能性需求与非功能性需求,以及其他需要沟通的利益相关者。需求收集过程并非数据工程独有,它可能出现在各种产品开发或产品管理场景中。根据具体应用,需求收集的方法可能略有不同。
但通常,需求收集后的下一步是决定如何实际构建产品或系统以满足这些需求。在数据工程中,您的工作将涵盖从需求收集到数据系统实施的全过程。
本节视频将分享一个我称之为“像数据工程师一样思考”的框架,您可以在任何项目中应用它。
第一阶段:确定业务目标与利益相关者需求 🎯
在此阶段,您的主要目标是确定驱动项目的业务目标和利益相关者需求。
以下是此阶段需要完成的步骤:
- 明确公司高层业务目标:首先需要清晰理解公司层面的业务目标。
- 识别利益相关者:找出所有与项目相关的利益相关者,并理解他们的需求如何与高层业务目标相关联。
- 与利益相关者沟通:与每位利益相关者进行对话,了解当前已有的系统(您将要构建或替换的系统),以及现有系统之外的利益相关者需求。
- 询问预期行动:在此阶段,询问利益相关者计划如何使用您提供的数据产品采取行动至关重要。这有助于您精准定位所要构建系统的实际功能性需求。
第二阶段:定义系统需求 📋
在第二阶段,您的目标是将利益相关者的需求转化为系统的功能性需求和非功能性需求。
简而言之,这意味着:
- 功能性需求:描述系统必须能够做什么以满足利益相关者的需求。
- 非功能性需求:描述系统将如何实现其功能的技术规格。
一旦得出一组功能性和非功能性需求,您需要记录结论,并向利益相关者确认,按照这些需求设计的系统能够满足他们的期望。
第三阶段:选择工具与技术 🛠️
在第三阶段,您将为构建系统选择工具和技术。
此阶段始于识别能够满足系统需求的工具和技术。通常,会有多种工具和技术可以满足任何单项需求,您需要评估它们之间的权衡取舍。
因此,您需要进行成本效益分析,以从这些工具中选择最佳组件。在此分析中,您可能需要考虑许可费用、云资源支出估算以及使用这些组件构建和维护系统所需的其他资源。
第四阶段:构建、测试与迭代 🚀
最后,在选择了您认为最佳的工具和技术组合后,您将搭建系统的原型,以测试其是否符合预期,并判断它是否能为利益相关者带来价值。
在投入时间和精力构建完整的数据系统之前,搭建原型并进行测试的这最后一步非常重要。您需要测试所设计的系统是否真的能够满足利益相关者的需求。
在此阶段,您需要与利益相关者再次确认,让他们评估所设计的系统是否能为其带来价值。我强烈建议您花费足够的时间迭代原型,以确保系统在投入生产后能够成功。
作为此最终阶段的最后一步,您将构建并部署您的数据系统。
系统运行后,您需要持续监控和评估系统性能,并不断迭代以持续改进。您构建的任何数据系统都需要随着时间的推移而演进。
这可能是由于利益相关者需求的变化,或者在某些情况下,出现了能够提升系统性能、降低成本或提供其他优势的新工具或技术。
因此,虽然我将此框架呈现为依次发生的四个阶段,但实际上,这将是一个持续且循环的过程。随着业务目标和利益相关者需求的演变,您的数据系统也需要随之演进。
您可以这样理解:作为一名数据工程师,您需要始终与利益相关者沟通他们的需求和期望,根据数据系统的需求评估这些需求,并根据需要更新您的系统以满足利益相关者的需求。

我意识到这个框架可能感觉有些抽象,因为我们尚未实际完成大部分工作。但我希望在课程的第一周就介绍这些概念,以便您在后续课程中牢记它们,并重新审视每一个阶段。
在本周,我们大部分时间都在讨论前两个阶段:识别业务目标与利益相关者需求以及定义需求。
在本课程的第四周,我们将接续之前视频中与数据科学家的对话,并与其他所有利益相关者完成沟通。我们将定义需求,然后将其转化为系统的技术规格和工具选择。接着,在实验练*中,您将完成整个过程,并实施一个满足需求的数据架构。

现在,让我们快速了解一下云上数据工程的一些实际考量。下节课见。
013:云上的数据工程 ☁️

在本节课中,我们将学*数据工程在云计算环境下的实践。我们将探讨从本地部署到云端的演变,并介绍本课程将如何采用“云优先”的方法,帮助你为成为一名数据工程师做好准备。
从本地部署到云端
上一节我们介绍了数据工程的生命周期和基本概念。本节中我们来看看数据工程实践环境的演变。
这门专项课程的核心是数据工程。到目前为止,在第一周的学*材料中,我们主要停留在较高的概念层面。我们审视了整体的数据工程生命周期和底层支撑,回顾了数据工程的一些历史,以及如何与利益相关者合作并为组织交付价值。
正如我在本周开始时所说,我意识到这可能不完全是你报名参加这些课程时所期望的内容。但正如我之前所说,这种高层次的思维框架和数据工程师的思考方式,对于后续所有内容都至关重要。我们将在整个课程中反复回顾这一点。
作为一名数据工程师,你所使用的实际工具和技术组合,在不同的公司之间可能会有很大差异。
正如我在关于数据工程历史的视频中所讨论的,随着公共云的出现,以及开源和专有工具的激增,各种规模和行业的公司现在都能使用同一套高性能的工具和技术。
如今,许多公司选择完全在云上构建其数据系统。但在不久之前,公司唯一的选择是在内部构建和维护自己的数据基础设施,这通常被称为本地部署系统。
今天,仍然有一些公司将其部分或全部数据基础设施维持在本地。在某些情况下,这可能是由于监管限制,或者公司有一些遗留系统,他们更倾向于在本地维护。
因此,作为一名当今的数据工程师,你可能会在一家拥有部分本地系统的公司工作,甚至可能负责将本地系统迁移到云端。
然而,越来越可能的情况是,你作为数据工程师的工作将完全在云端进行。
主要的云服务提供商
尽管AWS是第一个流行的公共云,并且至今仍是使用最广泛的云平台,但根据你的工作地点,你可能会遇到其他云服务提供商,例如谷歌云平台、微软的Azure等。
在本专项课程中,我们不会深入探讨如果你需要处理本地系统或从本地迁移到云端时可能遇到的细微差别或注意事项。相反,我们将采取“云优先”的方法,为你准备最可能遇到的数据工程师场景。
我们在开发这些课程时与AWS进行了合作。因此,在实验练*中,你将使用与全球数千家公司在其自身数据基础设施中使用的相同工具和技术,在AWS云上构建数据管道和架构。
到第一门课程结束时,你将能够根据我们讨论过的系统技术要求,建立一条使用适当云端工具和技术的数据管道,以满足这些需求。
本课程的学*方法

AWS云包含一套庞大的资源与工具。本专项课程的目标不是教你所有关于AWS数据工程的知识。相反,我们将采取“即时”学*方法,在你进行每个实验时,直接学*如何使用特定的工具。
通过这种方式,要成功完成这些课程,并不需要具备云计算方面的先验知识。
话虽如此,对云计算基础知识和术语有更广泛的了解,将有助于你在学*这些课程的过程中建立背景知识。
为了介绍AWS的工具和资源,我将邀请摩根·威利斯加入。他是一位首席云技术专家,专门教授人们如何在AWS云上取得成功。
请加入下一节视频,与摩根见面。

本节课中我们一起学*了数据工程向云端迁移的趋势,了解了主要的云服务提供商,并明确了本课程将采用与AWS合作的“云优先”及“即时”学*方法,为你在云端构建数据工程解决方案打下基础。
014:认识讲师与课程概述 🌟

在本节课中,我们将认识本课程的讲师摩根·威利斯,并概述数据工程基础课程的结构与目标。我们将了解讲师背景、课程涵盖的核心内容,以及如何为后续的实践环节做好准备。
讲师介绍 👩🏫
很高兴向大家介绍摩根·威利斯,她是AWS的首席云技术专家。
你可能在Coursera平台的其他课程中见过摩根,例如《AWS云从业者》和《云技术精要》课程。摩根,非常欢迎你加入我们。很高兴来到这里,乔。
在我们开始之前,你是否想更详细地介绍一下自己,包括你的背景以及你是如何开始教授全世界如何在AWS上构建出色应用的?当然可以。我最初获得了计算机科学学位,并担任了一段时间的软件开发人员。我确实非常热爱编程。
但我也意识到我同样热爱教学。因此,我转型成为一名软件开发训练营的讲师,之后加入了AWS担任培训师。现在,我为Coursera等平台教授我们的在线课程。我非常热爱这份工作,这无疑是我的梦想工作,能帮助人们在云计算领域实现他们的潜力。这真是太棒了。
课程目标与结构 🎯
欢迎来到数据工程世界,这里需要打下坚实的基础。这个基础的一部分可以称为概念和理论部分。
例如,就像我们本周讨论过的一些内容,比如需求收集、将数据工程项目从头到尾可视化为一系列阶段,以及如何开始像数据工程师一样思考。构建坚实数据工程基础的另一个重要部分是,实际动手构建数据工程解决方案的实践。
而这正是你们将在这些课程的实验环节中所要做的。当你刚开始在AWS云上构建时,可能会感到不知所措。你会接触到诸如区域和可用区等概念。
虚拟私有云、子网等等。没错,你还有不同的计算和数据库选项,以及存储选项。
网络和安全配置,而这仅仅是个开始。事实上,关于AWS云上的数据工程有太多需要了解的知识,因此我们提供了一项认证考试,让你可以成为AWS认证的数据工程师助理,并向雇主证明你熟悉AWS上的工具和资源。这项认证验证了围绕核心数据相关AWS服务的技能和知识,涉及的任务包括:数据摄取和转换能力、在应用编程概念的同时编排数据管道的知识、设计数据模型。
管理数据生命周期以及确保数据质量。通过这些课程,你将学*到该认证考试涵盖的许多关键概念和技术。如果你有兴趣,我鼓励你在完成本课程后继续学*并考取该认证。
课程起点与学*资源 📚
因此,我希望本周从基础开始,让你熟悉在这些课程中将会遇到的一些术语和概念。这些课程没有云知识先决条件,正如乔所说,对于完成实验所需的技术知识,我们会提供“刚好足够”和“及时”的内容,以确保你在这些练*中取得成功。
话虽如此,AWS云的内容远不止我们在这些课程中有时间详细涵盖的。如果你希望获得更深入的了解。
我推荐乔在本视频开头提到的两门课程:Coursera上的《AWS云从业者》和《云技术精要》课程。除此之外,我们每周还会提供额外的资源,供你喜欢时深入探索。那么,我们可以开始了吗?听起来很棒,交给你了,摩根。好的,太好了。我们将在下一个视频中见面,开始学*AWS云计算的基础知识。
总结 ✨
本节课中,我们一起认识了讲师摩根·威利斯,了解了她的专业背景和教学热情。我们概述了本数据工程基础课程的双重目标:构建概念理论框架与获得动手实践技能。课程将从AWS云基础开始,逐步深入,并为学有余力的学*者提供了进一步深造和考取专业认证的路径。下一节,我们将正式进入AWS云计算基础的学*。
015:AWS云简介 ☁️

在本节课中,我们将要学*亚马逊云服务(AWS)的基本概念。我们将了解什么是云计算、AWS的核心资源类型、以及其全球基础设施的架构。这些知识是构建现代、可扩展数据系统的基础。
在AWS,我们将云描述为通过互联网按需交付IT资源,并采用按使用量付费的定价模式。
换句话说,AWS旨在您需要时,即时提供构建数据系统或其他应用所需的资源。当不再需要这些资源时,您可以将其关闭。在每个月底,您只需为实际使用的部分付费。
正如Joe之前提到的,这与构建自己的本地数据中心模式截然不同。在本地模式中,您通常需要为未来数年所购买的IT资源做出长期承诺。
当提到IT资源时,我指的是计算、存储和网络等资源。
在AWS上,计算资源是运行代码的地方,例如虚拟机、容器托管服务或无服务器函数。存储资源是存放数据的地方,包括亚马逊简单存储服务(S3)或亚马逊弹性块存储等服务,以及可以运行关系型数据库、NoSQL数据库、图数据库等的数据库服务。网络资源则允许您将其他资源相互连接,并与外部互联网相连。亚马逊虚拟私有云就是一个网络资源的例子,它让您在云中拥有自己的私有网络。
除了计算、存储和网络,AWS在安全、数据流、摄取、转换等领域还有许多其他类别的资源和服务。
在云上构建数据系统的优势在于,云资源具有可扩展性和弹性。


我的意思是,例如,如果您正在构建一个包含S3对象存储的数据管道,您无需提前精确计算需要多少存储容量。您也无需在数据增长或减少时管理扩展操作。相反,服务会自动向上和向下扩展,它是弹性的。其他AWS服务也存在同样类型的可扩展性和弹性。
这意味着您无需提前猜测容量。您可以随时为系统的高峰需求或变化的流量做好准备,并且更容易避免为不需要的资源付费。
可以将使用AWS想象成消费电力。用电时,您只需为实际使用的部分付费。月底支付账单时,电力是如何产生或输送到您家中的细节对您而言是抽象的。
AWS资源和服务托管在AWS于全球各地建设的物理数据中心中。您通过互联网使用这些服务,这使您能够构建解决方案,而无需建设和管理自己的数据中心。

因此,当您使用AWS时,您不会以单个数据中心的角度来思考。相反,您会将资源部署到所谓的AWS区域中。区域是地理区域内数据中心的集合,您可以在其中使用AWS服务。

以这种地理分布式方式托管您的解决方案,可以确保系统的可靠性和可用性,并在单个数据中心因自然灾害或其他问题而离线时提供弹性。
AWS区域以其地理区域命名,例如“美国东部(弗吉尼亚北部)”、“亚太(孟买)”或“欧洲(法兰克福)”。每个AWS区域由多个可用区组成。
可用区是区域内数据中心的较小分组。它们被设计得彼此足够远,以至于如果发生电力中断、洪水或其他可用区级别的故障,它们可以故障转移到区域内的其他可用区,由其他可用区吸收流量,从而使您的系统不受问题影响。
其运作方式是:多个数据中心构成一个可用区,多个可用区构成一个AWS区域。

当您在AWS上创建资源时,您需要选择区域,根据所使用的服务,可能还需要选择可用区。在幕后,这些数据中心和可用区通过低延迟链路相互连接,这些链路运行在连接所有设施的AWS全球光纤网络之上。
在您作为数据工程师的工作中,您将经常像搭积木一样,将多个AWS资源和服务组合在一起以形成解决方案。AWS提供超过200项服务,其中一些是通用型的,另一些则用途更具体。
AWS全球基础设施还有更多内容,但这是一个良好的开端。本视频中涵盖的概念将在您深入学*AWS时反复出现。
本节课中,我们一起学*了AWS云计算的核心概念。我们了解了按需付费的模式、计算/存储/网络三类核心资源、以及区域和可用区构成的高可用全球基础设施架构。这些是理解和使用AWS服务构建弹性数据系统的基石。
016:AWS核心服务简介 🚀

在本节课中,我们将要学*亚马逊云科技(AWS)的核心服务。我们将这些服务分为计算、网络、存储、数据库和安全五大类别进行介绍,帮助你为后续课程中的实际操作建立基础概念。
概述
上一节我们了解了AWS云的基本概念和高级工作原理。本节中,我们来看看构成AWS云基础的一些核心服务。理解这些服务是构建和操作数据工程解决方案的关键。
计算服务 💻
在AWS上,计算服务有多种选择。在这些课程中,你将频繁接触到一个核心服务:Amazon Elastic Compute Cloud (EC2)。
简单来说,EC2是在AWS上提供虚拟机(VM)的服务。你可以将VM视为一台虚拟计算机或服务器,可以在其上运行任何你希望的操作系统(如Linux、Mac或Windows)以及任何应用程序,就像在任何实体计算机上一样,只不过它运行在AWS云上。
当你使用EC2启动一台虚拟机时,我们称之为一个Amazon EC2实例。启动EC2实例后,你对该实例拥有完全控制权,包括操作系统、应用程序以及实例上发生的任何其他操作。因此,EC2是一个非常灵活的选择,为你提供了高度的控制力。
以下是EC2实例的一些常见用途:
- 作为编程的开发机器。
- 运行Web服务器。
- 运行容器或机器学*工作负载。
- 部署单个实例或一组实例,并水平扩展以满足需求。
除了EC2,AWS还提供许多其他计算选项,例如使用AWS Lambda的无服务器函数(你可以托管代码以响应触发器或事件运行),以及像Amazon Elastic Container Service (ECS) 这样的容器托管服务。
网络服务 🌐
现在,让我们转向网络服务。每当你创建一个EC2实例或许多其他类型的AWS资源时,都需要将其放入某种网络中。


在AWS中,你可以创建并放置资源的私有网络被称为Amazon Virtual Private Cloud (VPC)。VPC是你在云中创建和控制的私有网络,与AWS云中的其他网络隔离。
你选择所需的私有IP地址空间大小,并将其划分为更小的网络,称为子网。一个VPC横跨一个区域内的所有可用区,但不能跨区域。因此,你需要在每个想要运营的区域创建一个VPC。大多数AWS资源也是如此,它们都受区域限制。你的数据和资源不会离开该区域,除非你专门构建的解决方案要求如此,这对于合规性和安全性非常重要。
因此,每当你创建某些AWS资源(如EC2实例或基于实例的数据库)时,都需要选择要将其放置在哪个VPC和哪个可用区中。
存储服务 💾
接下来,我们谈谈存储。在AWS上,需要了解多种不同类型的存储,如对象存储、块存储和文件存储,AWS为每种类型都提供了相应的服务。
对象存储最常用于存储非结构化数据,如文档、日志、照片或视频。在这些课程中,你将在即将到来的实验中花大量时间熟悉Amazon S3对象存储服务。
与对象存储相对的是块存储,它通常用于数据库存储、虚拟机文件系统以及其他对低延迟和高性能要求苛刻的环境。在AWS中,你可以将称为Amazon Elastic Block Store (EBS) 卷的块存储设备附加到EC2实例上,这些卷会挂载到操作系统,然后你可以使用在EC2上运行的程序来存储和访问数据。

最后是文件存储,这是普通非技术用户最熟悉的存储类型。在文件存储中,数据被组织成文件和目录的层次结构,就像你笔记本电脑上的文件系统或工作中的共享文件系统一样。AWS提供了一项名为Amazon Elastic File System (EFS) 的托管服务,它提供了一个可扩展的文件存储解决方案,可以同时挂载到多个不同的系统以进行文件访问。
数据库服务 🗄️
在某种意义上,可以说数据库是另一种存储服务,但数据库属于一个独立的核心类别。
尽管数据库在幕后使用块存储来存储数据,但它们还提供了管理结构化数据的特殊功能,例如支持复杂查询、数据索引以及其他通常不由通用存储服务提供的特性。
作为一名数据工程师,你将经常处理以关系数据库格式组织的表格数据。在这些课程中,你将非常熟悉Amazon Relational Database Service (RDS),顾名思义,这是一个基于云的关系数据库服务。


你还将使用一项名为Amazon Redshift的服务,这是一个数据仓库服务,允许你存储、转换数据并提供给最终用例使用。AWS上还有其他许多数据库服务,但RDS和Redshift是你在这些课程中最常看到的两个,稍后我会向你介绍其他服务。
安全服务 🔒
谈到云安全,AWS遵循我们所说的责任共担模型。
责任共担模型规定,AWS负责“云本身的安全”,而你负责“云内资源的安全”。为了更好地理解这意味着什么,我想用一个高层公寓楼的比喻来说明。
建筑所有者和物业管理公司负责确保物理建筑本身安全且符合规范,并确保每个公寓都有可用的门锁,可能还有其他安全措施。现在,如果你是楼里的租户,你负责实际使用这些安全功能,比如确保你离开时或晚上在家时锁好门。从这个意义上说,需要物业管理方和租户双方各尽其责,才能确保任何特定公寓的安全。
要了解责任共担模型在AWS上的运作方式,你可以将高层公寓楼的想法应用到Amazon EC2上。对于EC2,AWS运营和管理底层组件,从运行EC2实例的物理硬件和设施,一直到被称为管理程序层(在这里,计算资源被分配给你和其他AWS客户)。所有这些组件的安全是AWS 100%的责任。
而当你使用EC2启动一台虚拟机时,你负责管理该虚拟机的客户操作系统、任何软件更新或补丁、设置网络配置(如防火墙)、管理对你数据的访问,以及在需要时使用适当的加密技术。所有这些方面的安全是你100%的责任。
因此,需要你和AWS双方共同努力,才能维护一个安全的EC2实例。对于云上的任何其他资源也是如此。其他AWS服务的运作方式略有不同,在AWS责任结束和你责任开始的地方划定了不同的界限。随着你在课程中深入学*并接触不同的AWS服务,你会更了解这个概念。所以,如果这个安全责任共担的概念对你来说还不熟悉,请不要担心。


总结
本节课中,我们一起学*了将在这些课程中使用的几个核心AWS服务的简要介绍。我们涵盖了计算(EC2)、网络(VPC)、存储(S3, EBS, EFS)、数据库(RDS, Redshift)和安全(责任共担模型)五大类别。
通过这些课程的所有实验,你将能够访问AWS云资源,而无需创建自己的账户。话虽如此,在下一个视频中,我将简要介绍AWS管理控制台。如果你愿意,可以创建一个免费的AWS账户并跟着操作以熟悉环境。在下一个阅读材料中,你会找到设置自己AWS账户的一些说明,如果你有兴趣在这些课程的学*之外自行探索AWS,我邀请你这样做。但再次强调,这完全是可选的,你完全可以在不创建自己AWS账户的情况下成功完成这些课程。
请加入下一个视频,一起看看AWS管理控制台。
017:AWS管理控制台演练 🖥️

在本节课中,我们将要学*AWS管理控制台的基本操作。即使你之前没有使用过AWS或任何云服务,也无需担心。课程中的实验会为你准备好AWS环境,你无需拥有自己的AWS账户。本节课将为你展示控制台的界面和基本导航,帮助你为后续的实验做好准备。
课程概述
在学*数据工程的过程中,你将频繁地与云平台交互。AWS(亚马逊云科技)是其中一个广泛使用的平台。本节课程旨在让你熟悉AWS管理控制台,这是你启动每个实验后首先会进入的界面。我们将了解如何查找服务、启动一个基本的计算资源(EC2实例),并学*如何管理它以避免产生不必要的费用。
AWS控制台初览
你之前可能没有使用过AWS或其他云服务,这没有问题。为了完成本课程的实验练*,你不需要具备任何云服务的使用经验。
在每个实验中,都会为你设置好一个AWS环境。因此,你不需要拥有自己的AWS账户来完成实验。
你将在下周看到你的第一个实验,但现在我想花点时间向你展示AWS管理控制台的样子。每次你启动一个新实验时,这里将是你首先到达的地方。
如果你有兴趣自己探索控制台,可以按照上一个阅读材料中的说明创建你自己的AWS账户,并跟随本视频一起操作。或者,你也可以放松一下,我将为你预览在实验中将会用到的AWS管理控制台。

启动控制台与导航
当你开始每个实验时,会收到打开AWS管理控制台的说明。完成此操作后,你会看到一个类似这样的登录页面。由于AWS会持续更新其平台和服务,这个控制台的用户界面可能会发生变化,你的控制台看起来可能与视频中的略有不同。但我即将展示的所有基本导航说明,在控制台主页上应该保持相对一致。
在控制台主页上,有一个“最*访问”部分,显示你最*访问过的服务。当你开始一个实验时,这个部分可能不包含任何服务。但任何时候,如果你想访问特定服务以创建资源,可以点击这个搜索栏并开始输入你需要的服务名称。
例如,假设你想访问现有的EC2资源或启动新的EC2实例。只需在搜索栏中输入“EC2”,然后点击出现的服务。你将被带到类似此处所示的服务仪表板。
大多数服务在左侧都有一个导航菜单,你可以通过点击其中一个菜单项导航到特定窗口。
启动一个EC2实例

现在,假设你想从这个EC2仪表板启动一个新的EC2实例。你需要选择“启动实例”。这将带你到一个页面,你可以在那里为实例选择所有想要提供的配置细节。许多配置选项都有默认值,因此你可以快速开始。
以下是启动实例的基本步骤:
首先,你需要为实例提供一个名称。我将这个实例命名为“示例实例”。
然后,你可以选择要使用的亚马逊机器镜像(AMI),这将决定实例上预装的操作系统和应用程序以及其他配置。这里,我将保持选择Amazon Linux作为AMI。
接着,你可以选择实例类型,这决定了EC2实例提供的硬件能力的大小和组合。因为这只是一个关于如何使用管理控制台的快速演示,我将直接接受默认值,这里是一个T2 micro实例。T2是实例类型,micro是大小。
然后,你需要选择在没有密钥对的情况下继续,以便从本地连接到实例。从这里,你可以向下滚动,接受其余的默认值,并启动实例。目前,你不需要过于担心这些具体的配置细节。我只是想向你展示如何在实验练*中熟悉导航AWS管理控制台。在实验练*中,你将获得配置EC2实例的详细说明。
这个实例需要几分钟时间启动,所以我们将在它完成后回来。
理解控制台背后的API
当你使用AWS管理控制台这样启动一个实例时,你实际上是在调用AWS API来执行此操作。你也可以使用其他工具(如AWS命令行界面、CLI或AWS软件开发工具包SDK)执行相同的任务。AWS管理控制台只是与AWS API交互的一种方式。
查看与理解EC2实例
好的,现在EC2实例已经可用。在这里,我可以看到有一个正在运行的实例。我现在可以使用控制台与此实例进行交互。

但首先,我刚刚创建的这台虚拟机到底是什么?让我们查看一下EC2的文档,以更好地了解这个小云计算机的特性。
如前所述,这个实例是一个T2 micro,这是默认的EC2实例类型。在文档页面的顶部“通用用途”下,我可以选择T2来查看所有不同类型T2实例的规格。在“功能”下,我可以看到这个实例配备了一个3.3 GHz的处理器。然后在表格的“内存”下,我可以看到T2 micro有1 GB的内存或RAM。所以这确实是一台相当小的计算机。事实上,你的手机在处理和内存容量方面可能比这个T2 micro实例更强大。
如果你在AWS上需要一台功能更强大的虚拟机来运行你的工作负载,你可以选择其他T2实例之一,或选择不同的通用实例类型来满足你的需求。你还可以选择针对计算、内存或存储进行优化的实例类型,以及加速和高性能计算实例。
这里的要点是,对于EC2,有数百种实例类型可供选择。根据你的项目,你可以配置一台从手机处理能力的一小部分到云端超级计算机的各种规格的机器。
管理资源与成本控制
现在回到我们这里正在运行的T2 micro实例。当你使用自己的AWS账户工作时,有一件事你需要确保做到,那就是在不使用任何资源时将其删除或停止,以避免为此付费。对于EC2,你只在EC2实例运行时以及为附加到实例的弹性块存储(EBS)资源付费。
因此,为了避免在这里产生费用,我将通过选择实例,然后选择“停止实例”来停止该实例。这里会弹出一个警告,告诉我我仍将为关联的EBS资源或弹性IP地址付费(在本例中我们没有这些资源)。所以我将选择“停止”,这将停止该实例。

查找账户信息与区域
接下来我想向你展示的是如何找到你的账户号码和你当前正在工作的区域,这些信息在部分实验中会需要。在右上角,你可以点击账户名称旁边的下拉菜单来复制账户ID。我创建这个账户仅用于演示目的,你的账户ID将是独一无二的。
然后,你可以点击区域下拉菜单来查看或更改你正在操作的区域。提醒一下,你在这里看到的AWS区域是一个地理区域,包含托管你资源的数据中心。
课程总结
本节课中,我们一起学*了AWS管理控制台的基本导航和操作。我们了解了如何通过搜索栏访问服务,逐步完成了启动一个EC2实例的流程,并探讨了实例类型的概念。重要的是,我们学会了如何停止实例以控制成本,以及如何查找账户ID和当前区域信息。

再次强调,在现阶段,你不需要担心具体的配置细节。本节课的目的只是让你对将在实验中遇到的平台有一个初步的了解。在本课程的每个实验中,你都将获得关于如何与控制台交互以及如何为你将构建的数据管道设置各种资源的逐步说明。
接下来,我将把你交还给Joe来结束本周的课程。
018:第1周总结 🎯

在本节课中,我们将回顾第1周的核心内容,总结数据工程师的思维方式、关键概念以及后续的学*方向。
恭喜你完成第1周的学*。希望你已经开始适应以数据工程师的思维方式思考问题。也希望你通过Morgan的视频,对AWS云的相关术语和概念有了初步了解。
本周我们从一个场景开始:你被一家充满活力的电子商务公司聘为数据工程师。实际上,作为数据工程师,你可能会面临多种不同的工作场景。
以下是几种可能的情况:
- 你可能是一家公司聘用的第一位数据工程师,负责从零开始构建数据系统。
- 你可能加入一个成熟的数据团队。
- 你甚至可能加入一家已有数据系统,但原构建者已离职的公司,你需要理解现有基础设施并进行修改、扩展或替换,以满足业务需求。
无论你身处何种情况,本周讨论的内容都具有参考价值。构建成功数据系统的第一步,无论是从零开始、更新现有系统、独立工作还是团队协作,都是理解利益相关者的需求,以及他们如何从你提供的数据中获取价值。
当你能够将这些需求转化为系统要求,并设置合适的工具和技术来满足这些需求时,你就走上了为组织创造价值的道路。
我们为你提供了一个数据工程师的思维框架,你可以将工作视为分阶段进行。
以下是该框架的四个阶段:
- 识别业务目标与利益相关者需求
- 定义系统需求
- 选择合适的工具与技术
- 构建并评估数据系统
本周我们还回顾了数据和数据工程的历史,以了解我们如何发展到当前领域的状态。
我分享了在本课程中我们将采用的“云优先”方法的一些背景。此外,你和Morgan一起学*了在AWS云上开始构建所需的一些基本概念和资源。


在下一周的材料中,我们将深入探讨数据工程生命周期的各个阶段和底层逻辑。随后,你将有机会在一个动手实验活动中应用SP框架,在AWS上构建你的第一个数据管道。我们下周见。

本节课总结:本节课我们一起回顾了第1周的核心要点,包括数据工程师的多种工作场景、从需求出发的思维框架(识别需求、定义要求、选择工具、构建评估),以及数据工程的历史与云优先方法。这为后续深入学*数据工程生命周期和动手实践奠定了基础。
019:数据工程导论课程(第2周概览)🚀

在本节课中,我们将深入学*数据工程生命周期及其支撑要素。这些概念已在第1周引入,本周我们将详细探讨每个阶段及其实际应用。
上一周我们介绍了数据工程生命周期的整体框架。本周我们将深入其核心阶段:从数据生成开始,经过摄取、转换、存储,最终服务于下游应用。
数据工程生命周期深入 🔄
数据工程生命周期始于左侧的数据生成,这通常发生在数据工程师介入之前。随后,我们将探讨数据摄取、转换、存储以及如何为多种用例(如分析和机器学*)提供数据服务。
简而言之,我们将学*如何从源头获取原始数据,将其转化为有用形式,并使其可用于下游任务。
支撑要素详解 🛠️
在本周的第二课中,我们将关注数据工程生命周期的支撑要素。
以下是支撑要素的具体内容:
- 安全
- 数据管理
- 数据运维
- 数据架构
- 编排
- 软件工程


需要明确的是,本周与上周的材料一样,重点在于建立数据工程的高层思维框架,而非立即构建具体的数据基础设施。
我认为,在开始动手构建之前,确立正确的思维框架至关重要。这将使你在数据工程师工作的各个方面都更加成功。
理论与实践结合 ☁️
尽管本周侧重理论,但并非全是抽象概念。在周末,我们将看到这一思维框架如何在AWS云平台上付诸实践。
在实验活动中,你将亲手操作第一个端到端的云数据管道。
本节课中,我们一起学*了数据工程生命周期的详细阶段及其关键支撑要素,并了解到如何将理论框架应用于实际的云平台环境中。
020:源系统中的数据生成 📊

在本节课中,我们将要学*数据工程生命周期的第一阶段:源系统中的数据生成。作为数据工程师,你将需要从各种来源获取数据。理解这些源系统如何工作至关重要,因为你构建的数据管道将依赖于这些来源生成的数据。
源系统概览 🔍
上一节我们介绍了数据生成是数据工程生命周期的起点。本节中我们来看看数据工程师在工作中会遇到的几种常见源系统。

最常见的源系统是数据库。数据库可以是关系型数据库,其数据以相互关联的表格形式呈现,也可以是其他类型的NoSQL系统,例如键值数据库、文档存储等。这些数据库可能是某个Web或移动应用后端的一部分,也可能用于存储来自其他系统的数据。如果你还不熟悉不同类型的数据库,不用担心,我们将在后续课程中详细讲解。
除了数据库,你可能还需要处理文件形式的数据,例如文本文件、MP3音频文件,甚至视频或其他类型的文件。虽然单个文件本身可能不被称为一个“源系统”,但在数据工程实践中,你经常需要下载或被授予文件访问权限才能开始工作。
另一个常见的源系统是API。API是应用程序编程接口的缩写。简而言之,API允许你通过网络请求数据,并以特定格式(如XML或JSON)获取返回的数据。
数据共享平台也是一种源系统。组织可能建立此类平台,用于内部或与第三方共享数据。
正如之前提到的,物联网设备是另一种日益普遍的源系统类型。对于这类源系统,你可能需要处理许多独立设备(即物联网设备群)实时传输的数据流。这些流数据通常被发送到数据库,源系统所有者可能通过API或数据共享平台提供数据访问。在其他情况下,你可能需要摄取并合并所有这些独立的数据流,以供下游工作流使用。
现实世界的挑战与应对策略 ⚠️
在理想情况下,你所依赖的源系统会以一致且及时的方式交付所需数据,使你能够构建依赖于该源系统可预测性的下游系统。然而在现实世界中,源系统往往是不可预测的。
这些系统有时会宕机,或者管理系统的团队会更改数据的格式或模式。有时模式保持不变,但数据本身发生了变化。
当我刚开始担任数据工程师时,我记得曾使用一个由内部软件工程师团队维护的数据库。有一天,该团队决定重新排列其应用程序数据库中的列,并且没有告知我这些更改。后来我发现,我的数据管道所依赖的列被更改、重命名,甚至有些被删除了。这完全中断了一些下游数据工作流,我不得不向一些相当不满的利益相关者解释,这体验很不好。
因此,在从源系统访问数据时,必须了解这些系统的设置方式,以及可以预期数据和系统会发生何种变化。这意味着,作为数据工程师,如果你能直接与源系统所有者合作,了解这些系统的工作原理、它们如何生成数据、这些数据可能如何随时间变化,以及这些变化最终将如何影响你构建的下游系统,你将最有可能成功。
根据我的经验,与源系统利益相关者建立良好的工作关系,是成功的数据工程中一个被低估但至关重要的部分。
总结与预告 📝
本节课中我们一起学*了数据工程生命周期的第一阶段——源系统中的数据生成。我们探讨了常见的源系统类型,包括数据库、文件、API、数据共享平台和物联网设备,并讨论了在现实工作中应对源系统不可预测性的重要性。

根据你的源系统和目标,数据工程生命周期的下一个主要阶段——数据摄取,在不同的项目中可能看起来截然不同。在下一个视频中,我们将一起深入了解从源系统进行数据摄取的过程。
021:第21课 - 数据摄取模式详解 📥

在本节课中,我们将学*数据工程生命周期中的关键环节:数据摄取。我们将重点探讨两种主要的数据摄取模式——批处理与流式处理,并分析它们的特点、适用场景以及选择时需要考虑的权衡因素。
作为数据工程师,你将构建从源系统摄取数据开始的架构。这意味着将原始数据从源系统移动到你的数据管道中,以便进行后续处理。
根据经验,如果按照前一视频的建议,直接与源系统所有者合作以理解系统工作原理、数据生成方式、数据随时间可能发生的变化,以及这些变化最终将如何影响你构建的下游系统,那么源系统和数据摄取通常是数据工程生命周期中最大的瓶颈。做好这些准备,你将能很好地避免摄取阶段的常见陷阱。
设计数据摄取流程的关键决策
在设计数据摄取流程时,你需要做出的一个关键决策是数据摄取的频率。这意味着你需要决定多久将数据从左侧所示的这些源系统移动到你的数据管道中进行进一步处理。
以下是两种主要的频率模式:
- 批处理摄取:你可能选择每隔一段时间批量摄取数据,例如每小时一次或每天一次。
- 流式摄取:另一种日益常见的方法是,以*乎实时的连续事件流形式摄取数据。
因此,在本视频中,我将重点介绍这两种主要的数据摄取模式:批处理与流式处理。
理解批处理与流式处理
你可以将数据生产视为一个连续的事件系列。这些事件可能是网站点击、传感器测量或世界上发生的其他事情。这类事件在持续不断地发生。从这个意义上说,几乎可以认为所有数据在其源头都是“流式”产生的。
批处理摄取只是一种方便的方式,用于按大块处理这些事件流。它要么基于预定的时间间隔,要么在数据达到预设的大小阈值时触发。
例如,你可以将一整天的数据作为一个批次来处理。在很长一段时间里,批处理是摄取数据的默认方式。尽管如今有更多的摄取选项,批处理仍然是一种实用且流行的数据摄取方式,特别是在数据用于分析和机器学*的情况下。
另一方面,对于流式摄取,你正在以连续、*乎实时的方式摄取数据并提供给下游系统。

当我说“*乎实时”地摄取数据时,我的意思是在数据产生后很短的时间内(可能不到一秒钟)就使其对下游系统可用。在这种情况下,你需要使用特定的工具,例如事件流平台或消息队列,来持续摄取事件流。随着这些工具变得越来越普及,流式摄取也变得更加容易实现和流行。
选择摄取模式:权衡与考量
然而,流式摄取并非对所有用例都是最佳选择。在决定是否选择流式摄取而非可能被认为更简单的批处理方式时,需要考虑重大的权衡。
在着手构建流处理解决方案之前,你应该问自己一些问题:对实时数据采取哪些操作能比批处理数据带来改进?流式摄取在时间、金钱、维护和潜在停机方面是否比批处理成本更高?选择流式摄取而非批处理(或反之)将如何影响数据管道的其余部分?
批处理是许多常见用例(如模型训练和每周报告)的绝佳方法。我的建议是,只有在花时间确定了一个能够证明其相对于批处理的权衡是合理的业务用例后,才采用流式摄取系统。
同样重要的是要注意,流式摄取通常与批处理共存。例如,机器学*模型通常是在批处理基础上进行训练的。而同样的训练数据最初可能是通过流式方式摄取的,这可能是出于架构的某个独立目标,比如实时异常检测。
数据工程师很少有机会构建一个完全没有批处理组件的纯流式数据管道。相反,你将选择批处理和流式处理之间的边界在哪里。


摄取阶段的其他重要细节
除了在批处理与流式处理方法之间做出选择外,摄取阶段还有其他重要的细节需要考虑。例如,你可能会使用变更数据捕获来基于源系统中的数据变化触发特定的摄取过程。此外,你还需要决定是采用推送还是拉取方式,即源系统是将数据推送给你,还是你主动从源系统拉取数据。
我们将在整个专项课程中深入探讨所有这些细节及更多内容。但现在,请和我一起进入下一个视频,了解数据存储,这实际上是数据工程生命周期每个阶段都涉及的部分。
本节课总结

在本节课中,我们一起学*了数据摄取的核心概念。我们明确了数据工程师需要从理解源系统开始设计摄取架构。重点对比了批处理和流式处理两种主要摄取模式:批处理按预定间隔或大小批量处理数据,适用于模型训练、定期报告等场景;流式处理则以连续事件流形式*乎实时地处理数据。我们强调了在选择模式时需要进行的权衡,例如成本、复杂性与业务价值的平衡,并指出在实际系统中两者常共存。最后,我们提到了摄取阶段还需考虑变更数据捕获及推送/拉取策略等其他重要细节,为后续深入学*数据存储等内容奠定了基础。
022:数据存储 🗄️

概述
在本节课中,我们将要学*数据存储的基础知识。我们将探讨数据存储系统在日常生活中的体现,分析其背后的物理硬件和逻辑架构,并理解数据工程师如何在不同抽象层次上选择和使用存储解决方案。
日常生活中的数据存储
请思考一下,你每天通过笔记本电脑与数据存储系统互动的各种方式。
例如,你可能会创建或删除文件,或在不同的文件夹之间移动文件。在这个过程中,你正在改变数据在硬盘或固态硬盘上的存储方式。当你打开应用程序时,你正在将它们加载到随机存取存储器中。RAM是另一种存储类型,它允许更快的访问速度。你也可能从互联网下载新文件或应用程序,或者将部分文件自动备份到云存储或智能手机上。



此外,你可能会发送或接收消息,或与应用程序互动,这实际上是在你设备上的不同存储组件之间以及云端移动数据。
因此,几乎你在数字设备或在线进行的任何操作,都在与数据存储系统互动。你可能会遇到这些存储系统的限制,比如手机存储照片的空间不足,或者尝试发送过大的文件。
存储系统的功能与性能
你所遇到的功能、性能和限制,很大程度上与这些系统的设置方式有关。
同样,在你作为数据工程师的工作中,你所构建系统的功能、性能和限制,也与你最初选择用来支持这些系统的存储解决方案密切相关。
存储的物理硬件
首先,让我们看看一些原始的存储硬件。

在你的日常生活中,你可能已经熟悉了各种形式的固态存储,比如闪存卡、固态硬盘、笔记本电脑或智能手机中的存储。相比之下,你可能最*没有从软盘中读取过数据。如果你认为世界已经不再使用磁盘作为数据存储解决方案,这可以理解。

然而,事实是,磁盘仍然是现代存储系统的支柱。这主要是因为磁盘存储的低成本。在录制本课程时,磁盘存储的成本大约是固态存储的1/2到1/3。
RAM,通常被称为内存,是你可能熟悉的另一种物理存储形式。RAM提供比固态硬盘或磁盘快得多的读写速度,这使其成为许多应用和架构的关键组件。
然而,RAM存储的成本可能是固态存储的30到50倍。它也是易失性的,这意味着如果你的系统断电,在大多数情况下,根据你使用的RAM类型,内存中的数据会立即丢失。
数据在架构中的流动
在大多数现代架构中,数据在数据管道的各个处理阶段中,会经过磁盘存储、固态硬盘和内存。
然而,存储的物理组件只是其中一个方面。数据存储在你的整个架构中是如何实现的,同样重要。

现代云数据存储系统通常分布在多个集群和数据中心。这意味着网络、CPU、序列化、压缩和缓存等都是现代数据系统中存储数据的关键原始要素。
如果你不熟悉我刚才提到的所有内容,请不要担心。我们将在专项课程的第三门课中更深入地探讨存储的每个要素。
数据工程师的存储工作
作为数据工程师,你通常不需要负责管理数据如何在数据中心网络和物理存储设备之间移动和存储的细节。
相反,你将使用存储系统,如数据库管理系统,或对象存储平台,如Amazon S3。根据你的架构需求,你可能还需要使用像Apache Iceberg或Hudi这样的系统,以及基于内存的存储系统或流式存储。
所有这些数据存储系统都建立在服务器和集群中存在的物理和其他原始存储要素之上,允许这些系统使用不同的访问协议来摄取和检索数据。
最后,在你作为数据工程师的工作中,你很可能不仅会使用单个存储系统,还会使用组合在一起的存储系统,这些系统被安排成存储抽象层,如数据仓库、数据湖,或这些概念更*期的结合体——数据湖仓。
存储层次结构
使用这些存储抽象工具,你无需担心底层组件如何安排的细节,而是选择各种配置参数,以满足你在延迟、可扩展性和成本方面的系统要求。
那么,如果将存储视为一种层次结构,你会如何安排存储的不同方面呢?
- 在底层,你有数据存储的原始要素,包括各种物理组件,如磁盘、RAM和固态存储,以及各种非物理的原始要素,如网络和序列化。
- 在此基础上,你有由这些原始要素构建的存储系统,包括数据库系统、对象存储等等。
- 最后,在层次结构的顶部,你有存储抽象层,它们是存储系统的组合,使你能够满足高级别的数据存储需求,而无需担心过多的底层细节。
理解存储的重要性
作为一名数据工程师,你完全有可能将大部分时间花在这个层次结构的顶部或附*。这意味着你不需要思考数据在不同存储组件和系统之间移动的具体细节。
然而,如果你花时间了解整个存储解决方案的内部工作原理、能力和限制,直至原始要素,你的工作将最有效。
事实是,当今许多实践中的数据工程师并不深入了解他们构建的存储系统的细节。这会在性能和成本等方面导致不幸的后果。
碰巧的是,我曾为一个团队提供咨询,他们未能考虑到这些细节。他们需要将大量数据移入数据仓库,却无意中选择了对每一行数据直接进行行插入的方法。这意味着他们一次只摄取和写入一行数据到数据仓库中。
结果证明,这不仅非常慢,而且非常昂贵,因为直接行插入通常按使用次数收费。最终,他们发现了错误,并转向了批量摄取方法,但在此之前,他们已经浪费了大量时间,并在短短一周内用掉了年度数据仓库预算的一半。

因此,总而言之,作为一名数据工程师,精通存储对你有利。这就是为什么我们将在这些课程中探索各种存储解决方案的细节和影响。
总结
本节课中我们一起学*了数据存储的基础概念。我们了解到数据存储系统无处不在,其性能与成本取决于底层的物理硬件和逻辑架构。数据工程师通常在较高的抽象层次上工作,但深入理解从原始硬件到存储抽象层的整个存储层次结构,对于构建高效、经济的系统至关重要。忽视底层细节可能导致严重的性能问题和成本超支。
接下来,我们将探讨数据工程生命周期的下一个阶段:数据转换。
023:查询、建模与转换 🛠️

在本节课中,我们将要学*数据工程生命周期中的核心环节——转换阶段。这个阶段是数据工程师开始创造价值的关键步骤。我们将依次探讨查询、数据建模和数据转换这三个组成部分,理解它们如何共同作用,将原始数据转化为对下游用户有用的信息。
转换阶段的价值
数据工程生命周期中的转换阶段,是数据工程师真正开始创造价值的地方。
这是因为在转换之前的过程,即从源系统摄取和存储原始数据,并不能直接为下游利益相关者带来价值。正如之前所说,数据工程师的宏观工作流程是:从某处获取原始数据,将其转化为有用的东西,然后提供给最终用户。
转换,正是“将其转化为有用的东西”的阶段。那么,“有用”具体指什么呢?
什么是有用的数据?
想象一下,你的下游用户是一位业务分析师。假设他的任务是报告一系列产品的每日销售情况。他可能需要诸如客户ID、产品名称、价格、销售数量和销售时间等信息。

业务分析师通常精通SQL,他们会依赖你将原始数据进行转换,并以一种能够快速、轻松查询的格式提供给他们。
再举一个例子,想象你的下游用户是一位数据科学家或机器学*工程师。除了SQL,他们甚至可能精通多种潜在的数据转换方法。但他们的核心职能是使用数据进行预测分析。你可以通过将数据转换为可直接用于模型训练或分析的结构化特征,为他们提供巨大的价值。
转换的三个组成部分:查询、建模与转换
以上都属于数据工程生命周期的转换部分。但实际上,这个过程由三个部分组成:查询、建模和转换。
我将查询和建模与转换分开讨论,因为它们是任何数据管道的关键组成部分。如果做得好,它们能极大地增加价值;如果做得不好,则会带来风险。为了说明这一点,让我们从查询开始。
查询数据
当你查询数据时,你是在向数据库或其他存储系统发出读取记录的请求。例如,你可能需要查询存储在云数据仓库中的表格和半结构化数据。
你可以使用多种语言来查询数据,但在本课程中,我们将重点介绍结构化查询语言,简称 SQL。它目前仍然是一种流行且通用的查询语言。
你的查询可能涉及跨多个数据集的清洗、连接和聚合数据。你可能会使用SQL表达式来过滤数据,以便只检索特定的记录。
如果你还不熟悉幻灯片上展示的这些SQL命令,请不要担心。在后续课程中,你将有机会通过动手实验学*SQL的基础知识。
编写查询的方式不止一种,而编写不当的查询可能会产生负面后果。例如,它可能影响源数据库的性能,或者导致一种称为“行爆炸”的情况。即,一个包含表间连接(join)的查询产生的记录数远超预期,这可能会拖垮你的存储基础设施。在其他情况下,编写不当的查询可能只是运行缓慢,导致下游的报告或分析出现延迟。
在实践中,大多数数据工程师都能读写SQL,但可能不熟悉查询在底层是如何工作的,这可能会在他们构建的架构中带来不可预见的后果。我们将在专项课程的第三门课中详细探讨查询的具体工作原理。
数据建模
接下来我想讨论的是数据建模。数据模型代表了数据与现实世界关联的方式。数据建模涉及为你的数据精心选择一个连贯的结构,这是使数据对业务有用的关键一步。
例如,再次回顾那位需要创建产品销售报告的业务分析师的案例。你可能已经从上游的关系型源数据库摄取了所谓的“规范化”数据,其中包含产品信息、订单详情、客户信息等独立的表。这些数据之间通常存在复杂的关系。
为了满足这位分析师的需求,你可能需要对数据进行所谓的“反规范化”,以一种允许分析师快速高效地查询并获取报告所需数据的方式来建模数据。

一个好的数据模型旨在最好地反映组织的流程、定义、工作流和逻辑。例如,术语“客户”在你公司内部的不同部门可能意味着不同的事情。
为了成功地进行数据建模,你需要与利益相关者合作,理解他们的术语(比如“客户”这个词对他们意味着什么)以及数据的业务目标。你将在专项课程的第四门课中了解更多关于数据建模和规范化的知识。
数据转换
除了查询和建模,数据还必须进行转换,也就是说,需要被操纵、增强并保存以供下游使用。
正如我之前提到的,在整个数据工程生命周期中,你通常会对数据进行多次转换。例如:
- 数据在你接触之前就可能已经被转换了,比如当记录还在源系统中时就为其添加了时间戳。
- 你可能在数据摄取过程中,当数据“在途”时应用转换。
- 在摄取之后,可能会立即进行基本转换,以将数据映射到正确的类型,并将记录放入标准化格式。
- 在将记录发送到数据仓库之前,你可能会在流式管道中用额外的字段和计算来丰富一条记录。
- 更进一步,在下游,你可能会转换数据模式,并应用反规范化、用于报告的大规模聚合,或为机器学*模型训练准备特征化数据。
总结

在本节课中,我们一起学*了数据工程转换阶段的三个核心组成部分:查询、建模和转换。
- 查询是向存储系统请求数据,需要编写高效的语句以避免性能问题。
- 建模是为数据设计结构,以准确反映业务逻辑并方便下游使用。
- 转换是对数据进行各种操纵和增强,使其在整个生命周期中变得有用。
在整个课程中,你将参与大量涉及查询、建模和转换数据的动手练*。现在,让我们进入下一个视频,在那里我们将看看数据工程生命周期的最后阶段:为下游用例提供数据。
024:数据服务 📊

在本节课中,我们将要学*数据工程生命周期的最后一个阶段——数据服务。这个阶段不仅仅是让数据变得可用,更是让利益相关者能够从数据中提取业务价值的关键环节。

上一节我们介绍了数据存储和查询,本节中我们来看看数据服务的具体内涵。数据服务阶段的核心在于,将经过摄取、转换和整理的数据,交付给最终用户或系统,以支持实际的应用场景。数据价值的具体体现,取决于不同的最终用途,例如分析、机器学*、反向ETL等。在本课程中,我们将先概览这些不同的应用场景,了解数据服务在不同情境下的差异。在后续的第4门课程中,我们会深入探讨为每种用例提供数据服务的具体机制。
分析用例 📈
分析是从数据中识别关键洞察和模式的过程。作为数据工程师,你几乎肯定会为以下三种最常见分析形式中的一种或多种提供数据支持。


以下是三种主要的分析形式:
- 商业智能:分析师探索历史和当前的业务数据以发现洞察。作为数据工程师,你提供的数据最终会以报告或仪表板的形式呈现,帮助用户做出战略性和可操作的决策。
- 运营分析:关注监控实时数据以采取即时行动。例如,一个电子商务平台团队可能需要监控网站实时性能指标的仪表板。
- 嵌入式分析:这是一种较新的趋势,指面向外部客户的分析应用。例如,银行应用程序中显示用户消费历史趋势的仪表板,或智能恒温器配套应用程序中显示家庭当前及历史温度的数据。
在嵌入式分析中,作为数据工程师,你的工作是为面向用户的应用程序提供实时和历史数据。
机器学*用例 🤖



随着机器学**几十年的兴起,数据工程师的角色很可能涉及为机器学*用例提供数据。在这些课程中,我们将机器学*与其他服务用例分开讨论,因为它可能涉及额外的复杂性。
例如,在机器学*用例中,你可能需要负责提供用于模型训练的特征存储数据。你可能还需要为实时推理提供数据,或者支持用于跟踪数据历史和血缘的元数据与编目系统。我们将在后续课程中更详细地探讨这些场景。
反向ETL用例 🔄


除了分析和机器学*,另一个常见的数据服务用例,目前至少被称为反向ETL。

通过反向ETL,你会将经过转换的数据,以及分析和机器学*模型的输出,反馈回源系统。例如,假设你从客户关系管理系统中摄取了客户数据,经过转换后存入数据仓库。分析师可以取用这些数据来训练一个“潜在客户评分模型”。模型的结果可以返回到数据仓库,然后作为增强信息推送回CRM系统,丰富其中已存储的客户数据。
需要说明的是,“反向ETL”这个名称更多是因为缺乏更好的描述词汇,而非精准描述了这个过程本身。无论如何,这种实践正变得越来越普遍,作为数据工程师,你很可能会参与到反向ETL(或未来它可能被称呼的任何名称)的工作中。

本节课中我们一起学*了数据工程生命周期的数据服务阶段。我们了解到,数据服务不仅仅是提供数据访问,更是根据不同的最终用途(如分析、机器学*、反向ETL)来交付数据,从而创造业务价值。我们快速浏览了数据工程生命周期的所有阶段,包括源系统、摄取、转换、存储和服务。

在下一课中,我们将把焦点转移到贯穿所有这些阶段的生命周期“暗流”上。下一课见。
025:底层技术介绍 🔧

在本节课中,我们将学*数据工程生命周期中的一系列核心支撑实践,这些实践被称为“底层技术”。它们贯穿于数据工程的各个环节,是确保数据项目成功的关键。
我们一直在探讨数据工程生命周期,以及如何从源系统摄取数据、进行转换、存储并最终服务于终端用户。作为一个领域,数据工程正在迅速成熟。就在十年前,数据工程师的角色主要聚焦于技术层面。工具的持续抽象化和简化,已经扩展了这一角色的范围。
如今,数据工程所涵盖的内容远不止工具和技术。换句话说,这个领域正在向价值链上游移动,这对作为数据工程师的你来说是个好消息。
现代数据工程融合了传统企业实践,如数据管理和成本优化,以及较新的实践,如DataOps。对于你的数据工程师工作而言,有一系列这样的实践将适用于整个生命周期的各个环节。在《数据工程基础》一书中,我们将这些实践描述为数据工程生命周期的“底层技术”。
这些底层技术包括:
- 安全
- 数据管理
- DataOps
- 数据架构
- 编排
- 软件工程
在接下来的几个视频中,我们将逐一深入探讨这些底层技术。之后,你将开始探索数据工程生命周期和这些底层技术如何在真实的AWS云环境中具体实现。

让我们开始吧。
026:数据安全 🔐

在本节课中,我们将要学*数据安全的核心原则与最佳实践。作为数据工程师,您将负责处理敏感数据,因此理解如何保护这些数据至关重要。我们将探讨从个人数据保护到组织级安全文化的各个方面。
在深入探讨安全如何应用于数据工程师的角色之前,请先思考一下安全问题如何影响您日常的个人数据。
例如,您可能不会随意将银行账户信息告知他人。您也不会将您所有在线账户的密码公开发布在他人可见的地方。
同样地,作为数据工程师,您被委托管理敏感数据,无论是客户的个人隐私信息还是专有的商业信息。数据所有者信任您会保护他们的信息安全。因此,认识到您的角色至关重要:您需要整合正确的原则、协议和文化实践,以确保您所构建系统的安全性。
在本视频中,我将介绍一些在管理数据管道并为最终用户提供数据时,关于数据安全的基础原则和最佳实践。
最小权限原则
当您需要向其他用户或应用程序授予数据和系统资源的访问权限时,需要牢记一个关键的安全原则:最小权限原则。
这意味着您只授予用户或应用程序执行其工作所必需的、且仅在所需时间段内有效的数据和资源访问权限。
您不仅需要对组织内的其他人应用最小权限原则,对您自己也应如此。例如,就像您不会给团队中的每个人管理员权限一样,在您自己的工作中,非必要时不要在根Shell下操作,除非绝对必要,否则不要使用管理员或超级用户权限。
数据敏感性与访问控制
在思考如何最好地保护工作中的数据时,您不仅需要考虑数据访问,还需要考虑数据敏感性。
遵循最小权限原则意味着仅在绝对必要时才向用户显示敏感信息。除此之外,保护敏感数据的最佳方法是首先不要将其摄取到您的系统中。如果您没有明确的目的来摄取和存储敏感数据,那就不要这样做。这样,您就完全消除了意外泄露该数据的风险。


云环境下的安全考量
在当今以云为中心的世界里,安全又增加了一个维度,要求您理解诸如身份和访问管理(IAM)规则、加密方法和网络协议等概念。
在本专项课程中,随着我们更深入地探讨如何确保数据管道的安全性,您将看到更多关于这些主题的内容。
安全始于人
安全不仅仅是原则和协议,它也关乎人。安全始于您个人,也终于您个人,并贯穿于您组织中的其他个体。
在安全方面,您应该采取一种防御性的思维模式。当被要求提供凭据或敏感机密数据时,务必保持谨慎。设想潜在的攻击和泄露场景,并以此为指导来设计您的数据管道和存储系统。
在现实世界的数据泄露事件中,个人往往是许多最大安全漏洞的源头。例如,有人忽视基本预防措施,如不安全地与他人共享密码;有人成为网络钓鱼攻击的受害者(攻击者试图通过冒充权威人物或您信任的人来窃取敏感信息);或者有人在公司系统和数据中不负责任地操作。
避免常见安全失误
在数据工程安全方面,我经常惊讶地看到数据工程师将AWS S3存储桶、服务器或数据库意外暴露在公共互联网上,而这并非本意。有一些简单的修复方法可以防止这种情况发生,但我经常看到这种情况发生,因为数据工程师要么根本不知道安全最佳实践,要么在应用这些实践时不小心忘记了。
超越“安全剧场”:建立安全文化
在组织层面,我经常看到的情况是,许多组织建立了一种安全表象,可能是一套检查清单,以表明他们符合法规或合规标准,但组织文化中缺乏更深层次的安全精神。这种只遵循安全条文而没有安全文化和精神的做法,我称之为“安全剧场”。
真正的安全源于一种文化,在这种文化中,每个团队成员都认识到自己在保护数据方面的角色,从上到下每个人都把安全作为优先事项和*惯来拥抱。
总结与展望
因此,在您作为数据工程师的旅程中,请记住,虽然原则、协议以及工具和技术是您保护数据时的盟友,但真正的安全文化源于整个组织对责任和漏洞的共同理解。

随着我们在专项课程中的深入,您将获得与数据架构所有方面相关的安全考量的实践经验。
在接下来的视频中,我们将探讨数据工程生命周期中的下一个底层支撑:数据管理。
027:数据管理 📊

在本节课中,我们将要学*数据管理的核心概念,特别是数据治理与数据质量。理解这些概念对于成为一名高效的数据工程师至关重要,因为它们决定了数据如何为组织创造价值。
数据管理概述
在之前的课程中,我们探讨了数据工程师的角色。本节中我们来看看数据工程师工作的核心背景:数据管理。无论你从事何种数据工程工作,都必须思考你的工作如何为组织的利益相关者增加价值。数据可以成为极具价值的商业资产,但前提是得到妥善管理。
数据管理非常重要,因此存在一个国际组织——国际数据管理协会(DAMA),专门为公司和个人提供资源以正确进行数据管理。DAMA 提供了一份简洁的出版物:《数据管理知识体系指南》(简称 DMBOK)。正如你所见,数据管理涉及的知识非常广泛。
但请不要感到压力。作为一名数据工程师,你不需要记住这本书中的所有内容。实际上,虽然这是一本很好的参考书,但在数据工程工作中,你将专注于数据管理任务的一个子集,并与软件工程、IT 等其他团队共同承担数据管理的全部责任。
在本视频中,我将快速重点介绍作为数据工程师需要关注的数据管理关键方面。
数据管理的定义与范畴

首先,DMBOK 将数据管理定义为:在整个生命周期内,对交付、控制、保护并增强数据和信息资产价值的计划、方案和实践进行开发、执行和监督。
这个定义内容很多,甚至可能听起来有些模糊。让我们稍作分解。作为一个领域,数据管理包含许多方面和学科,每个方面都有其自身的职责,这可能使数据管理环境显得复杂。
DMBOK 将数据管理的不同方面分解为 11 个所谓的“数据知识领域”。这些领域包括数据治理、数据建模、数据集成与互操作性、元数据、安全性等。它们被安排在下图所示的框架中。
在本系列课程中,你会看到更多关于这些主题的内容。但如图所示,数据治理触及数据管理的所有其他领域,并且许多其他知识领域通过数据治理实践相互关联。
因此,在本视频中,我将重点讨论数据治理,因为它与你作为数据工程师角色中许多重要领域密切相关。
深入理解数据治理
根据另一本名为《数据治理权威指南》的书籍,数据治理首先是一项数据管理职能,旨在确保从组织收集的数据的质量、完整性、安全性和可用性。
从这个定义中,你可以开始看到数据治理涵盖的范围很广,从数据安全和隐私到数据质量和可用性。我们在上一个视频中稍微谈到了安全和隐私。在本视频中,我想重点讨论数据质量,它与你在定义中看到的其他关键术语(如完整性、可用性和可靠性)密切相关。
数据质量的核心
数据质量是一个深入且细致入微的话题,但其核心概念相对简单明了。
以下是高质量数据的关键特征:
- 准确性:数据正确无误。
- 完整性:数据包含所有必要的信息,没有缺失值。
- 可发现性:数据易于被需要的人找到和理解。
- 及时性:数据在需要时可用。
除此之外,高质量的数据能精确地代表利益相关者期望它代表的内容,这体现在定义良好的模式(Schema) 和数据定义上。符合这些质量标准的数据是决策中的强大工具,能为组织增加巨大价值。
相比之下,低质量的数据可能不准确、不完整或以其他方式无法使用。低质量数据可能导致利益相关者浪费时间、做出错误决策,甚至可能导致整个数据团队被解雇。
你将在下一门课程中学*如何在数据管道中监控和确保数据质量。但现在,我们将继续前进,探讨下一个贯穿始终的主题。
总结与预告
本节课中我们一起学*了数据管理的基础,特别是数据治理和数据质量的核心概念。我们了解到,数据管理的目标是最大化数据的价值,而数据治理是确保这一目标实现的框架,其中数据质量是关键支柱。

高质量的数据是准确、完整、可发现且及时的,它是可靠决策的基础。下一节视频中,我们将加入新的内容,探索数据架构如何应用于数据工程生命周期。
我们下节课见!
028:数据架构 🏗️

在本节课中,我们将学*数据架构的核心概念与设计原则。数据架构是数据系统的蓝图,它指导我们如何根据需求设计和构建稳健、可扩展且安全的数据系统。
什么是数据架构?
你可以将数据架构视为数据系统的路线图或蓝图。
在本课程的第一周,我们讨论了需求收集,以及如何将利益相关者的需求转化为具体的技术要求。为了将这些需求映射到成功的系统设计中,你需要像架构师一样思考。
需要明确的是,根据你的工作环境,作为数据工程师,你可能并不直接负责架构和设计决策。你的组织可能设有数据架构师这一角色,专门负责确立设计,然后交由你来实现。
然而,根据我的经验,能够像架构师一样思考,将使你在数据工程师的角色中更加成功。在某些情况下,例如在一家小型初创公司工作,你可能同时兼任架构师和工程师。无论如何,我希望在我刚开始从事数据工程时,就有人教我如何像架构师一样思考。
因此,在本视频中,我将简要介绍一些关键的架构思维原则。在整个课程中,我们将反复回顾这些原则,让你在设计构建稳健数据系统时充满信心。
数据架构的定义
在我们的著作《数据工程基础》中,Matt Haussley 和我将数据架构定义为:
数据架构是通过仔细评估权衡后,做出灵活且可逆的决策,从而设计出支持企业不断发展的数据需求的系统。
让我们花点时间来解读这个定义。
首先,数据架构需要支持组织不断发展的数据需求。这意味着一个好的设计不仅要满足当前的数据需求,也要为未来的需求做好准备。在实践中,这表示数据架构是一项持续的工作,而非一劳永逸的事情。
其次,定义指出,好的设计是通过灵活且可逆的决策实现的。这强调了企业的数据需求可能会以你未曾预料的方式演变,因此你需要更新架构。如果你的初始设计选择本身就是灵活且可逆的,那么随着时间的推移,你将更容易调整架构以满足组织的新需求。
最后,定义的最后部分指出,这一切都通过仔细评估权衡来实现。这些权衡可能涉及性能、成本、可扩展性或其他参数。
值得一提的是,在过去几乎所有数据架构都构建在本地系统上时,做出灵活且可逆的决策要困难得多,有时甚至是不可能的。例如,如果你决定购买并安装价值数百万美元的服务器硬件,无论你是否愿意,都可能在未来数年内被该系统所束缚。
如今,大多数数据架构都构建在云端,从某种意义上说,只要你最初做出了灵活且可逆的决策,你就可以随时改变关于架构技术选择的想法。
优秀数据架构的核心原则
为了进一步阐述这些理念,让我们看看一组优秀数据架构的原则。这些原则将在整个课程中反复提及。
在开始之前,我想说明你现在无需记忆任何内容。我只是想让你预览一下课程内容,并开始像架构师一样思考。
以下是优秀数据架构的九项核心原则:
1. 明智选择通用组件
通用组件是架构中将被组织内多个个人和团队使用的部分。一个好的通用组件选择,应既能满足单个项目的功能需求,又能促进团队间的协作。
2. 为失败做好规划
这条原则的含义很明确。一个好的架构不仅要设计在一切正常运行时的情况,也要设计在系统出现故障时的情况。
3. 为可扩展性而设计
可扩展的系统能够根据需要扩大规模以满足需求,也能在需求减少时缩小规模以降低成本。将可扩展性融入架构,你就能灵活应对需求变化,同时优化成本。
4. 架构即领导力
虽然“架构即领导力”这一原则可能不直接适用于你作为数据工程师的角色,但如果你努力像架构师一样思考,并向数据架构师寻求指导,随着技能提升和资历增长,你将能更好地领导和指导其他团队成员。最终,你自己也可能担任数据架构师的角色。
5. 持续进行架构设计
如前所述,架构设计不是一次性事件。相反,你需要根据组织不断发展的需求,持续评估你的系统,并不断进行架构调整。
6. 构建松耦合系统
松耦合系统由独立的组件构成,这些组件可以轻松替换为其他组件,而无需重新设计整个系统。
7. 做出可逆的决策
通过选择构建这种易于互换的组件,你就是在做出一系列可逆的决策。这意味着,如果你改变了主意,或者组织的需求发生了变化,你可以轻松地撤销之前的决策,并替换架构中的组件以满足新的设计规范。
8. 优先考虑安全性
我们已经了解了一些安全原则,如最小权限原则。在后续关于架构的讨论中,我们还将深入探讨其他原则,如零信任原则。所有这些原则的核心要点是:安全性是你作为数据工程师角色的核心。
9. 拥抱 FinOps
在云时代,数据的成本结构发生了巨大变化。FinOps 是一场运动,旨在将财务的业务优先级与 DevOps(或在此情况下的 DataOps)结合起来。在云端,大多数数据系统都是按需付费且易于扩展的。通过拥抱 FinOps,你可以设计出同时优化成本和潜在收入生成的系统。
总结与展望
以上就是对优秀数据架构关键原则的快速概览。
在本节课中,我们一起学*了数据架构的定义及其作为系统蓝图的重要性,并详细探讨了九项核心设计原则,包括选择通用组件、规划失败、设计可扩展性、持续演进、构建松耦合系统、做出可逆决策、优先安全以及拥抱成本优化。

下周的课程中,我们将更深入地探讨这些原则以及优秀数据架构的更多细节。现在,让我们继续学*数据工程生命周期的下一个重要环节。
请与我一起进入下一个视频,了解 DataOps。
029:DataOps 🚀

在本节课中,我们将要学*DataOps的概念、核心支柱及其在数据工程实践中的重要性。DataOps借鉴了软件开发领域的DevOps理念,旨在提升数据产品的开发流程与质量。
概述
大约在2007年,软件开发领域出现了一个名为DevOps的框架,旨在打破编写和测试代码的软件开发团队与部署和维护代码的软件部署团队之间的壁垒。DevOps借鉴了其他一些知名的方法论,包括精益和敏捷,以实现消除瓶颈、减少浪费、快速识别问题以及快速迭代等目标。DevOps运动使得软件产品的发布周期缩短,质量得到提升。随着数据领域的成熟,我们采用了一种类似的方法,称为DataOps,以改进数据产品的开发。
DataOps的文化与实践

上一节我们介绍了DataOps的起源,本节中我们来看看其核心的文化*惯与实践。DataOps首先是一套可以采纳的文化*惯和实践。这些*惯和实践包括优先考虑与其他业务利益相关者的沟通与协作、持续从成功和失败中学*,以及采取快速迭代的方法来改进系统和流程。这些也是DevOps的文化*惯和实践,它们直接借鉴了敏捷方法论,这是一个专注于以增量和迭代步骤交付工作的项目管理框架。
DataOps的技术支柱
在文化实践之外,DataOps还包含技术要素。以下是DataOps的三个关键支柱:
- 自动化:这是第一个支柱。
- 可观测性与监控:这是第二个支柱。
- 事件响应:这是最后一个支柱。
这些与DevOps的核心组件相似,但目标不同。在DevOps中,最终目标是在软件产品中提供特定的功能和特性。而在DataOps中,目标是提供高质量的数据产品。你可以将数据产品视为提供给最终用户的任何数据或数据系统。
接下来,让我们更详细地了解DataOps的这三个支柱。
自动化支柱详解
在自动化方面,一个加速软件构建生命周期的DevOps实践被称为持续集成和持续交付,简称CI/CD。通过CI/CD,开发人员能够自动化构建、测试和部署代码所需的许多手动流程。这种自动化不仅带来了更快的审查和部署周期,也减少了错误,最终使软件团队在构建高质量软件产品时更高效。DataOps采用了类似的自动化框架应用于数据处理,正如DevOps应用于软件开发一样。在DataOps中,自动化变更管理的总体目标保持不变。例如,当涉及管理代码、配置或环境的变更时。此外,DataOps还专注于数据处理管道和数据本身的变更管理。
为了理解自动化如何应用于数据处理,让我们设想你刚刚在一家小型组织开始工作,你的任务是构建一个数据管道。这个管道从从多个源系统摄取数据开始。你可能从数据库、一些文件、一个API或数据共享平台摄取数据。然后,你可能在摄取过程中执行一些实时转换,接着将摄取的数据存储在存储系统中,可能是一个数据库。假设你有两个最终用例需要服务,一个用于分析,一个用于机器学*。接下来,假设你执行一些进一步的转换,可能在将数据推送到另一个存储系统并使其对最终用户可用之前,对数据进行建模和聚合。
因此,在转换和服务阶段,你基本上有两个管道。如果你是这家组织的第一个数据工程师,并且处于开发数据系统的早期阶段,你可能会选择手动执行数据管道中的各种任务。例如,手动启动每个摄取过程,然后一旦这些完成,再手动执行转换、存储和服务阶段的每个后续步骤。从长远来看,这可能是一个快速启动并原型化数据管道某些方面的合理方法。然而,这种多阶段手动执行容易出错且效率低下,因为它需要你手动运行每个任务。
通过最低限度的自动化,你可能会选择采用所谓的纯调度方法。这意味着你将管道中的每个任务设置为在一天中的特定时间开始。例如,你可能在每晚午夜启动所有这些摄取任务。然后,你会估计所有数据被摄取并加载到存储系统所需的时间。接着,你可以安排下游的转换任务在那之后开始,依此类推,贯穿管道中的所有任务。这被称为调度,因为你创建了一个时间表来自动启动数据管道中的每个任务。
为了将DataOps自动化提升到下一个层次,你可以采用像Airflow这样的编排框架。编排框架在运行每个任务之前检查数据管道中任务之间的依赖关系。因此,你可以决定希望管道第一个任务开始的时间和频率。然后,一旦前一个任务成功完成,编排框架将自动启动后续任务。当任何任务出现错误时,编排框架还可以通知你,这样依赖于先前任务的下游任务就不会在不应该的时候启动。许多编排框架不仅自动化数据管道中任务的执行,还通过支持自动验证和部署数据管道的新方面来增强这些管道的开发,类似于软件部署的CI/CD过程。

可观测性与监控支柱
当涉及到下一个支柱,即可观测性与监控时,你需要记住的主要一点是,你建立的任何数据管道最终都注定会失败。引用亚马逊网络服务首席技术官Werner Vogels的话:“一切都会失败,而且总是如此。”这意味着,如果你不密切观察和监控你的数据系统,当它们失败时,你会措手不及。在最坏的情况下,你可能只有在你的下游利益相关者自己发现问题时,例如在他们的报告或分析仪表板中,才会意识到这些系统故障。在我与客户的工作中,我见过无数由于数据处理系统中未被发现的故障而导致错误数据在报告中停留数月甚至数年的案例。这类故障可能浪费时间和金钱,导致决策依据不足,并最终可能让你失去工作,如果利益相关者对你的工作失去信任的话。因此,可观测性和监控是你构建的数据系统的关键方面。
事件响应支柱
DataOps的第三个支柱是事件响应,这是关于利用你建立的可观测性和监控能力,快速识别事件的根本原因,并尽可能快速可靠地解决它。正如我之前所说,事情会出问题,它们出问题只是时间问题。对于事件响应,不仅关乎你用来识别和响应问题的技术和工具,还关乎开放和无责难的沟通,以及协调数据团队成员乃至整个组织中其他人员应对事件的努力。作为一名数据工程师,你应该主动发现问题,或者由你组织中的其他利益相关者向你报告问题。
总结与展望

本节课中我们一起学*了DataOps,这是一套相对较新的理念,仍在发展之中,并非所有组织都采纳了DataOps的最佳实践。在你的数据工程师工作中,你可能会发现自己身处一个DataOps相当成熟的组织,或者一个尚未拥抱DataOps的地方。DataOps是一套旨在提升数据产品质量和开发效率的文化实践与技术框架,其三大支柱——自动化、可观测性与监控、事件响应——共同构成了稳健数据工程的基础。
接下来,我们将更深入地研究编排,这是DataOps的一个关键组成部分,也是现代数据架构和管道中如此关键的一个部分,以至于我们将其视为数据工程生命周期中一个独立的底层支撑。
030:编排 🎼

在本节课中,我们将要学*数据工程中的一个核心概念——编排。编排是协调和管理数据管道中众多任务的关键,确保数据能够顺畅、准确地流动和处理。
什么是编排?
当你想到“编排”这个词时,脑海中可能会浮现出指挥家引导管弦乐队的画面。指挥家示意各种乐器或声部何时突出,并控制节奏和强度的变化,所有努力都是为了奏出美妙的音乐。
类似地,一个数据管道有许多需要协调的“活动部件”,才能获得良好的结果。作为数据工程师,你就是负责协调和管理数据管道中各项任务的“指挥家”。
我们在上一个视频中简要提到了编排,它是数据运维的一个基本组成部分。接下来,我将进一步阐述编排如何作为数据工程生命周期的底层支撑,发挥关键作用。
从手动执行到自动化编排
正如上一个视频提到的,如果你刚刚起步,例如在一家小型初创公司担任首位数据工程师,或在任何规模的组织中进行新项目的原型设计阶段,你最初可能会建立一个需要手动执行每个阶段任务的数据管道。
我们来看一个这样的管道:从多个源系统摄取数据到存储系统,同时应用一些“飞行中”的转换。然后,下游有更多的流程来转换、存储数据,并为下游用户(如机器学*和分析用例)提供数据服务。
手动执行数据管道中的所有步骤,即在需要时手动触发每个步骤运行,可能有助于系统各个方面的原型设计。但从长远来看,这不是一种可持续的数据处理方法。
纯调度方法及其局限
一旦你明确了数据管道中需要运行的任务,你可能会采用纯调度方法,让这些任务在一天中的特定时间或以特定频率自动运行。
例如,你可以将数据摄取和初始存储任务安排在每天同一时间开始。然后,你可以安排转换步骤在你预期所有摄取的数据都已存在于存储系统后一小时启动。
纯调度方法在历史上曾被广泛用于各种数据处理任务。然而,这种方法可能会遇到问题。
以下是可能出现的问题:
- 如果预定的摄取任务执行失败,可能会导致下游的转换任务也失败。
- 如果某个转换任务耗时超出预期,而下一个转换任务在前一个任务完成前就启动了,你的管道中可能会传播不完整、过时或有问题的数据。
现代编排框架
不久前,比纯调度器更复杂的编排框架实际上只供拥有资源构建自定义解决方案的大型企业使用。如今,有许多开源编排框架,使你无论团队或公司规模大小,都能在自己的数据管道中构建复杂的编排功能。


目前最流行的框架是 Apache Airflow。但其他一些较新的开源框架,如 Dagster、Prefect 和 Mage,也正在获得关注。
这些框架允许你实现数据管道的自动化,并构建复杂的依赖关系和监控能力。你仍然可以进行基于时间的调度,但你也可以构建依赖关系,例如,验证第一个转换任务已完成,再启动下一个转换任务。
或者,你可以不预定义任务启动的具体时间或频率,而是设置由事件触发的任务。例如,当源数据库中有一定量的新数据可用时,触发摄取步骤开始。
你可以在编排框架内设置监控,并触发警报,以便在例如某个转换任务执行失败或在特定时间前未完成时通知你。
有向无环图
许多编排框架要求你将数据管道设置为所谓的有向无环图。这其实是一个过于复杂的术语,用来描述数据如何流经你的数据管道。
让我们看看我们一直在讨论的这个管道的有向无环图(简称 DAG)会是什么样子。从某种意义上说,这已经是一个 DAG,其中每个图标代表管道中的一个不同任务,箭头显示数据如何从一个任务流向下一个任务。


现在我将修改一下这里的视觉表示,使其更明确地像一个你在其他地方会看到的 DAG 图。
我们将这些源系统称为 So1、So2、So3 和 Source4。我们从所有这些源摄取或提取数据,并且从这里的 Source4 开始有一个“飞行中”的转换步骤。
然后,将所有提取的数据存储起来。之后,你的管道会分叉:沿着顶部这条分支,你有两个更多的转换步骤,然后是服务于机器学*最终用例的存储;在底部这条分支,你有一个转换步骤,然后是服务于分析用例的存储。
- 有向:表示数据流只朝一个方向。
- 无环:表示没有循环,数据不会流回之前的步骤。
- 图:因为它由节点和边组成。
你可以将 DAG 视为数据如何流经你管道的流程图。你将在所选的编排框架内构建和部署 DAG。正如我提到的,你将能够为每个任务应如何触发、以及你想要设置何种监控和警报,指定标准和依赖关系。
在本课程后面部分,你将有机会在一些数据管道和流行框架中练*设置和运行 DAG。
总结
本节课中,我们一起学*了编排的核心概念。编排是贯穿整个数据工程生命周期以及数据运维关键方面的底层支撑。它使你能够从手动或简单的调度执行,过渡到自动化、可监控且具备复杂依赖关系管理的强大数据管道。

在下一个视频中,我们将探讨最后一个底层支撑——软件工程,看看它如何与数据工程师的角色相关联。
031:软件工程 👨💻

概述
在本节课中,我们将要学*数据工程生命周期中一个至关重要的“暗流”——软件工程。我们将探讨为什么编写代码是数据工程师的核心技能,以及如何编写高质量、可投入生产的代码。
在之前的课程中,我们讨论了数据工程生命周期中一些相当复杂的“暗流”,例如安全、数据架构、运营与管理,以及数据管道的编排。
在所有这些“暗流”中,或许最容易理解的是最后一个:软件工程。我的意思是,作为一名数据工程师,你需要知道如何阅读和编写代码。就这么简单。
但这不仅仅意味着临时拼凑一些能完成当前任务的代码,而是要编写生产级别的代码——这些代码应该是干净、可读、可测试且可部署的。
因此,软件工程是软件应用程序的设计、开发、部署和维护。
在不太遥远的过去,数据工程并非一个正式的职业。只有软件工程师偶尔会在工作中处理数据。随着企业逐渐认识到数据的价值,软件工程师开始承担数据工程的各个方面作为其工作的一部分。

*几十年来,数据的多样性和体量不断增长,软件工程中面向数据的部分变得愈发重要,并最终发展成为一个独立的领域。
多年来,那些从事数据工程的软件工程师构建了各种出色的解决方案。因此,如今作为一名数据工程师,你可以利用广泛的托管服务和应用程序,从而更高效地完成工作。

这是一件好事。它让你能将更多时间集中在为组织增加真正价值的最重要方面上。从某种意义上说,这些现有的服务和应用程序让你得以向价值链上游移动。
这也意味着,如今的数据工程师通常需要编写的代码量,远少于十到二十年前那些以软件工程为导向的前辈们。
然而,这并不意味着编码在数据工程师的工作中不重要。事实上,你能够编写出色的代码,并且所写代码质量上乘,这一点比以往任何时候都更加重要。
以下是数据工程师需要编写代码的几个关键场景:
- 数据处理代码:在数据工程生命周期的各个阶段,从摄取、转换到服务,你都需要编写核心的数据处理代码。
- 框架与语言:你需要精通诸如
SQL、Spark或Kafka等框架和语言。你也可能会遇到Python,或者像Java或Scala这样的Java虚拟机语言,以及用于命令行操作的bash。 - 其他语言:你可能还需要使用其他语言,如
R、Ruby或Go。但如果你专注于建立扎实的基础软件工程技能,在不同语言间切换就不会有太大困难。
本专项课程在实验练*中将主要关注 SQL、Python 和 bash,因为这是你作为数据工程师与数据交互最常见的方式。
此外,作为一名数据工程师,你很可能会参与到开源框架的开发中。




这种情况通常是这样发生的:你采用一个开源框架来解决特定问题,并最终为了你的具体用例而进一步开发该框架。只要你编写了优秀的代码,就可以提交一个拉取请求,将你的贡献添加到开源项目中,以帮助其他人解决类似的问题。
你还会参与的其他工作包括开发所谓的“基础设施即代码”或“管道即代码”解决方案,我们将在后续课程中讨论。
除了这些特定的实例,在你作为数据工程师的角色中,你还需要在数据工程生命周期的所有阶段,为日常的通用问题解决编写代码。
因此,正如我在本视频开头所说,作为一名数据工程师,你需要知道如何阅读和编写代码。编码将是你日常工作的一部分,而你编写干净、可读、可测试且可部署代码的能力,将转化为你为组织创造的价值。

值得你花时间去与你组织中的软件工程师交朋友,并向他们学*如何编写出色的代码。

总结
本节课中,我们一起学*了数据工程生命周期中的“暗流”——软件工程。我们了解到,编码是数据工程师的核心技能,其目标不仅是让代码运行,更是要编写出生产级别的高质量代码。我们探讨了数据工程师需要掌握的关键语言和框架,以及参与开源项目和编写“即代码”解决方案的可能性。
至此,我们完成了关于数据工程生命周期“暗流”的课程。我相信你已经受够了所有这些理论内容,准备好卷起袖子,在一些实际练*中应用这些概念了。在下一节课中,请与我一起看看数据工程生命周期及其“暗流”如何在AWS云上变为现实。
032:AWS云平台工具概览 🚀

在本节课中,我们将学*如何将数据工程生命周期和底层支撑概念,具体应用到AWS云平台的工具与技术中。我们将了解为何选择AWS作为学*平台,并预览后续实验中将接触到的核心工具。
现在您已经熟悉了数据工程生命周期及其底层支撑概念,是时候看看这些概念如何转化为AWS云平台上的具体工具和技术了。
首先需要说明,市场上存在其他云服务提供商,包括微软的Azure和谷歌云平台,以及其他一些规模较小的提供商。根据您作为数据工程师的工作环境,您可能会基于其中某个平台进行构建。
尽管如此,您在课程中学到的所有概念,无论您在哪一个云平台上构建,都是相关的。只是部分工具和实现细节可能会有所不同。目前,AWS是领先的云提供商,我们非常高兴能与他们合作开设这些课程。这样,您就能使用已被全球数千家公司采用的相同工具和技术,获得数据工程所需的技术技能。
在下一个视频中,Morgan Willis将向您介绍在本系列课程的实验环节中将会使用到的一些工具,并解释这些工具如何融入数据工程生命周期和底层支撑概念中。
之后,我将为您介绍本周实验练*的概况。
本节课中,我们一起学*了将数据工程理论映射到AWS云平台实践的背景与意义。我们了解到核心概念具有跨平台的通用性,同时认识到AWS作为行业领先平台的价值。接下来,我们将通过具体工具的学*和动手实验,进一步巩固这些知识。
033:AWS上的数据工程生命周期 🚀

概述
在本节课中,我们将学*数据工程生命周期及其底层支撑概念在AWS云平台上的具体实现。我们将逐一探讨生命周期的各个阶段,并将其与AWS提供的特定工具和技术联系起来,帮助你理解如何利用这些工具构建实际的数据系统。
源系统
上一节我们介绍了数据工程生命周期的整体概念,本节中我们来看看在AWS上如何实现源系统。正如之前提到的,最常见的源系统是数据库。
以下是你在AWS上可能遇到的主要源系统类型:
- Amazon RDS (Relational Database Service):这是一项托管服务,可为你配置所选关系型数据库引擎(如MySQL或PostgreSQL)的实例。RDS简化了配置和托管关系型数据库的操作负担,并负责补丁和升级等任务。其核心是提供一个托管的数据库实例。
- Amazon DynamoDB:这是一个无服务器的NoSQL数据库选项。使用DynamoDB时,你创建独立的表,这些表在总数据量上几乎没有限制。DynamoDB具有灵活的模式,非常适合需要低延迟访问海量数据的应用,例如游戏、移动应用和实时分析,其数据模型可以随时间演进,无需复杂的迁移。
- 流式数据源:
- Amazon Kinesis Data Streams:在本课程的最后一周,你将有机会使用它作为源系统,从一个销售平台博客流式传输实时用户活动数据。
- Amazon SQS (Simple Queue Service):虽然在实验中没有使用,但在构建自己的数据管道时,你可能会使用SQS来处理消息。
- Apache Kafka:一个开源的流处理平台。你可以自行部署,或使用AWS的托管服务Amazon MSK (Managed Streaming for Kafka),该服务为你管理底层基础设施,使在AWS上运行Kafka工作负载变得更加容易。
数据摄取
了解了数据来源后,接下来我们进入数据摄取阶段。这个阶段负责将数据从源系统移动到存储或处理系统。
以下是AWS上常用的数据摄取工具:
- AWS Database Migration Service (DMS):如果你需要从数据库摄取数据,可以使用DMS。它能够以自动化的方式将数据从源迁移或复制到目标。
- AWS Glue ETL:在本课程的实验中,你将主要使用AWS Glue ETL服务。它提供了支持数据集成流程的功能。
- 流式数据摄取:在实验中,你将使用Amazon Kinesis Data Streams和Amazon Kinesis Data Firehose。在实际工作中,你也可以使用之前提到的其他流式摄取工具,如SQS或Kafka。

数据存储
数据被摄取后,需要存储在合适的地方。本节我们探讨AWS上的数据存储选项。
你将练*使用以下存储方案:
- 传统数据仓库:例如Amazon Redshift,适用于结构化数据的分析查询。
- 对象存储(数据湖):主要是Amazon S3 (Simple Storage Service)。S3为数据湖提供了高扩展性、低成本的对象存储。
- 湖仓一体 (Lakehouse):这是一种架构模式,可以结合使用上述服务,实现对数据仓库中的结构化数据和对象存储数据湖中的非结构化数据的无缝访问。
转换与处理

存储了原始数据后,通常需要对其进行转换,使其适合分析或机器学*使用。

在本课程中,你将使用以下工具进行数据转换:
- AWS Glue:一个托管的ETL服务。
- Apache Spark:一个强大的开源分布式计算框架。
- dbt (Data Build Tool):一个专注于数据转换层(在仓库内)的流行工具。
你可以根据需求,组合使用这些工具,或将其作为Glue的替代方案。
数据服务
数据经过转换后,最终需要被服务给最终用户或应用程序。这主要涉及两种用例。


以下是两种主要的数据服务场景及其对应工具:
-
商业智能与分析用例:
- 查询工具:使用Amazon Athena(无服务器交互式查询服务)或Redshift来查询结构化和非结构化数据。
- 仪表板:你可能会使用Amazon QuickSight,或者开源的Apache Superset进行数据可视化。在本周的实验中,你将获得在Jupyter Notebook中操作仪表板的经验。
-
人工智能与机器学*用例:
- 为模型训练提供批量数据。
- 使用一些向量数据库选项,为产品推荐系统提供数据,或与大型语言模型配合使用。
总结

本节课中,我们一起学*了数据工程生命周期在AWS平台上的具体映射。我们从源系统(如RDS、DynamoDB、Kinesis)开始,经历了数据摄取(DMS、Glue)、数据存储(Redshift、S3、湖仓一体)、数据转换(Glue、Spark、dbt),最后到数据服务(Athena、QuickSight、AI/ML工具)。重要的是要记住,生命周期的每个阶段都有众多开源和托管服务选项,这里提到的只是你将在本课程中实践的一部分,旨在帮助你将学到的概念与实际工具联系起来。
034:AWS上的底层技术 🛠️

在本节课中,我们将学*数据工程生命周期中的底层技术如何在AWS平台上具体体现。我们将探讨安全、数据管理、数据运维、编排、架构和软件工程等核心概念,并了解AWS提供的相关工具和服务。
安全 🔒
上一节我们介绍了数据工程生命周期的整体框架,本节中我们来看看安全这一底层技术在AWS上的具体表现。
安全在AWS工作中以多种形式出现。AWS采用责任共担模型:AWS负责其数据中心和所提供服务的安全,而您负责使用这些资源构建的系统的安全。
例如,如果您将数据存储在Amazon S3上,AWS的责任是确保S3服务本身的安全,而您的责任是正确设置访问权限,确保数据仅对授权的人员和应用程序可用。
以下是AWS安全的关键概念和工具:
- 身份与访问管理:通过IAM,您可以设置角色和权限,控制对AWS资源的访问,确保用户和服务能够安全地执行任务。在数据管道中,您将使用IAM角色,它为用户或应用程序提供自动轮换的临时凭证,并授予对各种工具或数据存储区域的适当AWS API权限。
- 网络安全:对于AWS上的安全至关重要。您需要熟悉以下服务和功能:
- Amazon Virtual Private Cloud:即VPC。
- 安全组:这是实例级防火墙,是实施安全数据管道的另一个关键方面。
数据管理 📊
在安全之后,数据管理是另一个贯穿数据工程生命周期的关键底层技术。在AWS上,数据管理涉及数据的发现、编目和访问控制。
在这些课程中,您将使用以下AWS服务进行数据管理:
- AWS Glue爬网程序和Glue数据目录:允许您发现、创建和管理存储在Amazon S3或其他存储和数据库系统中的数据的元数据。
- Lake Formation:帮助您集中管理和扩展细粒度的数据访问权限。
所有这些也都与安全相关,但在此将它们列在数据管理下,因为它们专门涉及数据隐私和发现。


数据运维与编排 ⚙️
了解了数据的管理,接下来我们需要确保数据系统能够稳定、可靠地运行。这涉及到数据运维和编排。
在下一门课程中,您将使用名为Amazon CloudWatch的服务,它收集指标并为云资源、应用程序甚至本地资源提供监控功能。此外,还有Amazon CloudWatch Logs,可以帮助您存储和分析操作日志。
在课程2中,您还将使用Amazon Simple Notification Service,即SNS,它提供了一种在应用程序之间或通过短信/电子邮件设置通知的方法,这些通知由系统内的事件触发。
您在自己的工作中可能还会使用许多开源可观测性工具,例如Monte Carlo或BigEye。
对于编排,在这些课程中,您将使用Airflow。Airflow是一个编排工具,您可以将其作为开源工具实现,或使用AWS提供的托管版本。Airflow目前是行业标准,但您应该了解较新的编排工具,如Dagster、Prefect和Mage,它们旨在解决Airflow未设计处理的一些问题。
架构与软件工程 🏗️
在确保了系统的运行和流程的协调之后,我们需要从更高层面审视系统的结构和开发方式。这引出了架构和软件工程。
在架构方面,我们将在下周查看AWS完善架构框架。这是一套由AWS开发的原则和实践,可以帮助您构建系统时兼顾运营效率、安全性、可扩展性和可持续性。
在软件工程方面,在这些课程中,您将使用Amazon Cloud9 IDE进行开发。Cloud9托管在Amazon EC2上,因此该服务本质上是一个安装了IDE的虚拟机,您可以在浏览器中使用它。
在您自己的工作中,您可能还会使用诸如Amazon CodeDeploy之类的工具,它允许您自动化代码部署,以及各种CI/CD工具。您还将使用Git和GitHub处理版本控制。

总结 📝
本节课中,我们一起学*了数据工程生命周期底层技术在AWS平台上的具体体现。
我们探讨了安全的责任共担模型和关键服务(IAM、VPC),了解了数据管理的工具(Glue、Lake Formation),认识了数据运维的监控与通知服务(CloudWatch、SNS),介绍了编排的主流工具(Airflow)及其替代品,概述了架构的指导框架(AWS完善架构框架),并简要说明了软件工程的开发与部署工具(Cloud9、CodeDeploy、Git)。

接下来,Joe将带您完成第一个实时练*,您将在AWS上启动一个端到端的数据管道。
035:数据工程导论 第2周 实验演练预览 👀

在本节课中,我们将预览第2周实验的具体内容和操作步骤。你将了解如何探索已设置好的源数据库,如何使用Terraform创建数据管道资源(如AWS Glue和S3存储桶),如何运行数据转换作业,以及最终如何在Jupyter Notebook中查询和分析转换后的数据。
上一节我们介绍了实验环境的设置,本节中我们来看看实验的具体任务流程。
首先,实验的核心是探索一个已为你实例化的源数据库系统。该数据库是一个MySQL数据库,包含了名为classicmodels的示例数据。

以下是连接到并探索该数据库的步骤:
- 在AWS控制台中搜索并进入RDS服务,点击左侧的“数据库”,即可查看源数据库实例的详细信息,包括访问所需的端点(Endpoint)。
- 或者,在终端中运行命令
aws rds describe-db-instances --db-instance-identifier <数据库标识符>来获取端点。 - 使用MySQL客户端建立连接。命令格式为:
密码是mysql -h <数据库端点> -u admin -puseradmin,端口是3306。 - 连接成功后,使用
use classicmodels;命令选择数据库。 - 使用
show tables;命令查看数据库中的所有表。
如果你好奇数据的来源和结构,可以在实验文件夹的 data/ 目录下找到 mysqlsampledatabase.sql 文件,其中包含了创建并填充该数据库的所有SQL代码。
完成数据库探索后,输入 exit 命令退出连接。
上一节我们查看了源数据,本节中我们来看看如何构建数据处理管道。
实验使用Terraform代码来自动化创建AWS Glue实例和S3存储桶等资源。所有Terraform配置文件都位于 terraform/ 目录下,文件扩展名为 .tf。
以下是主要的Terraform文件及其作用:
glue.tf:定义了AWS Glue数据目录、连接、爬网程序和ETL作业的配置。s3.tf:定义了用于存储转换后数据的S3存储桶。- 其他文件负责网络和权限设置,这些将在后续课程中详细学*。
在 glue.tf 文件中,关键的资源配置包括:
- 一个连接到RDS源数据库的Glue连接。
- 一个用于爬取S3数据的Glue爬网程序。
- 一个Glue作业,它指定了源系统连接、包含转换代码的脚本位置(位于
infrastructure/terraform/assets/gluejob.py)以及转换后数据的目标位置。

该Python脚本的核心任务是将规范化的源数据转换为更适合分析的星型模式,即事实表和维度表。
资源定义完成后,接下来需要在终端中运行Terraform来实际创建这些云资源。
以下是创建资源的步骤:
- 导航到
terraform目录。 - 运行
terraform init来初始化Terraform,安装必要的提供商插件。 - 运行
terraform plan来预览Terraform计划创建的资源列表。 - 运行
terraform apply并输入yes来确认执行,开始创建资源。

创建完成后,你可以在AWS控制台中搜索“AWS Glue”和“S3”来验证资源(如Glue作业和S3存储桶)是否已成功创建。
资源就绪后,便可以运行Glue作业来处理数据。
在终端中,按照实验说明复制并运行启动Glue作业的命令。作业启动后,你可以通过AWS控制台进入Glue服务的“ETL作业”部分,在“运行”选项卡中监控作业状态。通常需要等待几分钟,直到状态显示为“成功”。

作业成功后,转换后的数据便已写入指定的S3存储桶。你可以前往S3控制台查看存储桶内容,应该能看到包含各个转换后表(对应维度表和事实表)的文件夹。
最后,我们将使用数据分析师工具来查询这些处理好的数据。
实验环境已预先设置好Jupyter Lab。打开Jupyter Notebook,你会看到一个包含多个代码单元的Python笔记本。
以下是笔记本中的主要查询示例:
- 第一个单元导入
awswrangler包,它允许使用Amazon Athena查询S3中的数据。 - 第二个单元包含一个SQL查询,用于从
dm_products表中提取所有产品信息。SELECT * FROM dm_products; - 后续单元包含更复杂的分析查询,例如按国家统计总销售额,或按国家、产品线、订单日期等多维度进行分组统计。
如果你对SQL还不熟悉,无需担心,后续课程将提供大量实践机会。如果你已掌握SQL,可以尝试完成单元中的可选查询问题或自行编写查询。
最后,你可以运行一个交互式仪表板来进一步探索数据。
完成实验所有步骤后,请务必返回实验设置说明页面点击“提交”。请注意,实验环境将在两小时后过期,请确保在时间结束前提交。

本节课中我们一起学*了第2周实验的完整流程:从探索源数据库开始,到使用Terraform创建数据管道资源,运行Glue作业进行数据转换,最后在Jupyter Notebook中对转换后的数据执行分析查询。现在,轮到你动手尝试了。请仔细遵循实验说明,如果遇到困难,可以随时回看本视频。完成实验后,我们将回到这里进行本周内容的总结。
036:实验演练 - 设置实验环境 🛠️

在本节课中,我们将学*如何访问并设置第一个实验所需的实验说明和Jupyter Notebook环境。我们将逐步完成从启动实验到配置所有必要工具的完整流程。
概述
本节教程将指导你完成实验环境的初始设置。你将学*如何访问Coursera上的实验、启动AWS Cloud9集成开发环境、下载实验文件,以及安装运行实验所需的软件工具。
启动实验
首先,你需要在Coursera平台上找到本周的“graded app”实验。点击并启动该应用后,你将进入实验的欢迎页面。该页面包含了设置实验、启动Cloud9以及打开Jupyter Notebook的详细说明。
完成实验后,你需要返回此页面提交你的成果。
以下是启动实验的具体步骤:
- 点击启动按钮,等待上方圆圈图标变为绿色,以打开AWS控制台。
- 请注意,首次启动实验时,环境加载可能需要几秒钟。后续尝试可能需要大约10分钟,因为创建的AWS账户需要执行清理程序。




配置AWS Cloud9环境
上一节我们启动了实验,本节中我们来看看如何配置核心的编程环境。
当AWS控制台图标变为绿色后,点击它将在新的浏览器标签页中打开AWS控制台。接下来,你需要启动AWS Cloud9 IDE来获取实验代码和详细说明。
以下是配置Cloud9环境的步骤:
- 在AWS控制台的搜索栏中输入
cloud 9并选择该服务。 - 进入新页面后,点击“Create Environment”按钮。
- 按照实验说明第4步的细节进行配置:
- 环境名称:
DEC C1W2 - EC2实例类型:
T3 small - 网络设置:选择“Secure Shell (SSH)”
- VPC设置:在下拉菜单中选择名为
D C1W2的VPC和名为D C1W2 public subnet的公共子网。
- 环境名称:
- 向下滚动并点击“Create”。AWS需要几分钟时间来设置环境。
注意:对于未来的实验,你可能需要选择其他EC2类型或不同的VPC设置。请务必仔细阅读设置说明,否则可能无法构建实验所需的Cloud9环境。

下载实验文件并查看说明


环境创建完成后,你可以打开IDE。在环境底部有一个终端,左侧应显示实验文件夹和文件。初始时,实验文件尚未下载。

以下是获取实验内容的步骤:
- 返回实验设置说明页面。
- 从第5步复制命令,并将其粘贴到Cloud9环境的终端中。
- 该命令的格式类似于:
aws s3 cp s3://[bucket-name]/[lab-content] ./ --recursive
- 该命令的格式类似于:
- 此命令会从为实验设置的S3存储桶下载实验内容。下载完成后,左侧将显示实验的文件夹和文件。
- 要访问详细的实验说明,请按照设置说明的第6步操作:打开指定的Markdown文件(例如
C1w2assignment.md),点击“Preview”,然后从下拉菜单中选择“Preview File”。 - 如果详细说明没有正确渲染,请点击刷新按钮。
安装必要软件
在开始实验主体部分之前,还需要执行一个设置步骤来安装Terraform并启动Jupyter Notebook。
以下是安装步骤:
- 返回实验设置说明页面。
- 从第7步复制命令,并将其粘贴到终端中。
- 该命令包含一个Bash脚本,用于安装Terraform并通过JupyterLab启动Notebook。
- Terraform现在开始安装,JupyterLab的安装也可能需要几分钟。
- 安装完成后,终端将输出一个JupyterLab的URL。复制此URL,并将其粘贴到一个新的浏览器标签页中,以访问JupyterLab环境。
理解实验工作区布局
至此,你已经设置了多个工作环境,理解它们各自的作用非常重要:
- Cloud9环境:你将在此环境中设置和运行数据管道。
- AWS管理控制台:你可以在此查看已创建的AWS资源的详细信息。
- JupyterLab环境:你将在实验的最后部分使用此环境(位于另一个浏览器标签页中)。
- 实验设置说明页面:实验结束时,你需要返回此页面提交实验。
我知道这涉及很多标签页,一开始在它们之间来回切换可能会让人不知所措。但随着你在专项课程中的不断深入,这一切都会变得更加熟悉。
总结
本节课中,我们一起学*了如何为数据工程实验设置完整的工作环境。我们完成了从Coursera启动实验、在AWS上创建并配置Cloud9 IDE、下载实验文件、查看详细说明,到安装Terraform和JupyterLab的全过程。现在,你的实验环境已经准备就绪,可以开始构建和运行数据管道了。

在下一个视频中,我将引导你完成设置数据管道的后续步骤。
037:实验内容预览 🧪

在本节课中,我们将预览本周实验的具体内容和操作步骤。你将了解如何探索源数据库、使用Terraform创建数据管道资源、运行AWS Glue作业,以及最终在Jupyter环境中查询已转换的数据。
实验环境概览
上一节我们完成了实验环境的设置,最终得到了一个Cloud9环境。环境左侧的文件夹结构中包含了实验所需的所有文件。
你已经打开了名为 C1_W2_assignment.md 的文件,其中包含了实验练*的详细说明。这些说明顶部有介绍,你的工作将从第2节“探索源系统”开始。
探索源数据库系统

如前所述,源系统数据库已为你实例化。你可以在AWS控制台中查看此数据库的详细信息。
以下是查看数据库详情的步骤:
- 在AWS控制台搜索并选择“RDS”服务。
- 在左侧点击“数据库”。
- 这里列出了源数据库实例。点击标识符可查看所有详细信息,例如允许你访问数据库的端点(URL)、端口号以及其他网络信息(如RDS实例所在的VPC和子网)。

你还可以通过终端运行以下命令获取端点:
aws rds describe-db-instances --db-instance-identifier <你的数据库标识符>
你需要将 <你的数据库标识符> 部分替换为实际的数据库标识符。现在,你看到了与控制台中相同的端点。在查看其内容之前,你需要先建立到该数据库的连接。
由于这是一个MySQL数据库,你可以通过以下命令连接:
mysql -h <数据库端点> -u admin -p
系统将提示你输入密码(useradmin),端口是 3306。
连接建立后,你可以使用以下命令选择要探索的数据库:
USE classicmodels;
你可以通过以下命令查看数据库中的表:
SHOW TABLES;
如果你好奇,还可以通过进入 data 文件夹并打开名为 mysqlsampledatabase.sql 的文件,查看用于填充数据库的脚本。在这里,你可以看到数据来源的一些信息和版本历史。
向下滚动,你会找到一系列SQL代码。首先是创建数据库本身的语句,然后是一系列创建表并填充数据的命令。目前,你无需担心所有这些SQL代码,在下一门课程中你将有机会阅读、编写和解释SQL命令。
最后,要退出数据库连接并继续实验说明,请输入:
EXIT;
创建数据管道资源
接下来,让我们为数据管道创建资源,即AWS Glue实例和S3存储桶。为此,我们提供了包含创建和配置这些资源代码的Terraform文件。
如果你点击左侧的 terraform 文件夹,所有以 .tf 扩展名结尾的文件都是Terraform文件。例如:
glue.tf文件包含AWS Glue实例的配置。s3.tf文件包含S3存储桶的配置。- 其他Terraform文件包含网络和权限设置,你将在课程2中了解更多。
现在,我快速浏览一下 glue.tf 文件,向你展示其中声明的资源:
- 这里定义了AWS Glue数据目录,我们将建立AWS Glue与RDS源数据库之间的连接。
- 这是另一个定义Glue爬网程序的资源,它将用于爬取S3存储桶。
- 最后,这是Glue作业,我们在其中指定了与源系统的连接、包含转换代码的脚本位置以及转换后数据的目标位置。
你可以在 assets 文件夹下找到该脚本,它包含提取数据、转换数据并最终加载到S3的代码。我们将在课程4中进一步深入了解AWS Glue的细节。

如果你好奇,也可以通过打开 infrastructure/terraform/assets 文件夹中的Python脚本 gluejob.py 来查看将应用于数据的转换。但你不必担心脚本的具体细节,它所做的就是将所谓“规范化”形式的数据,建模为事实表和维度表的星型模式,以便于分析。这是数据分析用例中处理表格数据时非常常见的工程实践。
要为此管道实际创建资源,你需要在终端中运行Terraform文件。让我们导航到terraform目录并开始执行命令。
使用Terraform部署资源
以下是使用Terraform创建资源的步骤:
- 首先运行
terraform init。此命令将安装创建AWS资源所需的任何文件。 - 然后,你可以运行
terraform plan命令,该命令会显示Terraform计划创建的资源列表。 - 最后,运行
terraform apply命令来创建资源。此时,你将再次看到计划,并需要确认你希望Terraform执行这些操作。输入yes并等待资源创建完成。

资源创建完成后,你可以通过AWS管理控制台查看它们。
验证资源与运行Glue作业

让我们进入控制台,在搜索栏中输入“AWS Glue”,点击该服务,然后在左侧点击“ETL作业”。在这里,你将看到刚刚创建的实例。
你也可以搜索S3存储桶。这里是将包含转换后数据的存储桶。

现在资源已创建,让我们运行Glue作业。我将从实验说明中复制命令,并将其粘贴到终端中以启动Glue作业。
要监控作业状态,请进入控制台并再次搜索“AWS Glue”,导航到ETL作业部分,然后点击作业名称。在“运行”选项卡中,你将看到作业状态,现在显示为“正在运行”。

你可能需要等待两到三分钟作业才能完成。可以刷新浏览器以查看最新状态。
一旦Glue作业完成且状态显示为“成功”,转换后的数据就应该在S3存储桶中了。让我们通过访问此S3存储桶的内容来验证一下。在这里,你可以找到包含转换后数据表的文件夹。
在Jupyter中查询数据
在实验的最后一部分,你将探索数据分析师如何在我们之前设置的Jupyter实验环境中查询数据集。我将点击Jupyter笔记本。
这是一个Python笔记本,其中包含对转换后的数据执行分析查询的单元格。在第一个单元格中,导入的 awswrangler 包允许你使用Amazon Athena从S3存储桶中提取数据。
以下是查询示例:
- 第一个查询语句从
dm_products表中提取所有产品。 - 下一个单元格包含一个按国家/地区查找总销售额的查询。
- 随后的单元格包含一个查询,进一步按国家/地区、产品线、订单日期和产品名称对销售总额进行分组。
如果这些代码和SQL查询语句看起来不熟悉,请不要担心,你将在课程2和3中获得编写和解释查询的实践经验。如果你熟悉SQL,则可以尝试此单元格中的可选查询问题或任何其他你选择的查询。
最后,你可以运行此交互式仪表板以进一步探索数据。
完成实验与总结
完成本实验中的步骤后,请务必返回实验设置说明页面并点击“提交”。请注意,实验环境将在两小时后过期,因此请确保在时间用完之前提交。
现在你对本周实验要做什么有了更好的了解,轮到你来尝试了。请仔细按照实验说明操作,如果在任何环节遇到困难,可以随时重新观看这些视频。完成本实验后,我将在这里与你见面,进行本周内容的快速总结。


本节课中我们一起学*了本周实验的完整流程预览,包括:连接并探索源数据库、使用Terraform脚本自动化创建AWS Glue和S3资源、运行数据转换作业,以及最终在Jupyter笔记本中查询和分析结果数据。请按照步骤动手操作,以巩固对数据工程管道基础的理解。
038:数据工程导论、源系统、数据摄取和管道、数据存储和查询|第1-2-3课 🎯

第2周总结 📋
在本节课中,我们将对数据工程课程的第二周内容进行回顾与总结。我们将梳理本周所学的核心概念与框架,并展望后续的学*方向。
恭喜你完成了本课程第二周的学*。正如我在课程伊始所强调的,本周的重点更多地在于构建一个关于数据工程的高层次思维框架,而非实际搭建数据基础设施。不过,你确实有机会在AWS上探索了一个端到端的数据管道。
为了开始规划如何将这些理论付诸实践,我们本周构建的实践经验和思维框架,都将帮助你在数据工程师工作的各个方面取得更大的成功。
因此,本周你学*了数据工程生命周期及其基础支撑要素。这些内容涵盖了作为数据工程师,你如何从某处获取原始数据、将其转化为有用的内容,并最终提供给终端用户的各个方面。
以下是本周课程的主要内容回顾:
- 第一课:我们探讨了数据工程生命周期的每个阶段。从数据生成和存储系统开始,然后研究了针对分析、机器学*和反向ETL等多种使用场景的数据摄取、转换、服务和存储。
- 第二课:我们学*了数据工程生命周期的基础支撑要素。这些要素包括:安全、数据管理、数据运维、数据架构、编排和软件工程。
在接下来的课程中,你将看到关于数据工程生命周期及其基础支撑要素所有方面的更多细节,并获得更多实践机会。
接下来,我们将深入探讨构建良好数据架构的具体含义。我们将在那里再见。

本节课中,我们一起回顾了数据工程第二周的核心内容,包括数据工程生命周期及其基础支撑要素的宏观框架。我们明确了理论框架与实践探索相结合的重要性,并为深入理解数据架构做好了准备。
039:数据工程导论 第3周概览 🏗️
在本节课中,我们将深入学*如何构建优秀的数据架构。我们将探讨数据架构在企业整体架构中的位置,分析具体的架构案例,并学*如何将利益相关者的需求转化为数据系统的技术选择。课程最后,您将掌握一套在数据工程旅程各阶段都有用的工具。

上周,我们简要了解了数据架构,并探讨了如何在数据工程工作中,即使您的职位并非数据架构师,也能通过像架构师一样思考来获得成功。
本节中,我们将更深入地探讨构建良好数据架构的具体含义。
数据架构与企业架构 🏢
首先,我们将审视数据架构如何融入更广泛的企业架构背景中。企业架构指的是您整个组织的架构。
理解这一点有助于确保数据系统与组织的整体战略和目标保持一致。
从需求到技术选择 🔧
接下来,我们将查看一些具体的架构示例。我们将学*如何开始思考将利益相关者的需求,转化为数据系统的具体技术选择。
这个过程是数据架构设计的核心。
架构师思维指导原则 🧭
此外,我将与您分享一些指导原则。在您学*像架构师一样思考时,可以牢记这些原则。
这些原则是设计稳健系统的基础。
本周实验:评估权衡与探索框架 ⚖️
在本周的实验环节,您将有机会评估实际数据架构在成本、性能、可扩展性和安全性等方面的权衡。实验将基于AWS云上的一个实际架构。
您还将有机会探索 AWS完善架构框架。这是一套互补的指导原则,能帮助您设计出稳健高效的数据系统。
以下是实验将涉及的核心评估维度:
- 成本: 系统建设和运营的经济投入。
- 性能: 系统处理数据的速度和效率。
- 可扩展性: 系统应对数据量或用户量增长的能力。
- 安全性: 保护数据免受未授权访问和泄露的措施。
总结 📚
本节课中,我们一起学*了数据架构的核心概念及其在企业中的定位。我们探讨了如何将需求转化为技术方案,并介绍了关键的指导原则。通过本周的学*和实践,您将掌握一套工具,这套工具将在您数据工程旅程的各个阶段持续为您服务。




请与我一同进入下一个视频,开始深入学*。
040:什么是数据架构 🏗️

在本节课中,我们将要学*数据架构的基本概念,了解它如何融入更广泛的企业架构范畴,并探讨架构决策的核心原则——灵活性与可逆性。
在深入探讨数据架构的细节之前,我们先退一步,看看数据架构如何融入一个更广泛的背景,即企业架构。企业架构的定义本身可能有些模糊和抽象,业界对此没有明确的共识,不同团体对其定义各不相同。

在《数据工程基础》一书中,我们采用了以下定义:企业架构是通过仔细评估权衡后,做出灵活且可逆的决策,从而设计出支持企业变革的系统。你可能会想,我们上周在数据架构的背景下是否已经见过类似的定义。
是的,你的想法正确。事实上,上周看到的数据架构定义是:数据架构是通过仔细评估权衡后,做出灵活且可逆的决策,从而设计出支持企业不断演变的数据需求的系统。
鉴于这两个定义的相似性,你可以看出数据架构与企业架构高度一致,并融入其背景中。实际上,企业架构包含多个领域,你可以将这些领域视为四个主要部分。
以下是企业架构包含的四个主要领域:
- 业务架构:适用于企业的产品或服务战略及商业模式。
- 应用架构:描述服务于业务需求的关键应用程序的结构与交互。
- 技术架构:涉及支持业务系统和应用程序部署所需的软硬件技术组件。
- 数据架构:正如你所见,它完全关乎支持企业不断演变的数据需求。
因此,你可以将数据架构视为企业架构的一个组成部分。这样,你就能开始理解,作为一名数据工程师,你的工作如何直接与组织的最高层目标和结构联系起来。
由于组织的结构可能随时间变化,这引出了另一个重要概念——变更管理,它正是企业和数据架构的核心。你可以预期组织的需求会不断演变,而你的数据架构需要适应这些变化。
亚马逊前首席执行官杰夫·贝佐斯提出了“单向门”与“双向门”的概念,适用于组织内所做的任何决策。单向门决策几乎无法逆转,门在你身后关闭并锁上,无法返回。


这个概念的一个简单例子可以这样理解:如果你打碎一个鸡蛋来烹饪,之后无法改变主意再将鸡蛋复原。因此,打碎鸡蛋是一个单向门决策。
就组织而言,例如,亚马逊本可以在某个时刻决定出售其AWS及所有云服务,或者直接关闭它。采取此类行动后,亚马逊几乎不可能重建一个具有相同市场地位的公共云。
另一方面,双向门是易于逆转的决策。你可以走过这扇门,如果喜欢所见,可以留下;如果不喜欢,可以走回来。


例如,在选择如何在S3这类对象存储系统中存储数据时,你可以根据性能、数据访问和成本需求,从一系列存储类别中进行选择。一个双向门决策的例子是:如果你选择将数据存储在S3的标准存储类别中,之后若存储需求发生变化,你可以付费过渡到任何其他存储类别。因此,这个决策是可逆的。


由于每个双向门决策的风险通常较低,组织可以更容易地做出更多此类可逆决策,快速迭代并改进其收集、使用和存储数据的方式。
灵活且可逆的决策制定是企业和数据架构的核心。在你的架构中尽可能追求双向门决策,你将能更好地应对组织面临的变革。
如果你发现自己面临看似单向门的决策,看看能否将其分解为一系列较小的决策,其中每个独立决策都是一个双向门。
因此,架构不仅仅是规划业务流程或数据流程,并模糊地展望遥远的乌托邦式未来。架构师需要积极解决业务问题并创造新机会。如果你在数据工程师的角色中像架构师一样思考,你构建的技术解决方案将不仅仅为了存在而存在,而是直接支持业务目标。

接下来,我们将探讨良好数据架构的原则。但在那之前,我想强调一个影响所有数据系统架构的非常有趣的现象——康威定律。下一个视频是可选内容,我不会就此对你进行测试,如果你想跳过,完全可以。但我觉得如果不在这些课程中至少提及康威定律,那就是我的失职,因为我敢保证,这将影响你构建的系统类型。
本节课中,我们一起学*了数据架构的定义及其在企业架构中的位置,理解了“单向门”与“双向门”决策的核心概念,并认识到灵活、可逆的决策对于构建能够适应变化的稳健数据架构至关重要。
041:康威定律 🏛️

在本节课中,我们将学*一个对任何系统架构都至关重要的指导原则——康威定律。理解这一定律将帮助你分析组织沟通结构如何影响其数据系统的设计。
在之前的课程中,我们讨论了适用于不同场景的各种原则和架构模式。本节中,我们来看看一个普遍适用的、至关重要的指导原则。
这个原则被称为康威定律。其提出者梅尔文·康威对此的最佳描述是:任何设计系统的组织,其产生的设计在结构上都是该组织沟通结构的副本。
这听起来可能像是一个奇怪的断言,但它在实践中是这样运作的:
想象一家公司有四个不同的部门:销售、市场、财务和运营。
以下是这些部门可能的工作模式:
- 如果这些部门在相对孤立的“筒仓”中运作,他们的沟通模式也将是孤立和筒仓化的。
- 当涉及到构建数据架构和系统时,他们将不可避免地构建出相对孤立和筒仓化的系统。
换句话说,销售部门会开发一套数据系统,市场部门会构建另一套,财务部门是第三套,运营部门则是另一套系统。你应该明白了这个模式。
反之,如果同一组织中的这四个部门进行跨职能沟通、分享想法并在部门间协作,那么他们构建的数据系统将反映出这种跨职能协作与沟通的文化。
我意识到这可能听起来很奇怪,但尽管看似奇特,康威定律在所有类型的组织中都具有显著的一致性。
作为数据工程师,你需要记住的主要启示是:当需要理解哪种数据架构适合你的组织时,你首先需要关注并理解该组织的沟通结构。
甚至可以说,如果你试图构建一个与你公司沟通结构相冲突的数据架构,你注定会遇到麻烦。

如果你有兴趣了解更多关于康威定律的信息,我在本周结束时的资源部分提供了一个链接。
本节课中,我们一起学*了康威定律,它揭示了组织内部沟通结构与其所设计系统结构之间的深刻联系。理解这一定律是设计有效数据架构的第一步。

在下一个视频中,请与我一同深入探讨优秀数据架构的关键原则。
042:良好数据架构的原则 🏗️

在本节课中,我们将深入学*良好数据架构的九项核心原则。这些原则是构建高效、可靠数据系统的基础,我们将对其进行详细拆解,以帮助你理解如何在实践中应用它们。
上周我简要提到了在构建数据架构时需要牢记的九项原则。
为了帮助你回忆,这里再次列出它们。在本专项课程中,我们将反复回顾这些原则。本周的主题是数据架构,因此在深入探讨具体架构之前,我想花更多时间详细解释每一项原则。在某种意义上,这些原则彼此关联。
为了便于讨论,我将其分为三组。在我看来,第一组的两项原则共同点在于,它们都涉及数据架构如何影响组织内的其他团队和个人。第二组原则的核心观点是,数据架构是一个持续演进的过程,你的架构会随着时间发展而变化。第三组原则则像是一系列虽未明言但被普遍理解的优先事项,它们是任何数据架构的基础,即你需要为你构建的任何系统考虑成本、安全性、可扩展性和故障模式。
当然,你也可以用其他方式来组合或关联这些原则。
但在这里,我将按这三组进行讨论。在本视频中,我将讨论第一组原则,即关于数据架构如何影响组织内其他团队和个人的原则。在接下来的几个视频中,我们将探讨另外两组原则。
明智选择通用组件与架构即领导力 👥

以下是第一组原则:明智选择通用组件和架构即领导力。数据架构师的主要职责之一,以及作为数据工程师可能承担的部分工作,就是选择能在组织内广泛使用的通用组件和实践。通用组件可以是任何在组织内具有广泛适用性的东西。
这包括对象存储、版本控制系统、可观测性监控与编排系统以及数据处理引擎等。云平台是采用通用组件的理想场所。
例如,云数据系统中计算与存储的分离意味着,你可以通过一个共享的存储层为组织内的不同团队提供数据服务,允许用户根据其特定用例查询数据。当你明智地选择通用组件时,它们将成为组织架构的一部分,促进团队协作并打破数据孤岛。
这并不是说总会存在能为每个团队提供完美解决方案的通用组件。明智地选择通用组件意味着识别那些团队能从使用相同数据工具和实践中受益的用例,同时避免因盲目采用“一刀切”的方法而在数据系统中制造生产力障碍。

作为数据工程师,你可以通过与组织成员协商,识别正确的通用组件来实践架构领导力。随着你资历渐深、承担更多责任。
你可能会成为指导他人并为这些组件提供适当培训的人。正如我之前所说,作为数据工程师,我也建议你向组织内或其他地方的数据架构师寻求指导,因为最终你很可能会担任架构师的角色。

在下一节中,我们将探讨第二组原则,这些原则关乎如何在你的架构中构建灵活性。
043:持续架构与API设计原则 🏗️

在本节课中,我们将学*数据架构中关于决策可逆性和系统设计的重要概念。我们将探讨“单向门”与“双向门”决策的区别,并深入了解亚马逊的“API强制令”如何塑造了现代松散耦合系统与云服务的基础。
在之前的视频中,我提到了“单向门”和“双向门”的概念。
“单向门”代表那些难以或无法逆转的决策,而“双向门”代表可逆的决策。
围绕可逆决策构建的系统允许你“持续进行架构设计”。我想提出来自亚马逊的另一个概念。
即所谓的“API强制令”,它源自杰夫·贝佐斯在2002年发给所有亚马逊员工的一封电子邮件。你可以通过本周课程末尾资源部分的链接阅读更多关于此强制令的细节。
但此强制令的要点是:所有团队必须使用服务接口(也称为应用程序编程接口或API)进行通信,并提供数据和功能。
该强制令最后,杰夫·贝佐斯表示,不遵守此规定的人将被解雇。由此可见他对亚马逊API概念的重视程度。
这意味着,无论任何特定团队在其自身系统中处理多么复杂的混乱情况,他们都必须向其他团队提供任何数据、功能和通信。
一个稳定且可预测的服务接口。
这使得亚马逊的各个团队能够作为一个松散耦合的系统协同工作,各个团队通过这些服务接口相互连接,并且任何团队内部的重组或工具更换都不会影响其他团队。
API强制令的另一部分是,所有这些服务接口或API都必须从一开始就设计为最终能够对外部世界的开发者公开。
这种向服务接口的重新定位,为最终成为亚马逊网络服务(AWS)奠定了基础,而AWS如今已被世界广泛用作云平台。
因此,在接下来的这组原则中,我们要做出可逆的决策。
构建松散耦合的系统,并持续进行架构设计。
正如你已经知道的,那些可逆的决策就是你的“双向门”。如果你不喜欢结果,可以轻松撤销的决策。
确保你的决策可逆的一个关键方法是,用松散耦合的组件构建你的数据系统。
在架构的语境中,所谓“松散耦合”,我指的是那些可以相对容易地替换,而无需重新设计整个系统的组件。
当一个系统由松散耦合的组件和可逆的决策构建而成时,你将始终拥有“持续进行架构设计”的能力。
正如我们已经谈到的,数据架构需要支持组织不断发展的数据需求。
这意味着数据架构本身也必须能够演进。
作为一名数据工程师,你的工作不仅是构建满足组织当前数据需求的系统,还要着眼于未来,以便能够不断适应业务需求的变化。
以及可用技术的变化。
在下一个视频中,请与我一起探讨最后一组原则。
重点关注在理解你所构建系统的成本、安全性、可扩展性和故障模式时的最佳实践。

本节课中,我们一起学*了数据架构中的关键设计原则。我们理解了“可逆决策”(双向门)的重要性,以及如何通过构建“松散耦合”的组件系统(例如通过定义良好的API)来实现这一点。这种以服务接口为中心、支持持续演进的设计思想,不仅是现代云平台(如AWS)的基石,也是每一位数据工程师构建灵活、健壮且面向未来的数据系统时应遵循的核心准则。
044:系统故障应对 🛡️


在本节课中,我们将学*如何为数据系统可能出现的故障做好准备。我们将探讨几个关键原则:为故障做计划、为可扩展性设计架构、优先考虑安全性以及拥抱FinOps(财务运营)。理解这些概念将帮助你构建不仅功能强大,而且在面对意外时依然稳健的系统。
除了构建满足利益相关者需求、打破团队间壁垒并能随组织需求变化而演进的数据系统外,如果这还不够,你还需要预见当事情出错时会发生什么。请相信,事情总会出错。在接下来的这组原则中,我计划为故障做好准备:为可扩展性设计架构、优先考虑安全性以及拥抱FinOps。
量化评估系统故障模式 📊
上一节我们介绍了为故障做计划的总体原则,本节中我们来看看如何具体量化评估系统的故障模式。
对于系统中的故障模式,最好采取务实和量化的方法,就像你对待系统性能的任何其他方面一样。因此,我们现在需要更明确地定义描述系统指标术语的含义,例如数据系统的可用性、可靠性和持久性。
以下是几个核心系统指标的定义:
- 可用性:通常称为正常运行时间,是指服务或组件预期处于可操作状态的时间百分比。例如,查看Amazon S3对象存储的不同存储类别,你会发现它们的年可用性范围从99.5%到99.99%。99.5%和99.99%听起来都是高可用性,甚至数字很相似,但请记住,99.5%的年可用性意味着你的存储系统每年预计会有大约44小时不可用,而99.99%的可用性意味着每年预计只有大约1小时的停机时间。不幸的是,100%的可用性永远无法保证,因为故障场景可能包括意外的停电或网络设备故障。但根据系统的需求,你可以选择具有所需可用性的存储类别。
- 可靠性:与可用性类似,但它是指在明确定义的性能标准内,特定服务或组件在给定时间间隔内执行其预期功能的概率。
- 持久性:指存储系统承受因硬件故障、软件错误或自然灾害导致数据丢失的能力。在云环境中,持久性至关重要,因为企业依赖云服务来存储和访问关键数据。例如,Amazon S3宣称具有极高的持久性,达到99.999999999%(11个9),这意味着Amazon S3中对象丢失的情况极为罕见。
与可用性、可靠性和持久性相关的概念还有恢复时间目标(RTO)和恢复点目标(RPO)。
- 恢复时间目标:是你的服务或系统中断可接受的最长时间。为你的应用程序建立RTO时,你需要考虑该应用程序不可用对内部和外部客户的影响,然后你可以据此选择满足此目标的S3存储类别。
- 恢复点目标:定义了恢复后可接受的状态。例如,对于数据存储系统,RPO可能指你的系统可以容忍的最大可接受数据丢失。
为你构建的系统明确制定RTO和RPO,将帮助你选择具有适当可用性、可靠性和持久性规格的组件来满足需求。这是“为故障做计划”的一个方面。

安全漏洞与零信任模型 🔐
你的系统可能失败的另一种方式是通过安全漏洞。这就是为什么“为故障做计划”的原则与“优先考虑安全性”的原则是齐头并进的。我们已经讨论过培养安全文化和最小权限原则。
这里我还想介绍所谓的零信任安全。要理解零信任的核心,先看看你可能称之为更传统安全方法的东西会很有用,即强化边界安全。采取强化边界方法相当于在你的系统周围建造一堵高墙,墙外的所有人和事物都是不受信任的,而墙内的所有人和事物在访问敏感数据和系统方面都是受信任的。强化边界方法的问题在于,攻击者只需突破这堵墙,就能获得对你所有数据和系统的无限制访问。在云时代,构建强化边界还有一个额外问题,即数据与系统通过互联网连接,实际上并不存在物理边界。相比之下,零信任意味着每个操作都需要身份验证。

你构建系统的方式应确保没有任何人或应用程序(无论是内部还是外部)被默认信任,相反,访问权限仅在需要时才被授予。
成本失控与可扩展性失败 💸
当发生诸如产生不可预见的高额成本或错失收入机会等情况时,你的系统也可能失败。
例如,在不可预见的成本方面,我指的是意外运行昂贵的云服务,导致你整个年度的预算在一个月或更短时间内被消耗殆尽。信不信由你,我见过很多这种情况发生。相反,错失的机会可能是你的产品需求突然激增,而你的整个系统因为未能做好快速扩展的准备而崩溃。因此,从这个意义上说,“拥抱FinOps”和“为可扩展性设计架构”的原则与“为故障做计划”的原则是相连的。
作为数据工程师,你需要考虑云系统的成本结构。例如,在运行分布式集群时,AWS按需EC2实例与Spot实例(顺便说一下,Spot实例是AWS上以大幅折扣提供的闲置EC2实例)的适当混合比例是什么?在成本效益和性能方面,运行一个规模可观的日常作业最合适的方法是什么?在云时代,大多数数据系统都是按需付费且易于扩展的,系统可以按查询成本模型、处理能力成本模型或其他按需付费模型的变体运行。现在可以为了高性能而扩展,然后为了省钱而缩减。然而,按需付费的方法使得支出更加动态,因此数据工程师面临的新挑战是在构建和维护系统时管理预算、优先级和效率。
课程总结 📝



本节课中我们一起学*了为数据系统故障做准备的几个核心原则。主要要点是,如果你为故障做计划、为可扩展性设计架构、优先考虑安全性并拥抱FinOps,你将能更好地满足组织的需求,不仅在你构建的系统按预期运行时如此,在故障发生时也是如此。
接下来,我们将深入探讨针对不同类型数据系统的一些具体架构方法的细节。请在下一个视频中与我一起仔细了解批处理架构。
045:批处理架构 🏗️

在本节课中,我们将深入学*批处理架构。这是数据处理的一种传统方法,涉及以批次或块的形式进行数据摄取、转换和存储。我们将探讨其核心概念、常见模式以及设计时需要考虑的关键原则。
上周我们简要介绍了数据摄取背景下的批处理与流处理概念。现在,我们将聚焦于这些概念如何体现在一些成熟的数据工程架构模式中。
本节的目标是让你思考不同架构选择所带来的权衡与影响。
在本视频中,我们将详细审视批处理架构。在下一个视频中,我们将探讨流处理架构。
什么是批处理架构?📦
批处理架构是数据处理的传统方法。在这种架构中,你以批次或数据块的形式进行数据摄取、转换和存储。
当实时分析并非关键需求时,批处理最为实用。通常,一个数据批次包含在某个固定时间段内收集的数据,例如一天。
例如,在一家电子商务公司,数据分析师可能希望按日分析特定产品的销售历史。因此,你可以建立一个批处理架构,每天一次性地摄取和处理这些数据。

典型批处理流程:ETL与ELT 🔄
那么,这可能是什么样子呢?这可能是所谓的提取-转换-加载或ETL管道的开端。

以下是其基本步骤:
- 首先,从一个或多个数据源提取数据批次,可能存入一个暂存区。
- 然后,应用一些转换来清理、标准化和建模数据。
- 最后,将数据加载到数据仓库中进行存储和提供服务。
这个模式还有一个变体,称为提取-加载-转换或ELT。
在ELT中,思路是在摄取数据后,先将其加载到数据仓库中,然后直接在数据仓库内部执行转换。
鉴于许多现代云数据仓库和其他存储抽象层计算能力的扩展,这种ELT架构或模式如今正变得越来越流行。
下游用例与数据服务 🎯
接下来,无论你使用ETL还是ELT架构,你都需要为下游用例提供数据服务,这些用例通常体现在数据仓库的右侧。
这些用例通常是分析或机器学*。但正如我之前提到的,另一种可能性是你的最终用例是所谓的反向ETL,即执行一些分析,然后将处理后的数据实际发送回数据管道起点的源系统。
你还可以在数据仓库和最终用例之间添加一个额外的层,称为数据集市。
数据集市是数据仓库的一个更精细的子集,专注于特定的部门、职能或业务领域。它旨在服务于分析和报告。
例如,你可以有一个专注于销售的数据集市,另一个用于市场营销,还有一个用于运营。这种设置可以使分析师和需要创建报告的人员更容易地访问数据。

通过数据集市,你还可以在初始ETL或ELT管道提供的转换之外,提供额外的转换阶段。这些额外的转换可能包括表之间的额外连接或聚合,有助于提高实时查询的性能。

设计批处理架构的考量 🤔
以上是一些典型的批处理架构示例。
如果你正在为你的组织建立这样的架构,那么根据良好数据架构的原则,有许多事情需要考虑。
以下是几个关键考量点:
- 协作与互操作性:如果你为不同的团队或部门服务多个最终用例,你如何为数据仓库和数据管道选择通用组件,以促进团队间的协作和互操作性?
- 故障规划:在规划容错时,你需要思考如果源系统离线或上游数据模式发生变化会发生什么。与源系统所有者建立联系是构建能够处理源变更的系统的良好第一步。
- 组件可靠性:你需要查看管道中每个组件的可用性和可靠性规格。
- 系统灵活性:你需要弄清楚如何构建系统的灵活性。例如,如果你决定稍后更改摄取频率,或者你预计每批数据的量会随时间发生巨大变化。
- 成本效益分析:为了拥抱灵活性,你还需要进行一些成本效益分析,以了解在系统不同组件的性能方面可能需要考虑哪些权衡,以及在不同场景下你能为业务提供何种价值。

我们将在整个课程中牢记这些原则。请记住,在构建数据系统时,你选择的技术总会带来一系列风险,同时也带来能为组织增加价值的机会。

总结 📝
本节课中,我们一起学*了批处理架构。我们了解到批处理是一种按固定周期处理数据块的传统方法,适用于非实时分析场景。我们探讨了其核心流程,包括ETL和ELT两种主要模式,并介绍了数据仓库、数据集市和反向ETL等下游服务概念。最后,我们讨论了设计批处理架构时需要权衡的关键原则,如协作性、可靠性、灵活性和成本效益。

接下来,我们将看看一些常见的流处理架构。下个视频见。

046:流处理架构 🚀

在本节课中,我们将要学*流处理架构的基本概念、发展历程以及现代数据工程中如何统一处理批数据和流数据。我们将从数据产生的本质出发,探讨流处理系统的构成,并介绍几种关键的架构模式。
正如上周所提到的,你可以将数据视为由一系列事件产生的。这些事件可能是网站点击、传感器测量或其他活动。
从这个意义上说,在数据源头,几乎所有数据都可以被描述为这种事件的连续流。也就是说,数据通常是以连续的方式产生和更新的。
我们上一节视频探讨了批处理数据管道。在批处理中,你需要等待数据积累,然后在预定义的时间间隔或数据达到特定大小阈值时,处理一批数据。因此,你只是以一系列数据块的形式处理数据流。
另一方面,在流处理数据管道中,你以连续、*实时的方式摄取数据并提供给下游系统。这里所说的“*实时”,意味着数据产生后(可能不到一秒)很快就能被下游系统使用。
最简单的流处理系统可以看作由生产者、消费者和流处理代理组成。
以下是其核心组件:
- 生产者是数据源。这可能是来自应用程序的点击流数据,或来自物联网设备的测量数据。
- 消费者可以是处理数据的服务或应用程序,也可以是数据湖或数据仓库。
- 流处理代理位于生产者和消费者之间,协调两者之间的数据流动。
消费者的下游可能是一些实时分析或机器学*用例。
在2010年代早中期,随着Kafka作为高可扩展事件流平台的出现,以及Apache Storm和SAMza等用于流处理和实时分析的其他框架的兴起,处理流数据的普及度激增。这些技术使公司能够对大量数据执行新型分析和建模,例如用户聚合、排名和产品推荐。
这种对流数据解决方案的新需求并不意味着批处理消失了。相反,它意味着数据工程师需要弄清楚如何将批处理和流数据统一到一个架构中。
Lambda架构是早期应对此问题的流行方案之一。在Lambda架构中,批处理、流处理和服务系统彼此独立运行。源系统同时将数据流式传输到两个目的地:一个用于流处理(处理后的数据可能存储在NoSQL数据库中),另一个用于批处理(可能使用数据仓库来转换和存储处理及聚合后的数据以进行分析)。该架构中的服务层通过聚合来自批处理层和流处理层的查询结果,提供统一的视图。
我在这里提到Lambda架构,只是希望你了解它。但这种架构带来了各种挑战和问题,例如管理具有不同代码库的并行系统等。在许多方面,技术和实践已经超越了Lambda架构,但Lambda架构仍然是后来这些流处理架构设计和工具的一个良好参考点。

上一节我们介绍了Lambda架构及其挑战,本节中我们来看看为解决这些缺点而提出的另一种架构。
作为对Lambda架构缺点的回应,Apache Kafka的原始作者之一J. Kreps提出了一种名为Kappa架构的替代方案。
Kappa架构的核心思想是使用流处理平台作为所有数据处理(摄取、存储和服务)的支柱。这促进了一种真正的基于事件的架构。这意味着,与其等待系统定期检查更新,不如在事件发生、数据产生时,自动将信息发送给需要更新的相关消费者,以便这些消费者能更及时地对信息做出反应。
以流处理平台为支柱,你可以通过读取实时事件流来应用实时处理。同时,你可以配置流处理器在从实时流读取时保留一定量的历史数据。这实际上允许你在需要时,通过重放保留数据中的大块数据,对同一数据流应用批处理。
虽然Lambda架构已不再流行,而Kappa架构也从未被广泛采用,但这两种架构都为克服统一批处理和流数据处理这一核心挑战提供了灵感和基础。管理批处理和流处理的核心问题之一就是统一多个代码路径。

前面我们了解了早期统一批流处理的尝试,现在来看看现代数据工程是如何解决这个问题的。
如今,工程师们通过几种方式寻求解决这个问题。谷歌开发了数据流模型以及实现该模型的Apache Beam框架。
数据流模型的核心思想是将所有数据视为事件。正在进行的实时事件流包含无界数据,而数据批处理则只是有界的事件流。边界提供了一个自然的窗口。因此,实时处理和批处理可以在同一个系统中使用几乎相同的代码进行。

Apache Flink和其他流处理工具如今被广泛使用。我们将在本课程中探讨这些及类似的工具。在当今的数据工程中,“批处理是流处理的一种特例”这一理念比以往任何时候都更加普遍。



在你的数据工程师工作中,可以预期会遇到管理批处理和流处理管道的挑战。面对这些挑战时,在选择系统组件时,你需要将良好数据架构的原则放在首位。
为灵活性和可扩展性而构建,并预见潜在的故障模式。无论你构建何种系统,都需要考虑的一件事是合规性。简而言之,合规性意味着确保你的数据系统符合法律、法规以及你自己组织的隐私协议和服务条款政策。
请与我一起进入下一个视频,讨论为合规性而设计的架构。
047:数据工程合规性架构 🏛️ | 课程 1-2-3, P47

在本节课中,我们将探讨数据工程中一个至关重要但常被忽视的方面:合规性架构。我们将了解为什么遵守法规对数据系统至关重要,以及数据工程师在其中扮演的角色。
在开始之前,需要明确指出,法规遵从性可能是这些课程中最枯燥的话题。没有人真的想讨论法律和法规,尤其是在我们可以讨论处理数据和使用酷炫技术的时候。然而,如果完全不讨论法规遵从性如何融入你作为数据工程师的角色,那将是一种失职。这主要是因为,你的数据系统最惨烈的失败方式之一,就是违反法规,导致你的组织被起诉并遭受巨额罚款。这种情况确实会发生。
那么,这里讨论的是哪些法规呢?一个重要的法规是 《通用数据保护条例》,简称 GDPR,于2018年在欧盟颁布。简而言之,GDPR旨在保护个人的隐私和个人数据。但GDPR下“个人数据”的定义相对宽泛,不仅包括个人身份信息,还包括其他可共同用于识别个人身份的信息。
为了符合GDPR,你需要确保从数据收集对象那里获得了适当的同意,并且如果个人希望将其数据从你的系统中删除,你能够及时删除数据。

现在,你可能会想,如果我的公司不在欧盟,或者我们不服务于欧盟的客户呢?从技术上讲,是的,你的公司和客户所在地至少会在一定程度上决定这些法规是否适用于你。然而,自GDPR颁布以来,全球数十个国家以及美国各州都采用了类似的法规。
作为数据工程师,你将负责构建不仅符合当今法规,也符合未来法规的系统。这些新法规可能在你当前运营的地区颁布,也可能在你公司未来扩展到的、已有法规的地区实施。保持系统更新以符合适用于你业务的法规,将是你的责任。
明智的做法是,构建符合现代数据保护法规(如GDPR)的系统,即使你当地的法规不那么严格;同时构建灵活、松散耦合的系统,以便你能适应法规的变化。
除了公司和客户所在地,你所在的行业也可能有自己的一套法规。例如,如果你在美国处理医疗保健数据,你需要遵守 《健康保险携带和责任法案》,即 HIPAA法案,该法案涉及敏感的患者数据。全球许多国家也针对医疗数据颁布了类似法律。

或者,如果你在组织中处理金融数据,你需要遵守美国的 《萨班斯-奥克斯利法案》 或其他地方的类似法律,这些法律规定了特定的财务报告和记录保存实践。
因此,这里的主要结论是,无论你身处世界何处,或从事哪个行业,都有适用于你作为数据工程师所构建系统的法律和法规。你能为组织创造价值的一种方式,就是避免因未能遵守必要法规而引发的诉讼和罚款。
在这些课程的其余部分,我们不会花太多时间讨论法规遵从性的细节,但至少希望让你意识到作为数据工程师角色的这一方面,以便你能将其与良好数据架构的其他原则一起牢记在心。

在下一课中,我们将探讨如何为你的架构选择合适的技术。我们下节课见。
本节课总结:我们一起学*了数据工程中合规性架构的重要性。核心在于,数据工程师必须构建符合 GDPR、HIPAA 等法规的系统,无论公司所在地或行业如何。关键在于设计灵活、松散耦合的架构,以适应不断变化的法规环境,从而避免法律风险并为组织创造价值。
048:选择工具与技术 🛠️
在本节课中,我们将学*如何为数据架构选择合适的工具与技术。上一节我们介绍了良好数据架构的设计原则及其重要性,本节中我们来看看如何将这些原则转化为具体的技术选型决策。
数据工程领域从不缺乏可用的工具与技术。事实上,数据工程师常常面临“选择过多”的困境。无论是数据摄取、存储、转换还是服务提供,你都会面对开源、托管开源、专有软件、服务等多种选项。面对这些决策时,必须牢记最终目标:交付满足最终用户需求的高质量数据产品。
换句话说,数据架构定义了实现业务数据需求的内容、原因和时机,而选择的工具与技术则是实现该架构的方法。你可能会认为,选择能带来成功结果的工具是理所当然的。然而,这个过程中存在许多可能出错的地方,这正是本节课要讨论的内容,以确保你为成功做好准备。
我们将首先探讨部署位置,即在本地、云端或某种混合模式之间构建系统的权衡。接着,我们将研究成本优化,并思考是自行构建工具还是购买现成解决方案,这需要考虑团队规模、能力以及真正驱动业务价值的活动类型。我们还将讨论如何既满足当前需求,又着眼于组织未来的潜在需求。所有这些讨论都将基于上一课介绍的良好数据架构原则以及上周学*的数据工程生命周期的潜在主线进行。
以下是本节课将涵盖的主要方面:
- 部署位置:分析在本地、云端或混合环境中部署系统的优缺点。
- 成本优化:评估自建工具与购买现成解决方案的成本效益,考虑团队能力和核心价值活动。
- 当前与未来需求:探讨如何在满足现有需求的同时,为未来可能的变化做好准备。
在接下来的视频中,我们将开始深入探讨这些内容。


本节课中,我们一起学*了为数据架构选择工具与技术的关键考量。我们明确了工具选择是实现架构目标的手段,并概述了在部署位置、成本优化以及平衡当前与未来需求时需要权衡的主要因素。下一节我们将具体分析不同部署位置的利弊。
049:本地部署与云数据系统 🏢☁️

在本节课中,我们将要学*数据系统部署的两种主要方式:本地部署系统和云数据系统。我们将了解它们各自的特点、优势以及现代行业的选择趋势。
本地部署系统时代
不久以前,大约就在二十年前,构建本地部署的数据系统是满足任何数据存储或处理需求的唯一选择。
这仅仅是因为现代云数据平台当时尚未出现。一个本地部署系统是指公司拥有并维护整个数据栈的硬件和软件。
这意味着公司需要负责运营,包括配置、维护、更新以及运行在其上的硬件和软件的扩展。
云数据系统的兴起
如今,许多公司在云上构建其整个数据系统。对于云数据系统,云服务提供商(例如 AWS)负责构建和维护硬件与数据中心以满足客户需求。

如果你在云上构建数据系统,你本质上是在租用系统所需的计算和存储资源。云计算和存储的好处在于,你可以轻松扩展以满足需求,或在不需要时缩减规模以节省成本。你无需维护或配置任何硬件,并且可以相对容易地改变系统中想要使用的工具或技术类型。
当前部署模式的选择
现在,许多公司选择完全在云上构建数据系统,而其他公司仍然维护本地部署系统,或采用某种混合系统,即部分组件在本地,部分在云端。
行业的势头无疑正朝着更多公司选择云而非本地数据系统,或从本地迁移到云的方向发展。这是因为云在灵活性和可扩展性方面提供了所有显而易见的优势。
然而,有些公司由于业务性质、法规、安全或客户隐私考虑,选择或必须将其部分或全部数据系统保留在本地。
对数据工程师的意义

作为一名当今的数据工程师,你可能会在一家拥有部分本地系统的公司工作,或者一家正在从本地迁移到云的公司工作。在这些课程中,我们将专注于在云上构建数据系统。
这是因为对于当今绝大多数商业用例而言,在云上构建数据系统是最佳选择。行业正朝着更多云、更少本地部署的方向发展。作为一名有抱负的数据工程师,我相信你最好将时间花在学*如何在云上构建数据系统。
本节课中我们一起学*了数据系统从本地部署到云端的演变历程,理解了两种模式的核心区别与各自的适用场景。下一节,我们将探讨软件与数据工程领域的另一个趋势:从单体架构向模块化系统的转变。
050:单体架构 vs 模块化架构 🏗️
在本节课中,我们将探讨数据工程中的一个核心概念:单体架构与模块化架构的区别。理解这两种架构模式的特点、优势与劣势,对于设计和构建灵活、可维护的数据系统至关重要。
概述
当我们讨论那些包含硬性依赖、灵活性有限的系统,与那些松散耦合、灵活性高的系统时,数据工程中另一个需要简要提及的概念是单体架构与模块化架构的理念。
单体架构 🧱
上一节我们提到了系统设计的两种思路,本节中我们首先来看看单体架构。
单体系统是一种自包含的系统,由紧密耦合的组件构成。在软件开发中,单体架构作为技术主流已存在数十年,大型团队协作交付一个单一的工作代码库。该软件产品的所有组件代码会被构建并部署为一个单一的应用程序。
单体系统的一个优势是简单性。所有功能都集中在一个地方,这意味着单体系统易于理解。你无需处理数十或数百种技术,通常只需面对一种技术和一种主要的编程语言。因此,如果你追求架构和流程的简单性与可推理性,单体架构是一个绝佳的选择。
然而,随着单体系统的增长,其维护也变得非常困难。由于单体系统由紧密耦合的组件组成,如果你需要更新一个组件,可能不得不更新其他组件,甚至常常需要重写整个应用程序。
例如,我曾为一家公司工作,他们有一个单体ETL管道,运行一次至少需要48小时。如果这个管道的任何地方出现问题,整个管道流程都必须重新启动。与此同时,下游焦急的业务用户等待着报告,这些报告默认已经延迟了两天,并且常常到得更晚。负责该管道的团队迫切希望替换它,但这将导致整个系统停机数周。因此,他们只能勉强维持,接受次优的性能,因为更新系统的任务过于艰巨且成本高昂。
以下是单体架构的核心特点总结:
- 紧密耦合:组件间依赖性强。
- 统一部署:所有功能作为一个整体构建和发布。
- 初期简单:技术栈单一,易于理解和推理。
- 难以维护:随着系统增长,更新和扩展成本高昂。


模块化架构 🧩
了解了单体架构的局限性后,我们来看看另一种设计思路:模块化架构。
相比之下,模块化系统由松散耦合的组件构成。它不是依赖一个结合了应用程序所有功能的大单体,而是依赖于将应用程序分解为自包含的关注领域。在软件开发中,真正的模块化系统随着微服务的兴起而出现。
在微服务架构中,与将对应多个服务的组件组合成一个单一的可部署实体不同,每个服务都作为一个独立单元进行部署。现代数据工程和数据处理技术已经转向模块化模型,为互操作性提供了强有力的支持。这意味着当今可用的大多数数据处理工具都可以轻松地与支持数据工程生命周期其他阶段的工具集成。
例如,以标准格式(如 Parquet)存储在对象存储中的数据,可以与任何支持 Parquet 格式的处理工具配对使用。随着技术发展而能够更换工具的能力是无价的。它通过支持灵活且可逆的决策以及持续改进,帮助你构建良好的数据架构。
以下是模块化架构的核心特点总结:
- 松散耦合:组件间独立性高。
- 独立部署:服务或组件可以独立更新和发布。
- 互操作性强:易于与其他系统或工具集成。
- 灵活可扩展:便于替换组件和持续改进架构。
后续课程展望
在接下来的课程中,我们将详细讨论为实现你的架构所需做出的各种选择细节。例如成本优化、选择开源还是商业解决方案等所有其他方面。我将继续从云优先和模块化的视角来阐述这些观点,因为我认为这是数据工程发展的方向。

总结

本节课中,我们一起学*了数据工程的两种核心架构模式:
- 单体架构:将所有功能紧密集成,初期简单但难以维护和扩展。
- 模块化架构:将系统分解为松散耦合的独立组件,强调灵活性、互操作性和易于演进。

理解这两种模式的权衡,是设计能够适应变化、支撑业务发展的健壮数据系统的关键第一步。请继续观看下一个视频,我们将深入探讨成本优化的相关策略。
051:成本优化与商业价值 💰
在本节课中,我们将学*数据工程生命周期中的成本考量。我们将探讨如何评估和优化数据系统的总成本,理解不同成本类型,并学*如何通过技术选择最大化商业价值。
在数据工程生命周期的每个阶段,你都需要从多种工具和技术中选择合适的方案来完成工作。
每一个选择都伴随着成本。这里所说的成本不仅指软件或服务的订阅价格标签。
还存在与实施相关的成本,即支付团队搭建和维护系统所需的时间成本。
此外还有机会成本,这意味着选择一种工具的同时,至少在短期内放弃了选择其他工具的机会。
因此,你的工具和技术选择将显著影响预算。作为数据工程师,你的职责是确保组织在数据系统上的投资能获得正向回报。
在本视频中,我们将通过三个主要视角来审视成本。首先聚焦于总拥有成本。之后快速了解总机会成本。最后将重新探讨我们上周简要提及的FinOps概念。
总拥有成本
总拥有成本是指一个解决方案、项目或计划在其整个生命周期内的总估算成本。
TCO这个术语并非数据工程专用,而是一个通用的商业术语,用于描述对某个项目的总投资,包括你所使用的产品和服务的直接与间接成本。
这包括硬件和软件的购置、管理维护和维修的成本,以及任何必要的培训费用。
对于数据系统而言,直接成本是指那些易于识别、可直接归因于数据产品开发的有形成本。
例如,你的直接成本包括参与该计划的团队薪资、所使用的所有AWS服务费用,以及任何软件订阅的许可费用。
你的间接成本,几乎可称为开销,是指那些不直接归因于数据产品开发的费用。
例如,这可能是由于网络停机、持续的IT支持或某些团队成员生产力损失所产生的成本。
在估算TCO时包含间接成本非常重要,因为这些成本可能相当可观。
硬件与软件成本分类
在硬件和软件成本方面,这些支出通常分为两大类。
第一类是资本性支出。Capex是为购买长期固定资产而支付的费用。在云平台出现之前,这类支出对于数据系统很常见。公司会预先支付一笔资金购买硬件和软件,然后将其安装在数据中心。这些通常高达数十万到数百万美元或更多的预先投资,会被视为Capex资产,并随时间慢慢折旧。
如今,随着向云的转变,许多公司构建数据系统时基本上实现了零Capex。
另一类主要成本是运营性支出。Opex是与日常运营相关的费用,因此是随时间分摊的。在数据系统中,Opex通常以按使用付费的形式出现,表现为定期订阅费或使用特定云服务的成本。
在对比本地构建与基于云的数据系统时,本地构建通常意味着巨大的Capex成本,而基于云的系统则几乎可以完全是Opex。在云平台出现之前,对于大型数据项目而言,以Opex为先的方法并不是一个真正的选项。随着云的出现,这种情况已经改变,因为数据平台服务允许你采用基于消费的模型进行支付。
数据项目的长期硬件投资 inevitably 会过时。因此,我建议你采取以云为中心的、Opex优先的方法,为你的数据管道选择灵活的按需付费技术。
总机会成本
与TCO相对,我称之为总机会成本。
这是指你选择特定工具或技术时所承担的、因失去其他机会而产生的成本。它更难量化,但其本质是,你做出的任何选择 inherently 排除了其他可能性。
如果你选择了包含特定技术组合的数据技术栈A来构建数据管道,那么你就选择了数据栈A的好处,而 effectively 排除了数据栈B、C等选项。
因此,在这种情况下,总机会成本就是被束缚在数据栈A上,而无法再从其他数据栈中获益所产生的成本。
如果数据栈A被证明是最佳选择,那么恭喜你,总机会成本 essentially 为零。
然而在现实中,数据工程工具和技术正在飞速发展。因此,即使你今天做出了最佳选择,未来仍然需要演进你的数据系统。
所以,如果数据栈A中某些曾是昨日最佳选择的组件如今已经过时,那么切换到不同组件或完全不同的技术栈就会产生相关成本。
构建灵活的系统
为了确保总拥有成本最小化,你需要构建灵活且松散耦合的系统,这些系统能够随着数据需求的变化以及工具和技术格局的演变而易于更新。
实现这一点的一种方法是预先识别数据管道中哪些组件最有可能发生变化。换句话说,将持久性技术与过渡性技术区分开来。
持久性技术是那些经受住时间考验的技术。在云存储中,这类技术包括对象存储和网络。另一个例子是SQL查询语言,它已经存在数十年,并且短期内不会消失。
过渡性技术,或者至少那些最可能具有过渡性质的,是那些处于前沿、崭新且处于数据技术栈中快速演进的领域的技术,例如流处理、编排和AI。
FinOps与成本优化
在成本优化的背景下思考技术选择时,FinOps作为一个概念与TCO和TOCO密切相关。
FinOps旨在最小化与你的数据系统相关的成本,同时最大化你创造收入的机会。
那么如何做到这一点呢?简而言之,你可以选择基于云的服务,这些服务允许你采用Opex优先的方法,使用灵活的按需付费技术,以及提供模块化选项,使你能够迭代、改进和增长。
总结
本节课我们一起学*了数据工程中的成本考量。我们探讨了总拥有成本及其直接与间接成本的构成,区分了资本性支出和运营性支出。我们还引入了总机会成本的概念,理解了技术选择带来的隐性代价。最后,我们了解了FinOps的理念,即通过选择灵活的云服务和模块化架构,在最小化TCO和TOCO的同时,最大化商业价值。关键在于构建能够适应变化的系统,区分持久性与过渡性技术。

接下来,我们将更深入地探讨在优化成本的同时选择正确工具和技术的主题。

请在下一个视频中与我一起,看看自建数据系统组件与购买现成解决方案之间的权衡。
052:自建 vs 购买 🛠️ vs 🛒

在本节课中,我们将探讨在构建数据架构时,如何权衡“自建”与“购买/使用现有服务”这两种策略。我们将分析各自的适用场景、成本考量以及如何为你的团队和组织做出最佳选择。
到目前为止,我们一直在讨论为你的架构选择工具和技术。我强调过,对于绝大多数公司而言,在云端使用灵活的按需付费服务通常是上佳之选。对于对象存储这类常见服务,使用亚马逊S3这样的云服务是比尝试自建定制化对象存储方案好得多的选择。
然而,根据你系统的需求,可能有些工具或技术需要你自行构建和定制。例如,许多团队选择在开源框架之上进行构建,以获得恰好符合他们需求的解决方案。在其他情况下,团队可能会选择自建解决方案或定制开源框架,以避免许可费用,或仅仅是为了避免受制于某个供应商。

数据工程生命周期中的选择范围
上一节我们提到了自建方案的适用场景,本节中我们来看看在数据工程生命周期的各个阶段,你实际上都面临着一系列工具和技术选择。
事实上,对于数据工程生命周期的几乎所有阶段,在选择工具和技术时你都会有一系列选项。当然,对于任何你需要的工具,你都可以从头开始构建。在某些情况下,如果你尝试做一件前人未做过的事情,这可能是你唯一的选择。
但对于大多数情况,除非你确信没有现成的解决方案能满足你的需求,否则不建议这样做。在已有现成解决方案的情况下,从头开始构建技术无异于“重新发明轮子”,我通常将这类活动称为“无差异的重体力劳动”。
这意味着这是艰苦的工作,并且最终可能不会为你的组织增加价值。
现有解决方案的类型
在考虑是否自建之前,了解有哪些现有解决方案可供选择至关重要。
当涉及到现有解决方案时,它们包括完全开源的选项,以及来自供应商的商业开源选项(本质上是某些开源工具的托管版本),此外可能还有专有的非开源软件和服务可供选择。
选择时的关键考量参数

以下是选择这些选项时需要考虑的一些关键参数。
首先,如果你选择完全开源的解决方案,你的团队是否有足够的精力和能力来实施和维护该系统?许多开源工具都有强大的社区支持,你可以在需要时获得帮助。但如果你是一个小团队,甚至只有一个人,那么托管开源或专有服务可能更适合你的需求。因为这可以让你腾出精力来构建和管理整个数据系统,而不会陷入部署和维护单个组件的泥潭。
其次,即使你的团队确实拥有从头构建和实施开源解决方案的专业知识和精力,这真的值得吗?表面上看,自己构建或使用开源解决方案似乎能节省成本,因为你避免了许可费用。但正如我们在之前的视频中讨论过的,总拥有成本远不止许可费用。它还包括构建和维护系统所需的团队成本。
除了成本,另一个需要考虑的重要点是,构建和维护一个定制或开源解决方案是否真的能为你的组织提供价值。换句话说,与使用托管服务相比,自建系统或使用开源方案是否能带来某些优势?还是说这仅仅是“无差异的重体力劳动”,即不提供任何额外价值的艰苦工作?
给团队的建设性建议

对于大多数团队,特别是正在构建数据管道并纠结于是自建、使用开源还是购买的小团队,以下是我的建议。
我的建议是,首先查看开源或商业开源解决方案。如果无法满足需求,再考虑购买专有解决方案。无论哪种情况,都有大量优秀的模块化服务可供选择。这将使你的团队能够专注于为组织提供最大价值的独特机会。
本节课中,我们一起学*了在数据工程中“自建”与“购买”决策的权衡。我们分析了自建方案的特定场景、评估了总拥有成本的概念,并强调了选择应基于团队能力与是否能带来独特价值。下一节课,我们将一起探讨工具和技术的“无服务器”与“有服务器”选项之间的区别。
053:服务器、容器与无服务器计算选项 🖥️📦⚡

在本节课中,我们将学*三种主要的云计算选项:服务器、容器和无服务器计算。我们将探讨它们各自的特点、适用场景以及权衡取舍,帮助你为数据工程项目选择合适的技术方案。
任何软件应用程序都需要服务器。服务器本质上是一台或多台计算机,通过提供CPU、内存(RAM)、磁盘存储,有时还包括GPU和网络资源,来支撑你的应用程序运行。服务器通过网络(通常是互联网)提供计算资源。
在云服务领域,根据你考虑的具体服务,有时你需要自行设置和管理运行应用程序所需的计算资源。而在其他情况下,你可以在以下三种计算选项中进行选择:服务器、容器或无服务器。本视频将详细介绍这三种选项之间的差异和权衡。
服务器选项 🖥️
如果你选择服务的服务器版本,你将负责设置和管理服务器(例如一个亚马逊EC2实例),包括更新操作系统、安装或更新软件包、配置网络、扩展规模以及保障安全。
容器选项 📦
与服务器不同,容器是一个更模块化的单元,它将你的代码和所有依赖项打包成一个可以在服务器上运行的包。
传统的虚拟机封装了整个操作系统,而容器则更为轻量级,它只打包和隔离用户空间,例如文件系统和一些进程。
对于容器化解决方案,你仍然需要负责设置应用程序代码和依赖项等核心元素,但底层的操作系统、网络等其余部分将由平台提供。
无服务器选项 ⚡
除了服务器和容器选项,在云数据工具领域,无服务器这个术语正变得越来越常见,用于描述特定的服务。如果你熟悉计算机的工作原理,“无服务器”这个词听起来可能有点奇怪——没有服务器怎么运行软件呢?
实际上,“无服务器”并不意味着没有服务器,它只是意味着设置和维护服务器不是你对该特定服务的责任。你可以与应用程序交互,而无需管理背后的服务器,也无需担心软件包的安装和依赖关系。因此,服务器对你来说基本上是隐藏的。
通常,无服务器技术运行在容器之上,因此这些服务可以自动扩展,内置了可用性和容错能力,并提供按使用量付费的计费模式。但在无服务器服务中,它们所运行的容器也被抽象掉了。

通过这种方式,无服务器技术可以让你花更少的时间担心计算基础设施,而将更多时间专注于开发数据产品。在前几周的实验中,你已经使用了一些无服务器服务,例如Amazon Athena和AWS Glue。
无服务器趋势随着2014年AWS Lambda的推出而全面兴起。这项服务允许你在响应事件时运行代码。它承诺可以在需要时执行小块代码,而无需管理服务器。自此,无服务器选项在流行度和多样性上呈爆炸式增长,现已远远超出了按需运行代码片段的范畴。
其流行的主要原因在于成本和便利性。你无需支付整台服务器的费用,只需在代码每次运行或使用特定服务时支付少量费用。
如何选择?🤔
那么,何时使用无服务器服务是合理的呢?和许多其他云服务一样,这取决于具体情况。作为一名数据工程师,你需要了解云定价的细节,以便能够预测无服务器部署的成本,并判断它是否比服务器选项更具成本效益。
例如,查看AWS Lambda的定价,你会发现,在事件发生率很高的环境中使用该服务,成本可能会高得惊人。与数据管道的其他领域一样,对你所使用的服务(无论是否无服务器)进行建模和监控至关重要。你可能需要直接监控,以确定实际的事件发生率、持续时间和每个事件的成本,从而在真实环境中建模无服务器服务与替代方案的总成本。
此外,云无服务器平台对执行频率、并发性和持续时间都有限制。如果你的应用程序无法在这些限制内良好运行,那么就该考虑采用面向容器的方法了。

你可以这样思考:无服务器最适合简单、离散的任务和工作负载。如果你的系统有许多移动部件,或者需要大量的计算或内存资源,那么无服务器可能就不太适合。在这种情况下,请考虑使用容器以及像Kubernetes这样的容器工作流编排框架。
对于云中的大多数现代数据工程应用,你都可以使用无服务器或容器化工具完成任务。因此,我建议首先考虑使用无服务器,如果可能的话,再考虑容器和编排。
总结 📝

本节课我们一起学*了三种核心云计算模型:服务器、容器和无服务器。服务器需要你管理底层基础设施;容器将应用及其依赖打包,提供了更好的可移植性;而无服务器则进一步抽象了基础设施管理,让你可以专注于代码逻辑,通常按实际使用量付费。选择哪种方案取决于你的具体需求、成本考量以及对控制层级的要求。理解这些选项的差异是构建高效、经济的数据架构的关键一步。


当你熟悉了这些无服务器选项后,请加入下一个视频,我们将通过探讨数据工程生命周期的潜在影响因素,来总结本课程,并了解这些因素如何在你为数据架构选择工具和技术时发挥作用。
054:底层技术如何影响你的决策 🔧

在本节课中,我们将探讨数据工程生命周期的六大底层暗流如何影响你在构建数据架构时对工具和技术的选择决策。
上一周,我们逐一分析了安全、数据管理、数据运维、数据架构、编排和软件工程这六大暗流与数据工程生命周期的关系。本节中,我们将更深入地审视,在选择数据架构的具体组件时,这些暗流是如何发挥作用的。
安全 🔐
在安全方面,不同的工具具备不同的安全特性。理解这些特性并确保部署正确的身份验证技术及其他最佳实践至关重要。需要特别警惕的一点是,只使用由信誉良好的组织或可信的开源社区开发的软件和工具。历史上曾出现过某些组织或国家推送包含可疑组件(本质上是间谍软件)的数据工具,从而危及你的数据管道。此处不再赘述,但核心要点是:确保你清楚工具的来源。如果是开源工具,请查看其代码并确保你理解其实现方式。
数据管理 📊

对于数据管理,某些数据治理实践的实现方式并不总是清晰的。一个好的做法是向提供该工具的公司或社区询问他们如何处理治理问题。以下是几个关键问题示例:
- 你的数据将如何受到保护,以防范来自外部和内部的破坏?
- 该工具如何遵守GDPR及其他数据隐私法规?
- 该工具如何提供数据质量验证?
数据运维 ⚙️
在选择数据运维工具时,主要在于理解它们在自动化和监控方面提供哪些功能。如果你正在考虑托管服务选项,务必理解提供商的服务水平协议,该协议描述了他们在可靠性和可用性方面的保证。
数据架构 🏗️

正如我们在本周材料中反复讨论的,对于数据架构,你需要关注任何给定工具如何提供模块化以及与其他工具的互操作性。良好的模块化和互操作性能够带来灵活性和松耦合。
编排 🧩
在编排领域,当前数据工程领域主要由 Apache Airflow 主导,你可以将其作为开源工具或托管工具来实施。此外,像 Prefect、Dagster 和 Mage 等其他方案也越来越受欢迎。在选择编排工具时,请注意这个领域正在快速发展,对你自身数据架构目标的深刻理解将有助于你确定哪种编排工具最适合你的需求。
软件工程 💻

对于软件工程,核心问题是你希望投入多少。我的意思是,根据你对团队带宽、专业知识的评估,以及哪些开发活动真正能为你的组织带来价值,你需要决定:是构建自己的工具,还是选择开源方案,或是采用商业开源或专有解决方案?主要要避免的是“无差异的重体力活”,即那些不为你创造价值的艰苦工作。建议首先查看开源和商业开源工具,如果它们无法满足你的需求,再考虑专有工具。

以上就是对数据工程生命周期各底层暗流如何在你选择数据架构实施工具和技术时发挥作用的一个简要概述。
总结 📝
本节课中,我们一起学*了数据工程六大底层暗流——安全、数据管理、数据运维、数据架构、编排和软件工程——如何具体地影响技术选型决策。我们再次覆盖了广阔的领域,虽然有些抽象地讨论了数据工程。我知道到目前为止我们似乎聚焦了很多理论,你可能已经迫不及待想要实践这些学到的概念了。这很好,因为很快就会有大量的动手实践。在下一课中,请与我一同了解AWS架构框架,并评估你在AWS上为自己的数据架构所做的架构选择。
055:AWS架构完善框架简介 🏗️
概述
在本节课中,我们将要学*AWS架构完善框架。这个框架包含一系列原则和最佳实践,能帮助你在AWS上构建可扩展且稳健的架构。我们将了解这个框架如何补充本课程已讨论的原则,并为你后续的实践提供指导。
到目前为止,在本课程中,你一直在学*数据架构的基础知识,以及为自身数据架构设计和选择工具时需要考虑的诸多因素。
本节中,我们来看看AWS架构完善框架。这个框架由一系列原则和最佳实践组成,旨在帮助你在AWS上构建可扩展且稳健的架构。
AWS架构完善框架补充了我们在本课程中已经讨论过的那套原则和实践。事实上,在撰写《数据工程基础》一书并阐述我们认为对设计良好数据架构至关重要的关键原则时,我和合著者Matt Hausey从AWS架构完善框架以及其他来源中获得了灵感。
如果你快速搜索一下AWS架构完善框架,你会发现各种优秀的资源,包括专注于特定用例的白皮书,以及AWS提供的一个帮助你应用此框架的工具。实际上,这个框架本身就可以成为一门完整课程的主题。
为了本课程的目的,在下一个视频中,Morgan将向你介绍这个框架的六个关键支柱。

以下是关于这个框架的更多信息:
Morgan将介绍这个框架的六个关键支柱,并向你展示可以去哪里学*更多关于该框架的知识并进行更多实践。
在那之后,我将在接下来的视频中与你见面,进行本周实验练*的讲解。

我们将让你有机会在AWS云上应用良好数据架构的原则。

总结

本节课中,我们一起学*了AWS架构完善框架的基本概念。我们了解到该框架是一套用于在AWS上构建稳健、可扩展架构的原则和最佳实践,它是对本课程已学内容的有效补充。通过引入这个框架,我们为后续在云平台上实际应用数据架构原则做好了准备。
056:AWS架构完善框架 🏗️

在本节课中,我们将学*AWS架构完善框架。该框架提供了一套最佳实践和核心策略,帮助我们在AWS上设计、评估和改进云系统架构。我们将了解其六大支柱,并学*如何应用这些原则来构建可靠、安全、高效且可持续的数据工程解决方案。
背景介绍
在AWS上构建系统,尤其是在刚开始时,可能会令人不知所措。AWS提供了众多选项和不同的解决方案构建方式。如何确保我们的设计是正确的?这正是AWS架构完善框架的目的:评估和改进解决方案,确保在AWS上的构建工作正确无误。
AWS不仅提供云系统构建服务,还与全球数千家客户紧密合作,帮助他们构建最佳的云解决方案以支持业务运营。AWS解决方案架构师、领域专家和其他人员拥有数十年的客户合作经验,涉及广泛的业务需求和用例,这使他们积累了丰富的正确实践方法。
基于这些集体经验,AWS构建了架构完善框架。该框架包含一套在云中设计系统的最佳实践和核心策略。
六大支柱概述
AWS架构完善框架包含六大关键支柱:卓越运营、安全性、可靠性、性能效率、成本优化和可持续性。以下将简要描述每个支柱。如果你有兴趣深入了解,可以在本周课程末尾的资源部分找到相关链接。
卓越运营
卓越运营支柱关注如何在AWS上更有效地开发和运行工作负载,监控系统以洞察运营状况,并持续改进流程和程序,以交付业务价值。

安全性
安全性支柱关注如何利用云技术保护数据、系统和资产。这与Joe在数据工程生命周期中介绍的安全基础理念一致。我们需要采用适当的工具来保护系统,并在团队中培养安全文化。
可靠性
可靠系统是指能够正确、一致地执行其预期功能,并能从故障中快速恢复的系统。因此,该支柱涵盖了从可靠性设计、故障规划到适应变化等各个方面。
性能效率
性能效率支柱侧重于采用数据驱动的方法构建高性能架构。在评估系统性能效率时,我们将评估一组计算资源有效满足系统需求的能力,以及如何在需求变化和技术演进时保持这种效率。
成本优化
成本优化支柱非常直接,与Joe本周早些时候提到的拥抱FinOps的观点密切相关。简而言之,成本优化意味着以尽可能低的价格点构建系统,以交付最大的业务价值。AWS提供了一系列服务,包括AWS成本资源管理器(Cost Explorer)和成本优化中心(Cost Optimization Hub),你可以在其中进行比较并获取关于如何优化系统成本的建议。
可持续性
在构建数据系统时,性能、可扩展性、安全性和成本可能是首要考虑因素,但考虑在云上运行的工作负载对环境的影响也很重要。可持续性支柱侧重于减少能源消耗并提高系统所有组件的效率。

框架的应用方式
重要的是要记住,架构完善框架的这六大支柱不会提供可以直接复制并应用到解决方案中的具体设计。相反,你可以将它们视为一套原则和问题,帮助你围绕现有解决方案进行富有成效的讨论,并帮助你在云中设计和运营可靠、安全、高效、经济且可持续的系统。
这几乎就像拥有自己的AWS解决方案架构师,可以帮助你思考不同架构选择的利弊。
如前所述,你可以跟随本周课程末尾资源部分的链接,了解更多关于每个支柱的信息,并探索架构完善工具(Well-Architected Tool)。该工具允许你评估自己的架构,发现潜在风险和改进机会。
特定领域应用:透镜(Lenses)
架构完善框架还有特定领域的应用,称为“透镜”(Lenses),你可以进行探索。透镜本质上是AWS架构完善框架的扩展,专注于特定领域、行业或技术栈,并提供针对这些背景的指导。

每个透镜都有自己的一套问题、最佳实践、说明和改进计划。特别推荐你查看数据分析透镜(Data Analytics Lens),它专注于数据特定的考量。数据分析透镜将引导你评估数据架构的可扩展性、安全性、性能和成本。它可以帮助你评估当前的数据架构,识别改进领域,并实施符合行业最佳实践的策略。
实践环节
接下来,轮到你尝试将本周讨论的原则应用到自己在AWS上的数据架构中了。
在接下来的几个视频中,Joe将引导你完成本周的实验练*。我们下周再见。

课程总结
在本节课中,我们一起学*了AWS架构完善框架。我们了解了该框架的背景和目的,详细探讨了其六大支柱:卓越运营、安全性、可靠性、性能效率、成本优化和可持续性。我们还学*了如何将该框架作为一套原则和问题来指导架构设计,并介绍了其特定领域应用“透镜”,特别是数据分析透镜。最后,我们预告了接下来的实践环节,鼓励你将所学应用到实际架构评估中。
057:实验介绍 🧪

在本节课中,我们将学*如何为一个已构建的数据管道扩展功能,使其能够向外部客户提供数据服务。我们将通过一个基于AWS架构的Web应用程序实验,来探索如何确保应用的可扩展性、资源效率以及安全可靠性。
在上周的实验中,你构建了一个数据管道,用于摄取、转换数据并提供给公司的数据分析师使用。
现在,你的公司希望向客户提供一些嵌入式仪表板,并通过第三方数据共享平台分享分析数据。

因此,你的任务是将这些转换后的数据分享给更广泛的公众,以服务于外部客户。
我们假设你已经构建了一个运行在这些EC2实例上的Web应用程序。在本实验中,你将使用这个Web应用程序,确保它能够扩展以满足客户需求,高效利用计算资源,并以安全可靠的方式设计。
你还将使用Amazon CloudWatch监控此应用程序的性能,同时应用良好的数据架构原则,并遵循AWS完善架构框架。
在开始实验之前,让我们先仔细看看这些EC2实例,以理解Web应用程序的底层架构。

以下是Web应用程序的架构图。
这个Web应用程序基于三层架构设计,包括数据层、逻辑层和表示层。这种类型的三层架构是部署Web应用程序解决方案的常见方式。
左侧的S3存储桶代表数据层,你的Web应用程序从这里提取数据。
中间的EC2实例和负载均衡器代表逻辑层,它承载处理客户端请求的应用程序逻辑。逻辑层从数据层查询数据,并将结果返回给右侧的表示层。
表示层由一个界面组成,该界面向通过其设备与Web应用程序交互的客户端显示结果。在这个例子中,你可以将显示客户分析仪表板的网页视为表示层。

让我们放大中间的逻辑层。
这里有两个主要组件:Amazon EC2自动扩展组和应用程序负载均衡器(ALB)。
自动扩展组由一组运行相同应用程序逻辑的EC2实例组成。它们用于增加应用程序的计算能力。
因此,不是由单个EC2实例处理所有客户端请求,而是将这些请求分布到多个EC2实例上。
自动扩展意味着EC2实例的数量可以根据Web应用程序的客户端请求数量增加或减少。该组配置为从两个实例开始,每个实例启动于不同的可用区,以增强应用程序的可用性和可靠性。
自动扩展组需要与一个应用程序负载均衡器关联,该负载均衡器有助于将传入流量分布到EC2实例上,并作为客户端的单一联系点。在本实验中,你将主要与运行应用程序逻辑的计算资源进行交互。
你将模拟流向Web应用程序的流量以评估其可扩展性。
然后使用Amazon CloudWatch监控应用程序上的计算资源和网络活动。
你将配置EC2实例以实现性能效率和成本优化,并调整负载均衡器的安全选项以控制流向应用程序的入站流量。要开始实验,你需要在Coursera上打开实验项目,并看到包含本实验所有说明的页面。
与上周在Cloud9或Jupyter Lab中进行的实验不同,你将使用AWS管理控制台来监控和更新Web应用程序的设置。
现在,要访问控制台,让我们启动实验,然后等待此图标变为绿色。
一旦它变为绿色,你可以点击它并进入控制台。


这里说明的前几部分涵盖了我在此视频中介绍的说明。在下一个视频中,我将引导你完成实验的第3和第4部分,在那里你将探索和监控应用程序的计算资源。我们下一个视频见。
本节课中,我们一起学*了实验的背景与目标,并详细了解了待评估Web应用程序的三层架构,特别是其逻辑层中自动扩展组和负载均衡器的关键作用。我们明确了实验将围绕评估可扩展性、监控资源以及优化配置与安全展开。
058:监控Web应用 🖥️📊

在本节课中,我们将学*如何监控一个Web应用程序的性能。我们将重点关注自动扩展组中的EC2实例以及通过应用程序负载均衡器进行的网络活动。课程将指导你如何获取应用地址、模拟流量,并使用Amazon CloudWatch监控关键指标。
实验预览与目标
上一节我们介绍了数据工程中监控的重要性。本节中,我们来看看一个具体的实验任务。该任务对应实验指南的第3和第4部分,核心是监控自动扩展组的EC2实例和应用程序负载均衡器的网络活动。实验环境已预先配置好自动扩展组和负载均衡器,你无需自行创建。
获取Web应用地址
首先,你需要找到Web应用程序的访问地址。由于负载均衡器是客户端访问应用的主要入口,因此地址需从负载均衡器获取。
以下是操作步骤:
- 在AWS控制台的搜索栏中输入 EC2 并进入该服务。
- 在左侧面板中,找到 “负载均衡” 部分。
- 点击 “负载均衡器”,查看你的应用负载均衡器。
- 在负载均衡器详情中,复制 “DNS名称” 下的地址。
- 将此地址粘贴到浏览器的新标签页中打开。
打开的页面是客户端与应用交互的界面。为简化演示,该页面仅显示一条包含托管应用逻辑的EC2实例详细信息的消息。请保持此标签页打开,后续实验将用到此信息。
模拟流量与监控指标
当客户端使用你的Web应用时,负载均衡器会接收HTTP请求(例如打开网页的请求)并将其转发给EC2实例进行处理。为了确保应用能够支撑预期流量,监控流入流量和计算资源使用情况至关重要。
可观测性与监控是DataOps中的重要实践,也属于AWS架构完善框架中的运营卓越支柱。在本实验的第4部分,我们将使用 Amazon CloudWatch 来跟踪Web应用的性能指标。

首先,你需要使用一个名为 Apache Benchmark 的开源工具来模拟网站流量。此工具可用于执行压力测试,即向你的Web应用发送大量请求。
以下是模拟流量并监控的步骤:


-
使用AWS控制台中的 AWS CloudShell(一个可直接从控制台访问的命令行服务)。
-
从实验指南中复制安装命令并在终端中运行,以安装Apache Benchmark工具。
-
使用以下命令生成压力测试,发送多个HTTP请求:
ab -n 7000 -c 50 <你的网页地址>在此命令中:
-n选项指定HTTP请求的总数。-c选项指定并发请求的数量。- 该命令将总共发送 7000 个请求,并以每次 50 个请求的并发方式发送。
- 请将命令末尾的
<你的网页地址>替换为你之前复制的实际网页地址。
请求开始发送后,你便可以监控自动扩展组中EC2实例的CPU使用率和网络活动。

在CloudWatch中查看监控结果

返回AWS控制台的EC2服务页面,按以下步骤查看监控图表:
- 在左侧面板中,找到并展开 “自动扩展组” 部分。
- 打开提供的自动扩展组,进入 “监控” 标签页。
- 选择 EC2 指标。重点关注以下三个图表:
- 第一个图表 显示了处理7000个请求时的CPU利用率。你可以看到处理流入流量所需的计算资源有所增加。
- 另外两个图表 分别监控入站和出站网络活动(以字节为单位),也呈现出类似的变化模式。

几分钟后,一旦所有7000个请求处理完毕,刷新监控界面,你应该能看到CPU利用率和网络活动均有所下降。
课程总结
本节课中,我们一起完成了实验的第3和第4部分。我们学*了如何获取Web应用程序的地址,使用Apache Benchmark工具模拟传入流量,并通过Amazon CloudWatch监控了EC2实例的CPU使用率和网络活动。这些实践是确保应用性能与可靠性的基础。

请继续观看下一节视频,我们将一起探讨你的Web应用在安全性、可用性、可扩展性以及成本方面的表现。
059:应用良好数据架构原则 🔧

在本教程中,我们将学*如何将良好的数据架构原则应用于一个Web应用程序。我们将重点关注安全性、可靠性、成本优化和可扩展性,通过实际操作来调整AWS云环境中的配置。
概述 📋
上一节我们模拟了Web应用的流量并监控了CPU使用率和网络活动。本节中,我们将根据实验指南第5至7部分的任务,预览如何应用良好数据架构原则,以确保应用的安全性、可用性、可扩展性,并优化成本。
安全性配置 🔒
根据“安全优先”架构原则和AWS Well-Architected框架的安全支柱,构建任何应用或数据系统时都应优先考虑安全。
为了控制对本实验Web应用的访问,您可以配置负载均衡器,使其仅接收特定类型的请求,同时阻止其他请求。当客户端向Web服务器发送请求时,需要地址和端口号。端口号是应用程序用来区分流量类型的虚拟标识符,每个端口可以与特定进程关联,以方便程序员。默认情况下,特定端口号被分配给常见请求。例如,端口80被分配给HTTP请求。然而,如果负载均衡器的安全规则配置不当,外部客户端仍可能访问其他端口。
对于本实验使用的Web应用,实验指南指出,由于配置错误,一些私有数据可能通过负载均衡器的端口90泄露。为了验证这一点,我将转到显示网页的标签页,复制地址,并将其粘贴到另一个标签页中,但这次我会附加:90来指定端口90。
此处的消息显示,有一些私有数据通过此端口显示,并且外部方可以轻松访问。要解决此问题,您需要调整负载均衡器的安全规则,即安全组。
让我们从控制台打开EC2,在左侧面板中导航到“网络与安全”部分,然后单击“安全组”。您可以看到两个安全组。第一个与自动扩展组的EC2实例关联,第二个与负载均衡器关联。如前所述,负载均衡器是客户端的主要联系点,应配置为接收来自外部互联网的流量,这将是您在实验部分调整的内容。但在调整之前,让我们验证EC2实例的安全组是否配置为仅接收来自负载均衡器的流量。
如果您单击EC2安全组的ID并向下滚动检查入站规则,您会发现此规则将负载均衡器安全组的ID列为源。这意味着EC2实例只能按预期从负载均衡器接收流量。
现在,让我们返回并调整负载均衡器安全组的配置。打开负载均衡器的安全组后,您会发现此规则将一堆零指定为源,这意味着它接受来自所有IP地址的请求,并且也接受端口范围内的所有可能端口号。这意味着任何源都可以使用任何端口访问负载均衡器,这是一个非常开放的规则。换句话说,使用这样的配置,您的Web应用对公共互联网的任何IP地址和任何端口号都是开放的,而这并不是您想要的。
让我们通过将HTTP请求限制为仅端口80来修复此问题。我将单击“编辑入站规则”,然后单击“添加规则”。在端口范围下,我将指定端口80。对于源,我将通过指定此块来选择所有IP地址。然后,我将删除第一条规则,然后单击“保存规则”。
现在您可以看到更新后的规则,端口范围为80。让我们验证端口90是否不再可从公共互联网访问。我将打开一个标签页,输入应用程序地址并附加:90。您可能仍会看到旧结果,因为Web浏览器可以缓存结果。但如果您不断刷新网页,您会注意到无法再访问包含私有数据的页面。如果您等待足够长的时间,您将收到此错误消息,提示“无法访问此网站”。这就是您如何调整Web应用的安全控制。
可靠性探索 🛡️
接下来,让我们转到实验指南的第6部分,探索应用的可靠性方面。
架构图告诉我们,自动扩展组配置为从两个EC2实例开始,每个实例启动于不同的可用区。为了验证这一点,我将转到显示应用程序网页的标签页。显示的消息显示了处理HTTP请求的EC2实例的内部IP地址及其可用区。我刷新此页面,现在您看到第二个EC2实例的IP和可用区。这意味着每次请求都由不同的EC2实例处理。
设计跨越多个可用区的应用与基于云的解决方案的可靠性支柱以及我们本周讨论的“为故障做计划”原则相关。这样,如果某个可用区出现问题,请求仍可以由托管在另一个区域的EC2处理。

成本优化与可扩展性 ⚙️
最后,让我们探索应用的两个方面:成本优化和可扩展性,这在实验指南的第7部分中涵盖。为了拥抱FinOps,您需要确保高效使用正确的资源。
请记住,上周我们了解到有不同类型的EC2实例,每种具有不同的处理能力和内存容量。当然,EC2实例功能越强大,您需要为每小时使用支付的费用就越多。目前我们使用的是t3.micro实例,但如果它们对您的应用来说功能过于强大且成本较高,您可以切换到t3.nano实例以降低成本。为此,您需要转到自动扩展组并修改启动模板,该模板保存了启动EC2实例的配置信息。
在AWS控制台中,我将搜索EC2,然后滚动查找左侧面板中的自动扩展组。我将单击组名并找到启动模板部分。此部分包含当前EC2实例的配置信息,因此您可以看到当前实例类型是t3.micro。让我们编辑模板。

在这里,我将单击“创建启动模板版本”以创建现有启动模板的新版本。除了实例类型外,我想保持一切不变,因此我将向下滚动到实例类型部分并搜索t3.nano。您会注意到nano和micro实例之间的区别在于它们的内存容量,当然还有定价。我将选择t3.nano,然后单击“创建模板版本”。
模板成功创建后,让我们返回自动扩展组,然后再次单击组名。在启动模板部分,我将单击“编辑”。然后在版本下拉菜单中,我将选择最新选项。别忘了单击底部的“更新”。这样,我就更新了该组未来将创建的所有EC2实例的启动模板配置,但我们也希望终止当前仍在运行的t3.micro EC2实例。
为此,我将导航到左侧面板的实例部分,选择当前运行的所有EC2实例,然后右键单击其中任何一个,并单击“终止实例”。EC2实例的状态现在显示为“正在关闭”。几分钟后,一旦您刷新UI,EC2实例的状态应显示为“已终止”。

您还会注意到已创建一个或两个新的t3.nano实例。这是因为自动扩展组的期望容量为两个实例,意味着它将始终启动两个实例。因此,如果您现在只看到一个实例在运行,过一会儿刷新UI后,您将看到两个t3.nano实例在运行。
对于实验指南第7部分的最后一项任务,我们将应用“为可扩展性而架构”的原则,通过使用自动扩展组的自动扩展属性来扩展和缩减资源。使用自动扩展组,您只需为使用的资源付费。因此,当需求减少时,AWS自动扩展将自动移除任何多余的EC2资源,帮助您避免超支。
目前自动扩展功能未启用。要启用自动扩展,您需要创建一个扩展策略,在其中指定触发自动扩展过程的指标和阈值。
因此,在EC2实例的左侧面板中,让我们导航到自动扩展组部分,然后单击组名并转到“自动扩展”选项卡。在这里,我将单击“创建动态扩展策略”,并按照实验指南中的名称命名策略。对于指标类型,我将选择“应用程序负载均衡器请求计数/目标”,对于目标组,我将选择端口80组。然后,我将选择60作为目标值,意味着当有超过60个HTTP请求时,自动扩展组可能会扩展以添加更多实例来处理增加的负载;当请求少于60个时,自动扩展组将通过减少实例数量来缩减。最后,我将将实例预热时间设置为60秒。此预热时间指的是新启动的实例在被视为可用于自动扩展评估指标之前,允许完全初始化的时间段。别忘了单击底部的“创建”。

现在,让我们使用Apache Bench进行更密集的压力测试,发送100万个请求,而不是7000个。我将单击此处底部的CloudShell图标,以便使用命令行发出请求并检查请求状态,同时监控应用程序的性能指标。


我将输入此命令,并将最后一个参数替换为应用程序的地址。测试需要几分钟才能运行。与此同时,让我们转到自动扩展组服务,然后单击“监控”,再单击“EC2”。在这里,您可以看到CPU使用率和网络指标中的一些活动。

几分钟后,您可以切换到“活动”选项卡,看到启动了额外的实例来处理增加的流量。


总结 🎯

本节课中,我们一起学*了如何将良好的数据架构原则应用于一个实际的Web应用。我们通过配置安全组规则增强了安全性,通过跨可用区部署验证了可靠性,并通过调整实例类型和启用自动扩展策略实现了成本优化和可扩展性。这些实践操作展示了在云环境中构建健壮、高效且安全的数据系统的基本方法。
060:数据工程(导论,源系统、数据摄取和管道,数据存储和查询|1-2-3课)|第3周总结 🎯
在本节课中,我们将对数据工程课程的第三周内容进行总结。本周我们深入探讨了数据架构,以及如何构建良好的数据架构。

概述
第三周的学*重点是数据架构。我们首先了解了数据架构在企业整体架构中的位置,然后分析了一些具体的架构示例,探讨了如何将利益相关者的需求转化为数据系统的技术选择。我们详细回顾了良好数据架构的原则,并有机会探索了AWS完善架构框架。最后,在实验环节,你的任务是在AWS云上为数据架构评估成本、性能、可扩展性和安全性等方面的权衡。
课程内容回顾
上一节概述了本周的学*目标,本节中我们来详细回顾各个核心环节。
数据架构与企业架构
我们首先审视了数据架构在更广泛的企业架构背景下的位置。数据架构并非孤立存在,它需要与企业业务目标、应用架构和技术基础设施保持一致。
从需求到技术选择
之后,我们研究了一些具体的架构示例。关键在于学*如何开始思考将利益相关者的需求转化为数据系统的技术选择。这个过程涉及对业务目标、数据特性、处理需求和约束条件的综合分析。
良好数据架构的原则
我们详细回顾了良好数据架构的核心原则。这些原则是构建高效、可靠、可维护数据系统的基础。
以下是构建良好数据架构需遵循的一些关键原则:
- 可扩展性:系统应能随数据量和用户量的增长而平滑扩展。
- 可靠性:系统需要具备高可用性和容错能力。
- 安全性:必须保护数据免受未授权访问和泄露。
- 成本效益:在满足性能要求的同时,优化资源使用以控制成本。
- 性能:确保数据处理的延迟和吞吐量满足业务需求。
- 简单性与可维护性:设计应易于理解、修改和运维。
AWS完善架构框架
你还获得了探索AWS完善架构框架的机会。这是一套补充性原则,可以帮助你在AWS上设计健壮且高效的数据系统。该框架围绕六个支柱构建:卓越运营、安全性、可靠性、性能效率、成本优化和可持续性。
实践:评估架构权衡
在本周的实验环节,你的任务是在AWS云上评估数据架构的权衡。这要求你在多个维度之间做出决策。
以下是实验环节需要评估的关键权衡维度:
- 成本 vs. 性能:选择更高性能的实例或服务通常意味着更高的成本。
- 可扩展性 vs. 复杂性:实现自动扩展会增加架构的复杂性。
- 安全性 vs. 便利性:更严格的安全控制可能会影响开发的便捷性或用户体验。
总结
本节课中,我们一起学*了数据架构的核心概念。我们探讨了数据架构在企业中的角色,学*了如何从需求推导出技术选型,重温了良好架构的设计原则,并借助AWS框架和动手实验,实践了在真实云环境中进行架构权衡决策的方法。这些知识为你设计和评估数据系统奠定了坚实基础。
我们下周的课程材料中再见。届时,我们将整合你在本课程中学到的所有概念,构建另一个AWS云上的数据架构。


AWS云上的数据架构
061:数据工程导论课程 - 第4周概览 🗺️

在本节课中,我们将回顾前三周的学*内容,并了解第四周的学*目标。我们将把之前学到的知识整合起来,通过一个实际的工作场景,学*如何从需求收集到系统实现的完整流程。
回顾前三周内容

在第一周课程中,我们简要了解了与数据工程师工作相关的需求收集。
我们探讨了你与公司数据科学家之间可能进行的对话,内容涉及他们正在进行的分析和机器学*项目的需求。你看到这样的对话如何迅速揭示出你需要与其他利益相关者(例如营销团队和软件工程师)沟通的必要性。
我们还介绍了一个数据工程师的思维框架。该框架包含以下步骤:
- 识别业务目标和利益相关者需求。
- 根据这些需求定义系统要求。
- 选择满足要求的工具和技术。
- 最终构建并部署你的系统。
这个简洁的框架包含了许多内容。即使我补充了每个步骤中的具体细节,例如第一步中询问利益相关者将采取什么行动,第二步中将利益相关者需求转化为系统要求,第三步中进行原型设计和测试,以及最后一步中演进你的系统,你仍然会发现有许多内容未被提及或详细说明。

本课程的第二周和第三周旨在填补这些细节,帮助你形成一个更完整的数据工程思维框架,理解数据工程领域,并了解在实践中作为一名数据工程师的角色和感受。
在第二周,我们学*了数据工程生命周期的各个阶段和底层支撑。我们不仅关注构成数据系统的组件,还关注所涉及的人员,包括源系统所有者和下游最终用户。
在第三周,我们深入探讨了良好数据架构的原则。你了解到,从一开始就应该考虑诸如为故障做计划、选择通用组件或系统设计元素等事项。
至此,你已经掌握了构成数据工程师工作关键思维模型的所有组成部分。

第四周学*目标
本周,我们将在一个实际的全职工作场景中,把所有学到的知识整合起来。
我们将从需求收集开始,然后选择工具和技术,最后实现你的系统。
接下来,我将从本课程第一周需求收集对话结束的地方开始,继续完成定义和记录功能性与非功能性需求的过程,并讨论可用于构建满足这些需求的系统的工具和技术。
在本周的学*过程中,我们将不时停下来,讨论一些概念和最佳实践。这些内容旨在帮助你在未来作为数据工程师遇到各种新场景时能够牢记于心。
在本周结束时,你将把需求转化为架构设计,并在AWS云上构建你的系统。
请与我一起进入下一个视频,开始学*。
总结


本节课中,我们一起回顾了数据工程思维框架、生命周期阶段和架构原则。从下一节开始,我们将把这些理论知识应用于一个完整的实践项目,体验从需求分析到云端部署的数据工程全流程。
062:需求层次结构 📊

在本节课中,我们将学*数据工程师如何通过“需求层次结构”来理解业务目标、利益相关者需求以及系统要求。我们将探讨如何从高层业务目标出发,逐步分解到具体的功能性和非功能性需求,从而构建出能够有效支持业务的数据系统。
正如上一节视频所述,本周的重点是整合“像数据工程师一样思考”框架的各个方面。该框架始于通过需求收集过程来识别业务目标和利益相关者需求。
此时,请开始将需求视为一种需求层次结构。
在这个层次结构的顶端,是业务的目标和目的。这些描述了整个业务成功的样貌,例如围绕增长收入、市场份额、用户基数或其他代表业务最佳结果的目标。
层次结构中的下一层是利益相关者需求。在本课程中,“利益相关者”主要指企业中的个体员工。他们各自在实现高层业务目标中扮演角色。为了成功完成工作,利益相关者有其需求,他们需要适当的资源、工具和管理等。在本课程中,你可以假设他们还需要稳健的数据系统。
在利益相关者需求之下,是系统要求。原则上,这可以是任何系统,但这里我们特指你将构建和维护的数据系统。这是一组你的数据系统必须满足的要求,以便很好地服务于利益相关者需求。
接下来,系统要求可进一步分为功能性需求和非功能性需求。
功能性需求是指那些可以用特定功能来表达的系统要求,即系统为了满足利益相关者需求而能够做什么。
例如,一个监控银行交易欺诈行为的数据系统的功能性需求可能是:系统能够立即报告潜在的欺诈交易。
另一方面,非功能性需求可以被视为系统的特性或属性,这些特性使其能够正常运行。这些特性可能涉及延迟、可扩展性、可靠性、成本或安全性等方面。
例如,一个从电商平台摄取数据的流处理管道,在可扩展性方面的非功能性需求可能是:系统必须能够扩展到同时处理来自10,000名购物用户的数据。
以上就是与你作为数据工程师工作相关的业务需求层次结构。这里的主要启示是,正如我们一直讨论的,你构建数据系统的工作直接关系到组织内其他人的工作以及业务的整体目标。这就是为什么理解利益相关者需求和业务目标对你的工作如此重要。
这让我们回到需求收集。
在本课程的第一周,我们首先与数据科学家进行了对话以理解他们的需求。你可以将那次练*视为从这个层次结构的中间某处开始的需求收集。
然而,理想情况下,你希望从顶层开始。这意味着需要与领导层讨论公司的目标。

如果你在一家小公司工作,甚至可能有机会与CEO对话。我强烈推荐这样做。如果你在更大的组织,你只需要沿着指挥链尽可能向上,以了解业务目标。
在本课程第一周,你看到了我与Seul的对话,她曾在许多大型组织担任首席数据官。并非所有组织都有CDO,但大多数会有一位首席技术官或CTO,他是公司里的技术高管。CTO负责领导工程部门利用技术改进产品和服务,目标是促进业务增长。
在下一个视频中,我将向你介绍我的朋友Matt Hsley,他在与包括CTO在内的C级高管对接方面拥有丰富经验,他也是《数据工程基础》一书的合著者。他将分享一些关于如何开始数据工程生涯,以及如何与业务领导者合作提出业务问题解决方案的建议。
然后,我们将看看是否能邀请他加入我们本周的需求收集游戏,在游戏中他将扮演你刚被聘为数据工程师的公司的CTO角色。
请加入下一个视频,与Matt见面。

本节课中,我们一起学*了数据工程中的需求层次结构。我们了解到,构建有效的数据系统始于理解顶层的业务目标,然后分解为具体的利益相关者需求,并最终转化为数据系统必须满足的功能性需求和非功能性需求。掌握这种从宏观到微观的思考方式,是确保你的数据工程工作与业务价值紧密对齐的关键。下一节课,我们将学*如何与高层管理者沟通,以更好地收集和理解这些需求。
063:与Matt Housley的对话 🎙️

在本节课中,我们将学*数据工程领域的核心动机、学*方法以及如何将理论知识与实践相结合。课程内容基于《数据工程基础》一书作者Matt Housley的分享,旨在为初学者提供一个清晰的学*路径。


课程概述
本节课程将探讨数据工程领域的教育现状、学*资源的价值以及进入该领域的实用建议。我们将了解《数据工程基础》一书的创作背景,并讨论如何通过结合书籍理论与课程实践来构建扎实的数据工程知识体系。
书籍创作的动机与目标
上一节我们介绍了课程的整体背景,本节中我们来看看《数据工程基础》这本书的创作初衷。




作者Matt Housley指出,撰写此书的动机源于发现数据工程教育和书籍市场存在一个明显的缺口。现有的材料大多侧重于具体的工具和技术,缺乏对数据工程领域本身的系统性定义,也未能提供一个指导从业者如何像数据工程师一样思考和工作的心智框架。
因此,本书的写作视角并非成为某个特定技术(X、Y、Z)或云服务商(A、B、C)的教程,而是旨在提供对数据工程领域第一性原理的审视。其核心受众是具有技术背景但希望转入数据工程领域的人士。同时,本书也适用于其他次要受众,例如需要与数据工程师紧密合作、将数据产品嵌入应用程序的技术产品经理。
书籍与课程的互补关系
在了解了书籍的定位后,我们来看看它与本课程如何相辅相成。

书籍与课程的目标受众高度相似,都面向希望转入数据工程或希望更好理解相关概念的人。书籍提供了数据工程生命周期和底层支撑要素的理论框架,而本课程则允许你通过动手实践来应用这个框架。课程使用AWS等流行云工具和技术,让你通过实验获得实践经验,从而将书中的概念与实际操作技能真正结合起来。
进入数据工程领域的建议
从理论框架过渡到职业发展,本节我们探讨如何迈入数据工程领域。
以下是给希望进入数据工程领域人士的一些建议:





首先,学*核心的数据概念非常有益。即使你拥有软件开发背景,也可能缺乏对分析数据如何使用足够的经验。因此,从使用像Microsoft Excel这样的工具开始探索数据是有帮助的,这能让你了解表格数据的形态以及数据的用途。


需要强调的是,获得第一份数据工程工作并不仅仅是学*某一套特定的技术栈。在早期阶段,广泛接触多种工具以培养通用能力是更佳选择。当你开始进入具体岗位后,才会专注于所在公司内部使用的特定技术栈。
像《数据工程基础》这样的书籍能提供思考框架,帮助你像数据工程师一样思考。拥有这个框架后,你就能将各种工具归入正确的类别,并有效地履行数据工程师的职能。
模拟对话:数据工程师与CTO
理论建议之外,真实的职场沟通也至关重要。接下来,我们将通过一个模拟对话,展示数据工程师如何与首席技术官进行交流。





这个模拟场景基于作者在Ternary Data咨询公司的工作经验。他们曾与众多不同规模和领域的公司合作,从中了解到高层管理者,特别是CTO,在工程和数据方面所关心的问题。对话将揭示数据工程师在实际工作中需要关注的核心业务与技术考量。
课程总结



本节课中,我们一起学*了数据工程领域的入门知识。我们探讨了《数据工程基础》一书的创作背景及其提供的核心心智框架,理解了书籍理论与动手实践课程之间的互补关系。同时,我们也获得了进入数据工程领域的实用建议,包括从核心概念入手、广泛接触工具以及构建系统性思维框架的重要性。最后,通过模拟对话的引入,我们为理解数据工程师在实际工作中的沟通场景做好了准备。
064:与CTO的对话 🎤

在本节课中,我们将通过模拟一位新入职数据工程师与公司首席技术官(CTO)的对话,来了解数据工程师在实际业务环境中的角色、面临的挑战以及如何将技术工作与公司战略目标对齐。我们将重点关注业务目标、技术债务、数据工具选择以及人工智能计划。
概述
本节课模拟了一位新入职的数据工程师“Joe”与公司CTO“Matt”的对话。Matt阐述了公司的业务目标、当前面临的技术挑战,并解释了数据工程师在这些计划中的关键作用。对话涵盖了市场扩张、技术现代化、数据工具选型以及机器学*项目支持等多个方面。
业务背景与挑战




上一节我们介绍了课程的基本场景。本节中,我们来看看CTO Matt如何描述公司的现状与核心挑战。



Matt首先介绍了公司的基本情况:作为一家电子商务平台,公司在有限的几条产品线上取得了相对成功,这得益于出色的营销和先发优势。
然而,公司目前面临两大核心挑战:
- 市场竞争加剧:随着市场发展,许多小型品牌涌现并蚕食市场份额。
- 技术债务风险:公司平台继承了一些陈旧的遗留代码,这些代码可能导致代价高昂的系统中断,损害客户品牌。
核心战略举措

基于上述挑战,公司制定了明确的战略举措。以下是Matt阐述的几项关键计划:




- 扩大市场份额:通过推出新产品来实现。
- 拓展国际市场:将业务推向更多国家和地区。
- 进行软件重构:这是支持以上业务扩张的技术基础。重构的目标是:
- 清除遗留系统中存在风险的旧代码。
- 使整个系统具备更高的可扩展性。
数据工程师的角色与影响
了解了公司的战略方向后,我们来看看这些举措将如何具体影响数据工程师的工作。
Matt询问这些变化对数据工程师Joe的影响。Joe回应说影响会很大,并期待帮助实现系统现代化。Matt对此表示赞同,并指出了他作为CTO经常担忧的一个问题:软件与数据之间的隔阂。



他解释道,开发人员经常在“真空”中编写代码,而数据工程师只能被动消费其输出的数据,这导致了一个大问题:遗留代码生成的数据模式非常难以用于分析。




因此,Matt对Joe的核心期望是:在软件团队重构代码时担任顾问角色,确保代码输出的数据适合分析,并尽量减少后续处理。虽然无法完全消除ETL(提取、转换、加载)过程,但如果能以正确的模式生成数据,流入分析系统的数据将干净得多。
技术栈与工具
明确了角色之后,数据工程师需要了解将要使用的技术工具。以下是Matt介绍的计划采用的技术:
作为重构计划的一部分,公司希望从批处理方式更多地转向流处理方式。





目前正在评估的AWS技术包括:
- Kinesis:亚马逊原生的流处理服务。
- Kafka:随着规模扩大,可能为某些管道采用。



Joe表示虽然缺乏实际经验,但学*过相关课程,并渴望将关于Kinesis和Kafka的实验室知识应用到实际场景中。Matt鼓励Joe在此期间搭建概念验证演示,试验这些技术的可扩展性,并扎实掌握相关技能,因为未来管理和扩展公司的流处理能力将是他的关键职责之一。
人工智能与机器学*计划
最后,我们探讨公司在前沿技术领域的规划。Joe询问公司是否在机器学*或人工智能方面有目标。
Matt指出,技术计划的另一个主要目标是提高客户留存率。核心软件重构将通过提供响应更快的网站和更少的停机时间来支持这一目标。





此外,公司正在开发一个推荐引擎。数据工程团队的工作将是开发数据管道来为该推荐引擎提供数据。这涉及:
- 分析产品分类中的数据。
- 分析客户在网站上的行为数据(如点击流、订单行为)。
- 与数据科学家合作,设计支持该流程的数据管道。


总结
本节课中,我们一起学*了数据工程师如何通过与技术高管的沟通来理解业务全局。我们了解到,数据工程师的工作远不止于构建管道,更需要:
- 对齐业务目标:理解市场扩张、产品创新等战略如何转化为技术需求。
- 弥合软件与数据的隔阂:在系统开发早期介入,确保数据产出便于分析。
- 掌握现代数据技术:如从批处理转向流处理,并熟练使用Kinesis或Kafka等工具。
- 支持数据驱动应用:为推荐引擎等机器学*项目构建可靠的数据基础设施。


通过这次对话,我们看到了一个成功的数据工程师需要具备技术技能、业务理解力和跨团队协作能力。
065:与市场营销部门的对话 📊
在本节课中,我们将学*如何与业务部门(以市场营销团队为例)进行有效沟通,以收集数据项目的具体需求。我们将通过一个模拟对话,分析如何识别现有系统的问题、理解业务目标,并明确数据工程需要交付的价值。
上一节我们介绍了需求收集的宏观框架,本节中我们来看看如何在实际对话中应用这些原则。
概述:对话的目标与框架
在与产品营销经理Colleen的对话前,数据工程师Joe已经了解到营销团队有两个核心需求:一个是关于产品销售指标仪表板,另一个是关于产品推荐系统。本次对话的目的是获取这两个项目的更多细节和期望。
任何需求收集过程都包含四个关键要素,本次对话将围绕它们展开:

以下是需求收集的四个关键要素:
- 了解当前向利益相关者交付数据的任何现有系统或解决方案。
- 理解这个现有系统或数据存在的任何问题。
- 理解利益相关者计划用你提供的数据采取什么行动。
- 确定需要与之交谈的其他利益相关者,或需要进行的对话,以收集任何缺失的信息。
请确保在观看对话展开时注意这些要素。
对话解析:从现状到期望
1. 仪表板系统的现状与问题
Joe首先询问了当前系统的状态。Colleen指出,仪表板在显示指标和趋势方面已经符合要求,但核心问题是数据延迟。
“目前的情况是,新销售的数据被记录下来,到我们能在仪表板上实际看到它,通常会有几天的滞后。”
现有仪表板的功能包括:
- 按类别和地区查看产品销售额。
- 显示每日数据的时间趋势图。
- 可以下钻到特定区域,查看单个产品或更细时间粒度(如每小时)的详情。
核心问题公式化:
数据延迟 = 数据记录时间 - 数据在仪表板可视时间 ≈ 2天
2. 业务行动与实时数据需求
Colleen进一步说明了为何需要实时数据。除了监控长期趋势,团队希望在特定产品趋势出现时实时看到,以便抓住势头,推出更有针对性的促销活动。
“我们现在偶尔会看到某些产品出现非常有趣的区域需求高峰,我们希望在这件事实际发生时就知道,而不是在需求已经消退后。”
需求高峰的特征是:需求在几小时内急剧上升,然后回落,有时持续一两天,有时仅几小时。
期望的解决方案:
理想数据延迟 ≤ 1小时
如果仪表板能反映过去一小时(而非两天)的销售数据,营销团队就能做好计划,在观察到销售额连续两三个小时稳步上升时立即采取行动。
3. 推荐系统的现状与期望
对于推荐系统,目前有一个非常基础的版本在运行。
“我们让数据科学家确定前一周销售额中最受欢迎的产品,然后平台团队在结账时将这些产品作为推荐展示给所有人。这更像是‘本周热门产品’,而不是任何个性化的推荐。”
当前系统可以表示为:
# 伪代码:当前推荐逻辑
weekly_popular_products = get_top_selling_products(last_7_days)
recommend_to_all_users(weekly_popular_products)
Colleen期望的是一个个性化推荐系统,能考虑客户的购买历史以及他们购物车中的商品,做出定制化推荐,类似于主流电商平台的做法。
期望的解决方案逻辑:
# 伪代码:期望的推荐逻辑
def generate_personalized_recommendation(user, cart_items):
user_history = get_user_purchase_history(user)
recommendations = recommendation_algorithm(user_history, cart_items)
return recommendations
总结与过渡
本节课中,我们一起学*了如何通过与业务部门的对话来细化数据需求。我们了解到,对于仪表板项目,核心需求是将数据延迟从天级降低到小时级,以支持实时营销决策。对于推荐系统,目标是从全局的“本周热门”升级为个性化的推荐。
通过关注现有系统、现存问题、业务行动和后续联系人这四个要素,数据工程师能够将模糊的业务愿望转化为明确、可执行的技术要求。

在下一节视频中,我们将深入剖析这段对话,拆解并提炼出具体的系统需求,为后续的数据管道与存储设计打下基础。
066:分析与市场营销部门的对话 📝

在本节课中,我们将学*如何将上一节与市场营销部门的对话内容进行整理,并开始将收集到的需求文档化。我们将使用一个层级结构来清晰地展示从底层系统需求到高层业务目标之间的联系。
在上一节中,我们与市场营销部门进行了一次对话,了解了他们的需求。这次对话在某种程度上也确认了您从数据科学家那里已经了解到的一些信息,并提供了关于最终用户具体需求的更多细节。
本节中,我们将回顾所学内容,并开始着手将收集到的需求整理成文档。
需求文档化方法 🗂️
我喜欢使用我们在之前课程中看过的层级结构来记录需求。这种方法可以轻松地可视化从底层的系统需求一直到高层业务目标之间的联系。
因此,在最顶层,我可以首先写下我所理解的业务目标。
记录业务目标 🎯
在本案例中,我们了解到的业务目标是:公司旨在通过专注于客户保留和忠诚度,以及扩展到新市场和新产品,来延续其增长轨迹。在这些努力中,他们渴望在决策过程中做到数据驱动。
在业务目标之下,我们现在可以添加利益相关者的需求。
记录利益相关者需求 👥
目前,我将把数据科学家和产品营销经理一起视为我们迄今为止交谈过的利益相关者。在这一点上,我们知道他们主要需要两样东西:一些分析仪表板和一个推荐系统。
以下是他们的具体需求:
分析仪表板需求
数据科学家和产品营销经理都表示,他们需要在仪表板中呈现实时或当前的数据。通过更深入地挖掘并询问他们计划用这些数据采取什么行动,我们了解到营销团队希望了解特定产品何时出现需求激增,以便他们能够对额外的促销活动做出反应。
鉴于这些需求激增的持续时间预计从几小时到一两天不等,每小时更新一次仪表板似乎就足够了。营销部门确认这完全可以满足他们的需求。
因此,我们得到了一个利益相关者需求。您可能会为数据系统捕获相关的功能需求,如下所示:
数据系统需要提供和处理不超过一小时前的数据。
推荐系统需求
当前的解决方案似乎只是在用户结账时在页面上显示一些热门产品。而营销团队希望拥有的是一个能够根据用户的浏览或购买历史以及他们在结账时购物车中的商品,提供定制化产品推荐的系统。
因此,我们得到了另一个利益相关者需求。为了满足这个需求,您的数据系统的功能需求可以这样描述:
系统首先需要为推荐模型的开发提供适当的训练数据,然后能够接收、转换用户数据并将其提供给训练好的推荐模型,最后将模型输出(可能以产品ID的形式)返回给销售平台。
需求转换的要点 ⚠️
我想在此暂停一下,强调一个事实:将利益相关者的需求转化为系统的功能需求可能有点棘手。
正如您在分析仪表板的例子中所看到的,营销团队实际需要的是仪表板本身。因此,很容易会写下一些关于仪表板功能或要显示指标的细节。但实际上,构建仪表板将是数据科学家的责任。数据科学家需要访问不超过一小时的数据。因此,就您的数据系统而言,只要您能够及时提供数据科学家所需的数据,那么您的系统就满足了这一功能需求。
对于推荐系统,营销团队需要进行定制化的产品推荐。为了实现这一点,将涉及多个人员和团队:数据科学家需要训练和部署推荐模型,平台团队需要能够接收来自模型的推荐以在平台上显示。就您的数据系统而言,您需要向数据科学家提供训练数据以开发模型,然后需要能够将客户数据从平台传递到模型,再将模型输出发送回平台。
当前文档化成果 📄

至此,我们已经为每个数据系统记录了一个功能需求。在实践中,任何给定的系统都可能有许多功能需求,以及比我们这里列出的更详细的细节。但为了简单起见,我们现在暂时只保留这两个功能需求。
这就是您如何开始记录功能需求的方法。很快,我们还将讨论如何记录非功能需求。但在那之前,我们将进行更多的利益相关者对话。

在本节课中,我们一起学*了如何将利益相关者的对话内容转化为结构化的需求文档。我们使用层级方法,从业务目标开始,逐步细化到具体的系统功能需求,并重点讨论了在转换过程中需要注意的关键点。下一节,我们将与维护销售平台(即您将从中摄取数据的源系统)的软件工程师进行对话。
067:与软件工程师的对话 👨💻


在本节课中,我们将学*如何与源系统的软件工程师进行有效沟通,以收集数据管道需求,并共同应对数据流中断、格式变更等常见挑战。通过与源系统所有者的协作,我们可以构建更健壮的数据系统。
上一节我们介绍了与数据科学家和产品营销经理的沟通。本节中,我们来看看如何与负责生成数据的软件工程师进行对话。
与源系统所有者沟通时,你仍然可以使用需求收集过程的前两个关键要素来引导对话。你可以询问系统所有者关于生成下游利益相关者所需数据的现有系统,并与所有者讨论你的利益相关者当前解决方案遇到的任何问题。在后续课程中,你将了解更多关于源系统的知识,以及在与源系统所有者合作时需要考虑的事项。
以下是对话的核心内容:
- 数据共享现状:目前,销售平台团队通过每日提供文件下载的方式,向数据科学家提供产品销售数据,以供营销团队分析。他们无法直接开放生产数据库的访问权限,因为这会给销售平台带来风险。
- 提议的解决方案:软件工程师提议建立一个生产数据库的只读副本。所有记录在写入生产数据库后,会立即被推送到这个副本中。然后,可以设置一个API,允许外部人员查询只读副本中的数据,而不会干扰生产系统。
- 数据延迟问题:数据科学家偶尔会遇到数据等待时间过长的问题。新的只读副本设置可以解决因系统维护导致文件导出延迟的问题。然而,服务器或数据中心故障导致的平台暂时宕机,仍可能造成数据不可用。最佳做法是建立自动通知机制,在宕机时提醒下游数据使用者。
- 模式变更问题:数据库模式(Schema)的变更(例如,因添加新功能、拓展新区域或产品线)可能会破坏下游的数据处理脚本。软件工程师通常会在部署变更前大约一周知晓计划。
- 协作与沟通:数据工程师需要被纳入变更通知的循环中,以便提前预知模式变化并相应调整数据管道。双方可以共同努力,确保通过API提供的数据格式保持稳定,或在无法避免变更时,给予充分的事先通知。
本节课中,我们一起学*了如何与源系统的软件工程师进行关键对话。通过这次模拟对话,我们看到,开放的沟通渠道对于构建健壮的数据系统至关重要。源系统所有者通常乐于协作,尤其是在他们理解你的需求之后。在下一视频中,我们将继续记录需求的过程,并探讨系统可能的一些非功能性需求。
068:记录非功能性需求
在本节课中,我们将学*如何记录数据系统的非功能性需求。上一节我们通过与源系统软件工程师的对话,了解了数据访问和稳定性的初步解决方案。本节中,我们将基于这些信息,继续完善系统需求文档,重点关注那些虽未被利益相关者明确提及,但对系统成功至关重要的特性。
回顾与启示
在上一节的对话中,我们与负责源系统的软件工程师交流,获得了几点关键信息:
- 他们建议通过建立读副本数据库和API来解决数据访问问题,这是在保护生产系统的同时提供数据访问的常见方法。
- 他们讨论了确保读副本数据库稳定性的方法,以尽量减少对下游系统的破坏性变更。
- 他们承诺在发生系统中断或计划更改数据库模式时提供通知。
需求文档结构

现在,让我们再次审视我们计划构建的数据系统的需求文档。我们采用一种分层格式来记录需求:

- 顶层是业务目标。
- 中层是利益相关者需求。
- 底层是系统需求。
目前,我们已经记录了两项功能性需求:一项针对分析仪表板,另一项针对推荐系统。接下来,我们可以开始为这些系统记录一些非功能性需求。
理解非功能性需求
非功能性需求比功能性需求更微妙。它们通常不是利益相关者直接要求的内容,而是系统为了良好完成任务所必须具备的特性或属性。
为分析仪表板定义非功能性需求
对于分析仪表板,我们已经记录了一项功能性需求:数据必须在源系统记录后一小时内完成摄取、转换并可供仪表板数据库使用。
以下是针对该系统的非功能性需求示例:
1. 可扩展性与延迟
考虑到摄取的数据量会随平台用户数量波动,一项非功能性需求可以是:
系统必须能够扩展到足以处理平台处于最高用户活动水平时期望的数据量,并在满足延迟要求(一小时)的前提下,完成数据的摄取、转换和服务。换言之,数据处理速度不能因数据量增加而减慢。
2. 可靠性与可维护性
基于与软件工程师的对话,我们可以设置数据检查以确保其符合预期格式,并且源系统工程师会在数据模式变更时提前通知。
- 可靠性需求可以表述为:
系统将执行数据质量检查,以确保摄取的数据符合规范。
- 可维护性需求可以表述为:
摄取和转换阶段必须易于调整,以适应数据模式的任何变更。


为推荐系统定义非功能性需求


现在,让我们思考推荐系统的非功能性需求。
1. 延迟
可以想象,如果目标是在用户浏览或购买商品时提供产品推荐,那么推荐必须相对即时。我们之前一直说“实时”或“接*实时”,但在实践中这意味着什么?
定义“实时”取决于所构建系统的具体细节。这里我们假设,数据系统从摄取用户数据到提供推荐数据的延迟必须小于一秒。
latency = time(serving_recommendation) - time(receiving_user_data) < 1 second
换句话说,从系统接收平台客户数据到向平台返回产品推荐数据所经过的时间应少于1秒。这个要求可能根据具体情况变高或变低,但一秒至少是典型推荐系统所期望的数量级。
2. 可扩展性
与仪表板应用类似,推荐系统也需要一项关于可扩展性的非功能性需求。系统需要能够扩展到平台的最大并发用户数。
3. 可靠性
系统在可靠性方面也可能有一项非功能性需求。例如,如果系统无法生成推荐或遇到其他错误,我们可能希望执行一种可预测的行为,以避免造成糟糕的用户体验。
因此,我们可以这样描述可靠性需求:
系统必须始终在一秒内返回一组推荐结果。如果推荐流水线因任何原因失败,它应默认回退到仅提供一组最受欢迎的产品。




总结
现在,我们已经为这两个系统记录了一些非功能性需求。在实践中,任何数据系统都可能有许多功能性和非功能性需求,这里我们只记录了针对这两个系统相对明显的一部分。
从这些需求收集示例中,需要理解的关键点是:重要的是不仅要理解你构建的系统将如何运行,还要理解这些功能将如何服务于利益相关者和业务的最终目标。
本节课中我们一起学*了如何识别和记录非功能性需求,包括可扩展性、延迟、可靠性和可维护性等方面。下一节视频中,我将在我们基于系统需求选择工具和技术之前,总结本课的一些主要主题。
069:需求收集总结 📝

在本节课中,我们将总结需求收集的核心要点,并探讨如何在项目约束(如时间、成本、范围)之间进行权衡。理解这些原则是构建成功数据系统的基石。
需求收集的核心价值
本课程的重点是需求收集,以及如何确保你详细理解所构建的系统将为利益相关者创造何种价值。
你或许曾期待一门数据工程入门课程会专注于工具和技术,用于构建大型复杂系统。感谢你坚持学*至此,我可以向你保证,你的时间投入是值得的。根据我的经验,失败的数据工程项目比成功的更为常见。我的目标是确保你为构建成功的数据系统做好准备。请放心,在后续课程中,我们将深入探讨各种工具和技术。
需求收集的关键要点 🎯
以下是本节课的主要收获:
在着手构建或修改任何数据系统之前,你需要识别将要服务的利益相关者,并在更广泛的业务目标背景下理解他们的需求。
具体做法是与组织中的许多人进行交流,可能包括从公司领导层到与你并肩工作的数据科学家和软件工程师在内的每个人。

在这些对话中,提出开放式问题至关重要,以便了解现有系统、系统存在的潜在问题以及利益相关者计划利用数据采取的行动。

记录所有发现同样重要。对收集到的需求进行适当记录,将使你能够与利益相关者确认,你计划构建的系统是否能够满足他们以及业务的需求。
总而言之,一旦你理解了利益相关者的需求,并为你的系统写下了一套功能性和非功能性需求,你就已经走上了为组织创造价值的正确道路。
需求权衡与“铁三角” ⚖️
到目前为止,我们一直专注于如何构建以服务利益相关者需求为最优化的数据系统。
本周我们尚未讨论的一个话题是如何在需求收集中评估权衡取舍。例如,你的利益相关者可能希望你尽快构建一个数据系统;或者在成本方面,你可能需要在有限的预算内工作。当然,在现实中,时间线和预算约束将是你参与的任何项目的一部分。因此,你与利益相关者的对话需要包括讨论什么是最重要的:系统的功能特性、部署时间线,还是成本。
项目管理中有一个被称为“铁三角”的概念,其中项目的三个方面从根本上相互制约。这三个方面是:项目的时间线、工作范围和成本。
所谓“相互制约”,是指你可以将每个方面想象成朝不同方向拉扯。例如,如果你增加项目的工作范围,那么时间线或成本或两者都必须增加。或者说,如果你想在更短的时间线内完成项目,那可能需要增加成本或减少范围,或两者兼而有之。
甚至有一句围绕这个概念的老话:好、快、便宜,你只能选两个。
换句话说,如果你想要又好又快,那么它就不会便宜。或者如果你想要又快又便宜,那么它就不会好,依此类推。
在现实中,每家公司都希望项目做得好,并且通常希望它们在合理范围内尽可能快地完成,同时符合一定的预算约束。那么你该怎么办呢?
自“铁三角”概念出现以来,许多作者指出,你无法同时优化这三件事的想法实际上是一种谬论。我现在不深入细节,但我鼓励你搜索“铁三角谬论”或类似内容,看看你能发现什么。
这并不是说你可以避免在构建系统时对成本、范围和时间线进行权衡取舍的需要。简而言之,打破铁三角的方法是通过应用我们在本课程中一直讨论的原则和流程,例如构建松散耦合的系统、优化“双向门”决策以及深入理解利益相关者的需求。通过应用这些原则和流程,你将能够更好地在可预测的时间线和预算内构建和维护高质量的数据系统。


下节预告
我们将在下一课中更深入地探讨权衡取舍的考量,届时你将了解可用于构建系统的不同工具和技术的实际成本与能力。我们下节课见。
070:需求收集与系统设计模拟 🎯

在本节课中,我们将通过一个模拟项目,练*如何将需求收集转化为系统实现。我们将回顾课程中已学的知识,并体验从需求分析到工具选型的完整流程。这是一个简化版的实战模拟,旨在帮助你理解真实项目中数据工程师的工作。
项目背景与目标 🎯
上一节我们介绍了推荐系统的基本概念,本节中我们来看看如何为一个具体的推荐系统项目收集需求并设计解决方案。你的目标是将一个项目从需求收集阶段推进到实施阶段,运用本课程所涵盖的知识。
这是一个微观模拟,真实世界中从需求收集到系统最终实现可能需要数周、数月甚至更长时间。而在这里,我们将在几小时内完成从一端到另一端的流程。这仍然是一个非常有用的练*,能帮助我们实践目前讨论过的内容。
课程计划与步骤 📋
以下是本练*的具体步骤安排。
首先,在下一个视频中,你将看到数据工程师与数据科学家之间的对话。这位数据科学家我们在第一周课程中已经接触过。对话将聚焦于我们在上一课中详细讨论过的推荐系统。你将可以访问对话的文字记录以及视频后的阅读材料,以便轻松回顾对话的任何细节。
你的目标是,通过回顾这段对话,提取出功能性和非功能性需求。这些需求将补充我们在上一课中写下的内容。
以下是完成此目标的具体步骤:
- 通过完成文字记录阅读材料后出现的测验来回答问题,从而识别需求。
- 完成需求识别测验后,在下一组视频中,你将听到AWS的Morgan介绍各种可用于实现解决方案的AWS工具和服务。
- 在有机会回顾这些内容后,你将准备进行下一个测验。在该测验中,你需要确定哪些工具和服务满足你的数据系统需求。
- 最后,你将进入实验环境。推荐系统的基础设施已为你设置好,你将根据测验中所做的工具选择,逐步定制该系统。
正如已经提到的,这是一个微观模拟,其体验比作为数据工程师在工作中所预期的要简短和有限得多。

但是,如果你花点时间想象自己在现实世界中经历这个过程,并思考在没有所有这些辅助的情况下构建这样一个系统可能会是怎样的,那么我认为这将是一个非常有用的练*。
总结 🏁
本节课中,我们一起学*了如何为一个推荐系统项目进行需求收集。我们概述了从分析对话、提取需求,到评估AWS工具并做出选择,最终在预设环境中实施定制方案的完整模拟流程。这个练*旨在帮助你初步建立从需求到实现的系统性思维。现在,让我们开始吧,请继续完成阅读材料和测验,我将在后续的视频中与你一起 walkthrough 实验练*。
071:与数据科学家的后续对话 📊

在本节课中,我们将学*如何通过与数据科学家进行深入对话,来明确一个推荐系统原型的数据需求、性能预期和未来扩展性。我们将把对话内容整理成一份清晰的技术需求文档。
很高兴再次见到你,科琳。你看起来有点像我不久前交谈过的那位软件工程师,只是没戴眼镜。不过,我们经常听到这种说法。
上次我们交谈时,我们讨论了你为营销团队正在进行的两个项目:一个分析看板和一个推荐系统。之后,我实际上有机会与产品营销经理进行了交谈,更深入地了解了他们对这两个系统的需求。接着,我会见了一位平台团队的软件工程师,以了解更多关于如何最佳地访问他们在销售平台上生成的数据。
现在,我想做的是从你这里了解更多关于你设想推荐系统将如何工作的细节,这样我们就可以开始构建一个服务于该系统的数据管道原型。
你能告诉我更多关于你在这个项目上迄今为止的工作吗?
当然可以。在过去一个月左右的时间里,我一直在尝试一些关于推荐系统的模型和想法。目前,我决定实现一个基于内容的推荐系统。
其工作原理是:我获取一组包含每个产品信息的特征,以及一组包含每个用户信息的特征。然后,我为每个用户和每个产品计算一个向量嵌入,并寻找这些嵌入之间的相似性,以便向用户推荐产品。因此,模型将用户和产品特征作为输入,并生成一个产品ID列表作为输出。
太棒了,看来你已经有了一个可以运行的东西了。
嗯,算是吧。我一直在本地机器上试验一些模型。我用最初从仪表板下载的一些用户和产品数据训练了一个基于内容的推荐模型。模型似乎运行得不错。我接下来想尝试的是,基于一批新数据重新训练模型,以观察其稳定性,并尝试了解在部署中我们可能需要多频繁地重新训练和更新模型。
好的,很好。那么,如果你能告诉我更多关于训练数据所需的格式和结构,我就可以开始制定一个数据管道的计划,以分批向你交付这些数据。
是的,那太好了。我使用的训练数据是表格格式。每一行包含一次产品购买的数据,其中列包括:
以下是用户特征集合:
- 客户编号
- 信用额度
- 城市
- 邮政编码
- 国家
以下是产品特征集合:
- 产品代码
- 库存数量
- 制造商建议零售价
- 产品线
- 产品规模
除了这些用户和产品特征外,还有一个1到5的评分值,代表用户对该产品的评分。
明白了。现在,如果要你猜测,你认为你可能希望多频繁地重新训练和更新已部署的模型?
简短的回答是,我还不确定。我计划监控模型的输出。实际上,如果除了在平台上展示推荐结果外,所有模型输出都能自动保存以供后续分析,那就太好了。然后,如果我注意到性能出现漂移或输入数据发生变化,我计划重新训练模型。所以,我可能希望每周重新训练一次模型,但也可能频率更低,比如每月或每季度。因此,如果交付新一批训练数据(并且如果我们有新的产品或用户特征,可能还需要修改格式)不需要太多的操作开销,那就太好了。
很好,这些都很清楚了。现在,你能再告诉我一些关于你期望推荐模型在生产中如何使用的信息吗?
好的,我是这样想的:我希望基于用户信息以及他们正在浏览或购物车中产品的任何信息来生成推荐。我设想的工作方式是,模型将设置为接收用户信息以及他们正在查看的任何数量的产品信息作为输入。然后,我可以基于用户信息找到一组推荐产品,并基于他们正在浏览或购物车中的产品找到额外的推荐产品。
那么,系统需要多快生成推荐?
当然,我们希望能够在用户浏览不同产品或结账过程中,*乎即时地向他们展示推荐产品。通常,一个新页面需要一两秒钟来渲染。所以,如果推荐系统能那么快工作,那就很理想了。
实际运行模型并生成推荐需要多长时间?
哦,模型非常快。在我的本地机器上,给定一组输入特征,生成推荐只需要几毫秒。我的设置方式是,我已经存储了产品目录中所有产品的向量嵌入,这样当我运行模型时,我可以快速进行相似性计算。据我了解,平台将当前在线用户的数据记录在一个事件日志中,所以应该可以以非常低的延迟从那个日志中流式传输事件。
因此,假设销售平台能够提供用户和产品数据,并以亚秒级延迟接收和渲染产品推荐,我大概有一秒左右的时间来完成整个往返过程,包括数据摄取、转换、向模型提供用户和产品特征,然后将推荐的产品ID列表返回给平台。
关于可扩展性呢?你预计需要同时为多少并发用户提供产品推荐?
公司目前数据库中有大约10万名客户,这意味着许多独立客户至少购买过一件商品,其中许多是回头客。随着公司扩展到新地区和产品线,我们预计这个数字还会增长。所以目前变化很大,有时平台上只有几个人在购物,但我们观察到同时在线用户的活动峰值可达1万人,未来可能会更多。
好的,听起来在并发用户数量方面可能会有很大的波动范围。
我想在信息方面,我已经得到了现阶段所需的一切。非常感谢你,科琳。
好的,太好了。如果有任何问题出现,请告诉我。
谢谢。
在本节课中,我们一起学*了如何通过与数据科学家沟通来定义数据工程需求。我们明确了推荐系统所需的数据格式(表格数据,包含用户特征、产品特征和评分)、模型类型(基于内容的推荐系统,使用向量嵌入计算相似性)、性能要求(亚秒级延迟,以匹配页面渲染速度)以及可扩展性预期(支持从少量到上万名并发用户)。这些信息为设计一个高效、可扩展的数据管道奠定了坚实基础。
072:AWS批处理管道服务 🚀

在本节课中,我们将学*如何将系统需求转化为具体的技术选型,并重点介绍AWS平台上可用于构建批处理数据管道的核心服务。我们将从理解需求与工具的匹配关系开始,逐步探讨不同的AWS服务选项及其适用场景。
从需求到工具选择
上一节我们讨论了如何收集系统需求,本节中我们来看看如何将这些需求转化为具体的技术和工具选择。

将系统需求转化为实际的数据系统时,你需要熟悉不同服务的用途。这就像为一次旅行选择交通工具。假设你需要将整个数据团队从A地运送到B地,你会如何选择?
以下是两种交通工具的参数对比:
- 大型喷气式客机:航程10,000海里,最高时速1100公里/小时,可容纳250多名乘客,成本2.25亿美元。
- 特斯拉 Model S:续航360公里,最高时速320公里/小时,可容纳4名乘客,成本约7万美元。

你会选择哪种交通工具?答案显然取决于你的具体需求。如果是从纽约到巴黎,可能需要飞机。如果只是从纽约到波士顿且只有四个人,特斯拉或许更合适。如果预算紧张,四辆自行车也可能是选项。
这个类比说明,除了系统需求,你还需要熟悉可供选择的技术,了解它们的用途以及如何组合它们来实现目标。
批处理工作负载的AWS服务
对于本周你将构建的数据系统,它包含批处理和流处理两个部分。在本视频中,我将介绍一些支持AWS上批处理工作负载的基础服务。下一视频我们将探讨支持流处理工作负载的AWS服务。
正如上周所见,批处理数据的一个常见方法是提取-转换-加载(ETL) 管道。在本周的练*中,你需要从源系统摄取数据,应用一些转换以使其符合数据科学家所需的格式,然后将其加载到存储中并提供访问权限。因此,ETL范式似乎是合适的。
你将摄取的数据是表格数据。我们假设你将使用的源系统是Amazon关系数据库服务(RDS)。正如Joe在课程早期提到的,数据库是数据工程师非常常见的源系统。通常,你无法控制源系统本身。因此,我们不会花时间比较不同的源系统,而是假设你需要做的选择在于下游的摄取和转换组件。
对于接下来的摄取和转换步骤,有多种不同的方法可供选择。
例如,你可以直接启动一个EC2实例,编写一系列脚本来连接数据库、摄取和转换数据,然后将其发送到某个存储位置。这当然可行,但请记住Joe关于避免“无差别的繁重工作”的建议。采用基于EC2的方法,你将负责安装软件、管理安全以及部署云服务器带来的所有复杂性。因此,在这种情况下,为一个相对简单的ETL管道创建自定义解决方案可能不是最佳的时间利用方式。
在比较服务的无服务器、传统服务器和容器选项时,Joe的建议是首先考虑无服务器工具,如果无法满足需求,再考虑容器和服务器选项。我同意这个建议,因此让我们看看在这种情况下有哪些无服务器选项。
AWS Lambda 是最早也是最流行的AWS无服务器工具之一。使用Lambda函数,你可以让代码响应触发器或事件运行。对于本周的ETL管道,你当然可以考虑使用Lambda函数从源系统提取数据、应用转换并将其发送到存储。然而,Lambda函数存在限制,例如每次函数调用有15分钟的超时限制,以及每次函数的内存和CPU分配限制等。这可能意味着你需要将任务分解成更小的块以适应这些限制。此外,编写Lambda函数需要你为特定用例编写自定义代码,这同样可能不是最佳的时间利用方式。
在专门用于数据批处理的无服务器工具中,有两个服务需要介绍。

核心批处理服务:Glue ETL 与 EMR Serverless
从某种意义上说,Amazon Glue ETL 和 Amazon EMR Serverless 这两个服务在功能上存在相当多的重叠,具体项目的细微差别可能决定了哪个工具最能满足你的需求。但概括来说,两者的区别在于控制力与便利性之间的权衡。简单来说,EMR Serverless 让你对能做的事情有更多控制权,而 Glue ETL 提供了更便捷的体验。让我们深入细节以便理解。
EMR 是作为一个大数据工具设计的,支持广泛的框架,如 Apache Spark 和 Apache Hive。因此,如果你的团队正在进行PB级别的数据分析,可能使用Hadoop,或者需要灵活性来集成自定义组件,那么EMR或EMR Serverless可能是正确的选择。
Glue ETL 也能处理大数据工作负载,但其真正的优势在于你可以访问的附加功能。例如,当你连接到源系统时,Glue使用称为爬虫程序的工具,自动发现和分类数据,并在此过程中创建元数据,包括表定义和模式等信息。这些元数据随后用于填充 Glue数据目录,这是一个包含所有数据资产信息的中央存储库。
有了数据目录中的信息,你可以使用 Glue可视化ETL工具 在AWS管理控制台中以图形界面设计管道,该工具会自动生成管道中需要运行的Spark代码。当你运行管道时,服务会维护Glue数据目录以跟踪你应用的转换,该目录可以在下游用于更轻松地与其他AWS服务集成。
在AWS上构建ETL管道的摄取和转换部分,还有其他选项可以考虑,但以上是我想要与你分享的主要选项。在本视频后的阅读材料中,你会找到关于我们提到的服务以及其他服务的更多详细信息。
存储与提供数据

当涉及到本周你正在处理的批处理管道的存储和服务方面时,你的选择主要取决于所服务的下游用例。
例如,如果你正在摄取规范化的表格数据,然后应用转换以星型模式对其进行建模以进行分析,那么你可以选择在另一个RDS实例中存储和提供数据。
或者,如果你想对海量数据集运行复杂的分析查询,并利用数据仓库提供的其他功能,你可以选择在 Amazon Redshift 中存储和提供数据,这是一个强大的数据仓库解决方案,尽管成本显著高于RDS。
本周,你将服务于一个机器学*用例,数据将用于训练推荐模型。当你的下游数据消费者是另一位技术数据专业人员,计划操作数据并将其集成到他们自己的系统中时,通常最佳且最便宜的存储和服务选项是 Amazon S3 上的对象存储。
在现实世界中,对于基于AWS构建的数据系统,S3作为此类“暂存区”相对常见,因为S3灵活、可扩展且具有相对成本效益。它允许你存储几乎任何类型的数据,并能轻松与其他AWS服务集成。
在S3中,你将数据存储在存储桶中,存储桶是对象的容器。构建数据管道时,根据手头的任务,你可能会在管道的不同阶段使用多个S3存储桶。
总结

本节课中我们一起学*了如何根据系统需求选择AWS批处理服务。我们探讨了从需求分析到工具选型的思路,比较了自定义脚本、AWS Lambda、Amazon Glue ETL和Amazon EMR Serverless等不同方案的优缺点,并了解了如何根据下游用例(如分析、机器学*)选择合适的存储服务(如RDS、Redshift、S3)。关键在于权衡控制力与便利性,并选择最符合项目目标且高效的工具组合。下一节,我们将把目光转向流处理工具。
073:AWS流处理管道服务 🚀
在本节课中,我们将学*AWS平台上用于构建流处理管道的核心服务。我们将探讨如何摄取、处理和存储实时数据流,并比较不同服务的特点与适用场景。
上一节我们介绍了AWS的批处理管道服务,本节中我们来看看用于处理实时数据流的服务。
流处理概述
在构建数据系统时,除了批处理组件,系统通常还需要一个流处理组件来处理连续到达的数据。流数据可能来自多种不同的源头。
以下是常见的流数据来源:
- IoT设备传感器数据
- 网站或移动应用的点击流数据
- 通过变更数据捕获(CDC)过程持续捕获的数据库变更
自定义流处理方案的挑战
与批处理类似,一种潜在的流数据摄取方式是启动一个EC2实例并编写自定义脚本来执行CDC或连接其他流数据源,然后转换数据并将其发送到下游。
这种基于EC2的方法意味着您需要负责安装软件、管理安全以及处理在云上部署服务器带来的所有复杂性。
遵循与批处理相同的思路,您也可以考虑使用Lambda函数作为无服务器选项来创建自己的流处理系统。但这同样需要为您所需的功能编写自定义代码,并且Lambda可能对您的特定用例存在潜在限制。
此外,与流数据源交互可能比运行批处理工作负载更复杂。因此,除非您100%确定现有开源或托管工具无法满足您的用例,否则您可能不应该使用EC2或Lambda构建自定义的流处理解决方案。
AWS流处理服务
现在,让我们看看一些可以支持流处理工作负载的AWS服务。
Amazon Kinesis Data Streams
Amazon Kinesis Data Streams是一项流行的AWS服务,支持实时数据摄取。
其工作方式是:数据生产者将数据发送到Kinesis Data Streams。Kinesis本身对您发送的数据类型并不挑剔,它是数据无关的。因此,您可以将JSON、XML、结构化或非结构化数据发送到数据流。
数据由生产者发布到流中,然后在Kinesis中存储一段可配置的时间。默认和最短保留时间为24小时,但也可以延长。存储的数据随后可以被数据流的消费者拉取。多个消费者可以拉取相同的数据并以不同的方式进行处理。
Kinesis消费者通常会将数据转移到其他地方(例如存储服务或数据仓库),或者对流过流的数据进行一些实时分析。这些消费者可能是从流中拉取并处理数据的软件应用程序,该应用程序可以运行在EC2或Lambda等计算服务上。
Amazon Managed Streaming for Apache Kafka (MSK)
除了Kinesis,您还有另一个选择:Amazon Managed Streaming for Apache Kafka,简称MSK。MSK是一项提供与Kinesis Data Streams许多相同功能的服务。
Apache Kafka本身是一个开源的流处理平台,是许多不同流处理用例的热门选择。MSK是一项完全托管的服务,使构建和运行使用Apache Kafka处理流数据的应用程序变得更加容易。
MSK运行开源版本的Kafka,这很有用,因为Apache Kafka社区的任何现有应用程序、工具或插件都受支持。
MSK的工作方式是:您首先创建一个Apache Kafka集群,MSK服务负责为您配置和运行Kafka节点的繁重工作。这使您可以避免那些无差别的繁重工作,将更多时间集中在自定义应用程序逻辑上。然后,您作为用户与MSK为您管理的所谓Kafka数据平面进行交互,以创建主题、生产和消费数据。数据生产者和数据消费者随后连接到集群以发送和接收消息。
服务比较与选择
Kinesis Data Streams和MSK都可以扩展到处理来自多个数据源的PB级数据量,延迟在毫秒级别,从而实现实时处理和分析。
在选择使用哪一个时,就像为数据系统的其他方面在类似工具之间做选择一样,这将取决于您的具体用例。但概括来说,您可以再次将其视为在控制力和便利性之间的权衡。
如果您是数据流架构的新手,通常推荐使用Kinesis,因为它相对用户友好且操作开销较低。另一方面,如果您已经在运行Kafka集群,或者团队内部拥有现有的Kafka技术经验,或者您寻求更高程度的灵活性和控制力,那么MSK可能是更好的选择。
数据摄取与存储:Amazon Kinesis Data Firehose
关于从流中读取数据并将其存储在其他地方的用例,接下来我想介绍的服务是Amazon Kinesis Data Firehose。
首先了解一下Data Firehose服务存在的原因:事实证明,Kinesis是作为流数据系统的服务首先推出的,AWS意识到许多Kinesis Data Streams用户只是简单地将流数据存储在S3或其他地方。但要以这种方式使用Kinesis,您需要编写自定义代码来创建与数据流的连接、读取流、分块数据然后存储它。
为了使整个过程更容易,AWS创建了Amazon Kinesis Data Firehose服务。它可以与Kinesis Data Streams集成,旨在让您能够从流中获取数据并将其存储在S3或Redshift等目的地,或发送到HTTP端点或Datadog、Splunk等第三方服务提供商。
Data Firehose的主要要点是,它帮助您更轻松地从流中读取数据并将其移动到存储,而无需编写自定义代码或自己创建任何复杂的集成。
除了Kinesis Data Streams,Data Firehose还与超过20个其他AWS源集成以摄取流数据,包括MSK等。
总结与实践预告

与我们在本课程中讨论的所有其他AWS云主题一样,关于流处理资源和服务还有很多需要了解的知识,但我认为您现在已掌握了所需的基础。
接下来是时候亲自动手实践这些服务了。在接下来的测验中,您将确定在本课程中一直关注的产品推荐系统的数据管道中,批处理和流处理组件应使用哪些服务。

之后,Joe将带您完成本周的实验练*,您将在其中实现这个批处理和流处理管道。祝您实践愉快,我们下节课再见。
074:实现批处理管道 🧪

在本节课中,我们将学*如何为一个推荐系统实现批处理架构。我们将使用 AWS 服务来转换数据,为后续的机器学*模型训练做好准备。
概述
在观看了与数据科学家的对话、探索了架构选择并完成了测验之后,现在是为推荐系统实现批处理和流处理架构的时候了。你将首先实现批处理管道,为数据科学家提供训练推荐系统所需的数据。接着,你将设置一个向量数据库来存储推荐系统的输出嵌入。最后,你将实现流处理管道,该管道使用训练好的推荐系统和向量数据库,根据用户的在线浏览活动输出产品推荐。
本实验包含详细说明,指导你如何使用 Terraform 创建资源以及如何在命令行终端中与它们交互。不必完全理解所有细节,本实验的主要目标是帮助你熟悉 AWS 上数据管道的批处理和流处理组件。
以下是批处理管道的架构图。

实验的第一部分聚焦于架构的这一部分,它负责转换数据,使其为训练做好准备。
探索源数据
与你在第二周看到的实验类似,这里提供了一个包含经典模型数据的 RDS MySQL 数据库,以及一个额外的表,该表由用户为他们购买的产品分配的评分组成。这些评分将作为训练数据的标签,推荐系统将在后台使用监督式机器学*模型进行训练。
为了准备训练阶段的数据,你将使用 AWS Glue ETL 从 MySQL 数据库摄取数据,然后将数据转换成特定形式。最后,你将把转换后的数据存储到标记为“数据湖”的 S3 存储桶中。你将使用 Terraform 创建 Glue ETL 和 S3 存储桶。
按照实验设置说明,我创建了这个 Cloud9 环境并下载了实验的详细说明。让我们从探索源数据库中提供的评分表开始。
要连接到源数据库,我们需要知道它的终端节点。

我将从实验说明中复制此命令,粘贴到终端中,将 MySQL DB name 替换为 D E, C1 W4 RDS,然后运行该命令。
这将返回数据库终端节点。接下来,我将使用 mysql 命令连接到数据库。主机是上一步获得的终端节点,数据库用户名是 admin,密码是 admin PWRD。

连接建立后,我将选择 classicmodels 数据库以查看其中的表。你可以看到有一个额外的 ratings 表。让我们通过运行以下查询来检查该表的内容:
SELECT * FROM ratings LIMIT 20;
该查询返回表的前 20 行。每一行包含客户编号、产品代码和产品评分。
探索完数据库后,你可以输入 exit 退出与数据库的连接。你将在课程 2 中了解更多关于连接和使用数据库的知识。
使用 Terraform 创建资源
在实验的下一部分,我将使用 Terraform 为批处理管道创建资源,包括 Glue ETL 和 S3 存储桶。首先,我需要在此环境中安装 Terraform。
scripts 文件夹包含一个名为 setup.sh 的脚本,其中包括用于安装 Terraform 和为 Terraform 定义一些环境变量的 shell 命令。该脚本还包含安装 PostgreSQL 的命令,你将在实验后期用它来设置向量数据库。
为了运行这些命令,我将复制该语句并粘贴到终端中。软件包安装完成后,我将把工作目录更改为 terraform 文件夹。
在运行 Terraform 之前,让我们快速查看一下这个文件夹的结构。在左侧,我将点击 Terraform,然后点击 modules。在本实验中,实验每个部分所需的资源被分组在文件夹或模块中。所以,如果我点击 etl,你可以看到用于 Glue 和 S3 存储桶的 Terraform 文件。
当你将 Terraform 文件组织成模块时,你需要在主 Terraform 文件中声明这些模块,该文件位于 modules 文件夹之外,这样你就可以向任何输入变量传递值,并在主文件中使用模块的任何输出值。
有一个声明 etl 模块的部分,其中包含指向该模块的链接以及传递给其输入变量的一些值。通过删除每一行中的 # 号来取消注释该部分,或者你也可以使用快捷键 Ctrl + / 或 Cmd + / 一次性取消注释整个部分。确保保存对文件的更新。
接下来,我将编辑 outputs.tf 文件,并取消注释声明 etl 模块输出变量的部分,即 S3 存储桶 data_lake 的 ID。如果你在此处取消注释第一行,请确保 etl 注释前没有空格。你将在课程 2 中更深入地理解这些各种 Terraform 文件。
保存更新后,我回到详细说明。在终端中,我将输入:
terraform init
然后:
terraform plan
最后:
terraform apply
Terraform 在创建资源之前总会提示确认。资源创建完成后,你可以看到输出文件。

运行 Glue 作业
现在,让我们运行将数据转换为所需形式的 Glue 作业。如果你好奇这个 Glue 作业的脚本是什么样子,可以打开 terraform 文件夹,点击 assets,然后点击 glue_job 来查看包含转换逻辑的 Python 脚本。
我回到说明中,复制此命令并粘贴到终端中以启动 Glue 作业。你可以通过写入以下命令来检查 Glue 作业的状态:
aws glue get-job-run --job-name <你的作业名> --run-id <上一步返回的ID>

我将用上一个命令返回的 ID 替换 job run ID。所以当前状态仍在运行,但如果你等待几分钟,状态将变为“成功”。我们将在课程 4 中进一步深入了解 AWS Glue 的细节。
验证输出数据
现在让我们检查 S3 存储桶 data_lake 是否包含训练数据。

在控制台中,我将输入 S3,点击该服务。


然后选择名称中包含 data_lake 的存储桶。



在这里,你可以看到一个标记为 ratings_ml_training 的文件夹,其中包含额外的文件夹,每个文件夹都与一个客户编号相关联。在对象存储中,这种组织数据的方式称为分区,它可以帮助你快速定位与任何客户相关的信息。
至此,我们已经将评分数据转换为可用于训练推荐系统的格式。在下一个视频演练中,我们将查看实验的下一部分,在那里你将设置一个向量数据库来存储推荐模型的输出。

总结

本节课中,我们一起学*了如何为一个推荐系统实现批处理管道。我们探索了源数据库中的评分数据,使用 Terraform 自动化创建了 AWS Glue ETL 作业和 S3 数据湖存储桶,并运行了数据转换作业。最终,我们将原始评分数据转换并分区存储,为后续的机器学*模型训练做好了准备。下一节,我们将继续学*如何设置向量数据库。
075:设置向量数据库 🗄️

概述
在本节课中,我们将学*如何设置一个向量数据库。这个数据库将用于存储和高效检索推荐模型生成的用户与商品嵌入向量。我们将从检查模型输出开始,然后使用 Terraform 创建数据库,最后将嵌入向量数据从云存储加载到数据库中。
检查模型输出
上一节我们介绍了批处理管道的架构。现在,转换后的数据已存储在 S3 数据湖中,并与数据科学家共享,用于训练推荐系统。
在本实验中,您无需亲自训练推荐系统,那是数据科学家的工作。您将使用一个已训练好的模型。
模型的输出存储在名为 “ML artifacts” 的 S3 存储桶中。我们通过检查该存储桶的内容来开始实验的第二部分。
在控制台中,回到可用存储桶列表,选择名称中包含 “ML artifacts” 的存储桶。
该存储桶包含三个文件夹:embeddings、models 和 scalars。
embeddings文件夹包含模型生成的用户和商品(即产品)的嵌入向量。models文件夹包含用于推理的已训练模型。scalars文件夹包含训练预处理阶段使用的对象。
目前,我们只关注嵌入向量。点击该文件夹,您会看到两个 CSV 文件:一个用于商品(产品),另一个用于用户。
这些嵌入向量将被模型用来为给定用户查找推荐商品。例如,商品嵌入向量将用于检索与用户购物车中商品相似的产品。
推荐模型首先会计算购物车中商品的嵌入向量,然后在商品嵌入向量中执行相似性搜索以找到类似产品。
数据科学家要求您将商品嵌入向量 CSV 和用户嵌入向量 CSV 文件上传到向量数据库,以使检索相似产品的过程更高效。

以下是创建向量数据库并上传嵌入向量的步骤。
创建向量数据库

按照实验第 2 部分的说明,我将打开 main.tf 文件,并取消声明向量数据库模块部分的注释。
接着,在 outputs.tf 文件中,取消注释 Spectre 数据库模块的输出变量。当您创建此数据库时,诸如数据库用户名、密码、主机(或端点)等输出文件将返回给您,以便您可以使用它们建立与数据库的连接。
请确保保存对 main.tf 和 outputs.tf 文件的更新。
现在,我们可以在终端中创建与 Spectre 数据库相关的资源。我将依次运行以下命令:
terraform init
terraform plan
terraform apply
在确认要创建这些资源后,创建 PostgreSQL 数据库大约需要七分钟。请注意,Terraform 不会覆盖之前创建的任何资源,它会保留它们并专注于创建新资源。
数据库创建完成后,您将能够找到主机名或端点。由于我需要此信息来连接向量数据库,我将复制此链接并粘贴到单独的笔记中备用。
我还需要密码和用户名,但它们被标记为敏感信息。因此,我需要从实验说明中运行这些命令,并将密码和用户名复制到单独的笔记中。

加载嵌入向量到数据库
现在,让我们将嵌入向量添加到向量数据库中。

点击左侧的 SQL 文件夹,然后打开其中的 SQL 文件。在这里,您可以找到一些 SQL 指令,用于将商品和用户嵌入向量从 ML artifacts S3 存储桶传输到向量数据库。
在此文件中,您需要指定存储桶的名称。我们回到控制台,进入存储桶列表,然后复制 ML artifacts 存储桶的完整名称。
接着,在 SQL 文件中,将存储桶名称粘贴到这两个 SELECT 语句中。请确保保存文件。
现在,您需要连接到向量数据库并执行 SQL 语句。

要连接到数据库实例,我将从实验第 2 部分的说明中复制连接命令,然后用我之前保存的数据库主机名替换命令中的主机部分。
系统将提示您输入密码,同样使用您之前保存的密码。输入时看起来不会显示任何字符,但按回车键后密码会被读取。
现在,为了在名为 postgres 的特定数据库中工作,我将在终端中运行以下命令:
\c postgres
同样,系统会提示您输入密码,请使用与之前相同的密码。
现在,为了运行来自 embedding.sql 脚本的 SQL 语句,我将在终端中运行以下命令:
\i sql/embedding.sql
然后,我运行以下命令来查看所有可用的表:
\dt
使用方向键向下滚动,查找包含嵌入向量的表。然后输入 q 退出查看。完成后,可以通过输入 \q 来退出连接。
总结

本节课中,我们一起学*了如何设置向量数据库。我们从检查已训练推荐模型的输出(即用户和商品嵌入向量)开始。接着,我们使用 Terraform 基础设施即代码工具创建了一个 PostgreSQL 向量数据库实例。最后,我们通过执行 SQL 脚本,成功地将存储在云存储中的嵌入向量数据加载到了新创建的数据库中,为后续高效的相似性搜索做好了准备。在下一节中,我们将介绍用于实时处理用户和商品数据的流处理管道部分。
076:实现流处理管道 🚀

在本节课中,我们将学*如何实现一个完整的流处理管道。我们将基于之前训练好的推荐系统和向量数据库,构建一个能够实时处理用户活动、生成产品推荐并存储结果的自动化工作流。
概述
上一节我们完成了推荐系统的训练和向量数据库的准备。本节中,我们将动手实现一个流处理管道。该管道的核心架构是:通过AWS Kinesis接收用户活动日志,使用Lambda函数进行数据处理和模型推理,最终将推荐结果存储到S3中。
以下是整个流处理工作流的架构图:

配置模型推理Lambda函数
在开始构建流管道之前,我们需要先配置一个关键的组件:模型推理Lambda函数。这个函数已经预先实现,但需要正确设置环境变量才能连接到我们准备好的向量数据库。
以下是配置步骤:
- 在AWS控制台中打开Lambda服务。
- 找到名称中包含
model inference的Lambda函数。 - 向下滚动并点击 Configuration 选项卡。
- 在左侧选择 Environment variables,然后点击 Edit。
- 在此处粘贴之前保存的数据库主机地址、用户名和密码。
- 点击 Save 保存更新。

核心概念:环境变量允许我们在不修改代码的情况下,动态配置Lambda函数的行为,其配置格式类似于:
DB_HOST=your_database_host
DB_USER=your_username
DB_PASSWORD=your_password
使用Terraform部署流处理管道
配置好Lambda函数后,接下来我们将使用基础设施即代码工具Terraform来部署整个流处理管道。这能确保我们的环境是可重复和一致的。
以下是部署流程:
- 根据实验指南第4部分的说明,在
main.tf文件中声明流处理模块。 - 同样地,在
outputs.tf文件中进行相应配置。


- 在终端中依次运行以下三条Terraform命令来初始化和部署资源:
terraform init terraform plan terraform apply
执行这些命令后,Terraform将创建Kinesis Data Firehose、用于存储推荐的S3桶以及流数据转换Lambda函数。

请注意:Kinesis数据流本身不会由Terraform创建,因为它已作为实验的预置资源提供。当你启动实验时,一个后台进程会自动向该数据流中注入模拟的用户活动事件。
验证管道运行结果
部署完成后,整个管道将自动运行。Kinesis Data Firehose会开始从数据流读取事件,调用Lambda函数将数据转换为推荐结果,并最终将这些结果传送到S3桶中。
为了验证管道的运行情况,我们可以进行以下检查:
1. 检查S3桶中的推荐结果
在AWS控制台中搜索并进入S3服务。

找到名称中包含 recommendations 的桶。进入桶内,你会发现数据已按照年、月、日、小时进行了分区。


核心概念:分区是一种将数据按特定维度(如时间)组织到不同文件夹的策略,其路径模式通常为:
s3://bucket-name/year=YYYY/month=MM/day=DD/hour=HH/
这种结构能帮助S3和查询引擎(如Athena)更快地定位和读取特定时间范围的数据。

2. 查看转换Lambda函数的日志
我们还可以查看数据处理过程的日志,以确认函数被正确调用和执行。

- 在AWS控制台中搜索并进入Lambda服务。
![]()
- 点击进入负责数据转换的Lambda函数。
- 点击 Monitor 选项卡,然后点击 View CloudWatch logs。
![]()

这里显示的日志记录了该函数在执行转换任务期间生成的信息,是调试和监控管道健康状态的重要依据。
总结与下一步
本节课中,我们一起完成了一个流处理管道的实现。我们配置了模型推理Lambda函数,使用Terraform自动化部署了包含Kinesis Firehose和S3的流处理架构,并验证了管道能够自动处理数据并生成分区存储的推荐结果。


现在轮到你了。请仔细按照实验指南的步骤操作,如果需要可以回看本视频。完成实验所有任务后,别忘了在实验设置说明页面提交你的成果。


重要提示:
- 实验环境将在两小时后过期,请合理安排时间。
- 如果对实验步骤有任何不清楚的地方,请不要担心。你将在后续的课程中对这些工具有更深入的理解。
![]()

完成实验后,我们将回到这里,对本门课程进行总结。
077:数据工程导论课程总结 📚

在本课程中,我们共同学*了数据工程的基础概念、生命周期及其核心组成部分。通过本课程,您已经迈出了成为成功数据工程师的重要一步。
课程回顾
上一节我们介绍了课程的整体框架,本节中我们来回顾一下各周的核心内容。
第一周:宏观视角与思维框架
在第一周,我们着眼于宏观图景。探讨了数据工程的历史及其发展脉络。我们审视了数据工程的定义及其生命周期,并以一个“像数据工程师一样思考”的框架结束了本周的学*。该框架可作为从需求收集到数据系统实施的参考。
第二周:数据工程生命周期详解
在第二周,我们深入探讨了数据工程生命周期的各个阶段。以下是生命周期的关键阶段:
- 数据生成与源系统
- 数据摄取
- 数据存储
- 数据转换
- 数据服务(用于分析、机器学*等最终用例)
同时,我们也研究了生命周期的底层支撑要素,包括:
- 安全
- 数据管理
- 数据运维
- 数据架构
- 编排
- 软件工程
这部分内容理论性较强,但理解这个高层思维框架至关重要。许多数据工程师在未理解此框架的情况下设计架构,常导致系统故障或安全漏洞。现在您已掌握此框架,它将指导您在后续课程中的工作。
第三周:数据架构与设计原则
在第三周,我们聚焦于数据架构以及构建良好架构的原则。这些原则将在您未来进行架构决策时反复用到。
第四周:综合实践
在第四周,我们进行了综合实践。您经历了从收集多方利益相关者需求,到最终实现一个产品推荐系统的完整过程。
如果您此刻感到有些信息过载,这完全正常。本课程涵盖了大量内容,且理论多于实践。因此,感觉知识储备激增但尚不确定如何应用,是可以理解的。
展望后续课程
但请不必担心,专项课程的后三门课程将全部围绕应用本课程所学的基础知识展开。
下一门课程将带您亲身体验源系统、数据摄取和数据管道。

期待在下一门课程中与您相见!

本节课中我们一起学*了数据工程的核心概念与生命周期框架,为后续的实践课程奠定了坚实的理论基础。
078:欢迎来到第2课程 🚀


在本课程中,我们将深入学*数据工程专业化的核心环节。你将了解如何从各种源系统获取数据,并掌握数据运维与端到端数据管道编排的关键知识。
欢迎来到数据工程专业化的第二门课程。在第一门课程中,你获得了数据工程领域的高层概述,了解了良好数据架构的原则,以及如何将利益相关者的需求转化为数据系统的需求和工具。
在本课程中,你将学*更多关于从源系统摄取数据、数据运维以及端到端数据管道编排的内容。
我们再次请到你的讲师乔·维兹,他也是畅销书《数据工程基础》的合著者。乔,你可以简要介绍一下学*者在本课程中将看到什么内容。
当然,安德鲁。正如你所说,本课程重点聚焦于数据工程生命周期的前两个阶段,即数据生成与源系统,以及从这些源系统进行数据摄取。
因此,我们将首先了解不同类型的源系统,例如数据库、对象存储和流处理系统。我们将深入探讨,作为一名数据工程师,你将如何在实际工作中与这些源系统进行交互。
之后,我们将研究从源系统摄取数据、数据运维与编排方面,以及构建数据管道。
这听起来很棒。对于许多人工智能系统而言,数据工程或数据摄取占据了约80%的工作量,而机器学*建模可能只占20%。但人们的注意力在这两个主题上常常是颠倒的,80%的注意力集中在AI建模上,而对数据摄取的关注、最佳实践和工具投入却远远不够。
事实上,在我早期于一家大型科技公司工作时,我曾负责公司的用户数据仓库。因此,每一条涉及单个用户的数据都应该进入我的数据仓库,这为公司创造了巨大价值。但设计数据库、数据库模式、摄取系统以及维护数据等智力工作,结果证明是一项相当庞大的工程。
这确实是一项庞大的工程。我一直认为,当我们谈论从源系统摄取数据时,这就是一切。如果你无法获取数据,那么你几乎无法对它进行任何处理。这听起来似乎很简单,但正如你指出的,很多时候摄取环节被忽视,或者重点放在了其他方面。因此,这是你需要正确完成的一项基础工作。如果无法获取数据,你确实无法进行其他任何操作。
所以,在本课程的这一部分,我们肯定会讨论如何理解你将从中获取数据的源系统、不同的数据摄取方式,以及编排这些数据管道工作流并对其进行监控的不同方法,以确保你能够保持数据质量、摄取性能和其他特性。这对于你作为数据工程师的工作至关重要。
事实上,我发现这对于许多不同的数据工作流都适用,从结构化的表格数据,到随着网络处理更多非结构化数据(如文本和图像),这一点似乎一直未变。甚至当我与训练大型语言模型的朋友交流,以及向领先的AI团队提供建议时,很多时候(虽然不是全部)实际上都花在了思考数据上,然后才是一些模型训练。但对于所有这些AI工作负载而言,数据摄取占据了如此多的时间,这真的很有趣。我想知道他们在数据摄取方面遇到了哪些复杂性,我猜想是在非常庞大的规模上工作。
是的,我认为确实存在很多互联网数据。例如,Common Crawl就有大量数据。但有了数据之后,你如何摄取它、处理它、筛选它以保证高质量?此外,如果你的数据存在缺口,你注意到你的模型在某些主题上表现不佳,你如何找出这些不足,以及究竟该去哪里获取数据(如果这些数据存在的话)来填补这些缺口?这些都是许多智力上的挑战。
我发现,即使是训练一些最大的开源大型多模态模型和其他大型基础模型的一线人员,也在花时间担心这些问题。
这很吸引人。我们在本课程中将要讨论、并且你将学*到的内容之一,就是从多种类型的源系统摄取数据。显然,我们会讨论摄取表格数据,但这只是当今整个数据宇宙中很小的一部分。当我们谈论从文本一直到图像和视频的非结构化数据集时,这个宇宙正变得越来越大。
我认为这在传统的数据世界中并未被充分考虑。因此,本课程将涵盖的内容之一,不仅仅是来自数据库的结构化数据集,我们还将涉及处理文本、图像数据等。这将帮助你作为一名数据工程师做好准备,不仅是为了今天的工作负载(例如,如果你在数据仓库领域工作),更是为了未来的工作负载。
到目前为止,数据的价值可能大部分来自结构化数据。但随着我们处理非结构化数据能力的增长,我们可能会看到这种平衡发生转变,也许已经在转变。世界上非结构化数据的体量远大于结构化数据的体量。因此,我认为这对数据工程师来说将是更大的挑战,也是更多的工作机会。
确实如此。希望这将是对数据工程生命周期的一次非常激动人心的介绍。再次强调,从源系统摄取数据、编排这些工作负载并监控这些工作负载,对于你作为一名数据工程师至关重要。正如安德鲁指出的,这只会变得更加有趣、更加激动人心,规模也会更大。
那么,让我们进入下一个视频,深入探讨所有这些主题。
079:数据工程(导论,源系统、数据摄取和管道,数据存储和查询|1-2-3课) - 第2课概览 📚

在本节课中,我们将要学*数据工程专项课程第二门课“源系统、数据摄取和管道”的整体结构与核心内容。课程将深入探讨数据生命周期的起点——源系统,并逐步引导我们构建稳健的数据管道。

欢迎来到“源系统、数据摄取和管道”课程的第一周。本周我们将从了解不同类型的源系统以及如何与这些系统交互开始。正如您在专项课程第一门课中所见,数据生成和源系统是数据工程生命周期的第一阶段。作为数据工程师,您通常不负责亲自生成这些数据或维护源系统,但从源系统进行数据摄取是所有数据管道的起点。因此,理解这些数据如何生成、存储在哪里、如何存储以及其部分特性至关重要,这样您才能为这些上游系统作为数据源构建稳健的数据管道。
在本课程的第一周,我们将深入探讨一些常见源系统的细节,包括不同类型的数据库、对象存储和流式数据源。在实验环节,您将有机会在AWS上实际操作这些源系统。

在第二周,我们将重点学*如何设置从源系统进行不同类型的数据摄取。
之后,在本课程的第三周,我们将关注数据运维(DataOps)的基础。您将使用基础设施即代码(Infrastructure as Code) 来自动化部分管道任务,并使用各种工具来监控数据质量。

最后,在本课程的第四周也是最后一周,我们将学*编排(Orchestration)技术,以协调数据管道中的各项任务。您将使用Airflow设置有向无环图(DAGs),使用基础设施即代码框架,并为您的数据管道实施监控解决方案。
总而言之,本课程将涵盖广泛的内容。

在下一个视频中,请与我一起开始,更深入地了解不同类型的源系统。

本节课中我们一起学*了第二门课程“源系统、数据摄取和管道”的总体路线图。课程将从剖析各类源系统开始,逐步过渡到数据摄取方法、DataOps实践,最终完成数据管道的编排与监控,为我们构建完整的数据工程能力打下坚实基础。
080:不同类型的源系统 📚


在本节课中,我们将要学*数据工程师在工作中会遇到的不同类型的源系统。我们将了解这些系统如何提供数据,以及这些数据通常以何种形式存在。课程将涵盖结构化、半结构化和非结构化数据,并详细介绍数据库、文件和流式系统这三种主要的源系统类型。
数据的主要类型
数据工程师处理的数据主要分为三种类型:结构化数据、半结构化数据和非结构化数据。
结构化数据
结构化数据以行和列组成的表格形式组织。你很可能在过去的工作中接触过结构化数据,无论是在电子表格、关系型数据库中,还是使用Python读取CSV文件。
半结构化数据
半结构化数据不以表格形式存在,但仍然具有一定的结构。一种常见的半结构化数据格式是JavaScript对象表示法,即JSON。
以下是JSON格式的一个示例:
{
"first_name": "Joe",
"last_name": "Reese",
"address": {
"city": "Wholesale",
"code": "12345",
"country": "USA"
}
}
JSON文件包含一系列键值对。每个值可以是不同的数据类型,例如数字、字符串或数组。键值对甚至可以包含另一系列键值对,从而形成嵌套的JSON格式。因此,即使数据不以表格形式呈现,它仍然具有一定的结构。
非结构化数据
非结构化数据没有预定义的结构。例如,文本、视频、音频和图像都是非结构化数据的例子。但需要注意的是,像视频、音频和图像这样的数据在幕后确实有其固有的结构,例如像素的维度以及红、蓝、绿等颜色信息。我们将在本课程中更深入地探讨非结构化数据。
源系统的三种主要类型
在摄取这些不同类型的数据时,可以将相关的源系统大致分为三类:数据库、文件和流式系统。
这三种源系统类型并不一定与上述三种数据类型一一对应。但可以说,从数据库中,你最常摄取的是结构化和半结构化数据;从流式系统中,你通常摄取的是作为数据格式的半结构化消息;而文件则可以是任何形式,从文本、图像、音频、视频到常规的行列式表格数据。
接下来,让我们逐一深入了解这三种源系统。
数据库
数据库以有组织的方式存储信息,允许你查找、检索、更新和删除数据。实现这一功能的核心操作被称为CRUD。
CRUD 代表创建、读取、更新和删除。创建操作排在首位,因为数据必须先被创建,然后才能被读取、更新或删除。
通常,一个称为数据库管理系统(DBMS)的软件接口位于物理数据库存储与用户或应用程序之间。DBMS允许你访问和操作数据库中存储的数据。
本周我们将关注两种类型的数据库:一种是存储行列表格信息的关系型数据库;另一种是非关系型数据库,也称为NoSQL或“不仅仅是SQL”数据库,它们存储非表格形式的数据。我们将在本周晚些时候更仔细地研究这两种数据库。
文件
除了数据库,你将与之交互的另一种最常见的源系统是文件。毫无疑问,你已经有很多处理各种类型文件的经验。
这些文件可能是存储在计算机中的文档、用手机拍摄的图像或视频,甚至可能是同事通过电子邮件发送给你的CSV文件。将普通的旧文件视为数据工程的源系统可能看起来有些奇怪,但从本质上讲,文件只是表示信息的一系列字节。各种类型的应用程序都将数据写入文件,因此文件是数据交换的通用媒介。
信不信由你,文件是数据工程师工作中最常见的源系统之一。文件就像数据一样,可以是结构化的(如电子表格)、半结构化的(如JSON或XML文件)或非结构化的(如文本、图像、视频或音频文件)。你可能从像Google Drive这样的文件系统、像Amazon S3这样的对象存储系统,或者仅仅是作为电子邮件附件来接收或访问这些文件。
流式系统
你可能摄取数据的第三种源系统是流式系统。你可以将流式系统视为提供连续的数据流,这些数据被记录为包含事件信息的消息。
这些事件包括世界上发生的某些事情或系统状态的改变。在实践中,你可能通过消息队列或其他流式平台与事件流进行交互。
例如,像智能恒温器这样的物联网设备可能会记录一个包含最新温度读数的事件,并将该事件作为消息发布到像Kinesis或Kafka这样的流式平台。然后,作为数据工程师,你可以设置另一个服务来摄取此消息,并向嵌入式分析仪表板发送更新。在这种情况下,你可以将流式平台视为从中提取原始数据的源系统。
在本课程后面的几周里,你将看到这些流式系统如何也能跨越数据工程生命周期,并在摄取和转换阶段用于处理各种下游用例的数据。
事实上,无论是数据库、文件还是流式系统,所有类型的源系统都可能扮演双重角色:它们可能是你摄取原始数据的系统,也可能是你在生命周期另一个阶段构建到数据管道中的系统。
总结
本节课中我们一起学*了数据工程师需要处理的不同类型的源系统。
我们了解到,数据工程师将从不同的源系统中提取原始数据。这些原始数据可能是结构化的、半结构化的或非结构化的。而源系统则可能是数据库、文件或流式系统。
在接下来的系列视频中,我将更详细地介绍每种不同类型源系统的特性。我们将从数据库开始,然后看看对象存储如何作为文件的数源,之后我们将更深入地探讨消息队列、日志和流式平台。请加入下一个视频,开始了解关系型数据库。




081:关系型数据库 🗄️

概述
在本节课中,我们将要学*关系型数据库。作为数据工程师,关系型数据库是最常见的源系统类型。我们将了解其基本概念、结构、优缺点以及如何与之交互。
什么是关系型数据库?
关系型数据库无处不在。许多Web和移动应用程序在后端使用关系型数据库。许多企业系统,如客户关系管理、人力资源和企业资源规划系统,也使用它们。关系型数据库还常用于在线事务处理系统,这些系统需要并发执行大量事务,例如银行或在线预订系统。


“关系型”一词源于这类数据库通常用于将数据存储在多个相互关联的表中。这些表通过一组键或共同属性相互关联。这些表通常根据业务中的信息结构进行组织。
例如,作为一名在电子商务公司工作的数据工程师,你可能需要处理一个关系型数据库。其中一个表存储客户信息,另一个表存储产品信息,第三个表存储订单信息。
数据库结构:多表与单表
上一节我们介绍了关系型数据库的基本概念,本节中我们来看看其具体的结构设计。
以这种方式构建数据库可以减少冗余,并使数据更易于管理。其核心在于避免同一信息在数据库的多个行或表中重复存储。
为了理解这一点,可以想象一下,如果不使用多个表,而是创建一个大表来存储每个单独的客户订单数据。在这种情况下,你的表可能包含大量列,包括客户的所有信息(如姓名、地址、电话号码等),以及他们购买产品的所有信息(如品牌、SKU编号、产品描述等),还有订单的详细信息(如日期、时间、购买金额和支付金额等)。
在这种场景下,如果一个客户为三种不同产品下了订单,这将被记录为数据库中的三行。那么表中将有三行包含完全相同的客户数据。或者,如果三个不同的客户购买了同一产品,那么数据库中会有三行包含该产品的相同信息。
简而言之,信息会在表的多个行中重复。除此之外,跨行的数据可能存在不一致。例如,如果客户更改了地址,除非你回去更新所有包含其旧地址的行,否则行之间就会出现不一致。如果某个产品的详细信息发生变化,你需要回去更新所有包含旧信息的行。
规范化与键
当你将客户、产品和订单的信息分离到多个表中时,情况就不同了。客户表中的一行代表一个客户,产品表中的一行包含一个产品的信息。如果客户更改地址或产品详情发生变化,你只需要更新包含该客户或产品信息的单一行。
数据库被组织成相关表的方式被称为数据库模式。关系型数据库通过使用键来表示表之间的关系。
- 主键:是表中唯一标识每一行的特殊列或列集合。对于客户表,主键可以是名为
ID的列。 - 外键:订单表和客户表之间的关系可以通过在订单表中设置
customer_id列来建立,该列引用客户表中的ID列。在这种情况下,订单表中的customer_id列被称为外键,它引用了客户表的主键(即ID列)。
除了行结构,在关系型数据库中,每一列都有唯一的名称和指定的数据类型。例如,在客户表中,可能有包含字符串的列,如ID、first_name和last_name,以及包含整数的列,如age。表中的每一新行都必须遵循相同的列结构,即相同的列序列和数据类型。这也是数据库模式的一部分。
现在,在具有此类模式的数据库中,要记录现有客户的新订单信息,你可以在订单表中创建一条新记录,并指明来自客户表的customer_id、来自产品表的product_id以及订单详情(如日期、时间、支付信息等)。同样,如果该客户更改地址或所订购产品的SKU编号发生变化,这些更改只影响客户表或产品表中的单一行,信息保持一致。
可以想象,建立表之间关系的方式有很多种,这就是数据规范化概念发挥作用的地方。数据规范化是20世纪70年代发展起来的一种方法,旨在通过以逻辑方式跨表存储数据来最小化冗余并确保数据完整性。
规范化的优缺点

但值得停下来思考一下:为什么首先要如此担心冗余或重复信息?像我描述的那样构建数据似乎合乎逻辑且有序,但有什么缺点吗?
事实证明,虽然规范化的关系型数据库结构提供了高度的完整性并最小化了冗余,但在查询数据时可能实际上很慢。如今,存储相对便宜,而速度往往至关重要。当然,数据完整性也极为关键。但如何存储表格数据的答案,可能取决于你试图优化什么。
作为一名数据工程师,你可能正在从关系型数据库系统中摄取规范化的数据。但根据你所服务的最终用例,你可能会决定在自己的存储系统中按照不同的模型来组织数据。如今,甚至有一些用例中,数据工程师选择采用所谓的“一个大表”方法,将所有数据记录在一个SQL表中以实现更快的处理,这在传统关系型数据库中连接多个表时可能无法实现。我们将在专业课程的第4课中更深入地探讨数据建模的细节。

关系型数据库管理系统与SQL
当需要与数据库交互时,你会使用关系型数据库管理系统。这是一个位于关系型数据库之上的软件层。市面上有许多流行的RDBMS,包括MySQL、PostgreSQL、Oracle和SQL Server。
大多数RDBMS都支持结构化查询语言。SQL提供了一组用于在关系型数据库上执行各种操作的命令。作为一名数据工程师,SQL将是你日常工作的一部分。
在下一个视频中,我将引导你了解一些在实验中将需要用到的SQL命令。然后在实验中,你将有机会练*使用SQL查询来查询关系型数据库中的数据。

总结

本节课中我们一起学*了关系型数据库。我们了解到它是数据工程中最常见的源系统类型,通过多表结构和键来组织数据以减少冗余。我们探讨了数据规范化的概念及其在确保数据完整性和减少冗余方面的作用,同时也指出了其在查询性能上可能的权衡。最后,我们介绍了通过RDBMS和SQL语言与数据库进行交互。接下来,让我们在下一个视频中一起看看NoSQL数据库。
082:SQL查询基础 🗃️

概述
在本节课中,我们将要学*SQL查询的基础知识。我们将从一个虚构的DVD租赁公司数据库入手,学*如何使用SELECT、FROM、WHERE、JOIN、GROUP BY等核心命令来检索和操作数据。课程内容将帮助你理解如何通过编写SQL语句来回答业务问题。
数据库与实验介绍
在实验中,你将使用一个名为“Bnio”的虚构DVD租赁公司的事务数据库。该数据库包含多个表,记录了商店、员工、客户、DVD库存和租赁交易等信息。
你将在Jupyter笔记本中编写SQL语句或查询,以从数据库中检索信息。为了有效地查询数据,你必须理解数据库的模式。
换句话说,你必须知道表的名称、它们包含的列,以及表之间如何通过主键和外键相互关联。
这个数据库是规范化的。这意味着像商店、员工和客户的地址这类数据被存储在单独的表中,以减少冗余,并在数据变更时更容易更新。
同样,关于电影和租赁交易本身的数据也存储在单独的表中。你可以参考这个实体关系模型,它展示了Rio数据库中表的关系和属性。

SQL基础:从单表查询开始
上一节我们介绍了实验的背景数据库。本节中,我们来看看最基本的SQL语句。我们将只关注三个表:包含电影标题和时长等信息的film表、包含电影类别列表的category表,以及显示电影ID与对应类别ID的film_category表。
最基本的SQL语句以SELECT子句开始,用于指定你想要的数据,后跟FROM子句,用于指定你想从哪个表检索这些数据。
例如,假设我想查看film表中的标题和发行年份。我可以这样写:
SELECT title, release_year
FROM film;
运行此查询后,我将获得所有标题和发行年份的列表。结果显示,film表中有1000部电影。如果我不想看到整个列表,可以使用LIMIT子句来限制返回结果的数量。
例如,如果我在查询末尾添加LIMIT 10,我将只从film表中获得前10个标题和发行年份。
但是,如果你想检索表中所有列的数据呢?
你可以在SELECT子句中列出所有列名,或者使用快捷方式,输入SELECT * FROM film。这将从film表中检索所有行和列的数据。
你将在下一门课程中学*查询在后台是如何执行的。但现在,你只需要知道,检索所有列的所有数据可能会消耗大量处理资源,尤其是在数据集非常大的情况下。
因此,我建议仅在需要查看表中所有数据时使用SELECT *。
使用WHERE和ORDER BY过滤与排序数据
上一节我们学*了如何选择数据。本节中,我们来看看如何通过布尔条件过滤结果。
例如,假设你只对时长少于60分钟的电影感兴趣。你可以在FROM子句后添加一个WHERE子句,根据length列过滤结果。
SELECT *
FROM film
WHERE length < 60;
这将返回96部时长少于一小时的电影列表。

你也可以按任意列对结果进行排序。例如,我可以在WHERE子句后添加ORDER BY length,以按电影时长升序排列结果。
如果我希望结果按电影时长降序排列,我可以在ORDER BY子句的末尾添加DESC关键字。
如果我想将结果限制为,比如说,10条记录,我可以在查询末尾添加LIMIT 10。
使用JOIN组合多表数据
你刚刚看到了如何使用SELECT、FROM、WHERE、ORDER BY和LIMIT子句从单个表中检索数据。如果你想探索来自多个表的数据呢?
你可以使用JOIN子句,基于表之间的共享列来组合两个或多个表中的记录。
例如,假设我想获取所有时长少于60分钟的电影标题及其对应的电影类别。
让我们扩展之前的查询,即SELECT * FROM film WHERE length < 60。我想基于匹配的film_id,将film表中的行与film_category表中的行组合起来。
因此,在FROM子句的末尾,我会写:JOIN film_category ON film.film_id = film_category.film_id。
这样,返回的结果将包括film表的所有列,以及每个匹配的film_id在film_category表中的列。
请注意,film_category表只包含category_id,而不包含类别名称。因此,我们需要再做一次JOIN,基于category_id将这些记录与category表中的行组合起来。
我将添加:JOIN category ON film_category.category_id = category.category_id。
现在,结果将包括film表的所有列、film_category表的所有列以及category表的所有列。
由于我只想要电影标题和对应的电影类别,我可以修改SELECT语句,指定我只想要film.title列和category.name列。
默认情况下,JOIN子句只组合两个表中在ON语句指定的列上具有匹配值的记录。它不会包含任一表中没有匹配值的任何记录。
例如,如果film表中有一行的film_id没有出现在film_category表中,那么该行将不会包含在结果中。这种类型的连接被称为内连接。你可以将连接结果想象成维恩图中中间重叠的部分。
其他类型的连接包括:
- 左连接:返回第一个表的所有记录,以及第二个表中任何匹配的记录。
- 右连接:返回第二个表的所有记录,以及第一个表中任何匹配的记录。
- 全连接:返回两个表的所有记录,并组合具有匹配值的记录。
回到上一个查询的结果,我可以看到相当多的短片属于儿童或纪录片类别。
使用GROUP BY进行数据分组与聚合
上一节我们学*了如何连接多个表。本节中,我们来看看如何对数据进行分组和聚合计算。
假设我想确切知道短片中最受欢迎的类别。我可以使用GROUP BY命令根据电影类别对行进行分组,然后使用COUNT命令计算每个电影类别的记录数。
GROUP BY命令写在WHERE子句之后。所以在这里,我将添加GROUP BY category.name。
然后,我将修改SELECT语句,选择category.name和COUNT(*),后者用于计算每个类别的所有行数。
我还可以使用AS命令为这个计数结果赋予一个别名,例如film_count。
最后,我将按film_count降序排列结果。

SELECT category.name, COUNT(*) AS film_count
FROM film
JOIN film_category ON film.film_id = film_category.film_id
JOIN category ON film_category.category_id = category.category_id
WHERE film.length < 60
GROUP BY category.name
ORDER BY film_count DESC;
如你所见,时长在一小时以内的短片中,最受欢迎的类别是纪录片,其次是动作片,然后是儿童片等等。
总结与后续
本节课中,我们一起学*了一些最常见的SQL命令,现在你已经准备好开始实验了。
实验还涵盖了一些数据操作操作,包括CREATE、INSERT INTO、UPDATE和DELETE。因此,在尝试每个练*时,请确保仔细阅读说明。


完成实验后,请加入我,一起了解NoSQL数据库。
083:NoSQL数据库 🗄️

在本节课中,我们将学*NoSQL数据库。我们将了解它们为何被创建,它们与关系型数据库有何不同,以及两种常见的NoSQL数据库类型:键值数据库和文档数据库。
21世纪初,像谷歌和亚马逊这样的科技巨头开始发现关系型数据库已无法满足其需求。
他们需要处理来自不同来源的大量数据,而这些数据无法整齐地放入关系型数据库模型中。
强制使用表格结构会导致数据冗余和大规模性能问题。
因此,这些公司引领了开发新型分布式非关系型数据库的道路,以扩展网络平台。
就这样,NoSQL数据库被开发出来,以克服关系型数据库的局限性。
它们牺牲了关系型数据库管理系统(RDBMS)的某些特性,如强一致性、连接操作和固定模式,以换取更高的模式灵活性、可扩展性和更好的性能。
在深入之前,我们先澄清一点。NoSQL并不代表“没有SQL”。
它的意思是“不仅仅是SQL”。这是一类数据库,它们摆脱了我们在上一个视频中看到的关系型框架,但一些非关系型数据库仍然支持SQL或类SQL查询语言。
NoSQL数据库基础
让我们回顾一下NoSQL数据库的基础知识。
NoSQL数据库具有非表格结构。

它们可以支持各种数据格式,包括键值、文档、宽列、图等。
我将在本视频后面讨论键值型和文档型,你会在接下来的几门课程中看到其他一些类型。
与关系型数据库不同,NoSQL数据库不需要预定义的模式。
这意味着你在决定如何存储数据时拥有更大的灵活性。
NoSQL数据库擅长水平扩展,这意味着可以自动将数据和工作负载分布在多个服务器上,以应对增加的流量需求。
当用户向一个分布在多个服务器或节点上的NoSQL数据库写入数据时,该写操作首先在单个节点上执行。
在这个分布式系统中,数据库的一个版本正在运行,然后这些更改传播到系统中所有其他节点可能会有轻微的延迟。
与关系型数据库不同,NoSQL数据库遵循最终一致性原则,而不是强一致性。这意味着数据库允许你从一个尚未收到最新写入更新的节点读取数据,你可能无法获得最新的数据。但只要有足够的时间,数据库将达到一致状态,从任何节点读取数据都会得到相同的数据。
对于提供强一致性的关系型数据库,在系统中的所有节点都更新之前,你将无法读取数据。
通过这种方式,最终一致性允许NoSQL数据库优先考虑速度,这对于系统可用性和可扩展性比实时一致性更重要的应用程序来说是完美的,例如社交媒体平台或内容分发网络。
在数据完整性方面,并非所有NoSQL数据库都保证原子性、一致性、隔离性和持久性原则,也就是我们将在下一个视频中看到的ACID合规性。
但有些数据库确实保证,例如MongoDB。
这意味着,如果你从NoSQL数据库获取数据,那么你可能需要采取额外的步骤来确保数据完整性。
最后,NoSQL数据库使用专门针对其数据模型定制的查询语言,这些语言通常(但不总是)与SQL不同。
两种常见的NoSQL数据库
现在,让我们更仔细地看看两种常见的NoSQL数据库类型:键值数据库和文档数据库。
键值数据库将数据存储为键值对的集合,类似于你在JSON文件或Python字典结构中可能找到的。
键作为唯一标识符来检索对应的值。
键和值都可以是从简单到复杂的任何对象。
这种类型的NoSQL数据库非常适合需要快速数据查找的场景,例如缓存Web或移动应用程序中的用户会话数据。
例如,当用户登录一个应用程序时,查看不同产品、将商品添加到购物车和结账等操作都可以存储在键值数据库中,以用户会话ID作为唯一标识符。
文档存储是一种特殊类型的键值数据库,它以类似JSON的文档形式存储数据。
每个文档都有一个唯一的键,用于标识文档并允许你检索该文档的数据。
文档被组织成集合,因此你可以将集合视为类似于关系型数据库中的表,而文档则类似于表中的一行。
在这个例子中,数据存储在一个名为“用户”的集合中。每个文档代表一个用户,ID是唯一标识每个用户的键。
这种局部性使得检索特定用户的所有信息比在关系型数据库中更容易,因为在关系型数据库中,用户信息可能分布在多个表中。
然而,文档存储不支持连接操作,因此与在关系型数据库中跨多个表组合信息相比,组合来自多个文档的信息更加困难且效率较低。
但它的优势在于灵活模式的概念。正如你在关系型数据库中看到的,所有记录都需要符合固定的模式,但对于键值数据库和文档存储,数据记录没有固定或预定义的结构。
文档存储通常用于涉及内容管理、目录和传感器读数的应用程序。例如,来自物联网设备的每次交互、产品或传感器读数,都可以存储为具有灵活模式的单个文档。
但要小心,这种灵活性可能有缺点。我曾见过文档数据库变得难以管理和查询,成为一场噩梦。如果你从NoSQL文档存储作为源系统获取数据,模式的灵活性使得源系统所有者更容易做出更改,从而破坏你的数据管道。
应用场景与总结

关系型数据库和NoSQL数据库都可以用于广泛的应用。
在处理在线事务的应用程序中,例如银行、金融和电子商务等领域,事情发生得很快,资金在流动,产品在移动。
在这些类型的在线事务处理(OLTP)应用程序中,数据中的任何错误或不一致都可能导致重大问题。
在下一个视频中,我们将看看原子性、一致性、隔离性和持久性原则,也就是所谓的ACID原则。在处理OLTP系统时,这些原则对你的数据源和数据管道至关重要。

本节课中,我们一起学*了NoSQL数据库。我们了解了它们诞生的背景、核心特性(如灵活模式、水平扩展和最终一致性),并深入探讨了键值数据库和文档数据库这两种常见类型的工作原理与适用场景。我们还比较了它们与关系型数据库的差异,并指出了在数据工程实践中需要注意的潜在挑战。
084:数据库ACID合规性 🧱

在本节课中,我们将要学*数据库事务处理中的一个核心概念——ACID合规性。理解ACID原则对于确保数据在交易过程中的可靠性和准确性至关重要,尤其是在处理银行转账、在线购物等关键业务时。
概述
关系型数据库和非关系型数据库都能支持高事务处理率,因此它们常被用于在线事务处理系统。这些系统通常需要存储快速变化的应用程序状态,例如银行账户余额或在线订单的详细信息。大多数关系型数据库系统默认是ACID合规的,这意味着它们支持原子性、一致性、隔离性和持久性原则,以确保OLTP系统中的事务被可靠且准确地处理。相比之下,许多NoSQL数据库默认并不完全ACID合规,但通常允许你通过配置来实现。
ACID原则详解
上一节我们介绍了ACID合规性的重要性,本节中我们来看看这四个原则的具体含义。
原子性
原子性确保事务被视为一个不可分割的单元。一个事务可能包含多个操作,但原子性原则保证这些操作要么全部成功执行,要么全部不执行。
公式/概念描述: 事务 = {操作1, 操作2, ...}, 原子性保证 ALL(操作) 成功 或 NONE(操作) 成功。

例如,客户下单购买商品的事务可能包含两个操作:从客户账户扣款和更新库存。如果在扣款后、更新库存前发生网络错误,原子性原则将回滚已完成的扣款操作,确保整个事务失败,客户不会被错误扣费。
一致性
一致性原则要求事务对数据所做的任何更改都必须遵循数据库模式中定义的一组规则或约束。这确保了数据库从一个有效状态转换到另一个有效状态。
公式/概念描述: 事务前状态 符合约束 → 事务后状态 也符合约束。
例如,如果库存数据库模式规定库存水平不能低于零,当前某商品库存为1。当客户试图订购2件该商品时,事务将失败并回滚,以保持数据库与预定义模式的一致性。
注意:这里的“一致性”与上节课提到的分布式系统中的“强一致性”概念相关但不完全相同。数据库系统的强一致性是ACID合规的结果,而ACID中的“C”更侧重于事务层面的约束遵循。
隔离性
隔离性确保当多个客户端尝试并发执行事务时,每个事务都像是被独立、按顺序执行的。
公式/概念描述: 并发事务 T1 和 T2 的效果,等同于某种顺序执行(如 T1 → T2 或 T2 → T1)的效果。
例如,假设库存显示某商品剩余10件,两个客户同时各自订购5件。隔离性原则保证,即使两个事务的时间戳相同,它们也会被独立、按顺序处理。最终库存将变为0,而不是5。如果一个订单是5件,另一个是10件,那么先被处理的订单会成功,后一个则会因库存不足而失败。
持久性
持久性原则保证,一旦事务完成,其效果就是永久性的,能够经受住任何后续的系统故障(如断电)。这对于在面临自然灾害等意外事件时保持数据库的可靠性至关重要。
公式/概念描述: 提交(事务) → 效果持久化, 即使发生系统故障。

ACID在分布式环境中的意义
ACID原则保证了数据库能维持一个一致的世界观。在现实世界中,数据库可能因为规模过大而被分区到多个服务器上,或者为了冗余和速度而被复制到多个数据中心。在这些情况下,确保你在整个服务器网络中读写的数据保持一致变得尤为关键。
这就是强一致性原则,它是ACID合规的一个关键特性。即使对于分布式数据库系统,这一原则也成立。
ACID合规性的权衡

需要注意的是,虽然关系型数据库通常默认是ACID合规的,但并非所有数据库都需要完全遵守所有ACID原则来支持应用程序后端。
以下是关于权衡的一些要点:
某些NoSQL数据库只具备一定程度的ACID合规性。通过放宽一个或多个约束,可以提高数据库的某些性能方面,使其更具可扩展性。
作为数据工程师,理解你的数据库何时需要ACID合规,可以帮助你预防灾难。

总结
本节课中,我们一起学*了数据库ACID合规性的四个核心原则:原子性、一致性、隔离性和持久性。我们了解了这些原则如何确保事务的可靠处理,以及在分布式环境下的重要性。同时,我们也认识到,在实际应用中,有时需要在严格的ACID合规性与系统性能、可扩展性之间做出权衡。
在接下来的实验中,你将使用DynamoDB(一种NoSQL键值数据库)进行实践。请跟随下一个视频,在开始实验前快速了解一下实验内容。
085:与Amazon DynamoDB NoSQL数据库交互 🗄️

概述
在本节课中,我们将学*如何与Amazon DynamoDB这一键值型NoSQL数据库进行交互。我们将通过Python代码在Jupyter Notebook中执行创建、读取、更新和删除(CRUD)操作。课程将涵盖DynamoDB的核心概念、数据结构以及使用Boto3 SDK进行实际操作的方法。
DynamoDB核心概念
上一节我们介绍了本实验的目标,本节中我们来看看DynamoDB作为键值数据库的基本工作原理。

DynamoDB是一种键值数据库,它将一组键值对项目存储在表中。每一行包含一个项目的属性,并由项目的键唯一标识。
例如,以下是两个键值项目,每个对应一个人:
- 键代表人员的ID。
- 值由一组描述该人员的属性组成。
DynamoDB将此类数据存储在如下所示的表中,每行包含人员ID和相应的属性。由于人员ID列唯一标识每一行,因此它代表此表的主键。
在处理DynamoDB时,你也可以将主键称为分区键。这是因为DynamoDB使用主键来确定分区,即项目将存储的物理位置。
你还可以为DynamoDB表定义复合主键。
例如,这里有一个表,其中每一行代表一个订单项,并由一个复合主键唯一标识。此复合键由两个键组成:
- 第一个代表订单ID,称为分区键。
- 第二个代表订单中的商品行号,称为排序键。
使用此复合键,你可以拥有两个具有相同分区键的项目,但它们必须具有不同的排序键,以便你仍然可以唯一地标识每个项目。DynamoDB使用分区键来确定项目将存储在哪个分区,并使用排序键对同一分区内的项目进行排序。

在这两个表中,你可以看到每个项目都可以拥有自己独特的属性。这是因为DynamoDB表是无模式的,这意味着你无需预先定义所有属性。

实验工具与数据
在本次实验中,你将使用Jupyter Notebook中的Python代码创建并与四个DynamoDB表进行交互。为此,你将使用Boto3,这是AWS软件开发工具包,允许你使用Python创建和配置AWS服务。
以下是Boto3的文档,你可以在其中找到用于与各种AWS资源交互的方法列表。如果你点击这里的DynamoDb,可以找到处理DynamoDB表时可用的所有方法。
在实验中,你将重点学*用于执行CRUD操作的方法,例如:
create_table:创建表。put_item,batch_write_item,update_item:在表中添加或更新项目。scan,get_item,query:从表中读取项目。delete_item:从表中删除项目。
要调用这些方法,你首先需要创建一个客户端对象,如下所示,它为你提供了一个代表Amazon DynamoDB表的接口。使用此客户端对象,你可以调用任何DynamoDB方法来创建表。

实验提供了从Amazon DynamoDB开发者指南下载的四个JSON文件。你将读取每个文件的内容并将其加载到DynamoDB表中。
以下是四个数据文件的简要说明:
- 产品目录文件:包含在Amazon上销售的某些产品的信息。每个产品由其ID定义,你将使用该ID作为相应表的简单主键。
- 论坛文件:包含有关某个AWS论坛的信息,用户可以在该论坛上发布有关AWS服务的问题或发起主题。对于每个论坛,你可以找到主题总数、消息数和浏览量。每个论坛由其ID定义,你将使用该ID作为相应表的简单主键。
- 主题文件:包含有关每个论坛主题的信息,例如主题标题、主题消息、总浏览量和给定主题的回复数。每个主题由论坛名称和主题标题定义,你将使用它们作为相应表的复合主键。
- 回复文件:包含有关每个主题回复的信息,例如回复时间、回复消息、发布回复的用户以及回复的ID(ID是论坛和主题标题的连接)。每个回复由其ID和回复时间定义,你将使用它们作为相应表的复合主键。
让我们看一下论坛文件。它包含一个put请求元素列表,每个元素包含一个将被提取并加载到DynamoDB表中的项目。请注意,每个属性由另一个键值对定义,用于指定属性的类型及其值。
因此,这里的字母N(代表数字)和S(代表字符串)是DynamoDB数据类型描述符的示例,它们告诉DynamoDB如何解释每个属性的类型。所有剩余的JSON文件都遵循相同的模式。建议你快速浏览其他JSON文件,以更好地理解每一个。

实验步骤演练
现在,让我们完成实验的第一个练*。我已经启动了实验并按照说明启动了Jupyter Notebook。我将运行这个单元格来导入所需的包,然后运行这个单元格来定义将在实验中用于标记目的的变量。
在这两个单元格之后,你会找到一些关于数据和DynamoDB表的解释,这些内容已在本视频中介绍过。
你的第一个练*是创建四个表,你将使用Boto3的create_table方法。如果查看文档,你会看到此方法需要表名和主键定义。你可以使用AttributeDefinitions参数定义构成主键的属性。使用KeySchema参数,你可以为每个属性指定它是分区键还是排序键(HASH表示分区键,RANGE表示排序键)。
在实验中,你无需为每个表编写这些参数代码。相反,实验提供了这些字典,它们代表了创建每个表所需的参数。

要创建表,实验提供了create_table_db函数,你将在其中调用Boto3的create_table方法。函数create_table_db接收表名和kwargs(关键字参数的缩写),kwargs是一个包含Boto3方法额外参数的字典。kwargs旁边的两个星号意味着字典中的元素被解包成一系列参数。
在这里,你需要完成调用Boto3方法的代码部分。使用客户端对象,对于表名,我将使用输入的表名,然后我将使用kwargs传入剩余的参数。
我现在将运行该单元格以及接下来的两个单元格来创建表。从这里,你可以继续完成剩余的练*。

请注意,有些练*被标记为可选。因此,你可以自由跳过可选部分。
总结
本节课中,我们一起学*了Amazon DynamoDB NoSQL数据库的基础知识,包括其键值存储模型、主键(分区键与排序键)以及无模式的特点。我们了解了如何使用Boto3 SDK通过Python与DynamoDB进行交互,并初步演练了创建数据库表的实验步骤。完成本实验后,你将掌握对DynamoDB执行基本CRUD操作的技能。
086:对象存储 📦

在本节课中,我们将学*对象存储的核心概念。对象存储是现代数据工程中用于文件存储和检索的重要机制。我们将探讨其工作原理、关键特性以及它为何成为数据湖等架构设计的首选存储方案。
正如本周早些时候提到的,文件是数据工程师日常工作中最常见的数据源系统之一。你可能从Google Drive等文件系统、S3等对象存储系统接收或访问这些文件,或者它们只是作为电子邮件的附件。文件可能来自许多不同的地方。
对象存储可以说是当今数据工程师工作中最重要的文件存储和检索机制。
对象存储的核心概念

对象存储将数据文件视为独立的对象,并将它们存储在不遵循传统文件系统层次结构的扁平结构中。这意味着,虽然你可能*惯于在本地计算机的文件夹和子文件夹层次结构中存储文件,但对象存储没有这种层次结构。
需要说明的是,这种扁平结构的概念可能会令人困惑。例如,如果你进入亚马逊S3,会看到一个“创建文件夹”的按钮,你可以随意创建文件夹和子文件夹,并愉快地将文件存储在看起来非常像分层文件系统的结构中。
然而,这实际上只是用户界面的一个功能,目的是让界面以一种熟悉的方式看起来井井有条。实际的存储机制是扁平的。这意味着,尽管在用户界面中看起来有文件夹和子文件夹,但所有文件实际上都存储在最顶层。这是有意设计的,因为它允许快速、直接地访问所有对象,而无需担心文件夹结构的开销。
对象的组成与特性
对象可以是任何东西,从CSV、JSON、文本、视频、图像或音频文件,到机器可读的二进制数据。这种多功能性使对象存储成为半结构化和非结构化数据的完美存储库,这在支持为训练机器学*模型提供数据等应用程序时非常有用。
对象存储作为数据源在后续的课程中扮演着关键角色。你将看到对象存储如何集成到整个数据工程生命周期中。现在,让我们看看对象存储的一些关键组件。
在对象存储中,每个对象都被分配一个通用唯一标识符,即UUID。这类似于一个“键”,访问和管理相应对象都需要这个键。
每个对象还有相关的元数据,这是关于对象的附加信息,如创建日期、文件类型或所有者。
值得注意的是,在初始写入后,对象在技术上变为不可变的,它们不支持随机写入或追加操作。从这个意义上说,对象存储中的文件不像关系数据库中的表或非关系数据库中的文档那样可以更新或追加。要更改存储在对象中的数据,你必须重写整个对象,并让UUID指向这个新对象。
使用对象存储,你可以启用对象版本控制,这允许你向对象添加元数据以指定其版本。因此,当你更新一个对象时,不是在同一个UUID下覆盖旧对象,而是可以保留该对象的多个版本。
为何使用对象存储?
那么,为什么要使用对象存储呢?
对象存储允许你存储各种数据格式的文件,而无需特定的文件系统结构。这消除了与分层文件夹系统和数据库相关的复杂性。
在云环境中,对象存储可以轻松横向扩展,为海量数据提供几乎无限的存储空间。
在可用性方面,云对象存储中的数据通常会在多个可用区复制,这意味着数据在多个相互隔离的物理数据中心之间复制。这使得数据具有高持久性和高可用性,即使在发生自然灾害的情况下也是如此。
例如,正如我在之前的课程中提到的,亚马逊S3提供“11个9”(99.999999999%)的数据持久性,这意味着S3上的对象存储可以承受并发的设备或数据中心故障。
此外,对象存储通常比其他存储选项更便宜,特别是如果你存储的是不需要经常访问的数据。
应用与总结
云对象存储用于许多应用程序,并且由于其灵活性、高可扩展性、成本效益和持久性,已成为数据湖和数据湖仓等新架构设计的首选存储方案。

接下来,你将有机会使用亚马逊S3对象存储。你将创建一个S3存储桶,从存储桶中查询数据,并实践对象版本控制。完成实验后,请加入下一个视频,了解作为流式系统数据源的应用程序日志。

本节课中,我们一起学*了对象存储的基本原理。我们了解到对象存储采用扁平结构管理文件,通过UUID唯一标识对象,并支持元数据和版本控制。其高可扩展性、持久性和成本效益使其成为处理半结构化和非结构化数据(如构建数据湖)的理想选择。
087:第9课 - 日志 📝

在本节课中,我们将要学*日志这一核心概念。日志是最简单的流式系统形式,它记录了系统中发生的事件信息,是数据工程师工作中重要的数据来源。
什么是日志?
上一节我们介绍了流式系统的概念,本节中我们来看看其最基础的形式:日志。
我能想到的最简单的流式系统类型就是日志。实际上,日志甚至算不上一个系统。它只是一个关于事件的记录,用于追踪系统或应用程序的活动。在之前的课程中我曾提到,开发者过去常常将来自软件应用程序的数据视为一种“废气”或副产品,其本身不一定具有内在价值,但可用于监控或调试系统。最常被视为“废气”的具体数据,就是软件应用程序生成的日志中包含的数据。
因此,当开发者部署一个产品或平台(如网站或移动应用)时,他们会进行设置,使应用程序内发生的所有活动都记录在日志中。日志可能包括用户活动,如用户登录或导航到特定页面;也可能包括后端事件的记录,例如数据库更新或尝试运行特定程序时生成的错误。在实践中,日志最常用于监控系统的健康状况。

日志的用途与价值
上一节我们了解了日志的基本定义,本节中我们来看看它的具体用途和潜在价值。
工程师会使用日志来触发警报,或在发生错误时调试问题所在。从这个意义上说,日志可能显得有些枯燥,“应用程序废气”这个描述似乎很贴切。
然而,日志是丰富的数据源,其用途远不止于监控应用程序的健康状况。因此,它们可以成为数据工程师工作中需要摄取数据的重要源系统。从本质上讲,日志是一个按时间顺序追加的记录序列,捕获了系统中发生的事件信息。
以下是日志可以支持的一些具体用例:
- 用户行为分析:例如,如果你是电子商务公司的数据工程师,你的网络服务器日志可以捕获详细的用户活动数据,用于支持下游的用户行为模式分析。
- 变更数据捕获:许多数据库系统都有日志,你可以通过一个称为变更数据捕获的过程来追踪数据库中的变化。你可以利用这些变化来触发你的摄取流程,使其基于数据库中新数据的到达而运行。
- 机器学*应用:或者,你可以摄取日志数据用于某些机器学*应用,如异常检测。例如,如果你正在摄取来自安全系统的日志数据。

因此,日志在追踪你将与之合作的许多上游软件系统中发生的情况方面起着至关重要的作用。这使其成为一个丰富的数据源,可以支持下游的多种用例,如数据分析、故障排除、性能监控、机器学*应用和自动化。
日志的结构与格式
上一节我们探讨了日志的用途,本节中我们来深入了解日志的具体结构和常见格式。
如前所述,日志是关于事件的记录。通常,你在日志中为每个事件找到的第一条记录是与该事件关联的人员、系统或服务账户,例如用户ID及其IP地址。
接下来,你会找到所发生事件的记录及其元数据。例如,用户将特定产品添加到购物车,以及该操作的状态。
最后,你会找到事件时间戳的记录。
日志数据可能被记录为简单的非结构化文本,或采用 JSON、CSV 格式,甚至可以是二进制编码数据。
除了描述事件时间和内容的数据外,日志通常还会包含一个标签,通过为每条记录分配所谓的日志级别来对事件进行分类。日志级别可能包括诸如 DEBUG、INFO、WARN、ERROR 或 FATAL 等标签,让你知道特定记录包含何种信息。
例如:
- 包含基本活动信息的记录会被分配
INFO日志级别。 - 包含错误消息的记录可能被分配
ERROR日志级别。 - 如果发生更严重的情况,例如主要系统故障并需要紧急关注,则可能带有
FATAL日志级别作为标签。
当你开始将日志构建到自己的数据管道应用程序中,而不是仅用于监控自己的系统时,我们将在后面更多地讨论日志级别。
总结


本节课中我们一起学*了日志。
作为数据工程师,理解如何处理日志、它们的类型、格式和应用非常重要。日志将是你所做工作的重要数据来源,可以帮助你排查问题、监控性能并服务于许多下游用例。

在下一个视频中,我们将一起看看一些更复杂的流式系统。
088:流系统 📡

在本节课中,我们将深入学*流处理系统的核心概念,包括事件驱动架构、消息队列与流式平台的工作原理,以及它们如何作为数据管道的数据源。
在专项课程的第一门课中,我们探讨了批处理和流处理在数据工程生命周期不同阶段的表现差异。在上门课程的最后一个实验中,你接触了一个数据架构示例,其中批处理和流处理在推荐系统的背景下协同工作。本节视频中,我们将更详细地审视事件驱动架构的细节,以及消息队列和流式平台如何作为数据管道的源系统工作。
核心概念定义
首先,让我们定义一些术语。到目前为止,在这些课程中,我们一直从事件、消息和流的角度来讨论流数据。
广义上说,一个事件就是世界上发生的某件事,或是系统状态的改变。例如,用户点击链接或传感器测量到的温度变化,都是事件的例子。正如我之前提到的,从某种意义上说,你可以认为所有数据在其源头都是流数据。这是因为本质上所有数据都是由发生在外部世界或某个系统内部的事件记录构成的。
一个消息是关于某个事件的信息记录。消息可能包含事件的详细信息,例如用户点击了哪个按钮或传感器记录了什么温度,以及围绕事件的一些元数据和事件发生的时间戳。消息可以持续生成以形成流。
一个流是一系列消息的序列,可能是一段时间内的一系列传感器读数或网站点击。消息和流共同构成了流数据。如果你想一次性处理大块数据(例如在特定的时间间隔内),那么这就是应用于消息流的批处理。如果你想在收到每条消息时立即处理,那么你需要一个能够根据传入消息采取行动的系统。这样,你就得到了一个系统,其中消息记录关于事件的信息,并在消息被接收时采取行动,换句话说,这就是一个流系统。
在实际应用中,你经常会听到“事件”和“消息”这两个词在描述事件驱动架构的各个组件时几乎可以互换使用。但不必为此担心。虽然严格来说,事件是发生的事情,而消息是关于这些事件记录的信息或数据,但在数据工程中,区分两者并不重要。


因此,当我们谈论事件或消息被生产、消费或存储在队列中时,它们都是指同一回事。
流系统的三大组件
无论如何,一个流系统包含三个组件:事件生产者、事件消费者和事件路由器(也称为流代理),它位于生产者和消费者之间。请注意,这里我也可以说消息生产者、消息消费者和消息路由器,意思是一样的。只是你经常会看到这些组件用“事件”来描述,所以我们在这里也沿用这个术语。
- 事件生产者:在流中生成消息。生产者可以是物联网设备、移动应用、API或网站等。
- 事件消费者(有时称为订阅者):处理每条单独的消息。在任何一个给定的流系统中,可能有多个消费者。例如,在电子商务场景中,当用户下订单时,订单系统可能会触发一个事件,该事件通过消息传递给支付服务以处理付款,然后传递给库存服务以更新库存。在这种情况下,支付服务和库存服务都是事件消费者。
- 事件路由器/流代理:例如 Apache Kafka,它充当缓冲区,过滤事件并将其从生产者分发到消费者。正是这个路由器帮助将生产者与消费者解耦,从而实现它们之间的异步通信。这样,生产者不必等待事件被传递给消费者就可以发送下一个事件。即使消费者暂时不可用,这也能防止事件丢失。
当你将事件系统作为源系统处理时,你的上游源可能是一个简单的事件生产者(如物联网设备),而你的系统则包含事件消费者。或者,你的上游存储系统可能由多个生产者、路由器和消费者组成,而你构建的系统实际上只是事件的下游消费者之一。
两种主要的流系统
在构建处理流数据的数据管道时,你会遇到两种主要类型的流系统:消息队列和流式平台。我经常看到这两种系统被混淆。尽管它们在运作方式上有许多相似之处和潜在的重叠,但它们之间有一个主要区别,那就是事件路由器的工作方式。
现在,我们来花点时间讨论一下这个区别。
消息队列

在消息队列中,事件路由器充当一个队列,累积生产者发送的消息。事件消费者然后以先进先出的顺序从队列中读取消息。一旦消费者从队列中读取消息并确认,该消息就会从队列中删除。
使用消息队列,事件生产者可以随时向队列推送新消息,事件消费者也可以随时读取它们。你可以将队列本身视为一种临时的存储解决方案,它允许事件生产者与事件消费者解耦。
作为一名数据工程师,你可能会遇到的一个消息队列示例是 Amazon Simple Queue Service。它是一个完全托管的队列服务,常用于微服务、分布式系统和无服务器应用。
流式平台
对于像 Apache Kafka 或 Amazon Kinesis Data Streams 这样的流式平台,事件生产者将事件流式传输到一个日志中。正如我们在上一个视频中看到的,日志是一个只追加的事件记录。事件路由器将日志中的消息分发给适当的事件消费者。消费者以只读操作的方式顺序处理日志中的消息。

这意味着,与消息队列不同,消息不会从日志中删除,数据是持久化的。由于数据以这种方式在流式平台中保留,因此可以从过去的某个时间点重放、批处理或重新处理日志中的事件。
总结与展望

因此,流系统将是你作为数据工程师需要从中摄取数据的源系统之一。正如你在上一门课程中看到的,并且在本系列课程中将继续看到的那样,你也可以将流系统构建到你自己的数据管道中,作为生命周期中摄取、转换和服务阶段的一部分。
以上是对你作为数据工程师可能遇到的一些常见源系统的概述。在下一课中,我们将讨论如何连接到这些源系统。我们下节课见。
089:课程概述 🎯

在本节课中,我们将学*如何连接不同的源系统,并探讨在实际工作中可能遇到的常见访问问题及其解决方法。我们将重点介绍身份与访问管理(IAM)和网络配置的核心概念,这些是确保数据管道顺利运行的关键。
在上一课中,我们探讨了数据工程师在工作中会遇到的一些常见源系统的实际细节。
在实验环节中,你练*了操作关系型数据库、NoSQL数据库以及对象存储中的数据。
当在实际工作中连接到源系统时,数据工程师相对经常会遇到阻碍你访问目标数据的意外问题。
这些问题可能源于多种原因,例如身份和访问管理(IAM)定义不当、网络配置损坏,或者仅仅是使用了错误的访问凭证。
这些问题乍听起来可能相对简单,但根据我的经验,在数据工程领域,这类问题会频繁出现。如果你不知道如何正确地调试和解决它们,它们可能会成为主要的障碍。
事实上,我认为解决这类问题是数据工程师的核心技能之一。因此,当我面试新的数据工程师时,我喜欢采用一个可以连接到目标源系统的、可运行的数据管道。

然后,我会破坏一些IAM或网络配置,并要求候选人解决问题。这能向我展示他们为在工作中排查此类问题所做的准备有多充分。
因此,在本节课中,我将首先详细介绍如何连接到不同的源系统。我将在AWS环境中进行演示,但我们将要探讨的原则同样适用于其他云平台。
在IAM规则和权限的背景下,我们将探讨云安全的重要性,其中IAM是控制和管理对基于云的数据源以及数据管道内其他组件访问权限的关键。
最后,我们将深入探讨网络配置。我将从一个高层次概述开始,然后Morgan将带你深入了解AWS上的网络细节,包括VPC、子网、网关、路由、安全组等。
所以,在本节课中,你将基于我们在上一门课程中学*的基础网络概念来构建知识。
在本课之后,你将接受技能测试。就像我在面试过程中对数据工程师候选人做的那样,我在下一个实验练*中为你设置了一个挑战。
在那里,你会发现一个数据管道,它应该与你之前某个实验中的管道相似。
但现在,我已经破坏了它。在那个实验练*中,你将体验到作为一名数据工程师,在云上连接到源系统是什么感觉。
我向你保证,这不会像标准的“Hello World”练*那样一切按预期进行。相反,你将置身于一个场景中,就像在现实世界中一样,事情不会按你希望的方式运行。
你的工作将是进行故障排除,找出问题的原因,然后解决它,以便连接到你需要的数据源。
请加入下一个视频,我将为你概述连接到源系统的方法。
本节课总结

在本节课中,我们一起学*了连接源系统时可能遇到的实际挑战,特别是身份与访问管理(IAM)和网络配置问题。我们了解到,解决这些访问障碍是数据工程师的一项核心技能。课程还预告了接下来的实践环节,你将在一个被故意破坏的实验环境中,亲身体验故障排除和解决问题的完整过程。
090:连接到源系统 🔌


在本节课中,我们将要学*如何连接到数据源系统。在能够摄取数据之前,首先需要建立与数据源的连接,并验证你是否有权从中读取数据。
概述
本周我们已经查看了多个源系统的示例。但在实际工作中,建立连接是数据摄取的第一步。事实上,你在之前的实验中已经有过一些连接经验。例如,在DynamoDB实验中,你使用了Boto3(AWS的Python软件开发工具包,即SDK)来创建与DynamoDB中某个表的客户端连接。你也通过在Cloud9 IDE中运行带有正确参数的命令,连接到了Amazon RDS MySQL实例。你在这里看到的端点(endpoint)和端口(port)信息用于定位正确的数据库实例,而用户名和密码凭证则用于验证你是否有访问数据库的适当权限。
由此可见,连接数据库或任何资源的方式不止一种。接下来,让我们更详细地探讨这些方法。
通过AWS管理控制台连接
如果源系统位于你所在组织的AWS账户内的某个资源中,你可以从管理控制台获取连接信息。
例如,如果我试图连接到一个RDS数据库实例,我可以导航到RDS服务,像这样定位我想要连接的数据库,并找到连接信息,包括端点和端口号。


需要说明的是,AWS总是在调整控制台界面的显示方式,因此我这里展示的界面可能与你实际看到的略有不同,但基本步骤是相同的。
控制台对于查找此类信息或启动资源和连接非常方便。但请记住,通过控制台工作意味着你需要导航并点击各种小部件和按钮来完成操作。



如果你将来需要重复这个过程,可能很难准确记住你采取了哪些步骤。而且,正如我所说,等到你想再次操作时,AWS可能已经改变了控制台的布局,这会使事情变得更加困难。



总的来说,通过控制台操作非常适合快速完成某些任务,例如在系统中进行原型设计时。但这个过程的可重复性和可追溯性不强。
通过命令行接口连接
作为一种更具编程性的方式来查找所需信息并连接到源系统,你可以在命令行接口(CLI)中运行代码。
通过这种方式,你可以获取数据库端点,然后使用特定于你所用数据库管理系统(DBMS)的命令语法连接到数据库。
以下是连接的基本步骤:
- 使用AWS CLI命令获取数据库实例的端点信息。
- 使用数据库客户端(如
mysql)和获取到的端点、端口、用户名、密码进行连接。
在连接和摄取过程中,直接在CLI中发出命令是数据工程师的常见做法,但这仍然相对手动。因此,它通常更适合简单的工作负载,而不是复杂的任务。
通过软件开发工具包连接
为了向可重复性和自动化更进一步,你可以使用像Boto3这样的SDK,通过在IDE(如Cloud9)中编写和运行代码来连接到源系统。或者,例如,从Jupyter笔记本中运行。
对于某些源系统,你也可以使用API连接器进行连接。例如,你可能使用Java数据库连接(JDBC)或开放数据库连接(ODBC)API将你的应用程序连接到DBMS,以便查询数据库。




你已经对其中一些连接源系统的方法有了一些经验。在本视频之后的阅读材料中,你会找到更详细介绍每种方法的资料。

总结

本节课中,我们一起学*了连接到数据源系统的几种主要方法:通过AWS管理控制台、通过命令行接口(CLI)以及通过软件开发工具包(SDK)或API。每种方法都有其适用场景,控制台适合快速操作和原型设计,CLI提供了更直接的命令控制,而SDK和API则为实现自动化、可重复的流程提供了强大的编程能力。理解这些连接方式是构建可靠数据管道的基础。
在回顾了这些材料之后,请加入下一个视频,我们将概述身份与访问管理(IAM)和权限。
091:IAM与权限基础 🔐

在本节课中,我们将学*身份与访问管理的基础知识。IAM是构建云上数据管道时确保数据安全的核心。我们将了解其基本组件、工作原理以及作为数据工程师应如何安全地配置和使用它。
在基于云的架构中构建数据管道时,身份与访问管理,也称为IAM,是数据工程师角色的核心。正如我在之前的课程中所说,作为数据工程师,您被委托管理敏感数据。这些数据可能是客户的个人隐私信息,也可能是专有的商业信息。数据所有者相信他们的信息在您手中是安全的。
云安全是一个广泛而复杂的主题,但为了本课程的目的,我们将专注于基础知识。这是因为,只需遵循一套基本的最佳实践,您就能成功避免绝大多数数据灾难。事实上,2023年的一项研究发现,超过一半的云数据泄露是由简单的人为错误引起的,例如密码或其他凭据的不安全存储,或IAM配置错误。这些数据泄露可能造成极其高昂的代价。因此,通过确保数据管道的安全性,您可以帮助公司节省资金,有时是数百万美元甚至更多,并保护公司及您自己的声誉。
在我与客户的工作中,我惊讶地发现许多错误可以通过简单的修复来纠正。我曾见过人们将机密数据存储在公共的S3存储桶中、将访问凭据上传到GitHub,或者为公司里的每个人提供对数据资源的基本管理员访问权限。这类问题很容易修复,但对公司构成重大风险,如果灾难在您负责期间发生,甚至可能让您丢掉工作。因此,我的目标是让您为成功做好准备,避免这种情况在未来发生在您身上。
让我们深入了解作为数据工程师,您将如何与权限和IAM打交道的基础知识。
首先,IAM是一个管理权限的框架。权限定义了身份(如个人或应用程序)可以对特定资源集(如数据库或ETL工具)执行哪些操作。IAM确保适当的一组身份在正确的时间访问正确的资源。还记得我们在上一课程中讨论的“最小权限原则”吗?IAM就是您在实践中运用这一原则的方式,因为它允许您仅授予人员或应用程序执行其工作所必需的资源访问权限,并且仅在所需的时间内授予。
例如,系统所有者可以授予数据摄取系统在有限时间内仅从数据库的特定表中读取数据的能力。通过在不必要时不授予对云资源的不必要访问权限,您还可以防止团队产生不必要的云成本。
许多云提供商都构建了IAM服务,帮助用户管理对其云资源的访问和权限。例如,AWS IAM是一项Web服务,可帮助您安全地管理和控制对您账户中AWS资源的访问。事实上,在本课程迄今为止的实验中,我们一直在使用AWS IAM为您提供对AWS资源的适当访问。

作为一名全新的数据工程师,您很可能不会成为在公司云服务账户中高级别设置IAM配置的人。但您将与各种云资源交互,并且可能需要为您作为数据管道一部分部署的资源配置IAM。因此,您至少需要对不同的IAM组件有基本的了解,以便安全地操作并在问题出现时进行故障排除。
接下来,我们将在AWS IAM的背景下了解这些IAM组件。但请注意,其他云提供商(如GCP或Azure)也有相同类型的组件,只是名称可能有所不同。

以下是AWS IAM中的核心组件:
- 策略:用于授予身份对AWS资源执行操作的权限。策略是一个JSON文档,详细说明了应拥有哪些资源和权限。
- 身份:AWS中有不同类型的身份。
- 根用户:创建AWS云账户的用户,对该账户中的所有资源拥有不受限制的访问权限。
- IAM用户:被授予对特定资源的特定权限。作为初级数据工程师,您很可能会在公司AWS账户中被分配一个IAM用户账户。您将获得一组长期凭证(如用户名和密码或访问密钥),可用于通过代码以编程方式访问AWS资源。
- IAM组:用户的集合。您可以将策略附加到组上。在这种情况下,策略是一个JSON文档,包含该组应拥有的资源和权限详细信息。这简化了资源配置过程。例如,您的公司可能有一个数据工程师IAM组,该组中的每个用户都有访问构建和维护数据管道所需资源的权限。
- IAM角色:不与特定人员或应用程序长期关联,而是由用户、应用程序或服务临时担任,以授予他们在有限时间内对您的AWS资源执行指定操作的临时权限。例如,默认情况下,EC2实例没有读取或写入S3存储的权限。但您可以创建一个对特定S3存储桶具有读写权限的角色,并让EC2实例在需要时担任此角色。与在EC2配置中存储长期用户凭证相比,这是授予EC2实例使用S3权限的更安全方式。
如果您在使用临时角色凭证发出请求时收到“访问被拒绝”错误消息,最好检查这些凭证是否已过期。这是IAM配置中另一个非常常见的问题。

为了帮助您了解IAM策略的工作原理,让我们看一下在上一课程实验中,授予您访问所需资源的AWS策略的一部分。
{
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:List*", "s3:Get*"],
"Resource": "arn:aws:s3:::dl-ai-data-engineering*"
},
{
"Effect": "Allow",
"Action": "glue:*",
"Resource": "arn:aws:glue:*:*:job/lab-job-*"
}
]
}
从第一个语句中,您可以看到该策略允许用户(在本例中是您)访问名称以 dl-ai-data-engineering 开头的任何S3存储桶(因为名称后面有这个星号*)。然后,您被允许执行这些操作,包括 list* 或 get*。同样,这些星号意味着您可以执行任何以 list 或 get 开头的操作。在本例中,这些操作包括列出存储桶的内容或您有权访问的存储桶名称;或者在 get 的情况下,这些操作包括从存储桶获取对象或获取有关存储桶的信息(如存储桶所在的区域)。
第二个语句类似,允许您访问与实验关联的AWS Glue作业。Action 下的 glue:* 意味着您可以对该Glue作业执行任何操作。因此,在实验期间,当您发出运行AWS Glue作业的请求时,AWS首先会评估此策略,以确定是否允许您使用Glue执行此操作。
以上就是IAM的基本组件:根用户、IAM用户、组、角色和策略。您可以在本视频后的阅读材料中找到有关这些组件的更多详细信息。

复*完这些材料后,请加入下一视频,一起了解云中的网络。
092:云中网络基础 🌐

在本节课中,我们将要学*在基于云的架构中构建数据管道时,网络配置的基础知识。网络是连接各种资源的桥梁,其配置方式对于确保数据在管道中顺畅流动至关重要。
上一节我们介绍了网络的基础概念,即网络是能够共享数据和相互通信的互联设备集合。本节中,我们将重新审视并扩展这些基础网络原则,为你解决连接源系统时可能遇到的问题做好准备。

云计算与物理基础设施
“云计算”这个术语听起来可能有些抽象,仿佛计算发生在虚无之中。但请明确,云和云计算是由遍布全球的、非常真实的物理数据中心构成的。
正如你在之前的课程中所学,AWS云是一个覆盖不同地理区域(称为“区域”)的全球网络。每个区域包含多个“可用区”集群,而每个可用区则由一个或多个数据中心组成,这些数据中心具备冗余的电力、网络和连接。
在许多云计算应用中,数据和资源会在不同区域和可用区之间进行复制,以确保即使一个或多个数据中心出现故障,系统也能继续运行。
区域选择的关键考量


作为数据工程师,在云上启动新资源时,你需要决定在哪个区域进行托管。
以下是选择区域时需要考虑的几个关键因素:
- 法律合规性:将数据存储在特定区域可能意味着需要遵守该地区独特的数据隐私或监管要求。
- 延迟与可用性:通常,终端用户距离托管资源的区域越*,网络延迟就越低。同时,资源复制的可用区越多,系统从灾难中恢复或抵御灾难的能力就越强。
- 成本:不同区域的资源成本可能有所不同,这也可能成为决策的一个因素。
在实际操作云资源时,很容易忽略一个事实:你实际上是在与遍布全球的物理设备网络进行交互。但作为数据工程师,理解这种全球基础设施的搭建方式,以及它如何影响你所构建系统的延迟、成本、可靠性和可用性,是非常重要的。
虚拟私有云与子网


回到云网络需要了解的重要内容。在任何给定的区域内,你可以创建自定义的虚拟私有云(简称VPC)。
VPC是跨越区域内多个可用区的较小网络。创建VPC可以让你更精细地控制谁可以访问哪些资源。
你可以将VPC内的空间进一步划分为子网,这些子网用于容纳你实际的数据管道资源。
每个子网可以拥有自己的安全规则(称为网络访问控制列表,简称网络ACL)以及通过互联网网关的路由配置。这使你能够为面向互联网的资源(如Web服务器)创建公共子网,并为内部资源(如数据库)创建私有子网。
例如,在之前课程的一个实验中,你接触的架构如下:源数据库位于私有子网内,以防止数据通过互联网被访问。然后,一个EC2实例位于公共子网中,使其能够运行一个Web应用程序,通过互联网向客户提供分析数据。
在那个实验中,你通过调整应用程序负载均衡器的安全组来控制对网站的公共访问。你没有保持所有端口开放,而是编辑了入站规则,阻止除端口80之外的所有端口接收所有传入流量。
网络配置的复杂性与重要性
在现实世界中,情况会迅速变得复杂,尤其是当你开始设置多个VPC、子网、网关以及资源之间的路由配置时。正是在这种背景下,连接数据库这样一个简单的操作,也依赖于多层网络配置,更不用说身份与访问管理权限了。

因此,理解网络配置的细节对于连接源系统至关重要。它也是成功编排和自动化数据管道所必需的,我们将在本课程的最后一周深入探讨这部分内容。

接下来,Morgan将带你详细了解AWS上的网络配置。之后,我会向你展示在即将到来的实验中你可以期待什么,在那里你将调试与数据库的连接。

本节课中我们一起学*了云网络的基础知识,包括云计算的物理本质、选择资源区域时的关键考量,以及如何通过虚拟私有云和子网来构建和管理安全的网络环境。理解这些概念是构建可靠、高效数据管道的基础。
093:VPC和子网 🏗️

概述
在本节课中,我们将学*AWS网络的核心概念,重点了解虚拟私有云(VPC)和子网。我们将通过一个具体的应用场景,演示如何为部署在AWS上的数据系统(如EC2实例和RDS数据库)构建安全的网络基础架构。

网络对数据工程师的重要性
正如Joe所强调的,网络将成为你作为数据工程师工作中的重要组成部分。起初,网络可能会让人感到不知所措,因为它涉及资源间的连接设置、权限、安全等诸多方面。但不必担心,掌握云网络是可以通过时间和理解一系列核心概念来实现的。通过本视频及后续的几个视频,我将详细介绍这些重要的核心概念,包括亚马逊虚拟私有云(VPC)、子网、网关、路由表、网络访问控制列表和安全组,并演示如何在AWS上为你的数据管道实现这些组件。


示例场景介绍
在接下来的几个视频中,我将通过一系列演示,展示如何为一个需要部署Amazon RDS数据库和Amazon EC2实例的场景构建VPC和网络组件。

在这个示例场景中,假设有一个运行在EC2实例上的Web应用程序,允许你查询运行在RDS上的数据库。这是一个后端带有关系数据库的典型Web应用的简单场景。最终的网络架构将如下所示:一个VPC,包含两个公共子网和两个私有子网;EC2和RDS数据库实例部署在私有子网中;公共子网中设有互联网网关;同时,还有一个应用负载均衡器位于运行EC2实例的Web应用前端。
我将逐步讲解与此场景相关的每个网络设置步骤,并解释所有这些组件。我们实际上不会部署EC2、RDS实例或应用负载均衡器,但会构建其所需的所有网络组件。希望通过一个具体的场景,能让网络概念更容易理解。
创建VPC和子网
首先,我们需要一个VPC和用于放置EC2和RDS实例的子网。让我们从AWS控制台主页开始完成这个任务。

在搜索栏中输入“VPC”并选择它,这将进入VPC仪表板。在这里,选择“创建VPC”按钮。
在创建VPC页面上,我们只创建一个VPC,然后手动创建子网。在继续之前,需要指出的是,每个区域的AWS账户默认都有一个“默认VPC”。这个默认VPC包含该区域每个可用区中的一个公共子网和一个互联网网关。
使用默认VPC可以让你快速启动面向公共互联网的EC2实例,无需额外设置。这对于实验性地启动公共资源(如简单网站)可能很方便。但对于大多数实际用例,你可能并不希望资源直接面向公共网络,而是希望资源受到网络保护。因此,对于任何实际工作,你的默认做法不应是使用默认VPC。相反,你应该为特定的用例创建自定义VPC。这就是我要在这里演示的内容。
正如你在之前的课程中学到的,AWS在全球范围内运营多个区域,这些区域由多个可用区(AZ)组成。一个VPC能够跨越创建该VPC的区域内的所有可用区。这里我们将创建一个VPC,但一个区域可以包含多个VPC。例如,你可能为不同的项目、环境或其他组织或技术考虑创建不同的VPC。默认情况下,每个VPC与其他VPC是隔离的。同一VPC内的资源可以相互通信,但两个不同VPC中资源间的通信则需要你进行设计和配置。

创建VPC时,需要为其命名、指定私有IP地址范围,并选择要放置的区域。给VPC起一个描述性的名称很有用,这样可以更容易地识别是哪个VPC。
我将这个VPC命名为“project1”。你可以看到,我创建这个VPC的区域是“美国东部(弗吉尼亚北部)us-east-1”,但如果需要,我可以从下拉菜单中选择另一个区域。
接下来,你需要定义IPv4 CIDR块。CIDR代表无类别域间路由,它定义了VPC内可以使用的私有IP地址范围,或者说VPC中可用的私有IP地址数量。任何部署到此VPC中的资源都将从此范围内分配一个私有IP地址。也就是说,如果你想创建一个可通过互联网访问的资源,你还需要为其分配一个公共IP地址。分配给它的任何公共IP地址都将来自AWS管理的公共IP池。因此,这里的CIDR范围仅用于私有IP地址。
这里我将输入“10.0.0.0/16”作为CIDR。我想暂停一下,详细解释这个CIDR,因为如果你不熟悉它,可能会觉得复杂。如果你是第一次深入了解网络细节,我将尝试简化它,使其更容易理解。
IP地址由四个用点分隔的数字组成。每个数字的范围是0到255。换句话说,地址中的每个数字都是一个8位整数值。在这个例子“10.0.0.0/16”中,“10.0.0.0”是我们网络的起始地址,“/16”部分是前缀长度,它告诉你地址中有多少位用于网络部分。因此,在这种情况下,“/16”表示前16位,或者说前两个8位整数,是网络前缀。
在二进制形式中,一个IP地址由32位组成,这再次意味着地址中点之间的每个数字代表8位。四个数字各8位,整个IP地址共有32位。正如我所说,“/16”意味着前16位(即前两个数字)是固定的,定义了网络,而剩余的16位(即另外两个数字)可以变化,用于该网络内的主机地址。这意味着任何部署到此网络中的资源都将拥有一个以“10.0”开头的私有IP地址,然后另外两个数字可以是0到255之间的任何值。如果我写的是“/24”而不是“/16”,那将意味着前三个数字是固定的,只有最后一个数字可用于分配主机地址。在下一步创建子网时,你会明白为什么需要了解这一点。
现在回到AWS控制台,我已经定义了创建VPC所需的不同部分,可以选择“创建VPC”。从这里开始,我需要创建子网。
子网是VPC内的子网络,或者说VPC私有IP空间的更小划分,你可以根据资源的网络访问和安全需求来分组资源。稍后,我们将使用网络访问控制列表和安全组来控制进出每个子网的网络流量类型。每个子网都与一个特定的可用区相关联,这意味着创建子网时,必须指定它位于哪个可用区。通过策略性地将资源放置在不同可用区的不同子网中,你可以增强应用程序的冗余性和可用性。常见的做法是,在你计划使用的每个可用区中至少创建一个公共子网和一个私有子网。
这里,我希望将EC2实例和RDS数据库部署到私有子网中,这样它们就不会暴露在互联网上。为了冗余性,我计划在此VPC的两个可用区中创建两个公共子网和两个私有子网,这是一个常见的模式。这样,例如,如果主数据库实例性能下降,或者可用区本身出现临时可用性问题,你还有在另一个可用区中运行的所有数据和实例,可以在故障转移发生后接管流量。
要创建这些子网,我将在导航中选择“子网”,然后选择“创建子网”。现在需要选择要在哪个VPC中创建子网。我将从下拉菜单中选择“project1” VPC。从这个页面,我可以创建所有四个子网。
对于第一个子网,我将其命名为“public-subnet-1”,然后选择一个特定的可用区,以便稍后确保我将其他子网部署到不同的可用区。为此子网选择“us-east-1a”。然后,我需要给它一个CIDR范围。子网的IP范围必须是VPC IP范围的子集。VPC定义为使用“10.0.0.0/16”,因此我将第一个子网的范围设为“10.0.1.0/24”。这意味着任何部署到此子网的资源都将被分配一个以“10.0.1”开头的IP地址,最后一个数字将用于标识特定的主机。
现在创建我的第一个私有子网,选择“添加新子网”,然后重复相同的步骤,但这次将子网命名为“private-subnet-1”,并给它一个CIDR“10.0.2.0/24”。
现在,让我们为另一个可用区(我将使用“us-east-1b”)再创建另外两个子网:公共子网和私有子网。接下来要做的是创建“public-subnet-2”,其CIDR为“10.0.3.0/24”,然后是“private-subnet-2”,其CIDR为“10.0.4.0/24”。最后,我可以选择“创建”,这将创建所有四个子网。
好了,你现在有了一个包含两个公共和两个私有子网、随时可用的VPC,它看起来像这样。就目前而言,部署到此VPC中的任何东西都无法访问互联网。你可以将EC2和RDS实例添加到这个示意图中,显示它们位于私有子网中。这些资源都无法从互联网访问,它们也无法发起与互联网上任何资源的连接。因此,在这一点上,它是一个封闭的网络。你需要部署和配置更多资源,才能使此VPC中的任何资源实现互联网连接。
总结

本节课中,我们一起学*了AWS网络的基础——虚拟私有云(VPC)和子网。我们了解了VPC如何作为你在云中的私有网络空间,以及子网如何进一步划分这个空间以实现资源隔离和高可用性。通过一个具体的部署场景,我们演示了如何创建自定义VPC和跨多个可用区的公共与私有子网,为后续构建安全、可用的数据系统网络架构打下了基础。在下一节中,我们将探讨互联网连接性,了解互联网网关和NAT网关的工作原理。
094:互联网网关和NAT网关 🌐


在本节课中,我们将学*如何为AWS虚拟私有云(VPC)配置互联网连接。我们将重点介绍两个核心组件:互联网网关和网络地址转换(NAT)网关。通过它们,我们可以让VPC内的资源安全地与互联网通信,同时保护内部资源不被直接暴露。
上节回顾与本节目标
在上一个视频结束时,我们创建了一个包含两个公有子网和两个私有子网的VPC。
正如之前所说,如果你将任何资源(如EC2实例)部署到公有子网中,该资源既无法通过互联网访问,也无法主动建立与互联网上其他资源的连接。
这是因为VPC和子网本身创建的是一个隔离的网络,没有流量可以进出。
在本视频中,我们将讨论如何使用互联网网关和网络地址转换(NAT)网关来实现互联网连接。
应用场景与连接需求
现在,回顾我们正在遵循的场景:你的VPC中会有一个EC2实例和一个RDS数据库。作为最佳实践,运行在EC2实例上的应用程序和RDS数据库都应该位于私有子网中,并且不需要与互联网直接连接。
然而,这里有两个之前未讨论的考虑因素:
- 运行在EC2上的应用程序偶尔需要从互联网上的资源下载更新,例如应用程序升级和补丁。
- 你仍然需要通过负载均衡器向运行在EC2实例上的应用程序提交请求,以便查询RDS上的数据。
这两个考虑因素意味着你的VPC实际上需要互联网连接。
互联网网关:VPC的“大门”
为了实现互联网连接,你首先需要将一个互联网网关附加到VPC上。
为了更好地理解互联网网关是什么及其作用,请将当前状态的VPC想象成一个没有门的房子。如果你建了一个没有门的房子把自己围起来,你将无法离开房子,外面的人也无法进入房子。
如果你在房子里,你可以在房间之间自由移动。但为了出去,你需要安装一扇通往外部世界的门。这就是我们目前的情况:一个没有门的房子。
因此,我们接下来要对VPC做的,就是安装一扇通往互联网的“门”,换句话说,我们将为其附加一个互联网网关。
互联网网关允许你公有子网中的资源与互联网连接。它们支持入站和出站流量。
创建互联网网关并将其附加到VPC只是允许互联网流量流向和流出公有子网的一个步骤。你还需要在路由表中配置路由,并配置网络安全规则。我们将在接下来的几个视频中完成这些操作。
NAT网关:私有子网的“单向通道”
我之前提到,我们的EC2实例将位于私有子网中,而这里我又说我们将附加互联网网关以允许流量流向和流出公有子网。如果我们的资源在私有子网中,这有什么帮助呢?
让我们回顾一下之前的两个考虑因素:
首先,EC2实例需要能够从互联网资源下载更新。这意味着私有子网中的EC2实例需要能够从VPC发起出站连接。
其次,你需要能够从互联网向应用程序提交请求。
让我们谈谈NAT网关和应用程序负载均衡器如何帮助我们满足这些要求。
NAT网关代表网络地址转换。这是一项允许私有子网中的资源连接到互联网或其他AWS服务,但阻止互联网主动与这些资源建立连接的服务。可以把它想象成一个受控的门道。


它只允许出站流量,并保护内部发起该流量的资源。
有了NAT网关,私有子网中的EC2实例可以从互联网下载更新和补丁,而不会将它们直接暴露给公共互联网。
应用程序负载均衡器:外部访问的入口
接下来,我们需要解决第二个考虑因素:允许外部用户向我们的应用程序提交请求。这就是应用程序负载均衡器(ALB)的作用。
ALB将传入的应用程序流量分发到多个后端目标,比如我们的EC2实例,这些实例托管在两个可用区中。ALB作为外部用户的入口点,处理负载并确保应用程序保持响应和可用,同时也允许我们保持这些EC2实例的私有性。
由于本课程我专注于该架构的网络方面,我们实际上不会构建这部分。然而,了解何时使用ALB来允许应用程序连接而不直接暴露后端EC2实例是很有益的。
实践操作:创建网关
现在,让我们创建并附加一个互联网网关,并向我们在上一个视频中构建的VPC部署两个NAT网关。
以下是操作步骤:

- 登录AWS管理控制台,在主页搜索栏输入“VPC”。
- 从VPC仪表板,在导航面板选择“互联网网关”。
- 在互联网网关页面,点击“创建互联网网关”按钮。
- 在下一页,为互联网网关命名(例如:Project1 Gateway),然后点击“创建互联网网关”。




现在我们有了一个互联网网关,但需要将其附加到VPC。请注意,一个VPC只能有一个互联网网关,并且一个互联网网关一次只能附加到一个VPC。这是一对一的关系。
- 选择“操作”,然后选择“附加到VPC”。
- 在下一个屏幕的VPC列表中,选择“project1 VPC”,然后点击“附加互联网网关”。现在该网关的状态显示为“已附加”。
这样,我们就为这个VPC安装了“前门”。
创建NAT网关
最佳实践是在你运营的每个可用区(Az)中创建一个NAT网关。因此,我将创建两个NAT网关,并将它们分别放置在每个公有子网中。
以下是创建NAT网关的步骤:
- 在导航面板,选择“NAT网关”,然后点击“创建NAT网关”。
- 在此屏幕配置NAT网关。首先,为其命名(例如:gateway 1)。
- 从下拉菜单中选择“Subnet1”。
- NAT网关需要配置一个弹性IP地址,以提供静态IP。点击“分配弹性IP”来完成此操作。







- 点击“创建NAT网关”。
- 重复上述步骤,但这次将NAT网关放置到另一个公有子网中。
- 将其命名为“Nat Gateway2”,从下拉菜单中选择“public Subnet2”。
- 创建弹性IP地址,最后创建网关。







当前架构与后续步骤
至此,我们的网络架构如下图所示,包含了EC2实例、RDS数据库和ALB。



在入站和出站互联网连接正常工作之前,我们还需要完成几个步骤。在接下来的步骤中,我们将完成设置必要元素的过程,包括配置路由表和定义安全规则以保护我们的VPC。
在本系列视频结束时,我们将拥有一个既具备安全互联网连接又具备强大访问控制的VPC。

本节总结
在本节课中,我们一起学*了如何为AWS VPC启用互联网连接。我们介绍了互联网网关作为VPC通往公共互联网的“大门”,以及NAT网关作为私有子网资源安全发起出站连接的“单向通道”。通过实际操作,我们创建并附加了互联网网关,并在两个公有子网中部署了NAT网关,为构建安全、可访问的网络架构奠定了基础。下一节,我们将深入配置路由表,将流量正确地引导至这些网关。
095:路由表 🚦

在本节课中,我们将要学*AWS网络中的核心组件之一:路由表。我们将了解路由表的作用,并学*如何为公有子网和私有子网配置路由,以实现互联网连接和内部通信。
上一节我们介绍了VPC、子网和互联网网关的基本架构。本节中我们来看看如何通过配置路由表来控制网络流量的走向。

概述
路由表是VPC中用于引导网络流量的基本组件。每个子网都可以关联一个路由表,其中包含一组规则(路由),这些规则决定了网络流量的去向。创建VPC时,AWS会自动创建一个默认路由表,允许VPC内的资源进行内部通信,但它不包含通往互联网的路由。因此,我们需要根据需求自定义路由表。
路由表的作用
路由表对于引导VPC内的网络流量至关重要。没有正确的路由,子网将不知道如何将流量导向互联网或VPC内的其他资源。
以下是路由表的核心功能:
- 控制流量方向:决定数据包从子网发出后的下一跳目的地。
- 实现网络隔离:通过为不同子网配置不同路由,可以控制其网络访问权限。
- 连接内部与外部:使VPC内的资源能够相互通信,并(有条件地)访问互联网。


配置路由表:分步指南


我们将通过AWS管理控制台,为架构中的四个子网(两个公有,两个私有)创建并配置路由表。




第一步:创建并关联路由表


首先,我们需要为每个子网创建一个路由表,并将其与对应的子网关联。
- 从VPC控制台,在导航面板选择“路由表”,然后点击“创建路由表”。
- 我们将为VPC中的每个子网创建一个路由表。
- 第一个路由表,命名为
public-route-table-1,选择Project1-VPC,然后点击创建。 - 创建后,通过选择“操作” -> “编辑子网关联”,将其与第一个公有子网(
public-subnet-1)关联。
- 第一个路由表,命名为
- 重复此过程,为其他三个子网创建路由表:
public-route-table-2,关联到public-subnet-2。private-route-table-1,关联到private-subnet-1。private-route-table-2,关联到private-subnet-2。
第二步:创建路由规则
创建好路由表并关联子网后,接下来需要添加具体的路由规则。我们将为公有子网创建指向互联网网关的路由,为私有子网创建指向NAT网关的路由。



以下是配置公有子网路由的步骤:
- 在路由表仪表板,选择
public-route-table-1,然后选择“编辑路由”。 - 表中已存在一条默认路由,用于VPC内部通信。要添加允许互联网流量的路由,点击“添加路由”。
- 在“目标”字段中,输入
0.0.0.0/0。在CIDR表示法中,/0前缀意味着它可以匹配任何IP地址,即代表整个互联网。 - 在“目标”下拉菜单中,选择我们上一课中创建并附加到此VPC的互联网网关。
- 点击“保存更改”。此路由将允许公有子网中的实例通过互联网网关向互联网发送和接收流量。
现在,让我们来配置私有子网的路由表。
以下是配置私有子网路由的步骤:
- 选择与我们的一个私有子网关联的路由表(例如
private-route-table-1),然后“编辑路由”。 - 同样,添加一条新路由,“目标”设置为
0.0.0.0/0。 - 这次,在“目标”中选择部署在对应可用区公有子网中的 NAT网关。
- 保存更改。此配置确保从私有子网实例发出的、目的地为互联网的流量都会被路由到NAT网关。这使得这些实例可以访问互联网(例如获取更新),同时保持与互联网直接入站流量的隔离。
- 对另一个公有和私有子网的路由表重复上述步骤。

配置总结
完成以上步骤后,我们的路由表已按需配置完毕,可以处理内部和外部流量。
- 公有子网:拥有将互联网流量指向互联网网关的路由,使这些子网内的实例能够与互联网通信。
- 私有子网:拥有将互联网流量指向NAT网关的路由,允许这些子网内的实例建立到互联网的出站连接,同时阻止直接的入站连接。
总结




本节课中我们一起学*了AWS路由表的核心概念和配置方法。我们了解到路由表是VPC网络的“交通指挥中心”,通过定义目标(如 0.0.0.0/0)和下一跳目标(如互联网网关或NAT网关),精确控制了子网内资源的网络访问路径。配置公有和私有子网的不同路由,是实现安全、灵活网络架构的关键一步。
在下一视频中,我们将介绍其他网络配置,例如安全组和网络ACL。这些配置将通过定义实例和子网的入站和出站流量规则,进一步加固我们的VPC安全。
096:网络ACL和安全组 🛡️

概述
在本节课中,我们将学*AWS网络中的两个核心安全组件:安全组和网络访问控制列表。我们将了解它们如何协同工作,为虚拟私有云中的资源提供多层安全防护,并掌握配置它们的基本方法。

回顾:路由表配置
上一节我们介绍了如何为子网配置路由表,以引导VPC内的流量。本节中,我们来看看在典型应用场景下,还需要了解的其他网络配置。
在我们的场景中,应用负载均衡器将互联网流量发送给EC2实例,EC2实例随后会与RDS数据库实例建立连接以执行查询。你可以配置网络规则,只允许你想要的网络流量到达这些实例。默认情况下,即使路由表已就位,也没有任何流量被允许到达这些实例。要改变这一点,你首先需要理解安全组和网络访问控制列表。

安全组:实例级虚拟防火墙
让我们从安全组开始。你可以将安全组视为实例级的虚拟防火墙,控制入站和出站流量。默认情况下,安全组拒绝所有入站流量,但允许所有出站流量。因此,你需要定义入站规则,以确定你希望允许哪些类型的流量,以及允许这些流量从何处来。
安全组是有状态的。这意味着如果你允许入站流量到达一个实例,那么返回流量会自动被允许,即使没有明确的出站规则来允许它。例如,如果你允许端口80上的HTTP入站流量,那么对这些HTTP请求的响应将被允许流出,而无需明确的出站规则。这种有状态的特性简化了安全组的管理,因为你无需为每个入站规则创建匹配的出站规则。
放置在VPC中的资源使用安全组。例如,EC2实例、负载均衡器和RDS数据库实例都可以使用具有不同规则的安全组。安全组的规则可以引用其他安全组。

在我们的示例中:
- 一个应用负载均衡器需要从互联网接受端口80的HTTP和端口443的HTTPS流量。
- 一个托管Web服务器的EC2实例需要允许来自应用负载均衡器的HTTP和HTTPS流量,因此可以引用负载均衡器使用的安全组。
- RDS数据库实例需要允许来自EC2实例使用的安全组的、端口3306上的TCP流量(这是MySQL等数据库常用的端口)。

这被称为安全组链。

创建安全组示例


现在,让我们通过一个示例来创建一个可供应用负载均衡器使用的安全组。
以下是创建安全组的步骤:
- 导航到VPC控制台,然后选择“安全组”。
- 选择“创建安全组”。
- 首先,为其命名,例如
ALBSG。 - 选择此安全组所属的VPC,因为安全组与一个VPC相关联。我们将选择
Project1 VPC。 - 接下来,我们需要定义入站规则。选择“添加规则”。
- 对于流量类型,选择
HTTP,这将自动将端口范围填充为80。 - 为源选择
0.0.0.0/0,这将允许来自互联网的端口80流量。 - 添加另一条针对
HTTPS的规则,它使用端口443,并允许来自互联网的流量。 - 选择“创建安全组”。
创建完成后,此安全组就可以与负载均衡器关联。



网络ACL:子网级安全层
现在,让我们继续学*网络ACL,它在子网级别提供了额外的安全层。
与有状态的安全组不同,网络ACL是无状态的。这意味着你需要明确地定义入站和出站规则。它们提供了对流量更精细的控制,对于在子网级别实施安全策略特别有用。
默认情况下,网络ACL允许所有入站和出站流量,但你可以修改这些规则以满足特定的安全要求。对于我们这个简单的用例,不需要改变此行为,但了解这一点仍然很重要,因为它是控制AWS上网络流量的主要方式之一。如果你在排查网络问题时,可能需要调整这些规则。
网络故障排查思路总结
在接下来的实验中,你需要排查数据库的连接问题,这是数据工程师经常会遇到的常见场景。因此,我现在想总结一下你在过去几个视频中学到的关于AWS网络的所有知识,以便你知道在尝试排查AWS上的网络连接问题时需要查看哪些地方。
以下是排查网络连通性问题时应遵循的步骤:

- 检查VPC和子网:确认VPC是否正确配置了互联网网关,并且已正确附加。
- 检查路由表:确认路由表具有适当的规则来正确引导流量,并且路由表与子网的关联配置正确。
- 检查安全组:确保安全组已配置所需的规则。
- 检查网络ACL:确认网络ACL允许必要的流量。
- 检查实例配置:再次检查实例配置,确保它们与正确的安全组和子网相关联。
在下一个实验中,你将通过排查数据库连接问题来实践这些概念,运用你所学到的知识来识别和解决网络问题。
总结

本节课中,我们一起学*了AWS网络中的两个关键安全组件。我们了解了安全组作为有状态的、实例级防火墙的工作原理,以及如何创建和配置它们。我们还探讨了网络ACL作为无状态的、子网级安全层的作用。最后,我们总结了当遇到网络连通性问题时,从VPC、路由表、安全组到网络ACL的系统性排查思路。掌握这些知识对于在AWS上构建和维护安全、可靠的网络架构至关重要。
097:AWS数据库连接故障排除实验演练 🔧

在本节课中,我们将学*如何解决连接AWS RDS数据库时遇到的常见网络、安全和权限问题。你将通过一个实验,从Cloud9终端连接到RDS数据库,创建表,并从S3桶下载数据填充该表。作为数据工程师,连接数据库、移动和读取数据是超级常见的任务,而排查这些基本任务中的连接和权限问题更是家常便饭。
概述
本次实验模拟了一个真实的故障排除场景。首先,你将尝试连接一个RDS数据库,但会遇到几个需要修复的问题。之后,你需要从一个S3桶下载CSV文件,并将数据复制到数据库中。在从S3读取文件时,你还会遇到权限问题。本教程将引导你逐步解决所有这些问题。
实验步骤详解
1. 检查并连接资源
首先,你需要在AWS控制台中定位提供的RDS数据库和Cloud9环境。
在控制台中搜索“RDS”并点击进入。在“数据库”列表中找到提供的数据库标识符,点击它并找到数据库终端节点。请保存这个终端节点,因为在排查连接问题时需要多次使用它。


接下来,创建Cloud9环境。在控制台搜索“Cloud9”,点击“创建环境”。输入环境名称(例如 DE-C2W1A1),选择实例类型为“t3.small”,网络设置选择“安全Shell(SSH)”。关键的一步是选择VPC。
上一节我们介绍了如何定位资源,本节中我们来看看如何配置网络以确保它们能够通信。
2. 解决VPC不匹配问题
当你首次尝试从Cloud9终端连接数据库时,连接会失败且没有明确的错误信息。这通常是由于网络配置问题。


问题根源:Cloud9环境运行在一个EC2实例上。如果这个EC2实例和RDS数据库不在同一个VPC中,它们默认无法通信。
排查方法:
- 在RDS控制台,查看数据库的“网络”选项卡,记录其VPC ID。
- 在Cloud9控制台,查看环境的“网络设置”选项卡,记录其VPC ID。
解决方案:
如果两个VPC ID不同,你需要删除当前的Cloud9环境,然后重新创建一个,并在VPC设置中选择与RDS数据库相同的VPC(例如名为 DEC-C2W1A1 的VPC),同时选择一个公有子网。
以下是创建新环境时的关键配置代码示例(概念性描述):
# 在AWS Cloud9控制台创建环境时,需手动选择:
# 环境名称: DE-C2W1A1
# VPC设置: 选择与RDS实例相同的VPC (例如 vpc-xxxxxx)
# 子网: 选择一个公有子网


3. 解决安全组规则问题
将Cloud9环境创建在正确的VPC后,再次尝试连接数据库,可能依然失败。现在需要检查安全组规则。
问题根源:即使资源在同一个VPC,RDS数据库的安全组规则可能不允许来自Cloud9 EC2实例的流量。
排查方法:
- 在RDS控制台,进入数据库的“安全”选项卡,查看其VPC安全组。
- 在EC2控制台,找到运行Cloud9环境的EC2实例,查看其“安全”选项卡下的安全组ID。
解决方案:
你需要修改RDS数据库安全组的入站规则,允许来自Cloud9 EC2实例安全组的流量访问数据库端口。

以下是添加入站规则的步骤:
- 编辑RDS安全组的入站规则。
- 添加一条新规则。
- 类型选择“PostgreSQL”(或根据你的数据库类型选择,如MySQL)。
- 端口范围设置为
5432(PostgreSQL默认端口)或3306(MySQL默认端口)。 - 在“源”字段中,粘贴Cloud9 EC2实例的安全组ID(格式如
sg-xxxxxx),而不是使用0.0.0.0/0(允许所有公共流量),后者存在安全风险。 - 保存规则。

核心安全组规则公式如下:
允许 入站流量
协议: TCP
端口: [数据库端口号,如 5432]
源: [Cloud9 EC2实例的安全组ID]
4. 解决密码认证失败问题
修复网络和安全组后再次连接,你可能会收到“密码认证失败”的错误。这是一个非常常见的问题。

问题根源:密码错误。可能原因包括密码轮换后未更新、输错密码或遗漏了密码更新通知。

解决方案:
- 仔细检查输入的密码。
- 如果确认密码无误但仍失败,可能需要联系团队获取最新的正确密码。
- 使用正确的密码重新连接。
使用 psql 客户端连接数据库的命令格式如下:
psql -h [数据库终端节点] -U [用户名] -d [数据库名]
# 执行后会提示输入密码
5. 创建数据库表
成功连接数据库后,下一步是在数据库中创建表。
实验提供了SQL文件来创建表结构。首先,你需要下载实验文件。然后,在Cloud9终端中连接到数据库,并执行DDL(数据定义语言)文件。
以下是操作命令示例:
# 1. 下载实验所需文件(假设脚本已提供)
# ./download_files.sh
# 2. 连接到数据库
psql -h [数据库终端节点] -U postgres -d postgres

# 3. 执行创建表的SQL文件
\i /path/to/sql/ratings_table_ddl.sql
# 4. 验证表已创建(可选)
SELECT * FROM ratings LIMIT 1;
6. 从S3下载数据并解决权限问题
表创建好后是空的,需要从S3桶中的CSV文件填充数据。首先需要将CSV文件下载到本地。

遇到的问题:运行提供的Python下载脚本时,会出现权限错误,拒绝访问S3桶。

问题根源:S3桶的策略(Bucket Policy)未授权Cloud9的EC2实例读取对象。

排查与解决方案:
- 在S3控制台,找到目标桶,进入“权限”选项卡下的“存储桶策略”。
- 你会发现现有策略可能拒绝了所有读取操作。
- 你需要用实验说明中提供的新策略替换它。新策略应包含以下关键部分:
Effect: AllowAction: s3:GetObjectResource: arn:aws:s3:::[你的桶名]/csv/*Condition:限制源IP为你的Cloud9 EC2实例的公有IPv4地址(可在EC2控制台找到)。

一个简化的策略示例如下:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::your-data-bucket/csv/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": "[你的EC2实例公有IP]/32"
}
}
}
]
}
- 保存策略后,重新运行Python下载脚本,文件应能成功下载到本地的
data文件夹。
7. 将数据导入数据库

最后一步是将下载的CSV数据导入到数据库的表中。
实验会提供一个包含 COPY 命令的SQL文件。你需要在 psql 连接中执行这个命令。
以下是操作命令示例:
# 1. 连接到数据库
psql -h [数据库终端节点] -U postgres -d postgres
# 2. 执行数据导入的SQL文件
\i /path/to/sql/copy_data.sql
# 3. 验证数据已成功导入
SELECT COUNT(*) FROM ratings;

总结
在本节课中,我们一起完成了一个完整的AWS数据库连接与数据导入的故障排除实验。我们学*了:
- 诊断VPC网络问题:确保Cloud9 EC2实例和RDS数据库位于同一VPC以实现网络连通性。
- 配置安全组规则:通过添加精确的入站规则,允许特定安全组(EC2实例)访问数据库端口,而不是开放给所有IP。
- 处理认证错误:细心核对并获取正确的数据库连接密码。
- 管理S3存储桶权限:通过修改存储桶策略,授予特定IP地址的EC2实例读取S3对象的权限。
- 执行数据库操作:使用
psql连接数据库,运行SQL文件来创建表结构(DDL)和导入数据(COPY命令)。

这些步骤涵盖了数据工程师在日常工作中最常遇到的基础设施连接和权限问题。掌握这些排查技能,对于构建和维护可靠的数据管道至关重要。你可以随时回看本视频,以便在独立完成类似任务时参考这些步骤。
098:源系统、数据摄取与管道(第1周总结)📚

在本节课中,我们将回顾数据工程生命周期第一阶段的核心内容,即数据在源系统中的生成。我们将总结本周学*的关于常见源系统、连接方式以及相关挑战的知识。
🎯 第一周内容回顾
恭喜你顺利完成本课程第一周的学*。本周我们聚焦于数据工程生命周期的初始阶段,即数据在源系统中的生成。无论你是从头构建新的数据系统,还是更新维护现有的数据管道,理解源系统的工作原理都至关重要。
上一节我们介绍了课程的整体目标,本节中我们来具体回顾第一周的核心知识点。
🔍 常见源系统详解
本周我们首先深入探讨了几种常见的源系统。以下是几种主要的源系统类型:
- 关系型与非关系型数据库:例如 MySQL、PostgreSQL(关系型)和 MongoDB、Cassandra(非关系型)。它们是结构化或半结构化数据的主要来源。
- 对象存储与文件日志:例如 Amazon S3、Azure Blob Storage。常用于存储大量非结构化或半结构化数据,如日志文件、图片、视频。
- 事件流处理系统:例如 Apache Kafka、Amazon Kinesis。用于实时处理连续生成的事件流数据。
🔗 云端架构下的数据源连接
接着,我们研究了在基于云的架构中连接这些数据源的方法。网络配置是实现连接的基础,它确保了数据能够从源系统安全、可靠地传输到处理环节。
以下是连接时需要考虑的几个关键方面:
- 网络连接:通过虚拟私有云、对等连接等技术建立安全的数据通路。
- 身份与访问管理:其核心是确保安全,通过最小权限原则控制谁可以访问什么资源。一个基础的权限策略可以用代码描述为:
{ "Effect": "Allow", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::my-bucket/*", "Principal": {"AWS": "arn:aws:iam::123456789012:user/DataEngineer"} } - 全链路安全:安全考虑必须贯穿从源系统到整个数据管道的每一个环节。
⚠️ 常见问题与排查
在本周的学*中,我重点指出了处理源系统时可能遇到的一些典型问题。例如,连接超时、数据格式不一致、权限认证失败等。你在实验环节也有机会动手排查其中部分常见故障,这有助于加深理解。
🚀 下周内容预告

第一周我们重点了解了数据的“源头”——源系统。在接下来的一周,我们将专注于从这些源系统摄取数据的不同方式。


我们将更深入地探讨批量摄取与流式摄取的细节与区别。同时,我们会梳理在设计数据摄取架构时应考虑的各种因素,例如数据量、延迟要求、成本和处理逻辑。
期待在下一周与你继续学*。
本节课中我们一起学*了数据工程生命周期的起点——源系统。我们回顾了关系型数据库、NoSQL数据库、对象存储和流系统等常见数据源,探讨了在云环境中安全连接它们的方法,并初步认识了可能遇到的挑战。这些知识为理解后续的数据摄取与处理流程奠定了坚实基础。
099:数据工程(导论,源系统、数据摄取和管道,数据存储和查询|1-2-3课)|第2周概览 🗺️

在本节课中,我们将要学*数据工程生命周期的下一个关键阶段:数据摄取。我们将回顾第一周关于源系统的知识,并深入了解如何从不同来源获取原始数据,为后续处理做好准备。
回顾与衔接
在第一周,我们详细探讨了源系统,并练*了如何与数据库和对象存储进行交互。上周材料的重点在于如何连接并与源系统互动,因为这些系统通常不是数据工程师直接设立或控制的。
然而,连接和与源系统交互,正是数据工程生命周期下一阶段——数据摄取——的开始。
数据摄取的核心任务
正如之前所说,数据工程师的工作是从某个地方获取数据,将其转化为有用的东西,然后使其可用于下游用例。数据摄取正是你工作中“从某处获取原始数据”的部分。
你已经知道,这个“某处”可能是一个数据库、一个API、一组文件,甚至是一个流式处理系统。事实上,在之前的课程实验中,你已经执行过多次数据摄取操作:
- 在前序课程中,你使用AWS Glue ETL作业将数据从Amazon RDS MySQL数据库摄取到S3存储。
- 你还从AWS Kinesis数据流摄取数据,并使用Kinesis Firehose将事件传送到S3存储桶。
- 在本课程第一周最后的实验中,你排查了连接数据库时的一些常见问题。
这一切都表明,你对数据摄取已经有很多了解。本周,我们将在你现有知识的基础上,增加深度和细节。


本周学*路径
以下是本周我们将要深入探讨的内容:
首先,我们将更详细地审视一些批处理和流式摄取模式。这意味着我们将区分以块或批次处理数据的模式,与处理连续数据流的模式。
接着,我们将与一位营销分析师进行对话,从中识别从REST API(一个我们目前尚未深入探讨的源系统)进行批处理摄取的需求。
然后,我们将与一位软件工程师交流,以探讨在前序课程中略过的流式摄取的一些要求。例如数据负载的特征(即你正在摄取的单个消息的特征)、事件速率,以及如何配置流式管道以将数据送达目的地。
最后,你将有机会在实验环节亲自构建这些解决方案,即:从REST API进行批处理摄取,以及从Web服务器日志进行流式摄取。
总结

本节课中,我们一起学*了第二周的概览。我们明确了数据摄取在数据工程生命周期中的核心地位,回顾了已有的实践经验,并预览了本周将深入学*的批处理与流式摄取模式、相关需求分析以及实践构建环节。

请跟随下一个视频,开始我们深入的学*之旅。
100:数据摄取的连续体 📊➡️💾

在本节课中,我们将要学*数据摄取的核心概念,特别是批处理与流处理之间的关系。我们将探讨如何根据不同的数据源和业务需求,在这两种处理方式构成的连续体中选择合适的点。
在之前的课程中,我们多次探讨了批处理与流处理之间的区别,这是数据工程师在工作中必然会遇到的。
从某种意义上说,几乎所有的数据都可以被视为一个连续的事件流。
这些事件可能发生在现实世界中,例如股价变动、你喜爱的体育赛事进球,或者用户在网站上点击按钮。在本课程中,我们关注的是当代码运行并记录这些事件时所产生的数字数据。
因此,在数据摄取方面,我的理解是:无论你使用何种系统,数据都是在某处作为一个无界的连续事件流生成的。所谓“无界”,是指这个流没有特定的开始或结束。
如果你在这些事件生成时,逐个实时地摄取它们,这就是流式摄取的一个例子。
相反,如果你对这个流施加一些边界,并将这些边界内的所有数据作为一个单一单元进行摄取,那么这就是批处理摄取。

当然,你可以用多种方式来决定如何为数据流施加边界。例如,你可以按特定的大小阈值(如分成10GB的块)来划分数据,或者按记录总数(如每生成1000个事件就摄取一次)来划分。更常见的是按时间来划分数据。例如,你可能决定摄取过去一周的所有销售订单数据,或者选择更频繁地(如每天)摄取数据。在这种情况下,你只是对初始数据流施加了不同的边界。
你可以继续这个思路:如果你想每小时、每分钟甚至每秒从源系统检索一次新数据,会发生什么?随着摄取频率的不断提高,在某个时刻,当批处理摄取的频率极高时,你实际上就回到了流式处理。
因此,这里的要点是:批处理和流处理并非两种完全独立的数据摄取方法。相反,它们存在于一个连续体上。你的数据管道在这个连续体上的位置,将取决于你所处理的源系统类型以及你最终要服务的业务用例。
传统意义上,批处理通常意味着将有界的大块数据作为一个整体进行移动和处理。在很长一段时间里,这几乎是唯一的选择。
随着工具和技术变得更强大、更灵活,对更小的数据块进行更频繁的批处理已成为可能。*几十年来,出现了所谓的微批处理工具,它们开始模糊批处理与流处理之间的界限。
对于什么算作批处理、微批处理,或者数据需要多接*实时处理才能被视为流处理,并没有严格的规则或行业标准。
在实践中,你选择以批处理还是流式方式摄取数据,将取决于从利益相关者需求中确定的业务用例,以及你所交互的源系统类型。
对于某些数据库,你可以使用像JDBC或ODBC这样的连接器(我们上周简要介绍过),也可以设置定期摄取,或者在记录了一定量的新数据时立即摄取。你还可以选择像AWS Glue ETL这样的无服务器摄取工具,它可以配置为连接到源数据库并定期摄取数据。
如果你要从API摄取数据(正如本周第一个实验要求的那样),你将需要根据该API的特定协议建立连接,并且会受到该API各种约束和限制的影响,例如一次可以摄取多少数据,或者可以多频繁地调用API。目前,通过API进行数据交换并没有统一的标准,因此这可能是一个有些令人沮丧的过程,涉及阅读文档、与外部数据所有者沟通以及编写和维护自己的自定义API连接代码。
尽管如此,我们正看到行业趋势是供应商提供API客户端库,以消除API访问的许多复杂性。同时,市面上也出现了越来越多的托管数据连接平台,它们为许多数据源提供了更简单的连接性。
因此,如果你需要从API摄取数据,我的建议是:尽可能使用现有的解决方案,只在没有其他选择时才进行自定义连接工作。
当文件作为源系统时(正如我们上周所看),你可能正在使用一个对象存储系统作为数据源。但你也可能遇到无法完全自动化文件摄取的情况,也就是说,你只需要手动下载文件或让人直接发送文件。
以下是常见的文件传输协议:
- 你可以使用命令行工具,如SFTP(安全文件传输协议)或SCP(安全复制)。
- 或者使用其他常见方式来摄取文件。
如果你想从流式系统摄取物联网设备或传感器数据,那么无论你最终目标是进行批处理还是流处理,你可能别无选择,只能设置一个消息队列或其他流式系统来摄取这类数据。
无论如何,我认为要熟悉不同摄取模式的各种考虑因素和注意事项,唯一的方法就是深入研究一些实际用例。我们本周的材料主要设置为两个案例研究:一个用于从API进行批处理摄取,另一个用于从Kinesis数据流进行流式摄取。
在本视频之后的阅读材料中,你将了解更多关于从本课程中已提及以及一些未提及的不同源系统进行摄取的知识。


本节课中,我们一起学*了数据摄取的连续体概念。我们了解到批处理和流处理并非截然分开,而是存在于一个频谱之上。选择哪种方式取决于数据源的特性和业务需求。我们还简要探讨了从数据库、API和文件等不同源系统摄取数据时的常见方法和工具。理解这个连续体,将帮助你在实际工作中为不同的场景设计最合适的数据摄取策略。
101:数据工程导论 - 与市场分析师的需求沟通 🎯

概述
在本节课中,我们将学*如何与市场分析师进行需求沟通,并基于对话内容,明确一个数据工程项目的数据需求。我们将重点关注从外部API(如Spotify)获取数据,以分析其与产品销售趋势的关联。
在专项课程的第一门课中,我们基于与不同利益相关者的对话进行了一些需求收集。
这些利益相关者包括数据科学家、首席数据官、产品营销经理以及一家虚构电商公司的软件工程师。
通过这些对话,你从首席数据官那里了解到,公司的目标是开拓新市场并提高现有客户的留存率。
你与这些利益相关者合作,为推荐系统搭建了一条数据管道。
这里,我们将基于这一系列对话,与一位负责寻找产品销量趋势洞察的市场分析师进行交流。
因此,在这个视频中,我将扮演数据工程师,我的朋友Colleen将扮演市场分析师。
让我们开始吧。
Colleen,你好,很高兴见到你。我也很高兴见到你。你好,我是Joe,新来的数据工程师,期待了解更多关于你正在做的工作。
是的,当然,我非常期待与你合作。
我正在做的工作是试图理解哪些外部因素可能是与客户购买*惯相关的信号。
在营销团队中,我们一直在集思广益,思考这些因素可能是什么,并且我们已经想出了一些希望进一步探索的想法。
听起来很酷。我想请你详细介绍一下。
好的。
我们当时在想,或许从广义上讲,一个人的情绪状态,比如更快乐或更悲伤、兴奋或放松,可能会影响他们在线购物的行为。
当然,我们无法确切知道我们的客户在任何一天的具体感受,但我们认为可以探索一些特定的想法。
我们特别希望研究在我们产品销售的不同地区,人们都在听什么类型的音乐,然后将这些数据与产品销量进行比较。
我明白了。
所以你在考虑从一些外部来源和关于人们收听信息中提取公共数据。
是的,没错。我一直在研究,看起来Spotify有一个公共API,我们可以从中提取关于不同地区哪些音乐艺术家正在流行以及人们随时间变化的收听趋势的数据。
这听起来像是你有可能帮助我们的事情吗?
当然可以。我是Niback的忠实粉丝,确实很喜欢音乐。
好的,那么我只需要更仔细地研究一下Spotify API。一旦我弄清楚细节,也许我们可以详细讨论一下你希望提取什么类型的信息,以及你希望如何获取这些信息。
好的,这听起来太棒了。在此期间,如果有任何我可以帮忙的地方,请告诉我。我期待在我们理清细节后与你进行更多交流。
太好了。谢谢。
好的,以上就是与市场分析师对话的一个例子。他们描述了一个项目的需求,该项目专注于从公共API提取数据,并希望将这些数据与产品销售数据一起进行分析。
现在我要承认,可能你也在想,研究地区趋势和人们听什么音乐,听起来可能不是一个特别高明的营销方法。你可能是对的。
但请相信我,在涉及不同利益相关者想要获取什么类型的数据时,我见过各种疯狂的事情。
所以,这里的重点不在于纠结这是否是一项值得投入的事业,而在于识别你需要构建的系统的关键需求。
在这种情况下,要确切知道构建整个项目数据管道的最佳方法是什么,当然需要更多信息。
但目前,我们将专注于数据摄取环节。你将在这里学到的关键点是,你需要从第三方API摄取数据。
你最终需要考虑其他细节,比如你将如何最终存储数据并提供给分析师使用。

这将取决于分析师的需求。

一般来说,当从API摄取数据时,你将考虑某种批处理摄取流程,但具体形式将取决于你对数据的目标用途。
在下一个视频中,我们将更仔细地看看流行的批数据处理范式——提取、转换、加载(ETL)与提取、加载、转换(ELT)之间的权衡,因为它们与你的数据摄取相关。
之后,我们将看看如何连接和调整来自REST API的数据。
我们下个视频见。
总结
本节课中,我们一起学*了如何通过与市场分析师对话来明确数据需求。我们了解到,项目需要从Spotify等外部API获取音乐趋势数据,并与内部销售数据关联分析。核心任务是构建数据摄取管道,并初步认识到后续需要根据分析需求考虑数据存储和提供方式。下一节我们将深入探讨数据处理的两种主要范式:ETL与ELT。
102:ETL vs ELT 🔄

在本节课中,我们将要学*两种非常重要的批处理数据摄取模式:ETL(提取、转换、加载)和ELT(提取、加载、转换)。我们将探讨它们的区别、各自的优缺点,并分析如何为一个具体的营销分析项目选择合适的模式。
上一节我们介绍了营销分析师的项目背景,本节中我们来看看如何为该项目选择数据摄取模式。
项目背景回顾
在之前的视频中,我们的营销分析师分享了他们的项目目标:将一些外部数据整合到他们对产品销售的分析中。对于这个项目,分析师主要关注数据的历史趋势,未来可能转向对当前数据进行更明确的分析,但并非实时或紧急需求。此外,数据将从第三方API获取。
虽然你通常可以灵活决定轮询数据的频率或数量,但你将受限于某种形式的批处理摄取。这是因为API调用的工作原理类似于网络请求,你发送数据请求并接收响应,而单位时间内可发出的请求数量通常是有限的。因此,对于这个项目的数据摄取,你面对的是一个批处理过程。
ETL与ELT简介
在之前的课程中,我简要介绍了ETL和ELT。它们是两种非常常见的批处理摄取模式。虽然从技术上讲,它们包含了数据工程生命周期中的转换和存储阶段,但在实践中,你需要在摄取阶段就考虑这两种模式之间的权衡。这就是我们现在要做的。
首先,我将进一步说明区分这两种流程的关键点,然后我们将看看哪一种可能更适合营销分析师的使用场景。
ETL:提取、转换、加载
ETL,即提取、转换、加载,是20世纪80年代和90年代流行起来的原始批处理摄取模式。
该流程始于从源系统(例如通过直接查询数据库或使用API)提取原始数据。然后,你在一个中间暂存区域对数据进行转换。最后,你将数据加载到目标存储目的地,如数据库或数据仓库。
在80年代和90年代,存储和计算能力极其有限。因此,制定一个明确的计划至关重要,包括你想要摄取哪些数据、以何种格式存储和访问数据等。数据仓库的建立成本高昂,且不适合运行包含复杂连接和转换的重型查询。因此,在那个年代,人们别无选择,必须在摄取过程中非常审慎地规划如何转换原始数据,以确保数据能够以高效的方式存储和提供。
公式/代码表示:
ETL流程:源系统 -> 提取 -> 转换 -> 加载 -> 目标数据仓库

如今,ETL作为一种摄取模式仍然非常流行。但随着云存储成本相对较低和计算能力的提升,它不再是唯一的选择。
ELT:提取、加载、转换
在2010年代初期,云存储系统变得高度可扩展,我们看到了建立在S3等对象存储系统以及Redshift等云数据仓库之上的数据湖的出现。这使得以相对低廉的成本存储海量数据,并直接在数据仓库中执行所有数据转换成为可能。就在这时,ELT(提取、加载、转换)的概念应运而生。
在ELT流程中,你从源系统提取原始数据,并直接将其加载到目标数据库、数据仓库甚至对象存储中,而不执行任何转换。
ELT的核心理念是,你无需预先决定如何使用数据。这在某种程度上很有吸引力,因为可以说,通过对原始数据应用转换并仅存储处理结果(如ETL所做),在此过程中会丢失一些信息。但使用ELT,所有选项都保留着,因为你只是捕获所有数据并保存以备后用,然后你可以随心所欲地查询和转换原始数据,信息永远不会丢失。
ETL与ELT的权衡
尽管这个范式听起来很吸引人,但说实话,当我第一次听说ELT的想法时,我认为这是一个糟糕的主意。我当时的想法是,为什么要在不深入思考如何使用数据的情况下,就把一堆原始数据堆在存储里?正如我在这些课程中一直强调的,任何数据工程项目的首要步骤都应该是牢固确立最终目标,然后才考虑如何构建系统来实现这些目标。
然而,随着时间的推移,我确实开始看到ELT的潜在好处。
以下是ELT的一些优势:
- 实施更快:因为它不需要提前详细规划如何转换数据。
- 数据可用性更高:可以更快地向用户提供数据(尽管是原始形式),因为ELT消除了对暂存服务器和中间数据转换的需求。
- 转换效率高:借助现代数据仓库的处理能力,数据加载到存储后,转换仍然可以高效完成。
- 灵活性更强:正如我之前所说,当你存储所有原始数据时,你可以在以后采用不同的转换方式或以不同的方式分析数据,这比一开始只存储转换后的数据更具可能性。
那么,ELT的缺点是什么?简而言之,如果你不小心,你的管道可能只会变成一个EL(提取-加载)管道,你将海量的原始数据提取并加载到存储中,却没有想好如何将其转换成有用的东西。当你不想花时间提前规划如何使用数据时,你最终可能会陷入通常所说的“数据沼泽”。
数据沼泽是指你的数据变得杂乱无章、难以管理且基本上无用的状况。我喜欢在谈到数据沼泽这个话题时展示这张图片:一个数据工程师坐在他的数据沼泽中,他保存了他认为将来可能有价值的一切东西,但现在,即使他能记住里面有什么,他很可能也找不到了。
在2010年代初期,数据沼泽很常见,因为公司发现可以保存字面上的每一份原始数据,以防万一。如今,这种情况已经得到了很大程度的清理,部分原因是法规要求公司以可审计或有序删除的方式存储数据,例如,当用户要求将其数据从公司系统中删除时。
尽管如此,当今相对较低的存储成本,结合现代数据仓库和其他存储抽象的强大处理能力,意味着ETL和ELT都可以是合理的批处理方法。
但无论采用哪种方法,重要的是心中要有一套清晰的目标,并相应地管理你的数据。


为营销分析项目选择模式
现在,让我们回想一下与营销分析师的对话。对于这个项目,你将从第三方API摄取数据。通常,通过API连接接收的数据将是半结构化数据,可能是JSON格式。在某些情况下,你可能还会检索非结构化数据,如文本和图像。
在这种情况下,营销分析师似乎旨在对数据进行一些探索性分析,无法预先确切说明可能需要哪些转换。因此,ELT管道可能是此摄取场景的正确选择,因为它为转换和服务阶段提供了更大的灵活性。

对于这个项目,我们尚未详细讨论的这个摄取用例的一个重要组成部分是关于从API摄取数据的部分。这就是我们下一步要探讨的内容。
总结
本节课中我们一起学*了ETL和ELT这两种核心的批处理数据摄取模式。我们了解了ETL作为传统模式的特点,以及ELT在现代云环境下的优势与潜在风险。最后,我们结合营销分析师的具体用例,分析了选择ELT模式的合理性,因为它能更好地支持探索性分析所需的灵活性。

在下一个视频中,请与我一起探讨如何将API作为数据源进行工作。
103:REST API 🚀

在本节课中,我们将要学*什么是API,特别是REST API,以及它们在现代数据工程中扮演的关键角色。我们将了解API如何促进系统间的数据交换,并为你后续实际连接和提取数据打下基础。
从“API指令”说起
上一节我们介绍了数据源系统,本节中我们来看看数据如何通过标准化的接口被获取。
在之前的课程中,我提到了所谓的“API指令”。这源自2002年杰夫·贝佐斯发给所有亚马逊员工的一封电子邮件。这封邮件的核心内容是:从今往后,所有团队都必须使用服务接口(即应用程序编程接口,或API)来进行通信、提供数据和功能。
这个指令旨在解决当时存在的问题:在那之前,亚马逊乃至其他所有组织的团队之间,都没有一个一致或稳定的方式来交换数据和服务,导致了效率低下。通过将API确立为不同团队之间稳定且可预测的服务接口,意味着任何单个团队都可以向其他团队提供数据、功能和通信,无论该团队自身的系统内部有多么复杂。
API指令的另一部分是,所有这些服务接口或API都必须从头开始构建,最终要能够对外部世界的开发者公开。这种向服务接口的重新定位,为后来成为亚马逊网络服务(AWS)奠定了基础,并为全球公司最终如何在内部和外部共享数据与服务指明了方向。
什么是API? 🤔
那么,API究竟是什么?它本质上是一套规则和规范,允许你通过编程方式与应用程序进行通信和交换数据。这里的“编程方式通信”指的是通过运行代码进行通信。
如果你做过一些软件开发,可能对连接API很熟悉。但即使你没有亲自设置过API连接,你也无疑每天都在直接使用API,例如在线搜索或使用手机上的应用程序。这是因为如今,API被构建来实现各种软件应用的功能。
以下是API的一些常见应用场景:
- 社交媒体应用使用API从网络服务器获取并向最终用户显示数据。
- API也用于促进电子商务网站和支付系统之间的交易。
- 许多公司提供面向公众的API,以便开发者可以访问他们的数据和服务,并将其集成到自己的应用程序中。
数据工程师与API 🔧
作为一名数据工程师,你将使用API来连接和提取来自各种源系统的数据,例如网络服务、云平台或第三方提供商。其方式是发送请求并以标准化格式接收响应。
API还可以提供元数据、文档、身份验证和错误处理功能,以方便数据提取。
最常见的API类型:REST API 🌐
最常见的API类型是所谓的REST API。REST代表表征状态转移。
REST API通常使用超文本传输协议(或者你可能更熟悉的叫法:HTTP方法)作为通信的基础。因此,你可以将与REST API的交互类比为浏览互联网时的行为。
当你在浏览器中点击一个链接时,你正在向服务器发送一个HTTP请求,以获取特定资源(如一个网页)。服务器则通过提供该资源来响应。
使用REST API时,你同样是在发送一个HTTP请求来获取特定资源,而API则根据你请求的内容来设置响应。
实践场景:连接Spotify API 🎵
在我们与营销团队的对话中,我们了解到他们希望分析存储在第三方平台(本例中是Spotify)上并通过API可用的数据。这是数据工程师经常会遇到的一个非常常见的场景:你需要从中提取数据的源系统,无论是内部系统还是外部第三方系统,都通过API进行访问。
在接下来的阅读材料中,我包含了一些在与API交互以从源系统摄取数据时你应该熟悉的技术细节。但熟悉其工作原理的最佳方式是亲自实践,而这正是你在下一个实验课中要做的。

因此,在阅读材料之后的视频中,我将带你了解这一切将如何运作。
总结

本节课中我们一起学*了API,特别是REST API的核心概念。我们了解到API是一套标准化的通信规则,它解决了系统间数据交换的混乱问题,是现代数据生态(如AWS)的基石。作为数据工程师,我们将频繁使用API从各种源系统(如Spotify)提取数据。REST API基于HTTP协议,其交互模式类似于浏览网页。掌握API是构建数据管道的关键第一步。
104:使用批处理从API获取数据 🎵

在本节课中,我们将学*如何与Spotify Web API进行交互,通过批处理方式获取数据。我们将探索分页的概念,并学*如何发送需要授权的API请求。课程将涵盖从创建账户、获取访问令牌,到实际执行API调用和实现分页数据提取的完整流程。
API核心概念
上一节我们介绍了本实验的目标,本节中我们来看看与Spotify API交互所需理解的核心概念。
Spotify Web API是一个RESTful API。你可以向其发送请求,以直接从Spotify数据目录访问音乐、艺术家、专辑和曲目。
每个特定的数据项(如播放列表、艺术家或专辑)被称为一个资源。你可以通过向代表该资源的端点发送HTTP请求来访问它。
常见的HTTP请求类型包括:
- GET:检索资源。
- POST:创建资源。
- PUT:更改和/或替换资源。
- DELETE:删除资源。
例如,在Spotify的API文档中,点击“Playlist”部分,你可以看到所有可用于与此资源交互的请求。



一个成功的请求会返回一个JSON格式的响应,其中包含所请求资源的信息。如果请求不成功,则会返回一个包含状态码的错误对象,用于解释失败原因。
授权与访问令牌
当我们向Spotify Web API发出请求时,需要指定资源端点以及一个访问令牌。
访问令牌是一个字符串,包含用于访问特定资源的凭证和权限。要获取访问令牌,你需要先创建一个Spotify账户,并从账户中获取客户端ID和客户端密钥。这两个值将用于授权过程和访问令牌的生成。
访问令牌的有效期为一小时。过期后,你需要请求一个新的令牌。
以下是获取访问令牌的代码示例:
def get_token(client_id, client_secret):
# 此函数使用client_id和client_secret向Spotify授权服务器请求访问令牌
# 返回一个包含访问令牌的响应字典
pass
请注意,其他API的授权要求可能不同。建议在开始使用任何API前,先查阅其官方文档。

实验准备:创建Spotify应用

在开始与Spotify API交互之前,你需要创建一个账户以获取用于生成访问令牌的密钥。


以下是创建应用并获取凭证的步骤:
- 访问Spotify开发者网站并登录你的账户。
- 点击右上角账户名,进入“Dashboard”。
- 点击“Create App”。
- 填写应用名称、描述。
- 在“Redirect URI”中,可以指定
http://localhost:8888/callback。 - 选择“Web API”作为类型。
- 点击“Save”。

应用创建后,进入应用设置页面,即可找到客户端ID和客户端密钥。你需要将这些值复制下来,在实验的Jupyter笔记本中,将它们粘贴到指定的环境变量文件中。
执行API请求
在Python中创建API调用,可以使用requests库。这是一个流行且易于使用的与API交互的库。
例如,要对Spotify API执行GET请求,可以调用requests.get()方法。你需要传入想要访问的资源的端点,并使用headers参数指定访问令牌。
以下是执行GET请求的代码结构:
import requests
def get_auth_header(access_token):
return {'Authorization': f'Bearer {access_token}'}
# 假设已获得访问令牌 `token_response`
headers = get_auth_header(token_response['access_token'])
endpoint = "https://api.spotify.com/v1/browse/featured-playlists"
response = requests.get(endpoint, headers=headers)
data = response.json() # 将响应转换为Python字典
在实验中,你会使用一个预先提供的函数来自动创建授权请求头。
理解响应与分页
让我们以获取“Featured Playlists”的端点为例,查看返回的响应。
响应是一个字典。对于“featured-playlists”请求,响应可能包含诸如message和playlists等键。playlists本身又是一个包含多个键的字典,例如:
href:指向该资源(包含当前查询参数)的端点链接。items:包含实际播放列表详情的列表。limit:本次返回的项目数量限制。offset:本次返回项目的起始偏移量。total:符合条件项目总数。next:用于获取下一页结果的端点URL(如果存在)。
offset和limit参数用于实现分页。这允许你分批提取大量数据,而不是一次性获取所有项目。
例如,默认请求可能返回前20个播放列表(offset=0, limit=20)。next字段提供的URL则可用于获取下一批20个项目(offset=20, limit=20)。
实验任务概述
在实验的第一部分,你将完成一个函数,该函数对“featured-playlists”端点执行GET请求,并允许自定义offset和limit参数。
接下来,你将实现分页逻辑以提取完整的特色播放列表。有两种方法:
- 手动递增
offset参数进行新的API调用。 - 使用当前API响应中
next字段提供的端点。
你将完成两个分别对应这两种方法的函数。
在实验的第二部分,你将构建一个批处理摄取流程,用于提取特色播放列表中曲目的详细信息(如曲目名称、专辑、艺术家)。这需要执行两个分页API调用:
- 获取特色播放列表的ID列表(使用第一部分的分页调用)。
- 针对每个播放列表ID,使用
get playlist端点获取其曲目信息。
你需要完成authentication.py中令牌刷新的部分代码,并完善endpoints.py中的两个分页调用函数。最后,在main函数中整合这些调用,构建完整的数据提取流程。
实验还包含一些可选部分,供你深入学*API调用。
总结与下一步
本节课中,我们一起学*了如何通过Spotify Web API进行批处理数据获取。我们涵盖了从账户创建、授权获取访问令牌,到使用requests库执行API调用、解析响应以及实现关键的分页技术。
完成本实验后,你将掌握与需要授权的RESTful API交互的基本技能,并理解如何构建一个简单的批处理数据摄取管道。

在开始实验前,请务必查阅Spotify API文档并创建你的账户。实验完成后,我们将在下一课中共同探索流式数据摄取模式。
105:与软件工程师的对话 🗣️

在本节课中,我们将详细探讨流式数据摄取。我们将通过一个产品推荐系统的案例,了解如何与上游的软件工程师沟通,以确定数据摄取的细节,包括数据格式、消息速率和存储策略。
在之前的课程中,我们接触过一个产品推荐系统,但并未深入其流式数据摄取的设置细节。本节视频将通过一次模拟的利益相关者对话,与一位软件工程师讨论该推荐系统的数据摄取方案。之后,您将在下一个实验课中亲自构建这个系统。
让我们开始与软件工程师的后续对话。
对话开始
很高兴见到你,Colleen。
我也很高兴见到你,谢谢。
我正在着手建立一个新的产品推荐系统,希望能与你合作,更好地理解如何从网站接收实时用户活动数据。
当然可以。我们网站的系统是这样工作的:我们在Web服务器日志中持续记录事件。这些事件包括内部系统性能指标、生成的任何错误或其他异常,以及用户活动,例如用户浏览不同产品或结账购买时点击的按钮或链接。
好的。在理想情况下,我可能希望只摄取用户活动数据,而不包括内部系统指标。你认为是否有可能将用户活动相关的事件记录分离出来,并推送到一个独立的日志中供我摄取?
是的,我们当然可以做到。我能想到几种实现方式。如果我们把用户活动消息推送到一个Kafka主题或Kinesis流中,你就可以直接从那里将数据摄取到你的管道中。
太好了,这听起来是个好方案。我认为如果能推送到Kinesis数据流,对我来说会非常合适。我一直在探索如何使用Kinesis来处理管道的其他方面,所以目前看来这是个很好的选择。
我另一个问题是关于数据负载本身和预期的消息速率。你能详细告诉我单个消息的格式以及写入流中的消息速率吗?
好的。消息以JSON格式记录。你可以预期的负载是一个JSON对象,包含会话ID、所有客户信息(如地理位置)以及他们的浏览活动(例如查看了哪些产品或加入了购物车)。关于单个消息的大小,它们略有不同,但通常在几百字节左右。
消息速率方面,你可以预期它会变化很大,这取决于任何给定时间平台上有多少用户。可以想象,一个用户每分钟可能产生几个事件,而在高峰时段,我们平台上可能有多达约10,000名用户。因此,这可能转化为每秒多达约1,000个事件。
好的,那么我们来粗略估算一下。假设每秒有1,000个事件,每个事件大小几百字节。这大概是每秒不到1兆字节。这应该完全在Kinesis数据流的处理能力范围内,根据配置,它们每秒可以处理数百兆字节的数据。
没错。另外,我需要在我这边配置的是消息在流中保留多长时间。如你所知,这个流本质上是一个仅追加日志,但我们会设置成消息在一段时间后被移除。
当然。我们的想法是,我们将实时使用这些数据来生成推荐,同时也会保存推荐模型的输入和输出以供后续分析。因此,如果一切顺利,我们不需要从流中重新读取消息。但我想,如果出现问题,我们可能希望有能力回退并重新处理流中的数据。也许我们可以在消息最初写入后,在流中保留一天。
好的。那么,在繁忙的一天,我们可能像你说的那样,每秒向流中写入约1兆字节的数据。一天大约有100,000秒,所以流的总大小在最坏情况下可能增长到大约100吉字节。这似乎是合理的。
好的。你还有其他想了解的吗?或者我们可以直接开始构建这个系统了?
目前就这些了。我们开始构建吧。
好的。
对话结束
以上是一个与上游利益相关者(即源系统所有者)的对话示例。正如我在这些课程中多次强调的,在与系统所有者讨论时,除了理解数据本身和摄取机制(如本例),还应该讨论其他可能影响数据管道的事项,例如模式变更或系统中断。不过,目前我们只聚焦于理解数据和摄取机制。
在下一个视频中,我们将详细解析这次对话的细节,并更深入地探讨流式数据摄取。
本节课总结
本节课中,我们一起学*了如何与软件工程师沟通以确定流式数据摄取的细节。我们讨论了:
- 将用户活动数据从系统日志中分离并推送到消息队列(如Kinesis流)的可行性。
- 数据负载的格式(JSON)和大致大小(几百字节/消息)。
- 预期的消息速率(峰值约 1000 events/sec)及其对系统容量的影响。
- 数据在流中的保留策略(例如保留一天,估算最大数据量约 100 GB),以支持可能的回放需求。

这些信息是设计和构建一个健壮的流式数据管道的基础。
106:流摄取详解 🚀


在本节课中,我们将深入学*流式摄取系统的核心概念与工作原理。我们将重点探讨消息队列与事件流平台这两种主要模式,并以Apache Kafka为例,详细解析其架构和关键组件。最后,我们会将Kafka的概念与即将在实验中使用的Amazon Kinesis服务进行对比。
流式摄取系统概述
在本课程的第一周,我们从数据管道作为数据源消费者的角度,探讨了包括消息队列和事件流平台在内的流式系统。
根据你所使用的具体系统,实际的数据源可能仅仅是事件生产者,也可能是流式系统的多个元素。例如,多个生产者、代理和消费者都可能位于你摄取系统的上游。
在与软件工程师的讨论中,我们制定的计划是让工程师建立一个Kinesis数据流,而你将作为该流的消息消费者。
本节视频将更详细地讨论消息流的细节,之后你将进入实验环节。
流式摄取的两种主要模式
作为快速回顾,流式摄取主要有两种模式:事件流平台和消息队列。
消息队列本质上是一个缓冲区,用于以异步方式将消息从事件生产者传递到消费者。消息队列通常以先进先出(FIFO) 的原则运行。这意味着事件消费者总是先读取队列中最旧的消息。一旦消息被消费,它就会从队列中删除。
事件流平台则不同,它通过将消息以追加日志的方式持久化存储来运作。事件路由器将日志中的消息分发给订阅者,并且可以重放或重新处理日志中的任何消息。
在实验中,你将使用Amazon的Kinesis服务作为事件流平台。另一个广泛使用的平台是Apache Kafka。本节视频将以Kafka为例讲解一些细节,并在概念存在对应关系时与Kinesis进行类比。下一节视频中,Morgan将更详细地介绍Kinesis。因此,到本周结束时,你将能对这两种解决方案都有所了解。
Apache Kafka 架构详解
Apache Kafka是一个开源的事件流平台。虽然流式平台有多种不同的类型和变体,但事件路由和存储的原理在各个平台间是相似的。
从高层次看,事件生产者通过网络将消息发送或推送到Kafka集群,该集群包含一台或多台服务器,也称为代理。然后,事件消费者从该Kafka集群读取或拉取消息。
让我们放大观察一下Kafka集群的内部结构。
主题与分区

在Kafka集群中,消息流被拆分并路由到称为主题的单元中。你可以将主题视为一个类别,用于保存一组相关事件;或者从另一个角度理解,它就像一条通往某处的道路。消息在主题中排队,类似于不同目的地的汽车在不同高速公路上排队。
一个主题可以包含任何类型的消息,例如欺诈警报、客户订单或物联网设备的温度读数。生产者的职责是将消息发送到其对应的主题。

每个主题有一个或多个分区。分区就是日志,包含有序、不可变的消息序列,你可以不断向其追加新消息。沿用“道路”的类比,分区就像是高速公路上的车道。更多的车道允许更多的汽车通过。因此,每个分区处理添加到主题中的一部分消息,这允许更高效的消息流。
同样,生产者的职责是决定将每条消息发送到哪个分区。这个决定可以基于轮询策略,或者通过基于消息键计算目标分区。
Kinesis的对应概念
在Kinesis中,所有这些概念本质上是相同的。但Kinesis不使用“主题”,而是使用“流”;不使用“分区”,而是使用所谓的“分片”。
消费者与消息传递
在另一端,消费者被分组,每个消费者组订阅一个或多个主题。组内的消费者协同工作,消费给定主题所有分区中的消息。每个分区只能分配给组内的一个消费者,每个消费者消费来自不同分区子集的消息。
当生产者将消息发布到主题分区时,该消息会被传递给每个订阅的消费者组中的一个消费者。
一旦消息被发布到主题,Kafka集群会根据可配置的时间段保留该信息,无论消息是否已被消费。这允许消费者在需要时重放和重新处理消息。
实际应用场景
在我们与软件工程师的对话中,我们了解到网站上的用户操作被记录为Web服务器日志中的消息,这些消息将被路由到一个Kinesis数据流。同样,这些消息也可以被路由到一个Kafka主题,你可以通过订阅该主题来消费它们。
在不同的情况下,你可以设想这样一个场景:你拥有直接监控Web服务器日志以获取新消息的权限。那么,你可以将Web服务器日志视为事件生产者。从那里,事件可以作为你摄取管道的第一步,被摄取到Kafka主题或Kinesis流中。
你还可以通过一个称为持续变更数据捕获(CDC) 的过程来监控数据库活动。通过处理数据库日志,你可以将数据变更流式传输到你的数据管道中,以确保管道中的数据与源数据库的数据更新保持同步。
课程总结与预告
本节课中,我们一起学*了流式摄取的核心概念。我们区分了消息队列和事件流平台,并深入探讨了Apache Kafka的架构,包括主题、分区以及生产者与消费者的协作方式。我们还了解了这些概念如何对应到Amazon Kinesis服务中。
接下来,Morgan将带你详细了解Amazon Kinesis Data Streams,这是在即将到来的实验中你将使用的流式摄取工具。之后,我会回来为你快速讲解最后一个实验,然后你将开始构建自己的流式摄取解决方案。




107:第29讲 - Amazon Kinesis Data Streams 详解 🚀

在本节课中,我们将学* Amazon Kinesis Data Streams 的核心工作原理。我们将了解其基本架构、关键概念(如分片、分区键)以及两种容量管理模式。通过本教程,你将能够理解如何根据数据读写需求来规划和配置一个 Kinesis 数据流。
上一节我们介绍了 Apache Kafka 的基本概念。本节中,我们来看看 Amazon Kinesis Data Streams 是如何工作的。
与 Kafka 类似,Kinesis 数据流系统也包含事件生产者(将数据推送到流)和消费者(从流中读取数据)。在即将进行的实验中,你将把一个 Kinesis 数据流作为上游数据源。虽然实验本身不要求你创建流,但理解其内部机制对于设计完整的数据系统至关重要。接下来,我们将深入探讨当你需要管理包含生产者、消费者和流的整个系统时,需要了解的 Kinesis 细节。
流与分片:容量的基础单元
在 Kinesis Data Streams 中,生产者将数据推送到一个特定的流。一个流由多个分片组成,分片是流容量的基本单位。当需要扩展流以摄取更多数据时,你就需要为流添加更多分片。
要确定你的用例需要多少分片,或者何时需要增加分片数量,你需要了解管道中预期的写入和读取操作的大小与速率。写入操作指生产者向流写入数据,读取操作指下游消费者从流中读取数据。
以下是每个分片的容量限制:
- 写入容量:每个分片每秒最多支持写入 1000 条记录,最大总数据写入速率为 1 MB/秒。
- 读取容量:每个分片每秒最多支持 5 次读取操作,最大总数据读取速率为 2 MB/秒。
因此,为特定用例确定所需分片数量需要进行一些分析和计算,主要依据预期的读写操作大小和速率。
容量管理模式:按需与预置
有时很难精确估计读写操作的数量,例如在一个全新的应用程序中。或者,你可能唯一能确定的是应用程序的流量会随时间剧烈波动,比如在电子商务平台或其他面向公众的应用中。
对于这些情况,你可以使用 Kinesis 的按需模式。按需模式会根据需要自动管理分片的扩容或缩容,你只需为实际使用的资源付费。从运维角度看,这比另一种模式更为便捷。
另一种模式是预置模式。使用预置模式时,你需要根据预期的读写请求速率,为应用程序指定所需的分片数量。然后,由你在需要时手动添加更多分片或进行重新分片。如果你的应用程序流量可预测,或者希望更精细地控制成本,预置模式可能更适合你的工作。
数据记录与分区键
流中传输的每个数据记录都包含三个部分:分区键、序列号和数据本身(数据以二进制大对象的形式存储)。
在设置系统的数据生产者时,你需要选择一个分区键。分区键用于决定数据记录被放入哪个分片。Kinesis 本身会在每条记录写入时分配一个序列号,以维护分片内记录的顺序。
例如,假设你想创建一个来自电子商务平台的交易流。那么,你可能希望使用客户ID作为分区键。这样,单个客户的所有交易都可以存储在同一分片中,从而使得下游消费者更容易提取与单个客户相关的记录进行聚合和分析。
消费者与数据读取
生产者将数据放入分片,消费者则从分片读取数据。通常,一个分片会有多个消费者读取数据。
默认情况下,消费者共享一个分片的读取容量,这被称为共享扇出。这意味着消费者会竞争读取容量,这对某些用例可能是个问题。
为了避免遇到这种容量问题,你可以进行设置,使每个消费者都能以分片完整的 2 MB/秒 读取容量进行读取,这被称为增强扇出。
数据处理与集成
你可以使用托管服务来处理存储在 Kinesis 数据流中的数据,例如:
- AWS Lambda
- Amazon Managed Service for Apache Flink
- AWS Glue
你也可以使用 Amazon Kinesis Client Library 编写自己的自定义消费者。
此外,你还可以进行设置,使一个流的输出成为另一个流的输入,从而构建更复杂的实时数据处理工作流。消费者也可以将数据发送到其他 AWS 服务,例如与 Amazon Kinesis Data Firehose 集成,将数据存储到 Amazon S3 中。
同样重要的是,Kinesis Data Streams 允许多个应用程序同时处理同一个流,每个应用程序独立消费数据,并将数据发送到下游的不同系统。


本节课中,我们一起学*了 Amazon Kinesis Data Streams 的核心机制。我们了解了流由分片构成,分片决定了读写容量;认识了按需和预置两种容量管理模式;掌握了分区键如何决定数据路由,以及消费者如何以不同模式读取数据。接下来,Joe 将带你详细了解即将进行的实验,然后你将亲自开始使用 Kinesis 进行流数据处理。祝你实验顺利,学有所获!
108:实验演练 - 流式数据摄取 📡
在本节课中,我们将学*如何构建一个流式数据处理管道。我们将使用 AWS Kinesis 数据流作为数据源,通过生产者脚本写入数据,并通过消费者脚本处理和转发数据。课程分为两部分:首先,我们将理解流式平台的基本组件;其次,我们将在一个电子商务场景中实现一个包含数据转换和路由的流式ETL管道。
第一部分:理解流式平台组件 🔧
上一节我们介绍了流式管道的概念,本节中我们来看看其核心组件如何协同工作。
首先,我们需要创建一个 Kinesis 数据流。它将作为一个简单的路由,连接生产者应用程序和消费者应用程序。
为此,我们提供了两个 Python 脚本:consumer.py 和 producer.py。
以下是脚本的核心功能:
- 生产者脚本:代表一个简单的生产者应用,向 Kinesis 数据流写入一条数据记录。记录是一个包含用户会话详情的 JSON 字符串,例如会话 ID、客户编号、城市、国家和浏览历史。该脚本使用 Boto3 库与 Kinesis 交互。
- 代码示例:
put_record方法用于将记录写入数据流。
- 代码示例:
- 消费者脚本:代表一个简单的消费者应用。运行时,它会遍历数据流的所有分片,读取每个分片中的所有记录,并在终端打印每条记录的信息。该脚本同样使用 Boto3。
- 代码示例:
get_records方法用于从分片获取记录。
- 代码示例:
在第一部分的实验中,你无需修改脚本,只需在创建 Kinesis 数据流后运行它们。
操作步骤如下:
- 首先在终端运行消费者脚本。你需要先激活 Jupyter Lab 环境,然后导航到
source/或src/目录,最后执行命令:python consumer.py <你的Kinesis数据流名称>。此时终端不会打印任何内容,因为数据流是空的。 - 保持第一个终端运行,打开另一个终端运行生产者脚本。同样先激活环境并导航到目录,然后执行:
python producer.py <数据流名称> ‘<JSON记录字符串>’。 - 此时,检查运行消费者脚本的第一个终端,你将看到消费者已经读取并打印了你刚刚发送到数据流的记录信息。
第二部分:实现流式ETL管道 ⚙️

理解了基本组件后,现在我们将回到最初的电子商务场景,实现一个更复杂的流式处理管道。
在本部分,你将获得一个作为源系统的 Kinesis 数据流。你将站在消费者一侧,从流式源摄取数据。
你将实现一个流式 ETL 管道:首先对摄取的记录进行简单转换,然后根据条件将这些记录继续流式传输到下游。
具体来说,你需要设置两个 Kinesis 数据流:
- 将美国客户的记录发送到第一个数据流。
- 将国际客户的记录发送到第二个数据流。
这样做的业务假设是:公司注意到不同国家的客户表现出不同的购买行为,因此需要由不同的推荐引擎处理。
对于这两个目标数据流,数据将由 Kinesis Data Firehose 自动摄取并传送到各自的 S3 存储桶。

你需要完成以下任务:
- 使用 Boto3 创建两个目标数据流、两个 Firehose 实例和两个 S3 存储桶。
- 修改位于
etl/文件夹下提供的消费者脚本中的转换代码。该脚本可从终端运行,需要指定源数据流名称和两个目标数据流名称。
脚本中的 pull_shards 函数已提供遍历分片并提取记录的代码。你的任务是在提取记录后,完成代码的转换部分。
转换需要为每条记录添加三个字段:
overall_product_quantity:浏览历史中所列产品数量的总和。- 公式:
sum(item['quantity'] for item in record['browse_history'])
- 公式:
overall_in_shopping_cart:购物车中所列产品数量的总和。- 公式:
sum(item['quantity'] for item in record['browse_history'] if item['in_shopping_cart'])
- 公式:
total_different_products:浏览历史中列出的不同产品的数量。- 公式:
len(set(item['product_id'] for item in record['browse_history']))
- 公式:
完成转换后,你需要根据记录中 country 字段的值,将转换后的记录发送到对应的目标数据流。
完成脚本修改后,在终端运行它:
python consumer.py <源数据流名称> <目标数据流1名称> <目标数据流2名称>
运行此命令后,消费者脚本将从源数据流读取记录,进行转换,然后根据国家发送到相应的 Kinesis 数据流。Kinesis Firehose 实例将自动把数据传送到 S3 存储桶。
总结 🎯
本节课中我们一起学*了流式数据摄取的实践方法。我们首先通过一个简单的生产者-消费者模型,理解了 Kinesis 数据流作为路由核心组件的工作方式。随后,我们在一个模拟的电子商务场景中,实现了一个完整的流式ETL管道,包括数据转换、基于业务规则(国家)的数据路由,以及利用 Kinesis Data Firehose 将处理后的数据自动交付到存储层(S3)。这套流程展示了构建实时数据处理管道的基本模式和关键技术环节。


现在,你可以开始动手实验了。完成实验后,我们将回顾本周的学*内容。
109:数据工程导论 第2周总结 📊
在本节课中,我们将回顾数据工程生命周期中“数据摄取”阶段的核心内容,重点关注批处理和流式处理两种模式,以及相关的工具与实践。
概述
本周我们探讨了数据工程生命周期中的数据摄取阶段,主要围绕批处理和流式处理两种模式展开。我们分析了适用于这两种摄取模式的工具,并完成了相应的实践练*。
批处理与流式处理:一个连续谱系
我们本周首先讨论的核心观点是:虽然批处理摄取和流式摄取常被视作两种不同的范式,但它们实际上存在于一个连续谱系中。
在这个谱系的一端,是低频次、相对大批量的数据摄取。而在另一端,是消息生成时即进行的实时流式摄取。在这两者之间,则存在着广泛的批处理和微批处理场景,以及不同的流式处理方法。
您为自身数据管道选择何种方法,应由利益相关者的真实需求和系统的具体要求决定。
批处理摄取:ETL 与 ELT
在专门讨论批处理摄取时,我们研究了 ETL 和 ELT,并探讨了如何根据系统需求权衡两者的优劣。
ETL 代表 提取、转换、加载。数据在加载到目标存储(如数据仓库)之前进行转换。
ELT 代表 提取、加载、转换。数据先被加载到目标存储,然后在该存储内部进行转换。
选择 ETL 还是 ELT,通常取决于目标系统的计算能力、数据量、转换复杂度以及对数据新鲜度的要求。
然而,您也看到,在流式管道中考虑进行“飞行中转换”同样重要。
实践练*概览
以下是本周完成的两个实践练*:
练*一:批处理摄取
您从公共 API 摄取数据,并练*了与 API 相关的特定概念,例如连接、身份验证和分页步骤。这些步骤适用于许多以 API 为数据源的摄取场景。
练*二:流式摄取
您为一个推荐系统设置了流式摄取。在该案例中,源系统是一个 Kinesis 数据流。您使用 Python 代码设置了一个消费者,对数据执行一些即时转换,然后将消息推送到两个独立的流中,以供下游的推荐模型消费。
通过这些练*以及期间讨论的概念,您深化并拓宽了对数据摄取的理解。
过渡与预告
上一节我们回顾了本周关于数据摄取的核心内容与实践。接下来,我们将展望下周的学*方向。
下周,我们将深入探讨数据工程生命周期中的一个重要底层主题:DataOps。

我们将更仔细地研究 DataOps 的一些关键概念,包括数据质量、自动化、监控和基础设施即代码。
总结

本节课中,我们一起学*了数据摄取阶段在批处理和流式处理模式下的不同特点与工具选择。我们理解了批处理与流式处理并非截然对立,而是一个连续谱系。我们探讨了 ETL 与 ELT 的权衡,并通过两个实验分别实践了从 API 进行批处理摄取以及为推荐系统设置流式管道。这些知识为您构建健壮的数据管道奠定了坚实基础。
110:第3周概览 🚀

在本节课中,我们将学*数据工程中一个至关重要的概念:DataOps。我们将探讨DataOps的三大支柱——自动化、可观测性与监控,以及事件响应,并了解它们如何帮助构建健壮的数据系统和高质量的数据产品。
欢迎来到第3周
本周的主题是DataOps。实际上,它也包含了软件工程和数据管理的基础元素。正如你在之前的课程中学到的,DataOps是一套实践和文化*惯,其核心是构建健壮的数据系统并交付高质量的数据产品。
DataOps真正起源于DevOps。DevOps是一套允许软件工程师高效交付和维护高质量软件产品的实践和文化*惯。
本周学*重点
本周我们将深入探讨DataOps的三大支柱的细节,即自动化、可观测性与监控以及事件响应。
需要说明的是,我们将花更多时间学*自动化和可观测性与监控,而事件响应部分会相对简略。这并非因为事件响应不重要,而是因为它更偏向于DataOps的“文化*惯”层面,在在线课程中围绕它设计实践练*更具挑战性。
深入探讨自动化
上一节我们介绍了本周的总体框架,本节中我们来看看第一个支柱:自动化。
在自动化部分,我们将重温上一课程中涉及的一些概念,例如持续集成和持续交付(CI/CD),然后聚焦于 “基础设施即代码” 的概念。
“基础设施即代码”指的是编写代码,当你运行它时,它会部署运行数据管道所需的资源。在本系列课程之前的实验中,你已经获得了一些使用AWS控制台为数据基础设施启动某些资源的经验。
然而,在实际的数据工程师工作中,通过基础设施即代码框架进行部署正成为常见做法,而不是手动启动实例和安装软件。
事实上,在你已经完成的许多实验中,你已经拥有了一些基础设施即代码的经验。我们使用了像 CloudFormation 和 Terraform 这样的基础设施即代码工具来设置实验环境,并在你的数据管道中部署各种资源。
在本周的第一个实验中,你将获得实际编写Terraform代码来部署基础设施的动手经验。在此之后的实验中,你将在你的基础设施之上进行构建,加入对数据质量和其他重要可观测性指标的监控。
行业专家访谈
本周另一个令人兴奋的安排,是一系列与DataOps领域行业专家的访谈。
在这些访谈中,你将听到来自实际为数据工程师构建相关产品的人士,分享关于数据质量和数据可观测性的关键见解。因此,这将是内容充实的一周。
课程材料与开场
为了开启本周的学*,我们首先将聆听我的好友Chris Burg的分享。他是 《DataOps宣言》 的合著者,也是流行数据可观测性和DataOps工具Data Kitchen的CEO。


接下来的视频是我与Chris的一次对话,你将听到他如何定义DataOps,以及为何他认为这一基础概念在构建数据产品时如此重要。

在此之后,我们将探讨DataOps的第一个支柱:自动化。
总结

本节课中,我们一起学*了第3周的概览。我们明确了本周的核心是DataOps,并介绍了其三大支柱:自动化、可观测性与监控以及事件响应。我们了解到自动化中的关键实践是基础设施即代码,并预告了本周包含的动手实验和行业专家访谈。接下来,我们将从Chris Burg的分享开始,深入DataOps的世界。
111:与Chris Bergh的对话 🎙️

概述
在本节课中,我们将与数据运维领域的专家Chris Bergh进行对话,探讨数据运维的核心概念、实践方法及其与DevOps的异同。我们将学*如何构建高效、高质量的数据交付系统,并了解如何避免数据工程师常见的职业倦怠问题。
你好Chris,很高兴能与你聊聊数据运维。我认为在这个领域,当提到数据运维这个词时,你是我最先想到的人,所以能与你交流真是太棒了。
当然。也许我应该为不了解你的人做一个简短的介绍。
我是Chris Bergh,在马萨诸塞州经营一家名为Data Kitchen的公司。我接受过工程师培训,曾在多家公司(如麻省理工学院林肯实验室、NASA和一些互联网初创公司)从事软件开发多年。后来在2005年,我萌生了一个好主意:我应该全职投入数据领域。于是我开始管理一个团队,团队成员包括我们现在所说的数据工程师、数据科学家和数据可视化专家。
我的生活一度变得很糟糕。系统总是出问题,我们永远无法满足客户的速度要求。我解雇了一些本不该解雇的人,将问题归咎于他人,而实际上这更多是我如何管理团队的管理问题。因此,在过去的*20年里,我一直在研究一个问题:如何让一个由技术人员组成的数据团队能够快速交付成果,快速提供新的洞察?如何以极高的质量交付数据和仪表板?以及如何过上不那么痛苦的生活?
我认为你开设数据工程课程很棒。我们两年前与Data.world合作,对700名数据工程师进行了一项调查,结果显示大约78%的人希望他们的工作能配备一名心理治疗师。也许我有点愤世嫉俗,但我觉得这个比例可能还偏低了。数据工程是一个充满挑战的职业,夹在疯狂的客户需求与难以驾驭的数据和基础设施之间,处境艰难。我正是从这样的背景出发,提出了数据运维的理念。
什么是数据运维?🤔
对于学*者来说,什么是数据运维?你会如何描述它?
可以把它看作一种方法,让你自己或你的团队能够向客户交付他们可以信赖的数据和洞察,并且能够以极低的风险、非常快速地更改这些洞察。其核心理念是:你能否建立一个“工厂”,持续产出完美的新数据集和新洞察,并能够随心所欲地快速调整这个“工厂”。
这听起来像是借鉴了精益思想。
是的。当我开始从事数据和分析工作时,有一件事让我感到惊讶。我原本是软件背景出身,当时觉得“数据这东西应该很简单”。但实际上,在很多方面,你就像在运营一条生产线。你可以把数据集的流入、存入数据库的多个层级、被模型和可视化使用、再到治理的每一步,都看作一个制造工位。而且你通常不止一条这样的“生产线”。
问题在于,如何让这条生产线产出“丰田汽车”,而不是70年代的“AMC Pacers”那种老式汽车。这是一个难题,在我的软件背景中并未涉及——即如何运营一条生产线。另一个奇怪的部分是,人们总是会向你提出新的需求,你的工作永无止境。向客户交付新洞察的最佳方式是:先完成80%,获取一些反馈,然后迭代改进。与其花几个月构建一个东西,不如尽早获得反馈。
这两件事是截然相反的:既要构建一条真正优秀的装配线,又要能非常快速地更换这条装配线。这很难做到。
但如果回顾像丰田这样的公司,他们能够在几天内(而不是传统大规模制造方式的几个月)完成生产线的更换。他们是如何做到的?并不是靠购买昂贵的机器人(虽然他们确实有机器人),关键在于他们如何思考自己的工作以及优化哪些方面。
许多团队试图优化“完成任务”本身,比如“我必须完成我的工作”。而“完成”的定义很有趣:“我完成了我的工作,我写好了SQL,我完成了。”但有人使用它重要吗?它下周会出问题吗?我不知道,反正我的工作完成了。归根结底,丰田也关注客户,关注如何让客户成功。不幸的是,许多数据和分析团队并不快乐,客户也对数据和分析团队不满意。
一个不为人知的小秘密是:大多数数据和分析项目都失败了。在我看来,这不是因为我们没有酷炫的技术,也不是因为人们不够聪明,而是因为人们工作的系统存在缺陷。因此,来自软件和制造业的这些原则,我认为非常适用。它们并非高深莫测,只是一些现成的、你可以拾起并使用的理念。
如何在实际工作中应用数据运维?💡
那么,如果有人刚接触数据领域,他们应该如何在自己的工作中思考这个问题?
我认为,思考你正在做的事情(比如我在写一些SQL),然后思考围绕这件事的相关事项。首先,当我写SQL时,我如何构建测试或验证来证明它是有效的?当我获得新数据时,我如何知道它没问题?
你为什么要这么做?因为测试是你送给未来自己的一份礼物。如果你不这样做,最终你将永远负责维护你的代码。如果出了问题,他们可能会在你度假时打电话找你,或者你不得不负责越来越多的代码。
当你刚开始时,很容易想成为英雄。“我是个英雄,我写了所有这些代码,我不断写,我对客户响应非常快。”你会进入完全的“英雄模式”。但随着时间的推移,你会精疲力尽,变得不快乐,想要一位心理治疗师。因此,数据运维的一个教训是:也许只有2-3%的时间可以当英雄,其余时间应该构建一个系统,这样你就不必成为英雄。这就是数据运维的意义:围绕你的代码构建一个系统——测试、可观测性、部署,这些都是围绕你编写的那一小段“柔软”代码的环境,它们能让你的生活变得可控。
数据运维宣言的灵感来源 📜
接下来,我们来谈谈数据运维宣言,是什么启发了它?
大约七八年前,我们去参加一个会议,没人知道我们在说什么。我解释了数据运维,他们问“那是什么?”。我当时想,天哪,这太糟了,没人真正理解我们在说什么。于是,我在飞机上写下了宣言的第一个版本,发给一些人征求意见,写了维基百科词条。多年来,我们写了很多东西来解释数据运维是什么。我们在网站上提供免费认证(你可以听我讲三个小时),但核心就是这个理念:构建工作系统非常重要,是为你的团队解决几个问题。
例如,看看这个问题:你团队新招了一个23岁的年轻人,他刚接触数据工程,可能拥有计算机科学学位。你希望这个人在头两周做什么?一个好的组织会说:第一,如果出了问题,他应该能够找到问题的根源——是数据问题、集成数据问题、模型问题还是可视化问题?第二,他能否进行一些小的修改?比如修复一个错误,并快速将其部署到生产环境。
在许多数据工程团队中,这些事情非常困难,你必须学*很多东西,几乎像学徒一样。因此,我认为数据运维要解决两个“23岁问题”:这个23岁的新人能多快找到问题?他能多快修复问题并以低风险将其部署到生产环境?可能还有一个“46岁问题”:你如何衡量你的团队?对我来说,数据运维就是关于这组问题,它们实际上与数据工程本身关系不大,而是关于如何管理一群协同工作的数据工程师。这就是我的出发点。当然,这其中也涉及很多工程任务,比如编写良好的数据质量验证测试很重要,部署速度很重要,做DevOps、管理环境、测试数据等都很重要。
数据运维与DevOps有何不同?⚖️
学*者肯定会有一个问题:数据运维与DevOps有何不同?
我认为,在很多方面,它们是相同的理念。都是关于如何让一群技术“极客”能够快速、高质量地交付成果。当然,两种方式都可能做得很糟糕。DevOps的理念是,你应该以小批量交付工作,不要花几个月时间做一件事。因为如果你那样做,很可能会错过客户的真实需求。
因此,DevOps和数据运维之间的主要相似点是:如果你的客户要求10件事,需要你花三个月,那么你应该在一周内交付其中一件。不要等到10件事都做完,因为很可能发生的情况是:他们只想要其中的4件,不想要另外6件,然后他们会说“不,我还想要另外3件”。这样你就产生了浪费——做了很多无关紧要的工作。
所以,我认为DevOps的理念是如何管理短周期的交付以及如何将其自动化。我认为其中也包含可观测性、减少生产环境错误等。但对于数据,无论你用什么词(数据运维或其他),核心理念是一样的:以低错误率运行,快速更改,并衡量你的工作。它们是非常相似的理念。所以,无论你称之为精益、全面质量管理、DevOps还是数据运维,它们都是同一回事:如何让“极客”们高效工作。而要做到这一点,你实际上需要做一些具体的事情,不仅仅是空谈,你需要构建一些东西,需要在你环境旁边构建“那条生产线”,需要构建“制造机器的机器”。
给学*者的建议与总结 🎯
非常感谢,这次对话非常有教育意义。最后,关于数据运维,你有什么希望自己早点知道的事情可以告诉年轻的自己,或者特别想告诉本课程的学*者吗?
我想说的是希望和英雄主义。第一点就像我之前说的,不要当英雄,这对你自己没有任何好处。第二点是,不要指望事情会自动运转良好。这听起来可能有点偏执,但不要信任你的数据提供者,不要信任你的服务器。要去测量和证明事情是有效的。因为在我的职业生涯中,我在这两方面都遇到过太多问题——要么指望事情能成,要么试图成为英雄。你可以围绕这些构建系统,这样你就可以保留一点希望,保留一点英雄主义,但最好是构建一个能够做到这些的高效组织。如果你做到了,你的生活将会好得多。你不会想陷入我们调查中80%的人那种境地,觉得“我的工作糟透了,我需要心理治疗师,压力太大了”。
太棒了,非常感谢你抽出时间,Chris。这对学*者会非常有帮助,谢谢你。
总结
在本节课中,我们一起学*了数据运维的核心思想。我们了解到,数据运维是一种旨在帮助数据团队快速、可靠地交付高质量数据洞察的方法论。它强调构建系统化的“生产线”,而非依赖个人英雄主义。关键要点包括:为代码编写测试和验证、实现快速且低风险的部署、培养可观测性,以及以短周期迭代的方式工作以获取早期反馈。我们还探讨了数据运维与DevOps在理念上的高度相似性,它们都源于精益思想,关注流程优化和客户成功。最后,Chris Bergh给出了宝贵的建议:避免陷入“英雄模式”,并通过构建系统和持续验证来建立可靠的工作流程,从而提升工作效率与职业幸福感。
112:DataOps自动化 🚀

在本节课中,我们将学*DataOps的自动化支柱。我们将探讨DataOps如何借鉴DevOps的自动化实践,包括持续集成与持续交付、版本控制以及基础设施即代码等核心概念。这些实践对于构建高效、可靠的数据管道至关重要。
在上一节中,我们介绍了DataOps的起源及其与DevOps的关系。本节中,我们来看看DataOps在自动化方面的具体实践。
自动化在软件工程中的一个关键方面是持续集成与持续交付,简称CI/CD。在软件开发的语境下,CI/CD流程涉及建立系统,以自动审查和测试新代码,然后自动交付或部署经过审查和测试的生产代码。
对于DataOps,CI/CD实践可以直接应用于数据管道中的代码和数据。无论是用于应用特定数据转换的代码、填充数据库的代码,还是数据本身,你都可以像维护任何其他软件应用代码一样维护它们。
以下是CI/CD在DataOps中的主要应用点:
- 代码自动化:数据转换逻辑、管道配置等代码的自动化测试与部署。
- 数据自动化:数据质量检查、数据验证流程的自动化执行。
- 管道运行:数据管道执行流程的自动化编排。
关于实际运行数据管道的自动化,正如我在之前的课程中提到的,有多种实现方式。例如,完全不使用自动化,手动运行数据管道中的所有流程;或者根据特定时间表设置管道各阶段的运行;你还可以使用像Airflow这样的编排工具,将管道定义为有向无环图来进行编排。我们将在下周深入探讨DAG以及测试和部署的自动化。
现在,无论是软件产品还是数据产品,任何CI/CD系统的一个关键基础是版本控制。在版本控制中,代码的每个新版本都会被记录。这使得如果当前版本因某些原因无法按预期工作或出现其他问题时,可以轻松回滚到以前的版本。
你可能已经在自己代码的语境中熟悉了版本控制,或许正在使用像GitHub这样的平台。在DataOps中,版本控制的概念同样适用于数据。就像你可以跟踪代码中的更改并回滚到以前的版本一样,通过DataOps,你可以跟踪数据在管道中的变化,并在遇到问题时能够回滚到以前版本的数据。
DataOps在自动化方面从DevOps借鉴的另一个概念是基础设施即代码。无论你是使用云平台资源构建软件应用程序还是数据管道,都可以将基础设施的设计作为代码库来维护,就像对待任何其他应用程序代码一样。
你可以运行该代码来部署你的基础设施,或者修改代码以重新定义你的基础设施,然后再次运行它以部署更新后的基础设施。通过使用代码以编程方式定义基础设施,你就可以像对待任何其他代码或数据一样,对整个基础设施进行版本控制。这样,如果你需要回滚到以前版本的基础设施,就像回滚到以前版本的代码一样简单。
因此,DataOps自动化实践将以多种方式成为你作为数据工程师工作的一部分。你可以开始看到DataOps如何开始与数据工程生命周期的其他基础领域重叠。
例如,DataOps与软件工程密切相关,因为许多DataOps实践直接借鉴自DevOps。当涉及到对数据维护版本控制的DataOps实践时,这直接与数据管理这一基础领域相关联,因为它允许你在数据的整个生命周期中交付、控制和增强数据的价值。
接下来,我想在DataOps自动化的语境下更深入地探讨基础设施即代码。然后在下一个实验中,你将有机会练*编写代码来定义自己的基础设施。


本节课中,我们一起学*了DataOps自动化的核心支柱。我们了解了CI/CD流程如何应用于数据和代码,版本控制对于维护数据完整性的重要性,以及基础设施即代码如何实现可重复且可靠的基础设施部署。这些实践共同构成了现代、自动化数据工程工作流的基础。在下一节课中,我们将更详细地探讨基础设施即代码。
113:基础设施即代码 🏗️

在本节课中,我们将要学*基础设施即代码的概念、工具及其在云数据管道中的应用。我们将了解如何使用代码来定义、部署和管理云基础设施,并重点介绍Terraform这一流行工具。
概述
上一节我们介绍了云数据管道的整体架构。本节中,我们来看看如何利用基础设施即代码来自动化创建和管理这些架构所需的资源。
正如前一个视频所提到的,你可以使用基础设施即代码,以编程方式定义、部署和维护你的云基础设施。这意味着你可以自动化创建云数据管道所需的所有资源,包括网络、安全、计算、存储以及其他数据管理和分析资源。
但基础设施即代码的概念实际上早于云计算,其更古老的根源可追溯到20世纪70年代的配置管理。即使在那个时候,工程师们也在努力高效地配置和管理一系列物理机,他们会编写Bash脚本来自动化一些配置任务。回顾过去,你可以将其视为基础设施即代码的原始雏形。
随着AWS在2006年发布EC2,任何人都可以随时轻松启动云计算资源。因此,工程师能够构建具有许多组件和复杂依赖关系的、更具可扩展性的应用程序。
在2010年代初期,软件工程师开发了诸如Terraform、CloudFormation和Ansible等基础设施即代码工具,使他们能够使用基于代码的配置文件来配置和部署基础设施。
如今,你可以使用这些工具,通过几行代码轻松管理云上的基础设施资源,而无需手动点击资源设置窗口或编写繁琐的批处理/Bash脚本。




事实上,你在之前的一些实验课中已经实践使用了基础设施即代码工具。例如,在上一门课程的第一次实验中,你看到了正在构建的数据管道的架构图。在幕后,我们使用CloudFormation自动创建并配置了该实验所需的所有必要网络资源,包括VPC、子网和RDS数据库。然后,你还运行了一些Terraform脚本来部署该基础设施的其他部分,包括Glue ETL作业、S3存储桶和Glue爬虫。
在本周的材料中,我将主要关注Terraform,因为这将是你在后续实验中要使用的工具。但值得注意的是,CloudFormation是另一个流行的基础设施即代码工具,并且是AWS原生的。Terraform和CloudFormation都是得到良好支持的工具,并拥有完善的文档。根据你所在的组织,你可能会使用其中一种工具,在某些情况下,你甚至可能同时使用两种工具,就像我们在这些课程的实验中同时使用两种工具来支持一样。
深入Terraform配置文件
现在,让我们仔细看看你运行过的一些特定Terraform配置文件,它们用于创建数据管道中的Glue ETL和S3存储桶组件。
我们放大S3配置文件的一部分来仔细观察。通过第一段代码,你设置了S3存储桶。这个存储桶有一个唯一的名称,其前缀基于本实验中为你定义的变量。你使用第二段代码来配置该存储桶,并允许对其进行公共访问。



请注意,此配置文件中使用的语言相对易于解释。它遵循一个简单的模式:
以下是Terraform HCL配置的基本结构:
resource "<PROVIDER>_<RESOURCE_TYPE>" "<RESOURCE_NAME>" {
<CONFIGURATION_KEY> = <CONFIGURATION_VALUE>
...
}
你以关键字resource开始,然后指定资源类型和你想要给该资源的名称。因此,在这个例子中,aws_s3_bucket告诉Terraform你希望将AWS设置为提供商,并将S3作为你想要配置的资源。你将整个字符串aws_s3_bucket称为资源类型,而data_lake是你想给这个新创建资源的名称。然后,在大括号内,你可以使用键值对来指定这些配置选项。
这个配置文件是用一种称为HCL(HashiCorp配置语言)的领域特定语言编写的,以创建Terraform的公司HashiCorp命名。你可以将HCL语法与Terraform结合使用,来管理跨多个云供应商的基础设施资源。

例如,以下是如何使用HCL在AWS中创建或更新一个VPC和一个EC2实例。注意,这段代码遵循了你在存储桶配置文件中看到的相同模式。

同样,以下是如何使用Terraform配置GCP计算实例。如你所见,代码遵循类似的模式,但在这种情况下,你指定GCP作为提供商。
声明式语言与幂等性
HCL被称为声明式语言,这意味着你只需要声明你希望基础设施是什么样子,例如,你想要创建什么资源,你希望配置参数取什么值。这也被称为基础设施的期望最终状态。然后,Terraform将找出实现此期望最终状态所需的确切步骤。
这使得Terraform具有幂等性,这意味着如果你重复执行相同的HCL命令,你的基础设施将保持与你第一次运行命令时相同的期望最终状态。

例如,假设你运行一个创建五个EC2实例的Terraform配置文件。Terraform将首先检查现有基础设施,看看具有这些特定配置的EC2实例是否已经存在。
如果它们不存在,Terraform将创建缺失的EC2实例。如果已经存在EC2实例,但其配置与你指定的不匹配,Terraform将更新现有的EC2实例以匹配期望状态。如果这些完全相同的EC2实例已经存在,Terraform将什么也不做,并让你知道它没有进行任何更改。

这与在批处理/Bash脚本和一些配置管理工具中使用的命令式或过程式语言形成对比,在后者中,你需要使用确切的配置任务序列。使用之前的相同例子,如果你使用命令式语言重复运行一组用于配置五个EC2实例的命令,那么每次都会创建五个新的EC2实例,无论它们是否已经存在。
因此,正如我之前提到的,在这些课程中谈论基础设施即代码时,我们将主要关注Terraform,因为它允许你跨多个云提供商管理基础设施,并且它是软件和数据工程师中非常流行的工具。只需注意,还有其他基础设施即代码工具存在。
总结
本节课中,我们一起学*了基础设施即代码的核心概念。我们了解到,它允许通过代码(如Terraform的HCL)声明式地定义基础设施的期望状态,工具会自动实现该状态并保证操作的幂等性。我们还回顾了其在自动化云数据管道资源(如S3、Glue)创建中的应用,并比较了Terraform与CloudFormation等工具。

在接下来的课程中,我们将更深入地探讨数据可观测性与监控。但在那之前,我将引导你完成在Terraform中创建资源的步骤,然后你将在本周的第一个实验中获得一些使用Terraform的动手实践经验。
114:使用 Terraform 创建 EC2 实例 🚀

在本节课中,我们将学*如何使用 Terraform 编写配置文件,以在 AWS 上创建和管理一个 EC2 实例。我们将了解 Terraform 的核心工作流程、配置文件的结构以及如何执行 Terraform 命令来部署基础设施。
在之前的实验中,你通过应用提供的 Terraform 配置文件,在 Terraform 中创建并配置了一些资源。
你将始终遵循一个一致的工作流程。
首先,编写配置文件来定义你的资源。

然后,要求 Terraform 准备你的工作空间。Terraform 随后会安装必要的文件,以便与云 API 通信,并创建一个执行计划,描述它将创建、更新或销毁的资源。
一旦你批准了该计划,Terraform 就会应用其提议的步骤,并在本周的实验中配置你的基础设施。你将有机会编写和运行自己的 Terraform 代码。
因此,我准备了一系列教程来帮助你做好准备。在这第一个教程中,我们将详细介绍如何准备配置文件来创建一个 EC2 实例。

在此过程中,你将更深入地了解 Terraform 的内部工作原理,并准备好使用 Terraform 创建任何其他资源。在深入细节之前,先提醒一下,这可能会感觉信息量巨大,但请耐心跟随。你不需要在第一次就掌握所有细节,很快你将有机会亲自实践这一切。
假设你想创建一个 E2 实例,并将其启动在你所选区域的默认 VPC 中,如图所示。
在这个例子中,我将使用弗吉尼亚西部区域,即 US East1。

为了简单起见,我选择在默认 VPC 中启动 E2 实例。但请回想一下,在本课程的第一周,Morgan 提到,你通常希望在自己的自定义 VPC 中启动资源,而将默认 VPC 仅用于快速实验。
让我们从创建定义此 EC2 实例的配置文件开始。
要编写配置文件,你可以使用任何你选择的 IDE。
在你的环境中安装 Terraform,并使用你的 AWS 凭证对 Terraform 进行身份验证。
你可以在 Terraform 网站上找到关于这些步骤的更多信息,链接在本周最后的资源部分。
在实验中,所有这些都将为你设置好。你只需按照说明操作,打开 Cloud 9,就可以立即使用 Terraform。
这里我使用 Cloud 9 作为 IDE。我已经安装了 Terraform,并创建了这个文件夹,它代表我将保存配置文件的根目录。

让我们继续创建第一个配置文件,并将其命名为 main.tf。
任何扩展名为 .tf 的文件都会被 Terraform 识别为配置文件。

你可以将配置文件结构化为五个部分。
在前两个部分中指定 Terraform 设置和提供程序。
然后在下一部分定义你想要设置的所有资源。
最后两个部分可以选择性地定义任何输入变量和输出值。
然后,你将为每个部分内的实体创建代码块。在 Terraform 中,代码块具有类似 JSON 的结构,以一个告诉你块类型的关键字开头。
然后,根据块的类型,如果需要,块可以包含字符串形式的标签。
每个块都有一个由花括号分隔的主体。在主体内,你可以定义块的参数或进一步的块。
让我们从第一部分开始。
你在这里看到的 terraform 块指定了 Terraform 设置,包括 Terraform 将用于创建资源的必需提供程序。
我想暂停一下,多说几句关于提供程序的内容,因为我觉得第一次使用 Terraform 时这可能会有点令人困惑。
在 Terraform 的语言中,提供程序是一个插件文件或二进制文件,Terraform 需要安装它才能与外部资源交互。

你可以在 Terraform 注册表中找到所有可用的提供程序,如图所示。
一些提供程序允许 Terraform 与云平台交互,而另一些是实用程序提供程序,允许你在 Terraform 中使用附加功能。
需要明确的是,在 Terraform 中,“提供程序”这个词并不是指你正在设置资源的云提供商。相反,此上下文中的提供程序是 Terraform 为了与外部资源交互而需要的那个插件或二进制文件。
让我们点击 AWS 提供程序。再次强调,这里的 AWS 提供程序并不是指 AWS 作为云提供商。相反,这是允许 Terraform 与 AWS 上的资源交互的文件。
所以在这里,你可以看到提供程序的版本、源代码及其文档的链接。
如果你点击文档,你将看到此提供程序提供的所有资源列表及其使用示例。
在使用 Terraform 时,这份文档会非常有帮助,因为它向你展示了在这种情况下为任何 AWS 资源需要指定的参数。
现在,让我们回到代码。由于在这个例子中我们只使用 AWS 资源,你只需要声明 AWS 提供程序作为必需提供程序。
对于每个提供程序,你需要指定一个本地名称、源位置以及可选的版本约束。
本地名称是你在配置文件中各处用来引用该提供程序的唯一标识符。
例如,这里我使用 aws 作为 AWS 提供程序的本地名称,这是 AWS 提供程序文档中使用的首选名称。
源 hashicorp/aws 是 AWS 提供程序的全局标识符。它指定了当你运行此配置文件时,Terraform 可以从哪里下载此提供程序。
你也可以通过指定 terraform 块内的必需版本来为 Terraform 本身设置版本约束。
在下一部分,你可以创建一个 provider 块来配置你刚刚声明的提供程序。
所以在这个 provider 块中,我指定了 AWS 区域。
请注意,我在 provider 关键字旁边使用的名称是 aws,这是我在 terraform 设置块中为此提供程序分配的本地名称。
我知道这感觉有很多细节,但别担心,你总是可以查阅特定提供程序的文档,并复制 terraform 设置和 provider 块的代码。

接下来,让我们在 resource 块中定义 EC2 实例。你以关键字 resource 开始。
然后指定所谓的资源类型,这是一个包含提供程序和资源的字符串,由下划线分隔。
所以前缀 aws 指的是我们之前指定的 AWS 提供程序,资源类型 aws_instance 指的是我希望 Terraform 管理的 AWS EC2 实例。
你总是可以在 AWS 提供程序的 Terraform 文档中搜索资源类型,以找到你想要用 Terraform 配置的所需资源类型的名称。
这里的下一个字符串代表你选择给此资源起的名字。

这两个字符串一起构成了一个唯一的 ID,你可以在配置文件的其他块中使用它来引用你的资源。
例如,你可以使用 aws_instance.web_server 来引用这个 EC2 实例。

现在,在 resource 块内部,你需要指定资源的参数。同样,你可以在文档中找到每个资源的参数列表。
例如,对于 EC2 实例,你有这个很长的参数列表。
但就像编写 Python 代码一样,你不需要指定每一个参数,因为大多数参数是可选的。
EC2 实例的两个必需参数是 AMI 和实例类型。
AMI 是一个软件模板,包含有关实例操作环境的信息,例如操作系统和系统架构。
AWS 提供了很长的 AMI 列表,你可以在 AWS 控制台的 AMI 目录中找到。
在这个例子中,我获取了最新的基于 Linux 的 AMI 的 ID。
对于第二个参数,我使用 t2.micro 作为实例类型。我还设置了可选的标签,给实例命名为 example-server。
请注意,我没有指定要在哪个子网中启动 EC2 实例。这是因为我希望它在默认 VPC 的任何子网中启动。
你在此配置文件中看到的内容足以创建一个 EC2 实例。
那么,让我们实际创建这个 EC2 实例。
在这个例子中,我将从 terraform init 命令开始。当你运行此命令时,Terraform 会安装配置文件中定义的提供程序。
所以在这个例子中,Terraform 下载 AWS 提供程序,并将其存储在一个名为 .terraform 的隐藏子目录中。
一旦 Terraform 成功初始化,你就可以运行 terraform plan 命令。

当你运行此命令时,Terraform 会创建一个执行计划,详细说明 Terraform 计划根据你的配置文件创建、更新或销毁什么。
所以在这种情况下,加号意味着 Terraform 计划创建所有这些组件。在其他情况下,你可能会看到减号,表示将被销毁的内容,或者波浪号,表示将被更新的内容。
最后,你可以运行 terraform apply 命令。
Terraform 将再次向你显示执行计划,但随后会停下来等待你的批准。所以在这里我将输入 yes,并等待 E2 实例的创建。
好了,Terraform 刚刚根据这些配置规范创建了 EC2 实例。如果需要,你可以在控制台中检查该实例。
在这个第一个教程中,你看到了如何设置包含 terraform 和 provider 块的配置文件,然后如何使用 resource 块创建 EC2 实例。

在下一个视频中与我一起,了解更多关于 Terraform 中其他块的知识,以及如何更好地组织你的 Terraform 目录。
总结
本节课中,我们一起学*了 Terraform 的基础工作流程:编写配置文件、初始化、计划和应用。我们详细了解了配置文件的结构,包括 terraform 块、provider 块和 resource 块,并成功创建了一个 EC2 实例。这为后续使用 Terraform 管理更复杂的基础设施打下了基础。
115:Terraform变量、输出与工作空间组织 🏗️

在本节课中,我们将学*如何为Terraform配置创建输入变量、如何利用输出值导出资源信息,以及如何有效地组织Terraform工作空间。这些技能将帮助你编写更灵活、更易于维护的基础设施代码。
上一节我们介绍了Terraform的基础配置。本节中,我们来看看如何通过变量和输出来增强配置的灵活性和可用性。
定义输入变量 📥
在之前的配置中,我们使用了硬编码的值,例如区域名称和EC2实例名称。为了避免在代码块中直接写入固定值,你可以创建输入变量来参数化你的配置。输入变量允许你自定义基础设施,并在创建资源时指定不同的变量值,而无需手动编辑配置文件。
以下是定义输入变量的方法:
- 变量声明:使用
variable关键字声明变量。例如,region和server_name是变量的标识符。 - 可选参数:每个变量可以包含三个可选参数:
description:用于记录变量用途的文档。type:变量的类型(如string)。default:为变量分配的默认值。
- 变量引用:如果未为变量分配默认值,则在Terraform应用配置前,系统会提示你指定其值。在其他代码块中,可以使用
var.变量名的语法来引用变量。
例如,在提供者(provider)块中,将AWS区域的硬编码值替换为 var.region;在资源(resource)块中,将实例名称的硬编码值替换为 var.server_name。
为变量赋值 🔧
为了自动为变量赋值而无需提示,你可以使用命令行标志 -var。更方便的做法是,在一个以 .tfvars 为扩展名的特定文件中定义变量值。
例如,在包含配置文件的同一目录中,创建文件 terraform.tfvars,并在其中为变量 server_name 赋值。更新配置时,只需运行 terraform apply 命令。Terraform将使用 .tfvars 文件提取变量值,并使用提供的值更新配置。
定义输出值 📤
你创建的任何资源都包含一系列特性或属性。例如,你可以查阅EC2实例的文档,查看其所有属性的列表,如ID、ARN(亚马逊资源名称)和公共IP地址。
在某些情况下,你可能希望导出这些属性,例如在命令行中打印它们、在基础设施的其他部分使用它们,或在其他Terraform工作空间中引用它们。为此,你需要将它们声明为输出值。
以下是创建输出值的方法:
- 输出声明:使用
output关键字声明输出值。例如,server_id和server_arn是这些输出值的标识符。 - 值参数:对于每个输出值,需要通过将其分配给EC2实例的属性来指定
value参数。 - 属性访问:你可以通过指定资源的标识符(即
资源类型.资源名称),然后使用.属性语法来访问属性的值。
例如,要访问EC2实例的ID属性,可以使用 aws_instance.webserver.id。对ARN属性也进行类似操作。
访问输出值 🔍
在命令行中,应用更新后,你可以看到Terraform检测到输出的变化,并告知你将创建这些输出值。输出值会显示在Terraform的消息中。

创建输出后,你可以使用 terraform output 命令查询所有输出,也可以通过指定其名称来查询单个输出。
组织工作空间 📁
目前,我们的配置文件中有多个代码块,每个块都有不同的用途。但是,如果你有多个资源、多个输入变量和多个输出值,将所有代码块声明在一个文件中,管理起来会变得非常繁琐。
更好的做法是将此配置文件拆分为多个文件。例如,你可以将所有输入变量声明在 variables.tf 中,所有输出值声明在 outputs.tf 中,所有提供者和Terraform设置声明在 providers.tf 中,所有资源声明在 main.tf 中。你还可以进一步划分 main.tf,将每个资源声明在单独的 .tf 文件中。
Terraform会自动将所有以 .tf 结尾的文件拼接起来,就像你将它们全部写在一个文件中一样。这样组织工作空间有助于维护你的基础设施。

本节课中我们一起学*了如何为Terraform配置定义和使用输入变量、如何声明和访问输出值,以及如何通过拆分文件来组织Terraform工作空间。这些实践将使你的基础设施代码更加模块化、可重用且易于管理。

在下一节视频中,我将展示如何使用模块来组织工作空间以及如何声明数据源。
116:Terraform 定义数据源和模块 🧱

在本节课中,我们将要学* Terraform 中两个重要的概念:数据源和模块。我们将了解如何使用数据块来引用外部资源,以及如何通过模块来组织和复用配置代码。

概述
上一节我们介绍了 Terraform 的资源块和输出块。本节中我们来看看如何声明数据块和模块。数据块允许你引用在 Terraform 外部或另一个工作区中创建的资源。模块则是一种将相关资源打包在一起以便复用的方式。
定义数据源
除了之前视频中看到的资源变量和输出块,你还可以在配置文件中声明数据块。在 Terraform 中,你可以使用数据块来引用在 Terraform 外部或另一个 Terraform 工作区中创建的资源。
Terraform 将这些资源称为数据源。你可以查阅提供商的文档和 Terraform 注册表来了解如何声明这些资源。你会发现,对于提供商中可用的每个资源,你都可以在 Terraform 中将其声明为资源或数据源,具体取决于你是要创建该资源还是从外部资源读取数据。
让我们来看两个使用数据块的例子。

示例一:引用现有子网
在之前的视频中,我创建了一个在默认 VPC 内启动 EC2 实例的配置文件。但现在,假设你想在已在此当前工作区外部创建的 VPC 的子网内启动 EC2 实例。
为了访问一个子网,我将声明一个数据块,如下所示。与资源块类似,在 data 关键字旁边,我将指定两个字符串。第一个字符串代表资源类型,你可以从提供商的文档中获取;第二个字符串是你为数据源选择的名称。现在,你可以在整个配置文件中通过这个名称来引用它。
以下是声明数据块的通用语法:
data “<资源类型>” “<数据源名称>” {
# 配置参数
}
你需要指定用于识别所需子网的参数。请务必查阅文档,以了解此数据源期望哪些参数。这里,我假设我知道子网的 ID,并将其分配给 id 参数。
声明数据源后,你就可以使用它的属性了。例如,要使用 id 属性,你可以这样写:
data.aws_subnet.selected_subnet.id
在 EC2 实例的资源块中,有一个 subnet_id 属性,我可以使用这个表达式来指定它,以便在所需的子网内启动 EC2 实例。
当然,既然你已经知道子网 ID,你也可以直接在资源块中引用它。但这里我想展示一个如何使用数据块的例子,因为在某些情况下,你可能无法直接获得子网 ID。因此,在数据块中,你可以使用其他参数来识别所需的子网。
示例二:自动查找 AMI
作为另一个例子,你也可以使用数据源来自动识别 EC2 实例的 AMI 参数。
在第一个视频中,我提到我从 AWS 控制台获取了这个 AMI ID。如果我想通过让 Terraform 代表我搜索并检索最新的 Linux AMI 来自动化这个过程,我可以使用以下数据块。
这里,我要求 Terraform 查找由 Amazon 拥有的、具有指定系统架构且基于 Linux 的最新 AMI。现在,在 EC2 实例资源块内部,你可以像下面这样指定 AMI:
resource “aws_instance” “example” {
ami = data.aws_ami.latest_linux_ami.id
# ... 其他配置
}
再次强调,你以关键字 data 开头,然后使用此数据源的资源类型和名称,最后指定你要访问 id 属性。
现在,让我们通过运行 terraform apply 命令来更新配置。你会看到 Terraform 计划销毁先前的实例,以创建一个具有更新网络设置的新实例。你还可以看到它执行了搜索以找到最新的 AMI,并且找到了我已经指定的同一个 AMI。现在,我将输入 yes 并等待更新完成。
使用模块
本教程中我想介绍的最后一个主题是 Terraform 中模块的使用。
模块是你的主目录中的一个子目录,你可以用它来将一起使用的资源分组。你可以将其视为打包这些资源的一种方式。在这个例子中,我将创建这个 website 模块,以分组用于创建网站的所有资源。
让我们将包含 Web 服务器定义的 main.tf 文件移动到 website 模块中。模块就像一个常规的根目录,因此它也期望你在其中声明提供商、输入变量和输出值。所以我需要将这些文件移动到 website 模块中。
模块充当一个包含资源、输入变量和输出值的文件夹。因此,你无法在根目录中直接访问这些信息。这意味着,如果你现在运行 terraform apply,它会报错,因为根目录将无法看到分配给输入变量的值。
为了解决这个问题,你需要在根目录中声明一个模块块来调用模块。如下所示,我选择 website 作为模块名称,并指定 source 参数,即模块目录。
现在,在这个模块块内部,我可以包含该模块的输入变量并指定具体值。这里,我需要为输入变量 server_name 指定一个值。为此,我将在主目录中创建这个 variables.tf 文件,并声明 server_name_root 变量。
然后,回到模块块中,我可以通过模块的输入变量将 server_name_root 变量的值分配给它。最后,在根目录的 .tf 文件中,我需要指定 server_name_root 变量的实际值。
最后,如果你还想将模块的输出 server_id 和 server_arn 也作为根目录的输出导出,你需要在根目录内创建一个输出文件。在这个文件中,你声明输出,并使用以下语法将它们分配给模块输出的值:
output “server_id” {
value = module.website.server_id
}
你以 module 开头,然后指定包含这些输出值的模块名称,接着指定你要访问的输出值的名称。

每当你添加、移除或修改模块块时,都需要重新运行 terraform init,以允许 Terraform 安装新模块或调整已安装的模块。所以这里我将运行 terraform init,然后运行 terraform apply。我们将输入 yes 并等待更新完成。
总结
本节课中我们一起学*了 Terraform 的数据源和模块。我们了解了如何使用 data 块来引用和管理外部资源,以及如何通过创建和调用 module 来组织和复用复杂的配置。这些功能有助于构建更清晰、更可维护的基础设施代码。我知道内容很多,但别担心,你可以随时回看这些视频来复*细节。本视频后我还附上了一些包含更多 Terraform 配置示例的可选阅读材料。我们将在下一个视频中快速浏览即将到来的实验。
117:使用Terraform实现DataOps 🚀

概述
在本节课中,我们将学*如何使用Terraform工具,通过代码定义和部署一个包含堡垒机(Bastion Host)和RDS数据库的云基础设施架构。我们将了解架构的组成部分、Terraform配置文件的结构,并完成一个动手实验。
架构图与实验步骤概览
首先,我们来看一下将要部署的架构图。你将使用Terraform创建一个数据库实例,并通过一个堡垒主机(也称为跳板服务器)来部署和访问它。
堡垒主机充当一个桥梁,连接来自公共互联网的授权用户与私有网络内托管的资源。当授权用户想要访问私有网络时,他们必须首先与堡垒主机建立一个SSH(安全外壳)连接,并使用SSH密钥来安全地访问私有资源。
外部用户可以通过SSH密钥向堡垒主机证明其身份以建立连接。一旦用户通过身份验证,堡垒主机就可以将请求转发到内部网络。
以下是本实验中将要实现的堡垒主机架构图。它包含一个托管在指定VPC私有子网内的RDS数据库实例,以及一个充当堡垒主机的EC2实例。EC2实例位于同一VPC的公共子网中,以便它可以接收来自公共互联网的外部流量,然后将安全流量中继到内部的数据库。
在本实验中,包含私有和公共子网的VPC已经创建并为你提供。你将在Terraform配置文件中将它们定义为数据块,然后使用它们的信息来创建RDS数据库和EC2实例。
当你创建EC2实例时,还将生成一个SSH密钥对。该密钥对包含一个你将存储在EC2实例中的公钥,以及一个你将保存在单独文件中的对应私钥。这一对公钥和私钥用于在SSH连接期间加密和解密外部用户与堡垒主机之间的消息,以便外部连接在实验中证明其身份。
在你使用Terraform创建所有资源后,你将使用私钥从Cloud9终端通过堡垒主机连接到RDS数据库。
为了创建数据库和EC2实例,实验为你提供了需要完成的Terraform文件。首先,你需要获取已提供的VPC及其子网的ID。这些资源是作为实验设置的一部分使用CloudFormation创建的。


要访问它们,你可以进入控制台,在搜索栏中查找CloudFormation。在堆栈名称下,点击不以“cloud9”开头的堆栈名称。在右侧,点击“输出”选项卡。在这里,你将看到使用CloudFormation在后台创建的资源列表。向下滚动,你可以在“值”列下找到VPC及其子网的ID。你在这里看到的其他资源(如S3存储桶和DynamoDB)的用途,我将在视频后面提到。
现在,让我们快速浏览一下提供给你的Terraform文件。堡垒主机架构资源的配置文件收集在一个标记为“bastion_hosts”的模块中。Terraform文件按此处所示进行组织,分为变量、输出、提供者以及每个资源(EC2、RDS和网络)的文件。请记住,Terraform会将所有这些配置文件连接在一起,将它们拆分为单独的文件只是为了提高可读性和便于维护。
Terraform配置文件详解
提供者文件
在提供者文件中,你会注意到所需提供者的列表不仅包括AWS,还包括其他提供者,如local、random和TLS。这些是实用程序提供者,提供了在创建资源时可以使用的功能。你将使用random来为数据库密码生成随机值,使用TLS来创建SSH密钥对,使用local来创建一个文件以存储SSH密钥对的私钥。我鼓励你在Terraform注册表中查看每个提供者的文档。
现在,在AWS块中,请注意区域和项目名称是通过使用变量来指定的。
网络文件
网络文件包含VPC及其子网的数据块。在实验中,你将完成这一部分,使用在variables.tf文件中声明的相应变量来指定子网和VPC的ID。向下滚动,你会看到网络文件还包含堡垒主机和RDS的安全组定义。安全组的配置使得堡垒主机可以从公共互联网接收SSH流量,而数据库只能接收来自堡垒主机的流量。你将在RDS和EC2配置中使用这些网络资源。
RDS文件
在RDS文件中,你有三个资源块。第三个块包含创建RDS实例所需指定的参数,例如服务器实例类型、分配的存储、子网组、安全组ID、引擎类型(本例中为Postgres)、端口号、数据库用户名和密码。你将填写其中一些参数的值。
第一个资源块对应于来自random提供者的random_id资源。此资源将生成一个随机数,你将把它分配给数据库密码。第二个块将创建一个子网组,其中包含提供给你的两个私有子网的ID。你将使用此资源来配置RDS数据库的子网组。请注意,你必须指定两个私有子网而不是一个。这是因为RDS被设计为期望至少有两个子网,以防你以后想切换到多可用区部署。
EC2文件
在EC2文件中,也有几个资源块。最后一个块包含EC2实例的配置。你已经在之前的视频中看到过一些属性,例如AMI、实例类型和子网ID。在本实验中,你还需要指定其他属性,例如其安全组的ID和密钥名称。密钥名称代表你需要与堡垒主机关联的SSH密钥对的名称。为此,你将使用第一个资源块tls_private_key来生成密钥对。第二个资源块local_file创建一个文件,用于存储密钥对中的私钥。而aws_key_pair资源块将在AWS中注册公钥,以便你可以在EC2实例的配置中使用其密钥名称。
变量与输出文件
这些资源文件期望一些在variables.tf文件中声明的输入变量。该文件包含指定项目名称、AWS区域、VPC及其子网的ID以及数据库用户名的变量。对应于VPC及其子网的变量没有默认值,因此你需要在模块外部的terraform.tfvars文件中为这些变量赋值。
该模块还有一些输出值,列在outputs.tf文件中。你的任务是完成此文件,以定义输出值,例如数据库主机、端口、用户名、密码以及堡垒主机的DNS。创建资源后,你需要导出此信息才能连接到数据库。
根目录配置
我们已经讨论过,模块中的所有内容都被封装并从根目录隐藏。因此,为了给模块变量赋值并使用其输出值,你需要在根目录中声明该模块。所以,在这个main.tf文件中,声明了模块。你可以看到,使用变量为其输入变量赋值。这就是为什么根目录也包含一个variables.tf文件,其中包含与模块变量类似的列表。对应于VPC及其子网的变量没有默认值。因此,你需要使用来自CloudFormation堆栈的ID,在terraform.tfvars文件中为这些变量赋值。
根目录还包含一个outputs.tf文件,其中包含从模块导出的输出列表。
你在这里看到的另一个文件是backend.tf文件,它包含一个后端块,允许你定义Terraform应将其状态数据文件存储在何处。每次运行Terraform时,都会创建或更新terraform.tfstate文件,以跟踪底层架构及其配置的状态。此文件包含将配置中声明的资源实例映射到实际AWS对象的信息。默认情况下,状态文件存储在本地。但是,如果你与团队在同一组资源上协作,则需要通过将状态文件存储在像S3存储桶这样的远程仓库中来与团队共享。在Terraform中,你可以定义一个S3后端,如你在此块中所见。S3存储桶已经提供给你,你可以从控制台的CloudFormation堆栈中找到其信息。你还可以在此块中指定DynamoDB表的名称。当你希望确保状态文件不会被两个人同时访问或修改时,需要使用一个表。DynamoDB表在状态文件更新时将其锁定,防止其他用户同时修改该文件。DynamoDB实例也通过CloudFormation堆栈提供给你。

总结


现在轮到你在本架构示例中练*使用Terraform了。完成配置文件后,你将运行Terraform来创建资源。最后,你将尝试通过堡垒主机连接到数据库。完成实验后,请加入下一课,学*DataOps的第二个支柱:数据可观测性与监控。
118:数据可观察性 📊

在本节课中,我们将要学*数据可观察性与监控的概念。这是数据运维(DataOps)的一个关键支柱,借鉴了软件开发领域的实践。我们将探讨为什么监控数据系统的“健康”状况至关重要,以及低质量数据可能带来的风险。最后,我们会介绍如何通过监控来及时发现数据问题。
可观察性原则的起源 🏗️
除了数据工程师借鉴和构建的自动化原则,可观察性和监控的原则与实践也是数据运维的关键支柱。这一理念同样起源于过去十年左右的软件开发领域。
随着云计算的兴起和向分布式系统的转变,软件工程师开发了可观察性工具。这些工具帮助团队了解其系统的运行健康状况。
软件系统的监控指标 📈
借助这些可观察性工具,团队能够监控诸如CPU使用率、内存使用率和响应时间等指标。这有助于快速检测异常、识别问题、防止停机,并确保软件产品的可靠性。
当涉及到数据可观察性和监控数据系统的健康状况时,软件团队所依赖的一些相同工具对数据工程师也可能有帮助。
数据工程师的独特监控需求 🔍
尽管如此,除了监控CPU使用率或系统响应时间等指标,作为数据工程师,你还需要了解数据的健康状况,或者说,数据的质量。
作为提醒,在之前的课程中,我们将高质量数据定义为准确、完整、可发现且及时可用的数据。此外,高质量数据在明确定义的模式和数据定义方面,完全符合利益相关者的预期。低质量数据则相反,它可能不准确、不完整或无法使用。
因此,当你能够向组织内的利益相关者提供高质量数据时,你就在为他们创造价值。但信不信由你,提供低质量数据实际上比根本不提供数据更糟糕。

当业务决策基于低质量数据做出时,对组织来说成本可能极高,并且可能导致利益相关者对数据团队的价值产生怀疑。
数据系统的隐蔽问题 ⚠️
提供低质量数据的数据系统从外部看可能完全正常。
例如,假设你有一个像移动应用或网站这样的软件应用程序。如果应用程序崩溃,或者你在尝试加载网页时收到404错误,很明显是出了问题。这些是可以触发软件工程师警报的事情,以便他们去修复问题。
对于数据系统,如果你的系统完全停止工作,并且你能够立即识别出它不工作,这实际上是潜在故障模式中最好的情况。在这种情况下,你可以调试问题并使系统重新启动运行。
另一方面,如果你的数据发生了破坏性变更,导致系统仍在工作但不再提供高质量输出,事情就会变得非常棘手。
为了更好地理解我的意思,让我们看一个假设的场景。
一个假设的数据质量场景 💸
想象一下,你是一家美国公司的数据工程师,该公司在欧洲销售某种产品。假设你正在摄取产品销售数据,并为下游分析用例提供数据。
现在,假设由于某种原因,管理记录产品销售的事务数据库的团队决定开始以欧元而非美元记录销售价格。
你的系统仍在工作,你仍在为流行的分析仪表板提供数据,这些仪表板中的数字甚至可能看起来合理。但现在,看起来收入突然下降了大约10%或20%,具体取决于当天美元兑欧元的汇率,这影响了所有在欧洲的销售。
这会触发领导团队的紧急会议,进而导致全员投入解决问题。
数据质量问题的本质 🎯

在数据质量方面,这将是一个例子,说明你的系统在眨眼之间就从提供高质量数据转变为提供不再准确的数据,或者至少不再是利益相关者所期望的数据。
当然,你可以争辩说这不是你的错。


数据工程师的责任 🤝
源系统所有者不应该做这样的事情,或者至少他们应该提醒你这种会影响你数据的变更。但正如我在这些课程中一直强调的,无论来自何处,你都应该预期并缓解那些扰乱或破坏你数据系统的上游变更。
一旦数据到了你手中,确保其质量就是你的责任。
那么,当你的数据系统受到干扰时,你如何确保尽快知道发生了什么?
这就是数据可观察性和监控发挥作用的地方。


总结 📝
本节课中我们一起学*了数据可观察性的重要性。我们了解到,数据系统的“健康”不仅指其运行状态,更关键的是其输出数据的质量。低质量的数据,尤其是那些系统看似正常运行时产生的错误数据,可能带来比系统完全故障更严重的后果。因此,数据工程师必须借鉴软件工程的可观察性实践,建立对数据质量本身的监控,以便及时发现上游变更等问题,确保交付给利益相关者的数据始终准确、可靠。
119:与Barr Moses的对话 🎙️

在本节课中,我们将与Monte Carlo公司的联合创始人兼CEO Barr Moses进行对话,探讨数据可观测性、数据质量以及数据工程师的职业发展。我们将学*如何理解数据系统的健康状况,以及如何与利益相关者有效沟通。
概述
数据可观测性是一个至关重要的概念,它帮助数据团队理解其数据系统的健康状况,并确保数据的可靠性和准确性。本节对话将深入探讨数据可观测性的定义、关键指标、成功案例以及数据工程师如何与利益相关者沟通。
什么是数据可观测性?
上一节我们介绍了课程的整体背景,本节中我们来看看数据可观测性的核心概念。
数据可观测性最好通过类比软件可观测性来理解。它旨在解决一个普遍存在的痛点:数据团队经常面临数据错误的问题,导致信任危机和运营中断。数据可观测性帮助数据团队恢复对数据的信心,理解数据的健康状况。
核心公式:数据可观测性 = 理解数据系统健康状况 + 持续改进
数据可观测性解决的核心问题
数据可观测性主要解决数据停机问题。数据停机指的是数据不准确或错误的时期。例如,Netflix在2016年因数据问题中断服务45分钟,这对收入和品牌声誉造成了重大影响。
数据问题可能出现在三个核心组成部分:
- 数据本身:即摄入系统的原始数据。
- 代码:用于转换数据的代码,通常由工程师编写。
- 系统:运行作业的基础设施。
数据可观测性旨在全面监控这些部分,及时发现并解决问题。
关键指标
为了衡量和改善数据可观测性,数据团队应关注以下三个关键指标:
以下是数据团队应追踪的三个核心KPI:
- 事件数量:每天发生的数据事件数量。
- 检测时间:从问题发生到被察觉所花费的时间。
- 解决时间:从发现问题到完全解决所花费的时间。
这些指标帮助团队量化其运营效率,并设定明确的改进目标。
成功案例:JetBlue航空
JetBlue航空公司是成功实施数据可观测性的一个典范。他们利用数据驱动内部运营和客户支持系统,例如确保行李准时到达。
JetBlue通过提升数据可观测性,显著提高了其内部团队净推荐值。NPS用于衡量内部客户(如运营和支持团队)对数据服务的满意度。更高的信任度直接促进了数据的使用效率和业务价值。
如何与利益相关者沟通
对于本课程的学*者而言,走出技术真空,与利益相关者沟通至关重要。
Barr Moses给出了两点关键建议:
- 主动对话:在创建公司前,她与数百名数据从业者交流,以验证“数据停机”是否是一个普遍而紧迫的问题。直接沟通是了解真实需求的第一步。
- 共同验证:不要仅仅停留在交谈。构建一个最小可行产品并与客户一起测试。客户的直接反馈是无可替代的,它常常会纠正你最初的设想。
在快速变化的行业中持续学*
数据领域变化迅速,就像“每隔几年就 reinvent 自己”。对于学*者,Barr Moses的核心建议是:
保持好奇心,追随你的热情。 她认为,外界的建议往往带有个人偏见,有时甚至相互矛盾。因此,最重要的是倾听客户的声音,了解市场的动向,并坚定自己的信念。她本人每周都与10-15位客户交流,这使她能够紧跟市场脉搏。
总结
本节课中,我们一起学*了数据可观测性的核心概念及其重要性。我们了解了衡量数据健康的关键指标,看到了JetBlue的成功实践,并获得了与利益相关者沟通以及在这个快速发展的领域保持学*的宝贵建议。记住,建立可靠的数据系统始于对其健康状况的深刻理解。
120:监控数据质量 📊

在本节课中,我们将学*如何为数据管道设计和实施有效的质量监控策略。我们将探讨监控哪些指标、如何确定优先级,并介绍一个用于自动化数据质量测试的强大工具。
通过前面的学*,我们确信数据可观测性和监控非常重要。
但在实际操作中,应该从哪里开始呢?
这正是本视频要讨论的内容。与我们在课程中讨论的许多其他事情一样,一切都始于利益相关者的实际需求。
从实践角度讲,对于数据管道,你可以决定监控的指标或质量标准范围很广。
例如,你可以监控每批或在某个时间间隔内调整的记录总数,或者监控特定列中的值范围是否保持在某个阈值内。
你也可以统计表中空值的总数,或者当前时间与数据中最新记录的时间戳之间的差值。
简而言之,你可以决定监控的事情非常多。

然而,与其为你能够测量或观察到的关于数据的每一个可能方面都设置监控和警报,你更应该识别最重要的事情并专注于它们。
如果你试图监控数据的每一个可以想象的方面,最终可能会造成混乱和警报疲劳,真正重要的东西会淹没在噪音中。
因此,在决定监控数据的哪些指标或方面时,第一个问题应该是:对于这个特定的用例,利益相关者最关心什么?
例如,利益相关者可能最关心查看当前数据,也许是不到24小时的数据。在这种情况下,你需要通过测量最新记录的摄取时间并验证其是否符合项目预期,来监控所谓的数据“新鲜度”。
当涉及到数据的准确性和完整性时,可以合理地假设这些对所有项目都很重要。
为了监控这些质量方面,你需要识别数据的哪些组成部分最重要,哪些不那么重要或可以安全忽略。
例如,如果你的利益相关者关注产品销售营收,那么数据中记录的购买金额必须准确、能够验证所有销售记录是否成功摄取、以及它们不包含空值,这些就至关重要。
相比之下,所有产品编号是否与产品描述匹配,或者每个产品的邮政编码是否正确记录,可能就不那么重要了。
正如你所想,数据的关键重要方面会因项目而异。
在整个课程中,我一直在强调你应该与源系统所有者沟通,以确保你了解未来需要预见或缓解哪些类型的变更。
虽然良好的沟通无可替代,但你也应该采取措施,在你的数据监控中建立检查或测试,以验证你正在摄取的数据的模式和类型是否保持一致。
如果一切顺利,这些检查可以作为很好的健全性检查,确保你摄取的数据仍然是你期望的格式。
这些检查还可以帮助在问题沿数据管道进一步传播之前,及早发现问题。
与数据工程中的许多事情一样,监控数据质量的方法有很多种。
你可以手动做一些事情,或者编写一些自定义代码来执行一组测试或触发警报。
在某些场景下,这些方法可能是有意义的,例如当你首次建立管道或进行原型设计时。

但如今,有许多工具可以用来确保数据质量,同时让你免于承担那些无差别的繁重工作。
接下来,是我的朋友Abe Gong的对话,他是Great Expectations的创建者之一。Great Expectations是一个开源工具,你将在下一个实验中使用它来测试数据质量。
这是一个可选视频,旨在为你提供关于此工具的更多背景信息。你也可以直接跳到下一部分,开始自己使用Great Expectations。
否则,我将在下一个视频中与Abe Gong的对话中与你再见。

本节课总结
在本节课中,我们一起学*了数据质量监控的核心原则。我们了解到,监控应从利益相关者的关键需求出发,优先关注对业务影响最大的数据维度,如新鲜度、准确性和完整性,而非试图监控一切。同时,建立对数据模式和类型的自动化检查,有助于在问题扩散前及时发现。最后,我们了解到可以利用像Great Expectations这样的专门工具来高效地实施这些质量检查,从而构建更可靠的数据管道。
121:与Abe Gong关于数据质量与Great Expectations的对话 🎙️🔍

概述
在本节课中,我们将学*数据质量的核心概念,并了解开源工具Great Expectations如何帮助数据工程师确保数据的可靠性与适用性。我们将跟随吴恩达与Great Expectations联合创始人Abe Gong的对话,探讨数据质量的重要性、定义以及实践工具的应用。
数据质量的定义与重要性
上一节我们介绍了数据工程的宏观背景,本节中我们来看看数据质量的具体含义。
数据质量必须基于“适用性”这一核心理念。这意味着数据应能满足特定用途的需求,无论是用于回答问题、构建机器学*模型还是其他任务。数据质量的目标是确保这些任务能够可靠、一致地运行,并且结果是可信的。
不同的数据系统对质量的要求可能截然不同。例如,一个报告常规指标的仪表板需要确保上游数据被正确记录、聚合,并且没有过大的时间延迟。而训练机器学*模型时,则需要更多地关注数据分布和偏差等问题。
Great Expectations项目的起源
以下是Great Expectations项目诞生的背景故事。
这个项目的灵感来源于处理数据质量问题的漫长夜晚。Abe Gong曾是一个数据科学爱好者小组的成员,其中包括Great Expectations的另一位联合创始人James Campbell。在一次会议中,Abe提出了一个想法:应该能够像测试软件一样测试数据管道。有趣的是,James也带着完全相同的想法来到了那次会议。
他们从一开始就秉持着简单的设计理念,旨在让这个工具能够在多种环境中部署,并轻松地与数据探索流程集成。
Great Expectations如何工作
Great Expectations的基本理念与软件测试相同,但针对数据进行了特定调整。
现代DevOps运动的一个重要部分是,对于构建的任何软件,都需要有可靠的测试来保证其持续工作。Great Expectations将这一理念应用于数据领域。
每个“期望”都允许你在数据管道的特定时刻、特定位置断言某些数据特征应该为真。其核心思想可以概括为:
# 示例:一个简单的Great Expectations检查
expect_column_values_to_be_between(
column="age",
min_value=0,
max_value=120
)
给学*者的建议
对于本课程的学*者,以下是如何有效使用Great Expectations的一些关键考虑因素。
Great Expectations非常灵活,可以在许多不同的场景中部署。一个关键的起始问题是:谁需要处理这些数据“期望”或要求?
- 场景一:个人或小团队。如果只是你自己或你的团队使用,你可以将期望紧密集成到现有工具链中,例如将期望存储在Git中。
- 场景二:需要跨团队协作。如果需要与其他利益相关者(如业务人员)协作,他们可能需要提供输入和更新要求,而你又不希望成为同步这些期望的中间人,那么你需要寻找其他方式来实现。有些团队使用笔记本来完成这项工作。
关于数据质量的最终建议
对于刚刚进入数据领域的学*者,请认真对待数据质量。
如果你尚未构建并维护过一个系统,数据质量问题可能尚未显现。但这是一个非常重要的问题,如果你不提前规划,它总会在某个时刻带来麻烦。这是一件不能忽视的事情。
总结

本节课中,我们一起学*了数据质量“适用性”的核心定义,了解了Great Expectations项目如何将软件测试的理念应用于数据管道,以确保数据的可靠性。我们还探讨了在实际工作中开始使用此类工具时需要考虑的关键因素,并强调了从一开始就重视数据质量的重要性。
122:Great Expectations核心组件 🧪

在本节课中,我们将学*Great Expectations的核心组件及其典型工作流程。Great Expectations是一个用于数据质量测试的开源工具,它能帮助我们确保数据符合预期标准。
概述
在接下来的实验中,你将使用Great Expectations进行数据质量测试。在此之前,我们先通过一个示例工作流程来概述其核心组件。
使用Great Expectations时,工作流程通常从指定待测试的数据开始,然后定义要对数据执行的期望或测试,最后根据这些期望验证数据。
为了实现这样的工作流程,你需要与Great Expectations的核心组件进行交互,这些组件包括数据上下文、数据源、期望和检查点。这些组件用于访问、管理和操作工作流程中所需的对象和过程。
核心组件详解
上一节我们介绍了工作流程的总体步骤,本节中我们来详细看看每个核心组件。
1. 数据上下文
要启动工作流程,你首先需要实例化一个数据上下文对象。数据上下文是Great Expectations API的入口点,它包含了一系列类和方法,允许你创建对象、连接数据源、创建期望以及验证数据。
通过数据上下文,你可以配置和访问Great Expectations项目的属性、对象以及元数据。
2. 数据源与数据资产
实例化数据上下文对象后,你需要声明数据源对象,它告诉Great Expectations从何处获取要验证的数据。数据源可以是SQL数据库、本地文件系统、S3存储桶,甚至是Pandas DataFrame。
连接到数据源后,你需要告诉Great Expectations需要关注数据的哪一部分。这是通过从数据源声明数据资产来实现的。
数据资产是数据源内记录的集合。它可以是SQL数据库中的一张表、文件系统中的一个文件,也可以是一个连接了多张表的查询资产,或者是匹配特定正则表达式模式的文件集合。
你可以进一步将资产中的数据划分为批次。例如,如果你的数据资产代表表中某一年度的销售记录,你可以将记录划分为月度批次并分别验证,或者按门店ID进行划分。你也可以将数据资产的所有记录作为一个批次来处理。
为了检索数据资产的批次(无论是单个还是多个),你需要从资产中创建一个批次请求对象。批次请求是从数据资产检索数据的主要方式,也是你需要提供给Great Expectations其他组件的内容。
3. 期望与期望套件
接下来,你需要定义你的期望。期望是一个用于验证数据是否满足特定条件的声明。
例如,你可以定义一个期望来检查某列是否不包含空值。你可以自定义期望,也可以使用期望库中已有的声明。例如,expect_column_min_to_be_between、expect_column_values_to_be_unique和expect_column_values_to_be_null都是可以直接使用的测试示例。
你可以为数据资产定义多个期望,并将它们收集在一个期望套件对象中。
4. 验证器与检查点
现在,为了验证你的数据,你需要创建一个验证器对象。验证器需要一个批次请求及其对应的期望套件。
你可以直接与验证器交互来手动验证数据,也可以通过使用检查点对象来简化验证流程。检查点接收一个批次请求和一个期望套件,并自动将它们提供给验证器,由验证器生成验证结果。
在此过程中,关于你项目的元数据将被生成,Great Expectations会将其保存在一些后端存储中。
5. 存储
Great Expectations支持不同类型的存储。最常见的存储包括:
- 期望存储:用于存放你的期望套件。
- 验证存储:用于存放根据期望套件验证数据时生成的对象信息。
- 检查点存储:用于存放你的检查点配置。
- 数据文档存储:用于存放关于期望、检查点和验证结果的报告。
你可以通过数据上下文对象访问这些存储及其设置。
总结

本节课中,我们一起学*了Great Expectations的核心组件及其在典型工作流程中的作用。我们了解了从数据上下文和数据源开始,到定义期望、创建验证器和检查点,最后利用各种存储保存元数据的完整过程。在接下来的视频中,我们将在一个示例数据集上应用这些步骤。
123:Great Expectations 工作流示例 🧪

在本节课中,我们将通过一个具体示例,学*如何使用 Great Expectations 来验证数据质量。我们将以 DVD 租赁数据库中的 payment 表为例,检查其 payment_id 列的唯一性、customer_id 列的非空性以及 amount 列的非负性。
项目初始化与环境准备
上一节我们介绍了 Great Expectations 的核心组件和典型工作流。本节中,我们来看看如何在一个具体项目中应用这些步骤。
首先,需要在本地机器上设置一个 PostgreSQL 数据库并加载数据。接着,在终端中安装 Great Expectations 包。

pip install great_expectations
然后,通过以下命令初始化一个新的 Great Expectations 项目。此命令会初始化数据上下文对象,设置项目文件夹结构,并创建检查点、期望、数据文档和验证存储等后端存储(默认为本地目录)。
great_expectations init
在提示时输入 y 以继续。请注意,后端存储的位置可以配置,例如在实验环境中,你可能会将其配置为 S3 存储桶。本视频中,我们将保持其为本地目录。
为了与 Great Expectations 的各个组件交互,我们将在同一根目录下启动一个 Jupyter Notebook 并创建一个新的笔记本文件。


连接数据源与创建数据资产
在笔记本文件中,我们首先导入 Great Expectations 包,并获取项目的上下文对象。通过此对象,我们可以连接数据源、定义期望、创建验证器并运行检查点。
import great_expectations as gx
context = gx.get_context()
接下来,使用上下文对象创建数据源对象。Great Expectations 提供了多种方法来连接不同的数据源。为了连接到本地的 SQL 数据库,我们调用 add_sql 方法。
# 创建连接字符串(请替换为你的实际数据库信息)
connection_string = "postgresql://username:password@localhost:5432/dvdrental"
datasource = context.sources.add_sql(
name="my_datasource",
connection_string=connection_string
)
连接建立后,我们从数据源创建数据资产。由于我们只关注 payment 表,因此添加一个表资产。
asset = datasource.add_table_asset(
name="payment_tbl",
table_name="payment"
)
如果你想基于日期或列值对数据资产进行分批,Great Expectations 也提供了相应的方法。例如,我们可以按 payment_date 列的月份进行分批。
asset.add_splitter_column_value(column_name="payment_date", method="monthly")
最后,在资产对象上调用 build_batch_request 方法来创建批次请求对象。
batch_request = asset.build_batch_request()
在继续工作流之前,我们可以快速查看一下批次划分情况。
batches = asset.get_batch_list_from_batch_request(batch_request)
for batch in batches:
print(batch.batch_spec)
你将看到数据被分成了四个批次,每个批次对应一个月的数据。
定义数据期望
现在我们已经创建了批次请求对象,接下来定义数据期望。我们将以交互方式直接使用验证器来完成。
首先,创建一个期望套件,它将包含我们定义的所有期望。
context.add_or_update_expectation_suite("my_suite")
然后,使用上下文对象获取验证器,并传入批次请求对象和期望套件名称。
validator = context.get_validator(
batch_request=batch_request,
expectation_suite_name="my_suite"
)
现在,使用验证器,你可以调用期望库中的任何期望方法。以下是我们要定义的三个期望:
- 检查
payment_id列值的唯一性。 - 检查
customer_id列不包含空值。 - 检查
amount列的所有值都是非负的。
# 期望1: payment_id 列值唯一
validator.expect_column_values_to_be_unique(column="payment_id")
# 期望2: customer_id 列值非空
validator.expect_column_values_to_not_be_null(column="customer_id")
# 期望3: amount 列最小值在0及以上(即非负)
validator.expect_column_min_to_be_between(column="amount", min_value=0)
结果显示所有测试都成功通过。请注意,虽然结果只显示了最后一个批次,但测试实际上在所有批次上都已运行。
为了能在其他会话中使用这些期望,我们需要保存它们。
validator.save_expectation_suite(discard_failed_expectations=False)
此方法将包含三个期望的期望套件 my_suite 保存到期望存储中。
使用检查点自动化验证过程
为了自动化验证过程,我们将创建一个检查点对象。
checkpoint = context.add_or_update_checkpoint(
name="my_checkpoint",
validations=[
{
"batch_request": batch_request,
"expectation_suite_name": "my_suite"
}
]
)
validations 参数是一个列表,包含数据批次与其对应期望套件的配对。在本例中,我们只使用了一个批次请求和套件。
现在,运行检查点。
checkpoint_result = checkpoint.run()
要获取每个结果的更详细信息,可以查看数据文档。
context.build_data_docs()
此方法会返回一个链接,打开后可以查看数据文档。在数据文档中,你可以找到每个批次上执行的验证结果。所有测试都应显示为成功。点击任何一行,可以找到关于已评估期望的统计信息、成功与失败的期望、对每列执行的期望及其对应结果。
你还可以在“期望套件”选项卡下找到关于 my_suite 的详细信息。
总结

本节课中,我们一起学*了如何将 Great Expectations 应用于实际数据验证任务。我们完成了从项目初始化、连接数据源、定义数据期望,到使用检查点自动化验证并查看结果的完整工作流。现在,轮到你通过实验来练*使用 Great Expectations 验证数据了。
124:与Chad Sanderson探讨数据合约 📝


在本节课中,我们将学*数据合约的概念。数据合约是一种确保数据源质量的重要方法。我们将通过与行业专家Chad Sanderson的对话,了解数据合约的定义、重要性以及如何在实际工作中应用。
在之前的实验练*中,你通过测试来确认数据管道是否满足数据质量预期。
还有其他方法可以与上游利益相关者共同维护数据质量预期,包括使用所谓的“数据合约”。让我们与我的朋友Chad Sanderson进行一次对话,探讨数据合约如何帮助确保数据源的质量保持高水平。这是一个可选视频,让你有机会听取行业专家的见解,但如果你愿意,也可以直接跳到本周的最后部分,听Morgan介绍你将在本周最后一个实验中使用的可观测性工具Amazon CloudWatch。
让我们开始吧,Chad。
你好,Joe。我很好,很高兴见到你。
我也很高兴见到你。
我们今天在这里讨论数据合约,这是课程中涵盖的一个主题。我认为你在向更广泛的社区推广数据合约及其可见性方面处于领先地位,我非常感谢这一点。我认为你是讨论数据合约的绝佳人选。对于本课程的学*者,如果你还不了解你,请简单介绍一下自己。
当然。我叫Chad Sanderson,目前是一家名为Gable.AI的数据基础设施初创公司的首席执行官。在此之前,我在微软、Convoy、丝芙兰等几家公司领导数据平台团队。我曾担任过分析师、数据科学家和数据工程经理。我在数据领域以及所有相关问题上花费了大量时间。
确实,这里有很多问题。让我们深入探讨一下。那么,什么是数据合约?
数据合约最简单的形式是数据的接口,是数据的API。其理念是,如果你是一名软件工程师,其他人以某种方式访问你的服务,你会提供一个接口。你不希望他们直接访问你编写的原始代码,你会围绕该接口提供文档、服务等级协议等期望。但在数据世界中,这个概念并不真正存在。我们从数据生产者那里提取数据,这些数据来自他们的应用程序、Excel电子表格、Salesforce或SAP。我们将这些数据加载到分析数据库和笔记本中,并对这些生产者产生硬依赖。因此,当情况发生变化时,生产者和消费者之间没有合同来规定什么可以改变、如何改变以及期望是什么。这种期望的违反最终导致了大多数数据质量问题。
是的,没错。那么,请带我了解一下数据合约出现之前的生活是怎样的,并分享一下你在工作中建立数据合约的经验。
我在大多数公司看到的情况是,我认为有几类不同的公司。第一类公司更像是你传统的集中式数据组织,由数据架构师领导,他们考虑数据建模、实体关系图,并与DBA团队以及最终的分析师团队合作。他们就像一个卓越中心,负责建立所有的ETL、架构。在那个世界里,数据合约的必要性稍低一些,因为整个基础设施从一开始就是为了服务于特定功能而构建和监督的。
但在云计算的现代数据世界中,我们拥有数据湖和所有这些新理念,我们采用了一种更联邦式的数据摄取方法。软件工程师可以构建他们想要的任何服务,这些服务会产生大量数据。我们将所有数据扔进某个数据湖,然后由数据工程团队进入,构建提取过程并将数据加载到其他系统中。这实际上就产生了问题。你现在有两组人:生产所有数据的生产者,以及消费所有数据并对其进行处理的消费者。这两方彼此之间没有沟通。当缺乏沟通存在,而服务仍在不断变化时,唯一的选择就是某种程度的混乱。这就是发生的情况。因此,下游数据团队不得不在他们的机器学*模型和管道中构建大量验证,因为他们预期会发生变化,并不断预期出现破坏性问题。当数据质量问题出现时,数据工程团队必须进行非常耗时的根本原因分析,比如某个仪表板的所有者抱怨某个指标看起来不对。问题被抛给数据工程团队,数据工程团队必须查看查询,思考所有潜在原因,必须一直追溯到源头,必须理解发生了什么变化,必须要求生产者修复它。一旦修复完成,他们还必须进行整个回填过程。基本上,数据工程工作就变成了这样。我认为很多人会将数据工程与我刚才描述的这套步骤联系起来。我并不认为这是理想的数据工程工作。
是的,看起来确实如此。在我的经验中,通常你受制于生产者。你常常受制于他们的突发奇想和变化,当事情出错时,你就得去清理。但有了数据合约,我相信本课程的学*者会有一个问题:数据合约的这个接口看起来是什么样子的?我该如何使用数据合约?使用它具体是什么感觉?
这个接口就是我们所说的数据合约的规范。我认为从高层次来看,合约本身有几个不同的组成部分。一个是规范,它非常类似于API规范,比如如果你做过任何实际创建API的工作,就会知道Swagger。另一方面,你有你的执行机制,即我们如何确保遵循该规范,以及如果发生违规,你有一些方法来记录和跟踪它。但就规范本身的样子而言,它通常由两个主要类别组成,你可以无限扩展它,但主要类别是数据对象的结构和数据的内容。在结构方面,你有构成模式的模式和业务逻辑。这些包括列名、存在的列数以及构成列的实际逻辑。在数据内容方面,你有你的数据质量规则、服务等级协议、个人身份信息等这类东西。你可能会附加额外的策略,比如合规性,例如我们期望数据始终以某种方式被使用,或者如果有人针对此数据编写查询,它应遵循特定格式。这就是进入合约的内容,它确实是无限可扩展的。但我的建议始终是确保合约中的所有约束都是可操作和可执行的,否则它就会变成一纸空文或握手协议。
嗯哼。😊,我认为,例如,握手协议。所以,“合约”这个词可能隐含了某种解释,即这个数据合约可能是某种具有法律约束力的协议或团队之间的握手协议。你如何回应这类看法?我想接下来的问题是,数据合约在多大程度上是沟通,在多大程度上是技术?
我认为这是个很好的问题。我绝对认为它不是法律合同。实际上,我听说过一些团队希望与供应商签订具有法律约束力的数据合约的例子。所以,如果你同意为始终以某种方式提供的数据支付一定金额,而事实并非如此,这对你的公司产生了实质性影响,那可能就是你想要请律师处理的事情。但如果你在公司内部运作,真的没有,甚至对内部另一个团队采取法律行动也不是一个好主意。因此,通常合约的执行更多是关于该执行的程序化性质。例如,集成测试是一种执行形式,或者向消费数据的人发送警报和监控,让他们知道发生了合约违规,是另一种执行形式。
然后是这个问题:这在多大程度上是协作和人的问题?我认为主要是人的问题。技术部分真正关乎的是使采用合约、同意合约以及根据合约采取行动的过程变得非常非常容易。我见过的一个常见模式是,数据工程师试图通过要求应用程序开发人员拥有数据工程流程来解决这个问题。例如,“作为软件工程团队,你现在拥有这套表”,或者“我们希望你们拥有DBT”。通常这效果不佳,因为应用程序开发人员对Snowflake或DBT一无所知,这被视为他们时间和精力的成本与负担,会拖慢他们的速度。没有软件工程师希望被拖慢。因此,技术在这个问题上的帮助方式是,它允许数据合约在开发人员已经在使用的工作流程中实施和执行,并使遵守该合约变得微不足道。这实际上我们在其他行业也看到过。安全领域遵循了一个非常相似的模式,你有一个非常小的安全工程师团队,组织中没有很多人,他们需要考虑很大的范围,并且他们某种程度上受制于应用程序开发人员做正确的事。DevSecOps是一种新兴模式,它不是希望公司里的每个人都遵循安全最佳实践,而是有一层技术位于DevOps工作流程中,对代码进行检查,并说:“嘿,我们正在发布的代码是否遵循这些最佳实践?”如果没有,就需要向相关人员发出沟通。
学*者还应该了解关于数据合约的哪些内容?另外,我认为一个后续问题是,如果他们想实施数据合约,他们该如何开始?就需要注意的事项而言,我认为有很多不同的方式可以实施合约,其中一些方式比其他方式更可能成功。因此,我认为带着“我们将创建一个庞大的合约,它将包含所有这些、一百万个不同的约束,并将此交给软件工程师,而他们没有任何技术来实际拥有这个合约”的想法去实施,是一种很好的方式让人们不把你当回事。这会显得工作量很大,非常可怕,并且不清楚他们将如何将其纳入现有的流程中。所以,我认为在你去找生产者进行对话之前,你需要对这个问题有一个好的答案。我认为另一件重要的事情是,软件工程师喜欢做重要的事情,实际上任何人都一样。我认为你不想做无关紧要的随机工作。我见过一些团队去找他们的工程同行说:“嘿,伙计们,你们需要拥有从服务中发出的所有数据。”即使只有10%的数据对分析团队有用。这就会变成一个奇怪的问题:“嗯,如果你只使用其中的10%,为什么要求我拥有100%?你拖慢了我的速度,让我思考模式演进和所有其他事情,而我并没有得到任何回报。我没有为你做任何事情。”所以,我认为有选择性地从合约开始,确保你专注于最重要的管道,即如果数据质量变差会产生明显影响的管道,是一个非常好的起点。就实际开始实施而言,说实话,纸质合约和仅仅进行对话就是一个非常好的开始。我交谈过的大多数数据生产者会说:“我根本不知道我的数据在公司里被用在哪里。如果我不知道它发生了什么,我很难想要拥有这些数据的所有权。”所以,仅仅是克服这个障碍,说:“嘿,A工程团队,你知道你的数据被用在机器学*模型X和CFO每天早上都会看的仪表板Y中吗?”这是一个很好的开始,让他们意识到对他们来说是副产品的东西如何影响更广泛的业务。
这太棒了,非常好的建议。Chad,谢谢你的时间。我相信学*者会从这次讨论中收获很多,谢谢你。
谢谢,Joe。
125:Amazon CloudWatch监控入门 🛠️

在本节课中,我们将学*如何使用Amazon CloudWatch来监控数据系统的健康状况。我们将了解监控的重要性、CloudWatch的基本工作原理、关键监控指标,以及如何为即将进行的实验做好准备。
概述:监控与可观测性的重要性
本周,您已经从Joe和其他讲师那里了解到,监控和可观测性对于确保数据系统健康至关重要。
在接下来的实验中,您将使用Amazon CloudWatch来监控AWS上的一个数据库。
因此,这里我想向您展示一些CloudWatch的工作原理细节,以便您为实验做好准备。
监控数据系统健康意味着什么
监控数据系统的健康意味着确保数据系统内的各个组件按预期运行。
如果系统的某个组件出现问题,成功的监控意味着您能在问题出现时立即知晓,甚至能在问题发生之前预测并纠正它们。
CloudWatch的自动监控机制
当您在AWS上使用资源时,许多资源会自动开始向CloudWatch发送指标,而无需您进行任何设置。
大多数情况下,这些是系统级指标,例如:
- CPU利用率
- 磁盘I/O
- 网络流量
- 内存使用率
这些指标可以帮助您大致了解资源的性能,并在潜在问题变得严重之前识别它们。
在最终用户发现问题之前识别问题非常重要,而健全的监控设置可以帮助您做到这一点。
自定义指标与仪表板
虽然许多AWS服务会自动向CloudWatch发送指标,但在某些情况下,您可能希望发送自定义指标。
自定义指标允许您监控应用程序中未被默认系统指标覆盖的特定方面。例如,您可能希望跟踪:
- 已处理的事务数量
- API端点的响应时间
- 活跃用户数量
您可以使用CloudWatch仪表板来可视化和监控您认为最重要的指标,并将系统中多个组件的指标聚合到一个统一的视图中。
这个视图将帮助您在问题出现时识别和诊断它们。此外,仪表板还可以向您展示随时间变化的数据,从而使您更容易识别模式和异常。
告警与基线设定
您可能不会一直坐着看仪表板。相反,您需要一种方式,在指标开始反映问题时得到通知。
您可以为此创建针对特定指标的CloudWatch告警。您可以定义这些指标的阈值,以便在阈值被突破时收到警报或自动执行其他操作。
在确定要为指标设置什么合理的阈值之前,您需要建立一个基线。
为此,您需要在不同时间、不同负载和条件下测量系统的性能,并确定什么是正常状态。
CloudWatch配置为最多保留15个月的指标数据,因此您可以在确定系统基线之前收集一段时间的指标。
通常,指标的可接受值取决于您的应用程序相对于基线的运行情况。
监控RDS的常见指标

在接下来的实验中,您将监控在本周第一个实验中设置的RDS实例。
以下是您可能需要为RDS监控的一些常见指标:
以下是您可能需要为RDS监控的一些常见指标:
- CPU利用率:CPU利用率过高可能表明您的RDS实例负载过重,需要扩展规模,或者查询需要优化。持续的高CPU利用率(例如超过80%到90%)可能导致性能瓶颈,从而减慢数据库操作。
- 内存消耗:这是RDS需要密切监控的另一个常见指标。高内存消耗也会降低性能,并可能表明您需要升级到具有更多内存的实例类型。
- 磁盘空间:另一个需要关注的指标是磁盘空间。如果磁盘空间持续高于85%,那么您可能需要考虑删除数据或将数据归档到其他系统以释放空间。
- 数据库连接数:监控数据库连接数也很重要。此指标显示到数据库的活动连接数。如果连接数接*最大限制,可能导致连接错误和应用程序故障。关注此指标有助于您管理连接池,并在需要时扩展数据库以处理更多连接。
以上是RDS向CloudWatch发送的几个简单指标示例,以及您需要监控它们的原因。
其他监控工具
除了CloudWatch,还有其他流行的第三方监控服务,例如Datadog或Splunk,您也可以使用它们来监控您的系统。

在监控其他AWS服务时,请记住,每个AWS服务都会发送不同的指标,哪些指标对您重要取决于具体的使用场景。
总结
本节课中,我们一起学*了数据系统监控的核心概念。我们了解到,监控旨在确保系统组件正常运行,并在问题发生时或发生前及时预警。Amazon CloudWatch是AWS上强大的监控工具,它能自动收集系统级指标,也支持自定义业务指标。我们通过仪表板可视化关键数据,并通过设置基于基线的告警来实现自动化监控。最后,我们以RDS数据库为例,探讨了CPU、内存、磁盘和连接数等需要关注的具体指标。希望这些知识能帮助您在接下来的实验中顺利使用CloudWatch。
126:数据工程(导论,源系统、数据摄取和管道,数据存储和查询|1-2-3课)|第3周总结 📊

在本节课中,我们将总结第三周关于数据运维(DataOps)的核心内容。本周重点探讨了如何通过基础设施即代码实现自动化,以及如何对数据和数据管道进行可观测性与监控,以确保为利益相关者持续交付价值。
本周核心学*内容 🎯
上一节我们介绍了课程的整体背景,本节中我们来看看本周具体学*了哪些关键主题。
本周你学*了数据可观测性的关键支柱、如何测试数据质量,以及如何通过数据契约与上游利益相关者达成一致。
以下是本周涵盖的具体知识点:
- 数据可观测性关键支柱:来自Bar Moses的理论,帮助你全面监控数据健康度。
- 数据质量测试:学*了来自Abegong的方法,确保数据的准确性与可靠性。
- 数据契约:通过Chad Sanderserson的分享,了解了如何与上游团队建立明确的数据供应协议。
- DataOps实践对话:回顾了与Chris关于数据运维实践的讨论。
实践工具与应用 🛠️
在理解了核心概念后,我们通过实践工具将这些理论应用于实际场景。
在本周的实验环节,你使用了Terraform和一系列监控工具来构建和守护数据基础设施。
以下是本周使用的主要工具及其作用:
- Terraform:一个云无关的工具,用于以代码形式开发和维护数据基础设施。使用
terraform apply等命令可以确保部署的一致性和可重复性,避免了手动配置云资源的繁琐与易错。 - CloudWatch:用于监控RDS实例的运行健康状况。
- Great Expectations:用于监控数据质量,通过定义数据测试断言(如
expect_column_values_to_not_be_null)来验证数据是否符合预期。


借助这些工具,你可以设置仪表板来可视化数据管道各阶段的运行状态,并配置警报以便在出现潜在问题时及时获得通知。
下周展望:工作流编排 🚀
本周我们聚焦于基础设施的自动化与监控,为可靠的数据管道打下了基础。下一周,我们将在此基础上引入工作流编排(Orchestration)的概念。
通过编排,你将为数据管道的自动化、监控、可观测性和版本控制工具箱增添更强大的工具。我们下周将深入探讨如何协调和管理复杂的数据工作流。
课程总结 📝


本节课中我们一起学*了数据运维的核心实践。我们掌握了通过基础设施即代码实现自动化部署,利用各类工具监控基础设施与数据质量,并理解了数据可观测性与契约的重要性。这些技能是构建可靠、可维护且能持续交付价值的数据系统的基石。
127:数据工程导论(第4周概览)🎯
在本节课中,我们将要学*数据工程生命周期中的一个核心概念——编排(Orchestration)。编排是自动化、可观测性和监控等数据运维(DataOps)支柱的关键组成部分,对于构建高效、可靠的数据管道至关重要。
从数据运维到编排 🔄
上一节我们介绍了数据运维的三大支柱:自动化、可观测性和监控。本节中我们来看看编排如何与这些支柱紧密相连。
编排与数据运维密切相关,因为它直接关联到自动化与可观测性这两大支柱。同时,编排也与数据管理和软件工程等数据工程生命周期的其他底层概念紧密相关。鉴于编排在数据工程师工作中的核心地位,我们将其视为数据工程生命周期中一个独立的底层流程。
编排工具的演进历程 🛠️
在深入编排细节之前,我们先回顾一下编排工具的发展历程。
以下是编排工具演进的主要阶段:
- 手工脚本阶段:在专用编排工具出现之前,工程师使用简单的脚本(如Shell脚本、Python脚本)来手动触发和管理数据管道任务。
- 任务调度器阶段:出现了如
cron(Linux)或任务计划程序(Windows)等系统级调度工具,可以定时运行任务,但缺乏任务间的依赖管理和复杂的错误处理。 - 第一代工作流引擎:出现了如
Apache Oozie、Azkaban等工具,开始支持任务依赖关系图(DAG)和更复杂的工作流管理。 - 现代编排平台:以
Apache Airflow为代表,提出了“管道即代码”(Pipelines as Code)的理念,通过Python代码定义、调度和监控工作流,极大地提高了管道的可维护性和可扩展性。
编排的核心概念与实现 🧩
了解了历史后,本节我们来看看编排的基本原理和实现方式。
编排的核心目标是自动化数据管道中各个任务的执行顺序、依赖关系、错误处理和重试机制。一个基本的编排系统需要管理任务的有向无环图(DAG)。
DAG 可以用以下公式抽象表示:
G = (V, E)
其中,V 代表任务节点的集合,E 代表任务间依赖关系的有向边集合。对于任意边 (u, v) ∈ E,表示任务 u 必须在任务 v 开始之前成功完成。
在代码中,一个简单的任务依赖可以这样定义(以伪代码示意):
task_a = PythonOperator(task_id='extract_data', ...)
task_b = PythonOperator(task_id='transform_data', ...)
task_c = PythonOperator(task_id='load_data', ...)
# 定义依赖:A -> B -> C
task_a >> task_b >> task_c
聚焦行业标准:Apache Airflow 🌪️
理论之后是实践。目前业界最主流的编排工具是Apache Airflow,因此我们将重点学*它。
Airflow允许你使用Python代码将工作流定义为DAG。它的核心优势在于“管道即代码”、丰富的算子库、可扩展的架构以及强大的Web UI用于监控和运维。在本周的实验环节,你将亲自使用Airflow来构建和管理数据管道。
以下是使用Airflow时通常会涉及的几个关键组件:
- DAG:定义工作流的Python文件,包含了任务集合及其依赖关系。
- Operator:描述单个任务执行逻辑的模板,例如
BashOperator用于执行Shell命令,PythonOperator用于执行Python函数。 - Task:Operator的一个实例,是DAG中的一个具体节点。
- Task Instance:Task的一次特定运行,具有状态(如成功、失败、运行中)。
- Scheduler:Airflow的核心服务,负责按照DAG定义和调度计划触发Task Instance。
- Web Server:提供图形化界面,用于查看DAG、监控任务状态、触发运行等。
总结 📚
本节课中我们一起学*了数据工程第四周的核心主题——编排。


我们首先明确了编排与数据运维(DataOps)中自动化、可观测性支柱的紧密联系。接着,回顾了编排工具从手工脚本到现代平台(如Airflow)的演进历程。然后,探讨了编排的基本原理,特别是基于有向无环图(DAG)的任务调度与管理。最后,我们将焦点对准了行业标准的Apache Airflow平台,概述了其核心概念与组件,为接下来的动手实验奠定了基础。编排是协调复杂数据管道、确保其可靠高效运行的关键技能。
128:编排工具出现前的数据管道自动化 🕰️

在本节课中,我们将学*在现代化的编排工具出现之前,数据工程师是如何自动化运行数据管道的。我们将重点介绍使用 Cron 进行任务调度的传统方法,并分析其优缺点。
概述:什么是数据管道自动化?
在深入探讨编排工具之前,我们先退一步,了解一下如何在没有这些工具的情况下设置和运行数据管道。自动化数据管道(或任何软件任务集)最简单、最传统的方法是建立一系列 Cron 作业。
Cron 是一个命令行工具,最早出现于 20 世纪 70 年代,用于在指定的日期和时间执行特定命令。
Cron 作业详解
要使用 Cron 调度任务,你需要编写一个称为 Cron 作业 的命令或条目。其基本结构是:指定五个由空格分隔的数字,后面跟着你想要调度的命令。
Cron 作业的结构如下所示:
* * * * * command_to_execute
从右到左,这五个数字分别代表:
- 分钟 (0-59)
- 小时 (0-23)
- 日 (1-31)
- 月 (1-12)
- 星期几 (0-6,其中 0 代表星期日)
你还可以使用星号 * 代替任何一个数字,表示对该字段没有限制。
例如,以下 Cron 作业:
0 0 1 1 * echo “Happy New Year”
这行命令会在每年 1 月 1 日的午夜零点,在运行该命令的计算机终端上打印 “Happy New Year”。前两个 0 表示第 0 小时的第 0 分钟(即午夜),接下来的 1 1 表示一月的第一天,而星期几字段的 * 表示不关心具体是星期几。
使用 Cron 调度数据管道任务
那么,如何用 Cron 来调度数据管道中的任务呢?我们来看一个假设的例子。
假设你有一个数据管道,需要从 REST API 摄取数据。你希望每晚午夜执行一次摄取操作,并且有一个名为 ingest_from_rest_api.py 的 Python 脚本来完成此步骤。
在这种情况下,你可以编写如下 Cron 作业:
0 0 * * * python ingest_from_rest_api.py
这里的 0 0 表示在午夜执行,其他位置的 * 表示无论日期、月份或星期几都执行。
接下来,你可能需要对 API 数据进行一些即时清洗或处理。假设你有另一个 Python 脚本 transform_api_data.py 来执行此步骤,并且你知道从 API 摄取所有新数据总是花费不到一小时。
那么,你可以将下一步(即时转换)设置为每天凌晨 1 点运行,Cron 作业如下:
0 1 * * * python transform_api_data.py
同时,假设你还需要在每晚午夜从数据库摄取数据。那么你需要另一个 Cron 作业:
0 0 * * * python ingest_from_database.py
最后,你可能希望将转换后的 API 数据与数据库数据合并。你可以再设置一个 Cron 作业,例如在每天凌晨 2 点运行,以确保它在前面的作业完成后才开始:
0 2 * * * python combine_api_and_database.py
通过这种方式,你可以编写所有必需的 Cron 作业,精心安排它们的执行时间,以顺序方式实现整个管道。这种方法被称为 点对点调度,在编排工具出现之前,许多数据管道正是通过这种方式实现自动化的。事实上,至今许多简单的数据管道仍然采用这种方式。
Cron 方法的局限性
需要明确的是,我并非建议你放弃编排工具而只用 Cron 作业来设置数据管道。这种设置方式存在许多可能导致失败的问题。
例如,如果一个任务运行失败、耗时超出预期或产生了意外结果,你的整个管道都可能失败。如果没有实现测试和调试来确定问题所在,你基本上无法准确知道它是如何或为何失败的。
更糟糕的是,由于没有任何内置的监控或警报来告诉你运行状况,你可能直到下游利益相关者来找你,询问为什么数据看起来不对劲时,才会发现故障。
为什么还要了解 Cron?

既然不推荐,为什么还要讨论 Cron 调度呢?
首先,对于理解数据管道自动化的含义来说,这是一种非常直观的方式。对于一些简单的任务,Cron 作业可以工作得很好,例如需要定期执行且没有下游依赖的数据下载任务。
其次,如果你正处于原型设计阶段,正在测试数据管道的各个方面,使用 Cron 可以是一种快速、简单的入门方式。
总结
本节课中,我们一起学*了在现代化编排工具普及之前,如何使用 Cron 进行数据管道的任务调度。我们了解了 Cron 作业的基本语法,并通过一个例子模拟了数据管道的调度过程。同时,我们也认识到这种点对点调度方法在错误处理、任务依赖和监控告警方面的局限性。

在接下来的视频中,我们将总体介绍编排工具,探讨它们*年来的发展,并开始学*如何使用 Airflow 来编排你的数据管道。
129:编排工具的演变 🚀
在本节课中,我们将学*数据编排工具的发展历程。编排是数据处理中的关键能力,我们将了解它如何从仅限大公司使用,发展到如今拥有多种开源和托管解决方案。课程将重点介绍Apache Airflow的崛起、其优势与不足,并概览其他新兴的编排工具。
编排的早期阶段
编排长期以来一直是数据处理的关键能力。但在过去十年左右的时间里,编排实际上只对最大的公司开放。这是因为当时尚不存在开源或托管的编排工具,构建自己的内部解决方案既复杂又昂贵。
开源编排工具的兴起
在21世纪后期,情况开始改变。Facebook开发了一个名为Dataswarm的内部工具,他们至今仍在使用。另一个名为Apache Oozie的工具在2010年代变得非常流行,但它设计用于在Hadoop集群内工作,在更异构的环境中更难使用。
受这些早期工具(特别是Dataswarm)的启发,Airbnb在2014年推出了Airflow,它已成为当今行业标准的编排工具。目前还有许多其他编排工具正在开发中,编排领域的格局无疑将在未来继续演变。
为何聚焦于Airflow
在整个课程中,我们大部分时间都主动避免过于深入地讨论任何特定的工具或技术。相反,我的目标是专注于那些无论你在哪里担任数据工程师都将广泛适用的技能和知识。
然而,在某些情况下,我会为一个你很可能在工作中使用的工具或技术破例,Airflow就是这样一个工具。目前,在编排方面,使用Airflow的团队比使用任何其他工具的团队都多。因此,这是招聘人员正在寻找的技能组合。
话虽如此,Airflow并非没有缺点。我对编排领域出现的一些其他较新的开源工具感到兴奋,因此我也会提到其中的几个。
Apache Airflow的诞生与优势
Airflow由Maxime Beauchemin和Airbnb的其他合作者开发。他们主要致力于满足自己内部的数据编排需求。然而,从一开始,他们就将Airflow构建为一个非商业的开源项目,愿景是他们为满足Airbnb内部需求而开发的工具,对其他面临类似挑战的团队也有用。
该框架迅速在Airbnb之外获得了巨大的关注度,于2016年成为Apache孵化器项目,并于2019年成为完整的Apache赞助项目。
如今,Airflow作为一个编排平台提供了许多优势,这主要得益于其在开源市场的主导地位。Airflow使用Python编写,使其几乎可以扩展到任何可以想象的用例。
此外,Airflow开源项目非常活跃,提交率高,对错误和安全问题的响应时间快。与数据工程中的许多开源工具一样,Airflow也可以通过包括AWS、GCP和Astronomer在内的多家供应商作为托管服务提供,适合那些寻求更全面支持的用户。
其他编排工具概览
尽管如此,Airflow肯定不是唯一的编排工具。在可扩展性、确保数据完整性和流式处理管道等方面,Airflow要么没有解决这些问题,要么有巨大的改进空间。
存在许多其他有趣的开源编排项目,例如Luigi和Conductor。较新的工具如Prefect、Dagster和Mage也获得了关注,因为它们旨在模仿Airflow核心设计的最佳元素,同时在关键领域进行改进。
以下是几个新兴工具及其特点:
- Prefect:提供了比Airflow更具可扩展性的编排解决方案。
- Dagster 和 Mage:在其他功能中,为数据质量测试和数据转换提供了内置能力。
- 其他工具:专注于为流式处理管道提供更好的编排支持。

总结与建议
我认为,在未来几年,这些较新的编排工具中的一个或多个完全有可能作为Airflow的替代品被广泛使用。根据你正在设置的管道类型,其中一个替代工具也可能更好地满足你的需求。
话虽如此,我目前的建议是学*Airflow,因为这是当今许多人正在使用的工具。但同时也要持续学*其他工具,并关注编排领域的新发展,以便在事物不断演变的过程中保持与时俱进。


本节课中,我们一起学*了数据编排工具从专有到开源的演变历程,深入了解了当前行业标准Apache Airflow的起源、优势与面临的挑战,并概览了Prefect、Dagster等新兴工具的特点。理解这一演变过程有助于我们选择适合当前需求的工具,并为未来的技术发展做好准备。
130:编排基础 🧭

在本节课中,我们将学*数据管道编排的核心概念。编排是协调和管理数据管道中多个任务自动执行的过程。与简单的定时调度相比,编排提供了更强大的功能,如任务依赖管理、错误处理和监控。
什么是编排?🤔
上一节我们介绍了使用Cron进行任务调度的基础。本节中我们来看看更高级的编排概念。
编排涉及一系列通用的概念和组件,无论你使用哪种工具来实现,这些概念都是相通的。虽然为数据管道设置恰当的编排比简单的Cron调度带来更多的运维开销,但它也带来了设置任务依赖、获取警报以及在出现意外时创建备用计划的能力。
有向无环图 📊
在之前的课程中,我们多次提到,数据管道通常被可视化为一种称为有向无环图的结构,简称 DAG。
你可以将每个任务视为图中的一个节点,用图论的术语来说,连接这些节点的箭头称为边。你可以看到数据在图的节点或任务之间只朝一个方向流动。因此,你的数据管道有一个整体的方向感,图中没有循环或回路。这就是图被称为“有向”和“无环”的含义。
记住,使用Cron调度时,我们也可以设置这样的管道。但如果一个任务的运行时间比预期长,而下一个任务在前一个任务完成之前就启动了,这可能会破坏下游的所有环节。
任务依赖关系 ⛓️
现在,在编排中,这就是依赖关系概念的用武之地。例如,你可以在这个管道中的任务之间建立依赖关系,要求前一个任务完成后,下一个任务才能开始。
大多数编排框架允许你,并且事实上要求你将数据管道定义为DAG。在许多情况下,它们还包含一个用户界面,你可以在其中可视化你的DAG,以及调试、故障排除和监控你的数据管道。
在Airflow中定义DAG 🐍
在Airflow中,你将通过编写Python代码以编程方式定义你的DAG。
以下是定义数据管道中所有任务和依赖关系的代码示例:

# 示例:在Airflow中定义一个简单的DAG
from airflow import DAG
from airflow.operators.python_operator import PythonOperator
from datetime import datetime

def my_task_function():
# 你的任务逻辑在这里
print("任务执行中...")
# 定义DAG
dag = DAG(
'my_example_dag',
schedule_interval='@daily', # 每天运行
start_date=datetime(2023, 1, 1),
catchup=False
)

# 定义任务
task = PythonOperator(
task_id='my_task',
python_callable=my_task_function,
dag=dag
)
你可以使用Airflow UI来可视化你定义的管道,它看起来像这样。在这里,你可以触发DAG运行、监控任务进度、可视化之前代码中定义的DAG,并排查任何问题。
运行条件与触发器 ⏰
当你将管道定义为DAG后,你可以设置DAG应该运行的依赖关系或条件。这些条件可以是基于时间的(如果你想在特定计划上运行DAG),也可以是基于事件的(如果你想基于事件触发DAG)。
例如,在Airflow中,你可以通过将参数schedule设置为daily来定义一个应该在每天午夜运行的DAG。要使你的DAG基于事件触发,你可以使用相同的schedule参数,但以不同的方式定义它。更具体地说,通过定义一个数据集的名称,你可以在数据更新时安排DAG运行。
你也可以让DAG的一部分等待某个外部过程完成。例如,某个外部过程将把一个CSV文件上传到S3存储桶,然后你可以设置你的DAG等待该文件在S3存储桶中出现。
以下是你可以如何在Airflow中定义一个名为“传感器”的任务,用于监听文件上传事件:
from airflow.providers.amazon.aws.sensors.s3 import S3KeySensor

wait_for_file = S3KeySensor(
task_id='wait_for_my_file',
bucket_key='s3://my-bucket/myfile.csv',
aws_conn_id='aws_default',
mode='poke',
poke_interval=60, # 每60秒检查一次
timeout=600, # 超时时间600秒
dag=dag
)



以这个任务开始的DAG部分将不会运行,直到myfile.csv在S3存储桶中可用。

监控、日志与数据质量检查 🔍
你还可以为DAG中的任务设置监控、日志记录以及警报。例如,你可能希望在特定任务失败时收到警报,或者监控一个任务运行了多长时间。
你还可以在此过程中设置数据质量检查,以确保流经数据管道的数据符合你的期望。这可能包括检查诸如空值的种类、某些数值的范围,或者只是验证你摄取的数据模式是否符合预期。
# 示例:一个简单的数据质量检查任务(概念性)
def data_quality_check(**context):
# 从上游任务获取数据
data = context['ti'].xcom_pull(task_ids='previous_task')
# 执行检查,例如检查空值
if data.isnull().sum().sum() > 0:
raise ValueError("数据中存在空值,质量检查失败!")
# 检查数值范围
if not (data['value'].between(0, 100).all()):
raise ValueError("数值超出预期范围!")
print("数据质量检查通过。")

再次说明,我现在展示的所有内容都是在Airflow中进行的,但我演示的这些概念是你可以从任何编排平台中期望的功能。


总结 📝
本节课中我们一起学*了数据管道编排的基础知识。我们了解了有向无环图是定义管道任务和依赖关系的核心模型。我们探讨了如何通过设置任务依赖来确保执行顺序,以及如何基于时间或事件来触发DAG运行。我们还介绍了监控、警报和数据质量检查的重要性,这些都是构建健壮、可靠的数据管道的关键组成部分。
在接下来的几个视频中,我将逐步指导你在Airflow中设置数据管道编排的步骤。
131:Airflow核心组件 🧩

在本节课中,我们将学*Apache Airflow的核心架构与组件。理解这些组件如何协同工作,是构建和运行可靠数据管道的基础。
概述
在开始本周的第一个实验之前,我们将花一些时间介绍Airflow。通过本系列视频的学*,你将了解如何构建一个简单的Airflow有向无环图,并为第一个实验做好准备。
在这个视频中,我们将从Airflow的底层架构开始。当你在Airflow中编写DAG时,有多个组件在幕后协同工作,以自动运行你的DAG,检查任务间的依赖关系是否满足,并将DAG的状态传递到Airflow用户界面。
Airflow核心架构
下图展示了Airflow的主要组件,包括运行Airflow用户界面的Web服务器、调度器、工作节点、元数据数据库以及DAG目录。


当你创建Airflow环境时,无论是直接安装Airflow还是使用Airflow托管服务,所有这些组件都将存在于你的设置中。你将主要与DAG目录和用户界面交互,其余组件将在后台运行。
核心组件详解
上一节我们介绍了Airflow的整体架构,本节中我们来详细看看每个核心组件的作用。
DAG目录
DAG目录是一个文件夹,用于存储定义DAG的Python脚本。这个DAG目录连接到运行Airflow UI的Web服务器。因此,对于你创建并添加到DAG目录的任何DAG,你将自动能够在UI中可视化它。
不仅如此,你还可以使用UI来监控、手动触发和排查DAG及其内部任务的行为。
调度器与执行器
但你并不总是需要从UI手动触发DAG。你也可以基于时间表或事件来触发它们,这需要借助Airflow的调度器组件。
调度器默认每分钟一次,持续监控你在DAG目录中定义的所有DAG及其对应任务。调度器检查是否有任何任务应该被触发,这取决于特定的时间表或检查其依赖项是否完成。
一旦调度器识别出一个准备触发的任务,它会将该任务推送到队列中,并使用执行器来管理任务的执行。执行器是调度器的一部分,它从队列中提取任务,并将它们发送给运行任务的工作节点。
以下是调度器检查任务的简化逻辑:
if task.dependencies_met and (task.schedule_triggered or event_triggered):
scheduler.queue_task(task)
工作节点与状态流转
当调度器触发一个给定任务时,你将看到任务的状态从“已调度”变为“已排队”。然后,一旦工作节点执行该任务,你将看到状态变为“运行中”,最终变为“成功”或“失败”。
调度器和工作节点将任务的状态以及DAG的状态存储在元数据数据库中。随后,Web服务器从数据库中提取这些状态,并在UI中显示给你。
托管服务示例:Amazon MWAA
以上是对Airflow核心组件的快速介绍。当你选择Airflow的托管服务时,例如Amazon Managed Workflows for Apache Airflow,所有这些组件都将自动为你创建和管理。
你可以在架构图中看到Amazon MWAA如何在云上组织Airflow的核心组件。




例如,它使用Amazon S3存储桶作为DAG目录,使用Aurora PostgreSQL数据库作为元数据数据库。其他组件包括AWS网络组件和支持数据安全、环境日志记录与监控的额外AWS服务。
实验准备
在本周的实验中,你将首先被引导设置Airflow环境。然后,你将使用Cloud9 IDE将DAG编写为Python脚本,将它们上传到S3存储桶,最后打开UI来查看创建的DAG。


理解Airflow环境以及组件之间如何交互,将帮助你在问题发生时进行排查。
总结
本节课中我们一起学*了Apache Airflow的核心组件及其协作方式。我们了解了DAG目录、Web服务器、调度器、执行器、工作节点和元数据数据库各自的作用,并预览了在托管服务(如Amazon MWAA)中的具体实现。理解这些是有效使用和排查Airflow的基础。请继续学*下一个视频,我们将浏览Airflow UI的一些功能。
132:Airflow用户界面(UI) 🖥️

在本节课中,我们将学*Apache Airflow的核心交互工具——用户界面(UI)。你将了解如何通过UI监控工作流、查看历史运行记录以及排查管道问题。
DAG视图概览
当你打开Airflow UI时,首先会进入DAG视图页面。此页面列出了你在DAG目录中创建的所有有向无环图(DAG)。
以下是DAG视图中显示的基本元数据:
- DAG ID: DAG的唯一标识符。
- 标签: 为DAG分配的自定义标签。
- 所有者: DAG的负责人。
- 调度计划: DAG的运行频率。
- 最*运行时间: DAG上次执行的时间。
- 运行状态: 显示当前排队、运行中、成功或失败的DAG运行数量。
对于每个DAG,还有一个更详细的视图,可以查看所有任务的状态,包括排队、运行中、成功、失败、跳过、等待重试或重新调度的任务数量。
在DAG视图中,你可以进行以下交互操作:
- 使用左侧的开关暂停或取消暂停一个DAG。
- 点击右侧按钮手动触发一个DAG运行,或将其从视图中删除。
- 根据状态或自定义标签筛选显示的DAG。

点击DAG ID可以获取该DAG的详细信息。
网格视图详解
点击DAG ID后,你将进入网格视图。此视图提供了每个DAG运行及其对应任务实例的详细信息。
视图左侧是一个条形图,展示了该DAG的所有历史运行记录。条形的高度代表每次运行的持续时间,颜色代表运行状态(例如,红色表示失败,绿色表示成功)。对于每次运行,你还可以查看所有独立任务实例的结果。
视图右侧包含四个标签页:详情、图形、甘特图和代码。
详情标签页
详情标签页显示历史DAG运行的详细信息,例如:
- 总运行次数
- 成功运行次数
- 失败运行次数
- DAG运行的最短、平均和最长持续时间
这些指标可以作为评估管道健康状况的依据。要查看特定DAG运行(例如失败的那次)的详细信息,可以在左侧条形图中选中它,然后在右侧查看其具体信息。
图形标签页
图形标签页以可视化方式展示你的DAG结构,帮助你理清任务间的依赖关系是否正确配置。当前看到的DAG可视化图不与任何特定运行实例对应。
如果你想查看特定DAG运行(例如失败的那次)中各个任务的状态,可以在左侧点击该次运行。此时,图中的每个任务会根据其在该次运行中的状态进行颜色编码。
假设你想了解任务“extract_from_API”失败的原因。点击该任务,顶部会出现一个名为日志的新标签页,其中包含了所有错误信息。根据这些信息,你可以尝试修复DAG代码。
修复完成后,如果需要重试该任务,可以点击清除任务。如果该任务成功运行并完成,管道中所有剩余的任务也将随之运行。
甘特图标签页
甘特图标签页展示了特定DAG运行中每个任务的排队持续时间(灰色部分)和运行持续时间。当你需要识别管道中的性能瓶颈时,这个图表会非常有用。
代码标签页
代码标签页显示对应DAG的源代码。请注意,这不是你编辑DAG代码的地方,但你可以通过此标签页确保UI中显示的代码与DAG目录中的代码保持一致。


课程总结

本节课我们一起探索了Apache Airflow用户界面(UI)的核心功能。我们学*了如何在DAG视图中总览和管理所有工作流,以及如何在网格视图中通过详情、图形、甘特图和代码等标签页深入分析每次DAG运行的细节、任务依赖、执行时间线和源代码。这些功能是监控工作流状态、排查问题和管理数据管道的基础。在下一课中,我们将实际动手构建一个简单的DAG。
133:使用Airflow创建DAG 🛠️

在本节课中,我们将学*如何使用Airflow的核心概念,如DAG和操作器类,来构建一个简单的有向无环图。我们将通过一个ETL过程的例子,详细说明创建DAG的每个步骤。
概述
我们将创建一个代表ETL过程的DAG,该过程包含三个任务:提取、转换和加载。本教程将重点介绍DAG的结构设置,而非每个任务的具体实现细节。

创建DAG实例
首先,我们需要创建一个DAG实例。这需要导入必要的包并使用上下文管理器来定义DAG。
from airflow import DAG
from datetime import datetime
with DAG(
dag_id='my_first_dag',
description='一个简单的ETL流程示例',
tags=['data_engineering_team'],
schedule='@daily',
start_date=datetime(2023, 1, 1),
catchup=False
) as dag:
# 任务将在此处定义
以下是DAG实例的关键参数说明:
dag_id:在Airflow UI中用于识别DAG的唯一名称。description:DAG的描述,鼠标悬停在DAG名称上时会显示。tags:标签列表,可用于在UI中过滤DAG。schedule:定义DAG的运行时间,可以使用Cron表达式(如0 8 * * *)或预设值(如@daily)。start_date:DAG首次执行的日期。catchup:布尔值参数。如果设置为True,当DAG从暂停状态恢复时,调度器会为错过的执行间隔触发DAG运行。
定义DAG任务
上一节我们介绍了如何创建DAG实例,本节中我们来看看如何定义其中的任务。我们需要使用Airflow的操作器来定义每个任务。
操作器是Python类,用于封装任务的逻辑或数据在管道中的处理方式。以下是一些常用的操作器:
- PythonOperator:用于执行包含任务逻辑的Python脚本。
- BashOperator:用于执行Bash命令。
- EmptyOperator:用于组织DAG,例如标记管道的开始和结束。
- EmailOperator:用于通过电子邮件发送通知。
- 传感器:一种特殊类型的操作器,可用于使DAG由事件驱动。
在本例中,我们将使用PythonOperator来定义三个任务。

from airflow.operators.python import PythonOperator
def extract_data():
print("执行数据提取")
def transform_data():
print("执行数据转换")
def load_data():
print("执行数据加载")
# 在DAG上下文管理器中定义任务
extract_task = PythonOperator(
task_id='extract',
python_callable=extract_data
)
transform_task = PythonOperator(
task_id='transform',
python_callable=transform_data
)

load_task = PythonOperator(
task_id='load',
python_callable=load_data
)
每个PythonOperator实例需要两个主要参数:
task_id:任务的名称,用于在Airflow UI中引用该任务。python_callable:一个Python函数,包含该任务需要执行的操作。
定义任务依赖关系
现在我们已经定义了DAG和任务,接下来需要指定任务之间的依赖关系,即任务的执行顺序。
我们可以使用位移运算符来定义依赖关系:
extract_task >> transform_task >> load_task
这行代码意味着extract_task必须在transform_task开始之前执行并完成,而transform_task必须在load_task开始之前执行并完成。
总结
本节课中我们一起学*了如何使用Airflow构建一个简单的DAG。我们涵盖了以下步骤:


- 创建DAG实例并配置其参数(如
dag_id,schedule,start_date)。 - 使用
PythonOperator等操作器定义DAG中的各个任务。 - 通过位移运算符定义任务之间的执行顺序。
完成DAG脚本后,您可以将其上传到Airflow的DAG目录(例如S3存储桶),然后在Airflow UI中检查和监控其运行状态。
134:XCom与变量 🚀

概述
在本节课中,我们将学*Airflow的两个核心功能:XCom(用于任务间传递小数据)和变量(用于管理全局配置)。我们将了解它们的工作原理、适用场景以及如何在代码中实现。
回顾:任务间数据传递的现有方法
在上一节中,我们通过实验构建了DAG,并与Airflow UI交互,解决了DAG中的问题。现在,我们准备探索Airflow的更多功能,并了解使用Airflow实现编排的最佳实践。
在之前的实验中,我们实现了一个DAG。在任务get_random_book中,我们从书籍API请求随机书籍的数据,然后将数据存储在S3桶中,供后续任务使用。这种方法通过中间存储(S3桶)在任务间传递数据。当需要在任务间传递大型数据集时,此方法很合适。
引入XCom:轻量级数据共享

但对于少量数据,有另一种称为XCom的方法可以使用。
XCom是“cross-communication”的缩写,是Airflow中用于在任务间共享数据的关键功能。它设计用于在给定DAG的任务之间传递信息,例如元数据、日期、单值指标或简单计算结果。
在任务中,如果您有一个值想在另一个任务中使用,可以将其存储在XCom变量中。
XCom的工作原理
以下是XCom的核心操作:
- 存储数据(推送):在任务中调用
xcom_push方法,将数据推送到元数据数据库。 - 提取数据(拉取):在任何任务中调用
xcom_pull方法,提取存储在XCom变量中的值。
每个XCom包含以下信息:变量名称(键)、存储的值、创建时间戳、所属DAG ID以及生成该变量的任务ID。

实战示例:使用XCom传递指标
让我们看一个例子。这里的DAG由两个任务组成。
- 任务一:
extract_metric:连接API,发送请求获取数据,然后基于返回数据计算一个指标。 - 任务二:
print_data:打印第一个任务计算的指标。
由于需要在第一个和第二个任务之间传递数据,我们可以在这里使用XCom功能。第一个任务使用函数extract_from_api,这是需要调用xcom_push的地方。第二个任务使用函数print_data,这是需要调用xcom_pull的地方。
深入代码:推送(Push)数据
这是extract_from_api函数的代码。
def extract_from_api(**context):
# 调用REST API,获取美国地区最新的40个远程数据工程师职位发布
# 计算其中要求高级数据工程师的职位比例
senior_ratio = compute_senior_ratio(api_response)
# 将计算出的值存储在XCom变量中
task_instance = context['ti']
task_instance.xcom_push(key='senior_ratio', value=senior_ratio)

我调用了一个招聘网站的REST API,获取美国地区最新的40个远程数据工程师职位发布。然后,我计算了其中要求高级数据工程师的职位比例。现在,我想将这个值传递给第二个任务。
首先,需要通过调用xcom_push方法将获得的值存储在XCom变量中。此方法需要两个参数:变量的键和计算出的值。xcom_push是与任务实例关联的方法。这意味着您需要一个任务实例(左侧)才能调用该方法。任务实例是代表当前运行任务的对象。
Airflow有一组内置变量,包含当前运行任务的信息,包括任务实例。此信息存储在名为airflow context的字典中,您需要将其作为参数传递给extract_from_api函数。要从上下文字典中获取任务实例对象,可以使用context[‘ti’],其中ti代表任务实例。然后,您可以在获得的任务实例对象上调用xcom_push。
深入代码:拉取(Pull)数据
然后,要在第二个任务中访问XCom变量中计算出的比例,需要调用xcom_pull。
def print_data(**context):
# 提取XCom变量中存储的值
task_instance = context['ti']
senior_ratio = task_instance.xcom_pull(key='senior_ratio', task_ids='extract_metric')
print(f"Senior Data Engineer Ratio: {senior_ratio}")
传入变量的键和创建XCom变量的任务ID。与在extract_from_api函数中所做类似,您也需要一个任务实例才能调用xcom_pull。因此,将上下文字典作为参数传递给print_data函数,然后使用context[‘ti’]再次获取任务实例,最后在此对象上调用xcom_pull方法。
运行DAG时,您可以通过单击Airflow UI中的“Admin”,然后导航到“XComs”来检查您的XCom。这里可以看到我们刚刚创建的XCom变量及其对应的值。

重要注意事项:XCom的局限性
关于使用XCom,我想提醒您注意:XCom并非设计用于在任务间传递大型数据集(如数据帧),因为它们会降低DAG和元数据数据库的性能。如果您需要在任务间共享大型数据集,应遵循上一实验中的做法,使用S3等中间存储。
引入变量:管理全局配置
现在,让我们讨论另一个Airflow功能。以同一个DAG为例,如果您检查第一个任务的API请求,会发现某些参数(如count和geo)的值是硬编码的,这意味着它们直接包含在代码中。
但是,如果您不希望这些值是固定的呢?因为您可能需要在未来的DAG运行中更改它们,或者您想尝试多个值。您可以更新代码中的值,但这种方法可能容易出错,并且效率不高,特别是如果这些值在代码中重复多次。
与其在DAG或任务定义中包含硬编码值,不如在Airflow UI中创建全局变量,或在开发环境中创建环境变量,并在代码内部使用这些变量。
在Airflow UI中创建变量



让我们在Airflow UI中创建两个变量:一个用于帖子数量,另一个用于位置。
- 单击“Admin”选项卡,然后选择“Variables”选项,您将看到变量列表。
- 要创建新变量,可以单击加号,然后指定变量的键和值。
- 对于位置变量,我将感兴趣的国家/地区列表指定为JSON对象。
- 对于帖子数量变量,我将其值赋为20。
在代码中使用变量
要在代码内部使用这些变量,您需要导入Variable模块。
from airflow.models import Variable
def extract_from_api(**context):
# 检索变量
num_posts = Variable.get("number_of_posts") # 返回字符串 "20"
locations = Variable.get("location", deserialize_json=True) # 返回反序列化的字典
# 在API请求中使用变量
# ... 使用 num_posts 和 locations 构建请求 ...
然后在代码内部,使用Variable.get()方法来检索帖子总数和位置列表。如果您希望此方法将JSON对象作为字典而不是字符串返回,请将参数deserialize_json设置为True。



总结与下节预告
在本节课中,我们一起学*了Airflow的两个重要特性:
- XCom:用于在任务间高效传递少量数据或元数据,通过
xcom_push和xcom_pull方法实现。 - 变量:用于集中管理配置参数,避免代码硬编码,通过Airflow UI创建并通过
Variable.get()方法调用。
在下一个实验中,您将练*在Airflow UI中创建变量,使用Airflow内置变量,并使用XCom变量在任务间传递数据。在进行下一个实验之前,请务必查看本视频后的阅读材料,其中列出了编写DAG的一些最佳实践,以确保您的代码高效、可读且可复现。
135:Airflow TaskFlow API 🚀

在本节课中,我们将学*Airflow的TaskFlow API。这是一种新的编程范式,旨在让编写DAG(有向无环图)变得更简单、更简洁,特别是当DAG大量使用Python函数时。我们将通过对比传统的操作符范式,来理解TaskFlow API的优势和用法。
概述
到目前为止,我们定义DAG的方式是实例化一个DAG对象,并使用Python操作符来创建任务实例,这被称为传统范式。Airflow 2.0引入了另一种范式,称为TaskFlow API。这个新范式的目标不是取代传统范式,而是让编写DAG更容易、更简洁。
TaskFlow API依赖于装饰器的使用,它帮助创建DAG及其任务,同时简化了代码编写。需要澄清的是,TaskFlow API中的“API”与REST API无关,你可以将其视为一个提供更友好编程体验的接口。
使用TaskFlow API定义DAG
上一节我们介绍了TaskFlow API的基本概念,本节中我们来看看如何使用它来定义一个DAG。
在传统范式中,我们显式调用DAG构造函数。而在TaskFlow API中,你可以使用@dag装饰器,并将DAG参数传递给装饰器,然后将DAG的内容定义为一个Python函数。
from airflow.decorators import dag, task
@dag(
schedule_interval='@daily',
start_date=datetime(2023, 1, 1),
catchup=False
)
def my_dag():
# 任务定义将放在这里
pass
# 必须调用DAG函数,否则DAG不会出现在Airflow UI中
dag_instance = my_dag()
@dag装饰器的作用是隐式调用DAG构造函数来创建DAG实例。函数名将用作DAG ID,在Airflow UI中标识该DAG。
使用TaskFlow API创建任务
在传统范式中,我们使用PythonOperator来创建任务。而在TaskFlow API中,我们使用@task装饰器来定义任务。
以下是创建任务的步骤:
- 使用
@task装饰器标记一个Python函数。 - 函数名将自动用作任务ID。
- 装饰器会隐式调用PythonOperator,从而简化代码。


@dag(...)
def my_pipeline():
@task
def extract_data():
# 提取数据的逻辑
data = fetch_from_source()
return data # 返回值会自动推送到XCom
@task
def transform_data(data):
# 转换数据的逻辑,`data`参数来自上一个任务的XCom
transformed = process(data)
return transformed
@task
def load_data(transformed_data):
# 加载数据的逻辑
save_to_destination(transformed_data)
要使用@task装饰器,需要从airflow.decorators中导入。
定义任务间的依赖关系
定义了任务之后,我们需要指定它们的执行顺序。在TaskFlow API中,我们仍然使用相同的位移运算符(>>)来定义依赖关系,但这次我们调用代表每个任务的函数。
@dag(...)
def my_pipeline():
extract = extract_data()
transform = transform_data(extract)
load = load_data(transform)
# 定义依赖关系:extract -> transform -> load
extract >> transform >> load
或者,你也可以将函数调用和依赖关系定义合并成一行:
extract_data() >> transform_data() >> load_data()

这种方式与传统范式达到的结果相同,但TaskFlow API让你的代码更简洁。
在TaskFlow API中使用XCom传递数据
XCom是Airflow中用于任务间传递小量数据的机制。我们来看看如何在TaskFlow API中使用它。
在传统方法中,你需要在函数中调用xcom_push来存储数据,然后在需要使用数据的任务函数中调用xcom_pull。
使用TaskFlow API,这个过程被大大简化:
- 推送数据:只需在任务函数中使用
return语句。返回值会自动存储为XCom变量。 - 拉取数据:在后续任务的函数中,直接将其定义为一个输入参数。Airflow会自动将前一个任务的XCom值传递给它。
@dag(...)
def my_pipeline():
@task
def extract_from_api():
data = call_external_api()
return data # 自动推送到XCom,键为‘return_value’
@task
def process_data(data): # `data`参数自动从extract_from_api任务的XCom拉取
result = perform_calculation(data)
return result
# 定义依赖并传递数据
raw_data = extract_from_api()
processed_result = process_data(raw_data)
你仍然可以在TaskFlow任务中显式使用xcom_pull和xcom_push,例如通过访问Airflow上下文,但这通常不是必需的。




混合使用传统范式与TaskFlow API

需要特别注意的是,@task装饰器并不能替代所有类型的操作符。因此,根据你的用例,你可能仍然需要在同一份代码中结合使用两种范式。
例如,你可能有一个使用PythonOperator的复杂任务,同时其他任务使用@task装饰器。你仍然可以使用位移运算符来定义它们之间的依赖关系。
from airflow.operators.python import PythonOperator
@dag(...)
def mixed_dag():
@task
def taskflow_task():
return “Hello from TaskFlow”
def traditional_function(**context):
value = context[‘ti’].xcom_pull(task_ids=‘taskflow_task’)
print(f“Got: {value}”)
traditional_task = PythonOperator(
task_id=‘traditional_task’,
python_callable=traditional_function
)
# 定义依赖
taskflow_task() >> traditional_task
在开始最后一个实验之前,请务必查看本视频后提供的关于分支(Branching)的阅读材料,它将帮助你在实验中创建动态管道。
总结

本节课中,我们一起学*了Airflow的TaskFlow API。我们了解到:


- TaskFlow API是Airflow 2.0引入的一种新范式,使用
@dag和@task装饰器来简化DAG和任务的定义。 - 与传统范式相比,TaskFlow API减少了需要跟踪的名称(如task_id),并通过隐式调用操作符和自动处理XCom使代码更简洁。
- 我们学*了如何使用装饰器定义DAG和任务,以及如何设置任务间的依赖关系。
- 我们探讨了如何在TaskFlow API中优雅地使用XCom在任务间传递数据,通常只需使用
return语句和函数参数。 - 最后,我们认识到TaskFlow API与传统范式可以共存,根据实际需求混合使用能提供最大的灵活性。
完成实验后,Morgan将带你了解在AWS上编排数据工程任务的一些可选方案。
136:AWS上的编排 🚀

在本节课中,我们将学*在AWS云平台上编排数据工程任务的不同选项。我们将介绍Apache Airflow的几种部署方式,以及AWS原生的编排服务,帮助你根据项目需求选择最合适的工具。
上一节我们介绍了使用Airflow编排数据管道的基础知识。本节中,我们来看看在AWS环境中,你有哪些具体的编排工具选择。
在AWS上运行Airflow的选项
首先,对于Airflow本身,在AWS上托管和运行工作流有多种方式。
最需要手动操作的方式是,你可以在Amazon EC2实例上或容器中运行开源版本的Airflow。在本周的实验中,你使用的就是运行在EC2实例上一组容器中的开源Airflow。
采用这种方法,你可以完全控制Airflow环境的配置和扩展。但这同时也意味着你需要承担更多责任,因为你必须自己管理所有底层基础设施和集成。
正如我之前所说,在选择构建数据管道的工具和服务时,通常需要在便利性与控制力之间进行权衡,并考虑特定用例的需求。
如果你在AWS上运行Airflow的目标不是追求控制力,而是优化便利性,那么你可以选择使用Amazon Managed Workflows for Apache Airflow(MWAA)。这是一项托管服务,它为你运行Airflow,并处理底层基础设施的供应和扩展等任务。
当你使用MWAA时,它会为你设置一个Apache Airflow环境,使用的用户界面和开源代码与你从互联网上下载的相同。
下图展示了MWAA的架构。你现在熟悉的调度器和工作器组件托管在AWS Fargate的容器中,它们可以访问托管在Amazon Aurora上的Airflow元数据数据库,用于存储任务状态和DAG的状态。


MWAA还集成了其他AWS服务。例如,MWAA将Airflow日志和指标发布到Amazon CloudWatch,使用Amazon S3作为存放Python脚本的DAG目录,并使用AWS密钥管理服务对数据进行加密。


除了MWAA,AWS上还有其他支持类似功能的编排服务。
AWS原生编排服务
以下是AWS提供的其他编排选项。
AWS Glue工作流 与Airflow类似,它允许你创建、运行和监控复杂的ETL工作流,其中多个Glue作业和爬虫程序可能相互依赖。一个Glue工作流包含作业、爬虫程序和触发器。
你可以在构建工作流之前先构建这些组件,然后使用AWS Glue控制台以可视化方式构建并查看工作流图的结构。你可以基于触发器运行这些Glue工作流,触发器可以是按计划、按需或来自Amazon EventBridge的事件。
AWS Step Functions 是AWS上的另一个编排选项。Step Functions允许你将多个AWS服务和状态编排成称为状态机的工作流。
状态机中的状态可以执行各种操作。状态可以是任务,例如处理数据的Lambda函数、转换数据集的Glue作业或运行容器化应用程序的ECS任务,仅举几例。状态还可以根据其输入做出决策,执行基于这些输入的操作,然后将输出传递给其他状态。

因此,与Airflow类似,Step Functions旨在协调任务并管理它们之间的依赖关系,允许你定义涉及多个步骤或状态的复杂工作流。
如何选择编排工具
当需要在Airflow(托管版或开源版)、Step Functions、Glue工作流或其他完全不同的编排工具之间做出选择时,就像其他任何选择一样,最终将取决于你的需求以及你试图优化的目标。
基于Python DAG和插件生态系统的Airflow提供了很大的灵活性,适用于复杂的工作流。Step Functions提供了一个无服务器选项,具有广泛的原生AWS服务集成,这对于以AWS为中心的工作流可能是理想的选择。而AWS Glue工作流专为ETL流程设计,允许你在无服务器环境中编排Glue作业、爬虫程序和触发器。
正如Joe之前提到的,编排工具的格局正在迅速发展。

因此,除了练*使用Airflow等流行工具外,你最好的策略是随时了解替代工具和新兴工具的最新动态,以便在你未来的数据架构中做出最佳选择。
本节课中,我们一起学*了在AWS上编排数据工程任务的多种途径。我们探讨了Airflow的不同部署模式(从自我管理到全托管服务),并介绍了AWS Glue工作流和Step Functions这两种原生服务。理解这些工具的优缺点,将帮助你在构建数据管道时,根据对控制力、便利性、复杂度和云服务集成的需求,做出明智的技术选型。
137:第2课总结 🎉

在本节课中,我们将回顾数据工程专项课程第二课的核心内容。你已经完成了从高层次框架到具体技术实践的广泛学*,为成为一名成功的数据工程师奠定了坚实基础。
课程完成祝贺 🎊
恭喜你完成数据工程专项课程的第二课。至此,你已经完成了四门课程中的两门。实际上,考虑到你已经涵盖的大量内容,你的学*进度已远超一半。
课程内容回顾 📚
上一节我们介绍了数据工程生命周期的高层次框架,本节中我们来看看你在第二课中具体完成的工作。这些工作涵盖了从源系统、数据摄取到数据运维与编排的多个关键领域。
以下是你在本课程各周学*的主要内容:
-
第一周:源系统
- 探索了数据工程师将接触的各种源系统。
- 实践操作了关系型数据库、非关系型数据库以及对象存储。
-
第二周:数据摄取架构
- 深入研究了批处理与流式摄取架构的细节。
- 设置了从REST API进行批处理摄取,并使用Amazon Kinesis建立了流式摄取。
-
第三周:数据运维与自动化
- 在数据运维的背景下探讨了自动化、可观测性与监控。
- 使用Terraform开发了基础设施即代码。
- 使用Great Expectations实施了数据质量检查。
- 使用CloudWatch设置了监控与告警。

- 第四周:数据管道编排
- 在自动化、可观测性与监控方面更进一步。
- 使用Airflow为数据管道实现了编排功能。
学*成果与展望 🚀
综上所述,你已经涵盖了广泛的知识领域,并且在培养成为成功数据工程师的核心技能方面进展顺利。
展望未来,在下一门课程中,你将专注于如何在数据管道中使用现代存储系统和存储抽象。我们下一课再见。😊

本节课中我们一起学*了数据工程第二课的全部核心模块,包括源系统处理、批流摄取架构、数据运维自动化工具链以及管道编排。你已掌握了构建可靠数据管道的关键实践技能,为后续深入学*数据存储与查询做好了准备。
138:数据存储与查询概述 🗄️

在本课程中,我们将要学*数据工程专业化的第三个核心模块:数据存储与查询。完成前两门课程后,你已经对数据工程领域有了高层级的概览,并深入了解了源系统、数据摄取与编排。本节课程将聚焦于如何有效地存储数据,以及如何从存储中高效地查询数据。
上一节我们回顾了数据工程生命周期的基础,本节中我们来看看构成现代数据系统的基石——数据存储与查询技术。
课程内容概览 📋

欢迎来到数据工程专业化的第三门课程。在完成前两门课程后,你已经取得了丰硕的成果。
在第一门课程中,你获得了数据工程领域的高层级概述,包括数据工程生命周期——一个用于思考数据工程师工作的框架,并实践构建了数据工程解决方案。
在第二门课程中,你深入研究了源系统、数据摄取和编排。
凭借前两门课程,你已经为成为一名数据工程师积累了强大的知识和技能基础。
讲师介绍与课程预告 👨🏫
再次欢迎你,我是这些课程的讲师Jovies。很高兴再次见到你。或许你可以简要介绍一下学*者将在本课程中看到的内容。
当然,谢谢Andrew。本课程的前两周将全部关于数据存储。然后在第三周,我们将讨论查询。
此时,你可能会想,一整门课程都讲存储和查询?这真的有必要吗?请相信我,虽然存储和查询乍看之下似乎很直接,但它们绝非易事。Andrew,你对此怎么看?
数据存储的复杂性 🤔
我认为数据存储和查询一点也不简单。关于如何存储数据,存在许多决策,这些决策将影响你后续如何高效地使用数据。
例如,选择何种存储类型——从廉价但仅适合间歇性访问的长期存储,到使用关系型数据库或键值存储的数据存储,再到将数据存储在内存中。
此外,还有数据库模式的设计,甚至可能包括决定将数据存储在世界的哪个部分的数据中心。所有这些都会驱动性能,并影响你必须处理的法规问题,例如数据主权。
最*,我就在与一家半导体产品公司合作一个项目,他们不能让数据离开本国。因此,我们必须设计一个在美国编写、但仅在该国运行,并且只与美国团队共享汇总结果的系统。这只是一个例子。
但不同公司的需求是如此多样,这导致了为处理这些迥异需求而开发的各种工具和框架。
存储与查询的层次结构 🏗️
确实如此。存储和查询涉及大量复杂性。因此,正如你在前几门课程中所见,请将数据存储视为一种层次结构。
在底层,你有存储的原始“原料”,包括物理存储元素,如磁盘、固态硬盘和内存,以及不那么有形的存储元素,如CPU、压缩、网络和序列化。
在此基础上,你有由这些原始原料构建的存储系统,例如数据库和对象存储。
再往上,你有由这些存储系统构建的存储抽象,例如数据仓库、数据湖和数据湖仓。
数据查询的工具与技术 ⚙️
当涉及到查询你存储在系统中的数据时,作为一名数据工程师,你需要了解广泛的工具和技术,以确保你的系统高效工作。
这听起来很棒。我对你将在本课程中涵盖的所有内容感到兴奋。我认为,在你作为数据工程师的工作中,拥有存储解决方案和查询方面的深厚专业知识,将帮助你在生命周期的每个阶段都更加成功。
本节课中我们一起学*了第三门课程的总体目标,即深入理解数据存储的复杂性和层次结构,以及高效查询所需的各种工具。良好的开端是成功的一半,让我们开始学*吧。
139:数据工程(导论,源系统、数据摄取和管道,数据存储和查询|1-2-3课) - 第3课概览 🗂️

在本节课中,我们将要学*数据工程生命周期中至关重要的一个环节:数据存储。我们将探讨存储的层次结构,从物理硬件到高级抽象,并了解如何根据数据特性和业务需求选择合适的存储方案。
存储可以说是数据工程生命周期中最复杂的组件。这是因为数据在生命周期中会多次被存储,而您选择的存储解决方案将影响从成本、性能到最终用户体验的方方面面。因此,数据存储确实贯穿了生命周期的所有阶段,从数据工程师控制范围之外的源系统,到数据摄取、转换,最终到为最终用户提供数据服务。
在本课程中,我们将重点关注数据工程师直接处理的存储环节,即从数据摄取到数据服务的过程。要为您的数据架构选择合适的存储解决方案,您需要了解数据的特性,包括其类型、格式、大小,以及不同利益相关者在不同时间点将如何访问和更新数据。
回想一下,您可以将存储视为一种层次结构。


存储层次结构解析
底层:原始组件 🧱
在底层,是构成任何存储系统的原始“原料”。这些组件包括用于物理存储数据的磁盘、固态硬盘和内存,以及存储和传输数据所需的过程,例如网络、序列化和压缩。
您通常不会直接与这些物理存储组件或过程交互,而是与由这些原始组件构建的存储系统进行交互。
中间层:存储系统 💾
一个存储系统包含一个内部管理系统,用于组织您的数据并允许您与存储的数据进行交互。您已经在课程2的背景下了解过其中一些存储系统,例如数据库和对象存储。
当时我们主要讨论了用于处理事务的OLTP系统,其重点是实现低延迟的读写查询。然而,支持事务处理的存储系统与支持在线分析处理(OLAP) 的系统不同。OLAP系统专注于对数据应用聚合和汇总等分析活动,以支持业务决策。
如今,我们还有更专业的存储系统,如图和向量数据库,它们可以支持机器学*和分析用例。
顶层:存储抽象 🏗️

在存储层次结构的顶层,存储系统被组装成存储抽象,包括云数据仓库、数据湖和数据湖仓。
因此,在本课程的第一周,我们将重点关注前两层:原始组件和存储系统。
课程内容安排
第一周:深入存储基础
我们将更深入地研究物理存储技术的特性,并探讨序列化和压缩算法的技术细节。然后,我们将探索块、对象和文件存储的云存储范式。我们还将涵盖分布式存储系统,最后讨论各种类型数据库中数据存储的细节。
您将比较行式数据库和列式数据库之间的性能,以理解它们在OLTP和OLAP系统中的用例。接着,您将探索数据在NoSQL、图和向量数据库中是如何存储的,类似于您在课程2中探索关系型和NoSQL数据库作为源系统时所做的那样。
在本周的第二课中,您将获得使用Cypher语言查询Neo4j数据库的实践经验,这是一个具有向量搜索功能的图数据库。
第一周的主题是评估原始组件和存储系统层面在存储成本与性能之间的权衡,以便您在设计数据架构时能够开始做出明智的存储决策。
第二周:聚焦存储抽象
在第二周,我们将重点关注顶层——存储抽象。您将学*如何为利益相关者在摄取、转换和服务阶段所需的数据选择合适的抽象存储方式。
第三周:查询与性能优化
在本课程的最后一周,我们将探讨查询如何工作以检索存储的数据,不同的存储解决方案如何影响查询性能,以及改进查询性能的技术。
总结
本节课中,我们一起学*了数据存储的核心概念及其在数据工程生命周期中的重要性。我们介绍了存储的层次结构模型,从物理硬件到高级抽象,并概述了本课程三周的学*路线:第一周深入存储基础技术,第二周学*如何选择存储抽象,第三周探讨查询机制与性能优化。尽管本课程只有三周,但内容非常丰富。请继续观看下一个视频,我们将从数据存储的“原始组件”开始学*。


140:数据存储的物理组件 📚
在本节课中,我们将要学*数据存储系统的物理基础组件。理解这些“原材料”的特性、性能、数据持久性和成本,对于数据工程师选择适合特定应用场景的存储系统至关重要。
数据在管道中流转时,会经过持久化存储介质(如磁盘)和易失性内存(如RAM)。本节我们将详细比较这些不同的物理组件,帮助你理解它们之间的差异。
磁性硬盘驱动器(HDD)💽
磁性硬盘驱动器,通常称为硬盘或HDD,使用涂有磁性薄膜的旋转盘片来存储数据。其工作原理类似于老式唱片机,需要通过移动磁头来定位盘片上的特定磁道。
每个盘片包含圆形的磁道,磁道被分割为称为扇区的存储单元。磁道号和扇区号共同构成一个唯一地址,用于组织和定位数据。
执行写入操作时,读写头通过改变磁场方向来磁化薄膜,从而在特定地址物理编码二进制数据。磁场指向一个方向代表存储比特“1”,指向相反方向代表存储比特“0”。读取数据时,同一个读写头检测指定地址的磁场并输出比特流。
核心概念:数据寻址
数据地址 = 磁道号 + 扇区号
固态硬盘(SSD)⚡
固态硬盘使用闪存单元中的电荷来存储数据。带电的单元代表比特“1”,不带电的单元代表比特“0”。
由于消除了机械部件,SSD可以通过纯电子方式更快地读写数据。
HDD与SSD性能对比 ⚖️
上一节我们介绍了HDD和SSD的基本原理,本节中我们来看看它们在性能上的具体差异。
HDD读取数据的延迟取决于两个机械操作的时间:
- 寻道时间:读写头物理定位到正确磁道所需的时间。
- 旋转延迟:目标扇区旋转到读写头下方所需的时间。
这些机械操作存在物理限制。目前,典型的商用HDD转速约为每分钟7200转,这意味着获取数据的平均延迟约为4毫秒。因此,HDD每秒最多只能执行几百次I/O操作。
相比之下,通过SSD中的电荷读取数据要快得多。新型SSD通常每秒可执行高达数万次I/O操作,数据获取延迟约为0.1毫秒。这使得SSD更擅长随机访问,即可以非常快速地读取或更新任何位置的数据。
在数据传输速度方面,HDD每秒可从磁盘向内存或RAM读写高达300兆字节的数据,而SSD的速度可能比这快10倍以上。
通过分布式存储系统和并行处理,可以获得更好的读写性能。例如,可以将数据分布在许多HDD和集群上,并同时从这些集群读取。在这种情况下,传输速度主要受网络性能限制,而非磁盘本身的物理限制。对于SSD,可以通过将存储分割为多个分区,并让大量存储控制器并行运行,以同时处理更多数据事务。采用并行处理方法,SSD的传输速度可达每秒数千兆字节。我们将在本周晚些时候深入探讨分布式存储和并行处理。

HDD与SSD成本与选型建议 💰
现在我们已经从性能上比较了HDD和SSD,接下来考虑一下成本。

对于存储相同容量的数据,商用HDD通常比SSD便宜2到3倍。这就是为什么即使数据传输速度较慢、延迟较高,HDD仍然构成了大部分数据存储系统的骨干。
以下是选择存储介质时的建议:
- 选择HDD:如果你的应用需要以每次1兆字节或更大的块进行不频繁的数据访问,且不需要超快的读写速度,那么HDD是更具成本效益的选择。
- 选择SSD:SSD常用于OLTP系统的商业部署,因为它们允许关系数据库每秒处理数千笔事务。然而,由于其较高的成本,SSD并不总是分析型存储的最佳选择。
易失性内存:RAM与CPU缓存 🧠
让我们转换视角,看看易失性内存组件,即随机存取存储器(RAM)和CPU缓存。
为了让CPU处理数据,需要将数据从持久化磁盘存储(如SSD和HDD)传输到RAM。RAM通常直接连接到CPU,因此速度非常快,能比磁盘存储更好地匹配CPU的处理速度。

目前,RAM的数据传输速度约为每秒100千兆字节,数据获取延迟非常低,约为0.1微秒,这使其能够执行数百万次I/O操作。这些指标可能因硬件和配置规格而有很大差异。
但RAM并非无所不能。由于它连接到CPU,其单位存储数据的成本更高,通常比SSD贵30到50倍。它也是易失性的,意味着如果断电,存储在RAM中的数据可能在不到一秒内丢失。因此,通常只使用RAM来存储CPU执行的代码以及该代码直接处理的数据,而不是需要持久保存的内容。这使得RAM非常适合用于缓存、数据处理或索引,我们将在本课程后面讨论。
一些数据库将RAM作为主要存储层,因为它允许非常快的读写性能。在这些应用中,必须始终牢记RAM的易失性。即使数据在集群中的内存间进行了某种复制,导致多个节点宕机的停电也可能造成数据丢失。
比RAM更快的一种内存是CPU缓存,它直接位于CPU处理芯片上。你希望使用CPU缓存来存储频繁访问的数据,以便在处理过程中进行超快速检索。由于其位置优势,它的数据获取延迟约为1纳秒,数据传输速度高达每秒1太字节。

缓存不仅用于CPU。你还可以在多种应用中使用缓存,将频繁和最*访问的数据存储在快速访问层。例如,可以使用浏览器缓存来存储下载的网页资源,以便更快地加载网页;也可以使用数据库缓存来存储常用查询的结果。
总结 📝
本节课中,我们一起学*了物理存储数据的不同组件之间的性能和成本权衡。作为数据工程师,扎实理解这些权衡有助于你评估不同的存储技术,确保它们满足数据处理工作负载的性能要求。



在下一个视频中,我们将探讨序列化和压缩等其他对现代数据系统中存储数据至关重要的组件和过程。
141:数据存储所需的过程 🗄️

在本节课中,我们将要学*数据存储系统底层除了物理介质外,还包含哪些关键组件和过程。我们将重点探讨网络、CPU、序列化与压缩在现代数据系统中的作用,理解它们如何共同构成数据存储的“原材料”。

概述
之前讨论存储层次结构时,我们聚焦于最底层的物理存储介质。然而,底层还包括了在现代数据系统中存储和传输数据所必需的其他组件和过程。本节视频将详细解析网络、CPU、序列化与压缩如何在云时代的存储系统中发挥作用。
网络与CPU:分布式存储的基石
在云时代,存储系统日益趋向分布式。这意味着数据可以被拆分、复制并分布在许多互联的服务器上,以提升读写性能、数据持久性和可用性。
因此,你可以将网络以及处理读写请求细节所需的CPU视为存储解决方案的“原材料”之一。这些细节包括跨多台服务器聚合读取结果和分发写入操作。我们将在后续课程中更深入地学*分布式存储系统。
数据序列化:格式转换的关键
无论你是将数据存储在单台服务器还是分布式存储系统中,当你将数据存入文件、数据库或通过网络发送时,都需要将其转换为不同的格式。
这是因为存储在内存中的数据与存储在磁盘中的数据具有不同的表示形式。在系统内存中,数据以经过优化的数据结构形式存储,便于CPU高效访问和操作。但这种格式并不适合持久化存储到磁盘或通过网络传输。
因此,你需要使用一个称为序列化的过程,将数据转换为一种标准格式(通常是一个字节序列),以便高效存储或在网络上共享。当你想读取数据时,则会使用反序列化过程,从序列化格式中重建原始的数据结构。
序列化的两种主要方式
以下是两种主要的序列化方法:
- 基于行的序列化:在这种方式下,你逐条记录地对表格数据进行编码和存储,使得一个连续的字节序列代表一行数据。如果你编码的是半结构化数据,则逐个对象或逐个文档进行编码,使得代表单个对象或文档的数据在磁盘上呈现为连续的字节序列。这种方式非常适合需要访问整行数据的事务型操作。
- 基于列的序列化:在这种方式下,你逐列地对数据进行编码和存储,使得序列化格式中的一个连续字节序列代表一列数据。如果你编码的是面向列的半结构化数据,则所有对象中同一个键对应的值会被存储为一个连续的字节序列。这种方式非常适合需要对特定列执行操作的分析型查询。
常见序列化格式
作为数据工程师,你可能会遇到多种数据序列化格式:
- CSV:一种流行的基于行的格式。它实际上很容易出错,因为它不支持预定义的模式,需要应用程序自行定义每行每列的含义。如果应用程序为其数据添加了新行或新列,你必须手动处理这种变更。因此,如果可能,应避免在数据管道中使用此格式。
- XML:在HTML和互联网兴起初期很流行,但现在被视为一种遗留格式,因为对于数据工程应用而言,其序列化和反序列化速度通常较慢。如今,XML在纯文本对象序列化方面已很大程度上被JSON格式取代。
- JSON:如今被视为通过API进行数据交换的新标准,也是一种非常流行的数据存储格式。
- Parquet:一种基于列的二进制格式,专为高效存储和大数据处理而设计。
- Avro:一种基于行的二进制格式,它使用模式来定义数据结构,并支持模式演进。
本周晚些时候,我们将更深入地学*数据库中行存储与列存储的对比,以及这些流行的格式。

你在序列化以及如何在文件和数据库中存储数据方面所做的决策,会影响整体查询性能。例如,最*一个数据团队发现,仅仅将序列化格式从CSV切换到Parquet,就能将作业性能提升100倍。
数据压缩:提升效率与性能
假设你已经将数据序列化,以便存储在磁盘上或通过网络传输。随着数据量的增长,你可能希望提高存储效率并加速数据传输。
数据压缩是一种减少表示数据所需比特数的方法,对于需要处理日益增长的大型数据集的现代数据应用而言,它是一个关键组件。
压缩算法不是直接将数据编码为比特序列,而是使用复杂的数学技术来识别数据中的冗余和重复,然后以更高效的方式重新编码数据。

例如,可应用于CSV、JSON和XML等基于文本的数据格式的传统压缩算法,会识别出现最频繁的字符,并以不同于出现频率较低的字符的方式对它们进行编码。这些算法不是将每个字符映射到固定长度的比特序列,而是将常见字符匹配到较短的比特序列,将不常见字符匹配到较长的比特序列。这样,压缩后的数据文件总共占用的比特数更少,从而节省磁盘空间。
压缩文件大小相对于原始未压缩文件大小的比率称为压缩比。
除了减少磁盘空间占用,压缩还能提高查询性能,因为它减少了处理查询时将必要数据从磁盘加载到内存所需的输入/输出(I/O)时间。
*年来,工程师们创造了新一代的压缩算法,它们优先考虑速度和CPU效率,而非压缩比。这些算法常用于压缩数据湖或列式数据库中的数据,以优化快速查询性能。本视频后的可选阅读材料中包含了一些这类Zoo压缩技术的示例。
总结

本节课中,我们一起学*了构成数据存储基础的关键“原材料”。我们了解了网络和CPU如何支持分布式存储,探讨了序列化过程如何将内存中的数据转换为可存储或传输的格式,并区分了基于行和基于列的序列化策略及其适用场景。最后,我们介绍了数据压缩的原理及其在节省存储空间和提升查询性能方面的重要作用。
现在你已经了解了这些组件如何使数据存储成为可能,接下来我们将从存储层次结构的底层向上移动,探索由这些“原材料”构建而成的存储系统本身。


接下来的可选阅读材料是关于压缩的。之后,我们将探讨三种云存储选项:文件存储、块存储和对象存储。
142:块存储、对象存储和文件存储 📚


在本节课中,我们将学*三种常见的云存储系统:块存储、文件存储和对象存储。作为一名数据工程师,你需要在众多云存储选项中进行选择。这些存储系统建立在比之前视频中提到的“原始组件”更高的抽象层次上。选择最适合你用例的系统时,你需要权衡这些选项之间的性能和可扩展性。
文件存储系统 📁
上一节我们介绍了云存储的基本概念,本节中我们来看看文件存储系统。文件存储系统将文件组织成目录树结构,类似于你笔记本电脑上文件夹的组织方式。每个文件夹包含其文件和子文件夹的元数据,详细记录了名称、所有者、修改日期、访问权限以及指向实际文件和子文件夹本身的位置指针。

因此,要在磁盘上定位一个文件,你需要给操作系统一个路径来遵循,例如 /user/Matthew_Howsley/output.txt。操作系统从左到右遵循这种层次结构,从根目录(由正斜杠 / 表示)开始,然后找到 user 目录,接着是 Matthew_Howsley 子目录,最后定位到文件。

以下是文件存储的主要应用场景:
- 当你需要为多个用户或主机提供对文件的集中访问,并且这些文件需要易于共享和管理时,可以使用文件存储。
- 你可以使用托管的云文件存储服务,例如 Amazon Elastic File System (EFS)。该服务为你、你的应用程序和利益相关者提供通过网络访问共享文件的能力,而无需管理网络、扩展磁盘集群或配置。
- 文件存储通常构建在块存储之上,底层存储机制的复杂性对你来说是抽象的。
尽管文件存储是一种更易于访问和理解的存储格式,但其读写性能并非最高,因为它需要跟踪文件层次结构。


块存储系统 🔧
上一节我们了解了文件存储,本节中我们来看看块存储。块存储为高速事务性数据访问提供了所需的性能和灵活性。块存储将文件分割成小的、固定大小的数据块,你可以将这些数据块存储在磁盘或固态硬盘上。这允许你为任何给定的数据片段精确分配存储空间。
每个块都有一个唯一的标识符,类似于该块的地址,这有助于你高效地检索和修改单个块中的数据,从而提供比文件存储更高的性能和更低的延迟。
你通常基于分布式架构设计块存储系统,将数据块分布在多个存储磁盘上,这带来了更高的可扩展性和更强的数据持久性。这使得块存储成为大多数现代存储解决方案的支柱,包括本地文件系统、事务性数据库和虚拟机存储。
当你将文件存储在块存储中时,存储应用程序将数据写入多个块,并将这些块的标识符记录在一个数据查找表中。当你请求特定文件时,应用程序从相关块中检索数据,并将其合并为原始序列供你读取。这一切对你都是抽象的,因此你可以通过其唯一标识符定位任何块,并更新该块,而无需替换整个文件。
这使得块存储非常适合数据需要频繁访问和修改的用例。以下是块存储的主要应用场景:
- 事务性数据库系统:通常以块级别访问磁盘,以实现高性能的随机访问。这使得 OLTP 系统能够以低延迟执行小型读写操作。
- 虚拟机持久存储:例如 EC2 实例。在实验中,当你创建那些运行在 EC2 实例上的 Cloud9 环境时,系统会自动为每个实例附加一个由块存储卷支持的主存储设备。你可以在块存储卷中安装操作系统、文件系统和其他计算资源。
对于 EC2,默认存储是 Amazon Elastic Block Store (EBS)。你可以根据用例从各种 EBS 卷类型中进行选择。例如,一些卷构建在高性能 SSD 上,非常适合对延迟敏感的工作负载;而另一些则使用经济高效的磁盘来存储不常访问的数据。


由于块存储卷通常附加到计算实例,其可扩展性受限于计算资源的扩展能力,因此块存储的容量通常上限在几 TB。
对象存储系统 🗃️
上一节我们讨论了块存储,本节中我们来看看对象存储。对象存储将数据存储层与计算层解耦,因此它可以扩展到 PB 级或更多的存储容量。在云环境中,你的存储容量仅受预算限制。使用对象存储,你很可能在耗尽对象存储空间之前就花光了钱。
因此,云对象存储允许你使用临时集群处理数据,并根据需求扩展这些集群。这些临时集群在后台运行,你无需担心它们。这是使大数据对小型组织可用的一个重要因素,这些组织无法负担仅为偶尔运行的数据作业而拥有硬件。
让我们回顾一下在课程 2 的存储系统背景下学到的关于对象存储的知识。与传统的分层文件存储系统不同,对象存储将文件作为不可变的数据对象存储在扁平结构中。
在对象存储系统中,你将对象组织到顶级逻辑容器中,例如 S3 存储桶。每个对象被分配一个唯一的标识符或键,你可以用它来在其容器内查找对象。因此,S3 中的对象标识符可能如下所示:



s3://bucket-name/path/to/object/data_example.json
第一部分指的是存储桶名称,该名称在整个 AWS 中必须是唯一的。path/to/object/data_example.json 是指向特定对象的键。
一旦你最初写入数据,对象就变得不可变。即使你想更改一个 1GB 文件中的一个字符,也必须重写整个对象,而不是像在块存储中那样只做一个小改动。这看起来像是一个限制,但实际上消除了支持变更同步的开销,因此你可以将对象分布在许多存储节点上,每个节点都包含自己的磁盘,无需在所有节点之间传播数据更改。这使得对象存储能够水平扩展,并支持跨多个磁盘的极高性能并行读写。
每个节点保存对象的分片,这些分片会在多个节点之间复制以确保持久性。这种高可扩展性和持久性使得对象存储非常适合作为云数据仓库和数据湖的存储层。它允许这些存储抽象以经济高效的方式容纳海量数据。
但由于对象是不可变的,对象存储不擅长支持需要低延迟进行许多小更新操作的事务性工作负载。相反,对象存储非常适合存储大规模 OLAP 系统所需的数据,这些系统侧重于读密集型的分析工作负载,而不是写密集型的事务操作。

在现代数据工程应用中,对象存储还在机器学*管道中扮演着关键角色,这些管道需要大量非结构化训练数据,例如原始文本、图像、视频和音频。

因此,文件存储、块存储和对象存储都有广泛的应用场景。以下是选择建议:
- 如果你的重点是简单的数据共享和易于管理,且对性能和可扩展性要求不高,那么文件存储系统可能是最直接的解决方案。
- 如果需要支持需要低延迟频繁读写操作的事务性工作负载,则应选择块存储。
- 如果需要对海量数据集执行分析查询,则可以选择对象存储,因为它具有高可扩展性和并行数据处理能力。

云提供商通常在这三种常见存储选项中提供不同的存储层级。


在下一节视频中,我们将一起学*如何通过考虑用于根据访问频率对数据进行分类的热、温、冷分类方法,来决定合适的存储层级。
本节课中我们一起学*了三种主要的云存储类型:文件存储、块存储和对象存储。我们了解了它们各自的组织结构、性能特点、适用场景以及优缺点。文件存储易于理解和管理,适合共享;块存储性能高,适合频繁读写的事务性工作负载;对象存储可扩展性极强,成本效益高,适合存储海量数据和分析工作负载。理解这些区别对于为你的数据工程项目选择正确的存储解决方案至关重要。
143:热数据、温数据、冷数据 🗂️

在本节课中,我们将学*云数据存储服务中的不同存储层级。理解这些层级如何根据数据的访问频率、成本和性能需求进行划分,是设计高效且经济的数据存储解决方案的关键。
概述
大多数云数据存储服务都提供不同的存储层级供您选择。选择层级时,需要考虑成本、访问速度、访问频率和合规性要求。本节将介绍一种基于数据访问和使用频率的分类方法:热数据、温数据和冷数据。
热数据 🔥
在频谱的一端是热数据。热数据是访问频繁且需要快速检索时间的数据。
例如,在产品推荐应用中,您需要频繁访问产品目录和用户的购买历史记录。您可能还希望将频繁运行的查询结果存储在缓存中,以便快速为客户提供产品推荐。
为了提供快速的读取访问,通常希望将热数据存储在利用高性能存储介质(如SSD和内存)的系统中。因此,热数据的存储成本通常更高,但检索数据所需的时间和计算资源相对较低,因为您存储数据的方式优化了速度。

温数据 🌡️
温数据的访问频率低于热数据,但仍需要随时可用。
例如,这可能用于不需要实时更新的常规报告和分析的数据。通常希望将温数据存储在利用速度较慢的磁盘或混合存储系统的低成本存储系统中。
与热数据相比,温数据的存储成本较低,但检索数据通常需要更多的时间和计算资源。
冷数据 ❄️
在频谱的另一端是冷数据。这是很少被访问且通常用于归档的数据。
例如,您可能决定归档项目文档或保留旧电子邮件以满足合规性目的。您希望将冷数据存储在基于低成本磁盘构建的最具成本效益的存储层级中。
因此,冷数据的存储成本最便宜,但与温数据相比,检索这些数据需要更长的时间并需要更多的计算资源。
层级选择与权衡 ⚖️
一般来说,当您从具有快速访问的高性能存储转向具有较慢访问的低性能存储时,存储价格会下降。
如果您将所有数据存储在热存储中,您将能够非常快速地访问数据,但存储价格会非常高昂。如果您将所有数据存储在冷存储中,那么您将节省存储成本,但代价是数据访问的检索时间长且计算需求高。
因此,您通常需要为各种存储需求选择存储层级的组合。
实践示例:Amazon S3
以在Amazon S3中存储数据为例:
- 您可能将用于实时交易的频繁访问的热数据存储在所谓的 S3 Express One Zone 或 S3 Standard 层级中。
- 您可能将需要每周或每月访问的温数据(例如用于微调产品推荐系统)存储在 S3 Standard-Infrequent Access 或 S3 One Zone-Infrequent Access 层级中。
- 最后,您希望将历史冷数据归档在某个 S3 Glacier 层级中。
设计存储解决方案时,除了访问频率,还需要考虑存储解决方案的可扩展性和持久性等因素。
总结


本节课我们一起学*了数据存储的三种主要层级:热数据、温数据和冷数据。我们了解了它们基于访问频率的定义、典型的应用场景、存储介质选择以及相关的成本与性能权衡。掌握这些概念有助于您根据业务需求,在云存储服务中做出明智的层级选择,从而平衡性能与成本。
在下一个视频中,我们将更深入地探讨分布式存储系统,并讨论与该架构相关的权衡。我们下节课见。
144:分布式存储系统 🗄️

在本节课中,我们将要学*分布式存储系统的基本概念、工作原理以及其在数据工程中的重要性。随着数据量的增长和访问模式的复杂化,单机存储已无法满足需求,分布式存储成为了云环境下的默认选择。

分布式存储架构概述
上一节我们介绍了数据存储的基本需求,本节中我们来看看分布式存储架构是如何工作的。
当数据存储需求增加且数据访问模式变得更加复杂时,单台机器的存储能力将无法满足需求。这时,你需要将数据分布到多台服务器上。实际上,在云环境中,无论是使用块存储、文件存储还是对象存储,分布式存储都是默认的数据存储方式。
在分布式存储系统中,数据被分布和复制到多个通过网络连接的服务器上,这些服务器被称为节点。节点组成了集群,而多个集群共同构成了分布式存储系统。每个节点都包含如磁盘或SSD等物理存储介质,因此分布式系统的总存储容量是所有节点容量的总和。每个节点通常还具备处理能力,用于管理数据、执行复制和访问控制。
通过这种方式存储数据,你可以轻松地实现系统的水平扩展,即通过向集群添加更多节点来应对增长的数据量和负载。相比之下,单机存储架构只能进行垂直扩展,即只能升级单台服务器的存储容量。通过将数据分布在多个节点上并在集群间复制,你还能确保更高的容错性和数据持久性。这意味着即使系统的一个或多个组件发生故障,你的数据也能长期保存。这与高可用性密切相关:如果一个节点因硬件、软件故障、网络中断或其他问题而不可用,你仍然可以从另一个未受影响的节点(可能位于不同的地理位置)访问数据。
在性能方面,分布式存储系统将大型处理任务分解为较小的子任务,由各个节点分别处理。这有助于系统并行处理许多读写操作。由于数据在多个节点上复制,系统还可以从最*或负载最轻的副本节点提供读取请求,从而使你能够更快地访问数据。
鉴于这些优势,许多存储解决方案,包括对象存储、云数据仓库、Hadoop分布式文件系统(HDFS)、Apache Spark等,都依赖于分布式存储架构。
数据分布方法:复制与分区
作为数据工程师,你会发现有两种常见的方法可以在多个节点间分布数据:复制和分区。
以下是这两种方法的详细说明:
- 复制:你在几个不同的节点(可能位于不同的地理位置)上保存相同数据的副本。这种冗余性带来了更高的可用性,并有助于提升性能。
- 分区(也称为分片):它将大数据集分割成更小的子集,称为分区或分片,然后将不同的分区分配给不同的节点。
在实践中,你可能会结合使用这些方法来分布数据。例如,你可以对一个大数据集进行分区,并将分片分布到不同的节点,然后复制这些节点以创建良好的冗余级别。大多数数据库可以自动以对你透明的方式进行分区和复制,或者你也可以指定复制和分区参数,以便对分布式存储系统进行更精细的控制。

分布式存储的挑战与CAP定理
分布式存储的一个挑战是,跨节点复制变更需要时间。因此,当你尝试从一个正在更新的节点访问数据时,你面临两种选择:要么等待更新完成后再访问数据,要么访问该节点当前可用的、可能不是最新的数据。
这种权衡由CAP定理进行了总结。该定理指出,任何分布式系统最多只能同时保证以下三个属性中的两个:一致性、可用性和分区容错性。
以下是这些属性的定义:
- 强一致性:意味着每次读取都能反映最新的写入操作。请注意,这与你在课程2中看到的ACID原则中的“一致性”不同。ACID中的一致性确保事务内的任何数据更改都必须遵循数据库模式定义的一组规则或约束,使数据库从一个有效状态转换到另一个有效状态。而CAP中的强一致性属性有助于实现这一条件。
- 可用性:意味着每个请求都会收到响应,即使响应中的数据不一定是最新的。
- 分区容错性:意味着即使网络发生中断或故障,导致某些节点与其他节点隔离,系统也能继续运行。
由于没有分布式系统能完全避免网络故障或意外中断,网络分区通常是必须容忍的。也就是说,构建保证分区容错性的系统通常是给定的前提。因此,你通常必须在一致性和可用性之间做出选择,因为CAP定理指出任何分布式系统最多只能保证三个属性中的两个。
这意味着,在你尝试访问一个仍在更新的节点的场景中,你可以选择将系统设计为取消请求(这降低了可用性但确保了一致性),或者配置系统继续进行读取操作(这提供了高可用性但存在不一致的风险)。旨在符合ACID原则的数据库系统(如RDBMS)通常会选择一致性而非可用性,而不符合ACID原则的NoSQL数据库系统则通常选择可用性而非一致性。
与ACID原则相对,实际上存在一组称为BASE的原则,可用于设计和评估分布式数据系统。BASE代表:
- 基本可用:意味着大部分时间都能获得一致的数据。
- 软状态:意味着事务的提交状态是不确定的。
- 最终一致性:意味着在某个时间点后,读取数据将返回一致的值。

实践应用与配置选择

作为数据工程师,你需要理解你的数据库如何处理一致性。这可以由数据库技术本身、数据库配置参数或在单个查询级别的一致性配置来决定。一旦你理解了数据的技术限制和业务用例,你可能需要与其他利益相关者协商一致性要求。
让我们回顾课程1中的场景:你需要向数据科学家提供销售数据,以便他们为营销团队更新分析仪表板。软件工程师已经设置了生产数据库的只读副本,以便你可以摄取、转换、存储并提供所需的销售数据给数据科学家。
假设数据库是使用Amazon RDS Aurora实现的,这是一个分布式关系数据库服务。该数据库有一个主数据库实例,支持严格的读写后一致性(即强一致性)。但如果数据科学家重视即使不是最新数据也能立即访问销售数据的能力,那么你可以在Aurora中设置只读副本。
这些只读副本会跟踪对主数据库实例所做的所有更改,并更新它们自己的数据副本。然后,在逐个查询的基础上,你可以决定是从支持强一致性的主数据库实例读取,还是从支持最终一致性的某个只读副本读取。

总结与后续
本节课中我们一起学*了分布式存储系统的核心概念。我们探讨了其架构如何通过节点和集群实现水平扩展、高可用性和容错性。我们介绍了两种关键的数据分布方法:复制和分区,并深入分析了分布式系统设计中的核心权衡——CAP定理,以及与之相关的ACID和BASE原则。最后,我们通过一个实际场景了解了如何根据业务需求选择不同的数据库一致性配置。
接下来,我包含了一个关于数据库分区的可选阅读材料,如果你有兴趣可以深入了解,它涵盖了数据库如何在不同节点间分布。之后,我将引导你完成一个实验,在那里你将有机会在云中实际操作对象、块和文件存储系统,这些系统都采用了我们讨论的分布式存储架构。你还将把这些系统与主要将数据存储在RAM而非磁盘的内存存储系统进行比较。


我们下个视频见。
145:比较云存储选项 🧪

在本节课中,我们将通过一系列动手实验,探索云对象存储、文件存储和块存储的核心特性。你将学*到不同存储方案的结构、数据操作方式以及性能差异,特别是内存缓存如何显著提升数据检索速度。
实验概览
在开始实验前,我们先快速了解一下你将完成的练*内容。本次实验分为几个部分,分别对应不同的存储类型。
第一部分:探索对象存储
上一节我们介绍了实验的整体安排,本节中我们来看看对象存储的特性。你将探索这种存储方案的扁平化结构以及其对象的不可变性。
以下是你在对象存储部分将完成的任务:
- 使用Boto3将一个包含员工信息的CSV文件上传到S3存储桶。
- 上传文件时,选择
data/csv/employee.csv作为所创建对象的标识符。请注意,前缀data/csv/只是对象键的一部分,并不代表S3存储桶中实际存在的目录。 - 你将完成一个函数,该函数将向你证明前缀
data/csv/并不代表S3存储桶中的一个实际对象,而data/csv/employee.csv才代表一个对象。
你可以创建共享相同前缀的不同对象。例如,如果你想按年份组织销售数据,可以在对象键中指定年份,并将其用作前缀,以代表该特定年份销售数据的所有对象。这有助于你组织数据,并更快地从正确的存储桶中检索对象。
由于对象是不可变的,你无法就地修改它们。因此,如果你使用存储桶中已存在对象的相同键来上传一个新对象,那么旧对象将被新对象替换。或者,正如你在之前的课程中所见,你可以启用对象版本控制。这样,当你使用现有键上传对象时,旧版本会被保留,并会创建该对象的新版本。
在本实验中,你将再次试验这一特性:在提供的存储桶中启用版本控制,修改员工数据,然后使用相同的键再次上传。接着,你将使用Boto3的 list_object_versions 方法来验证是否创建了对象的新版本。此方法会返回对象的旧版本和新版本的元数据。
第二部分:探索文件存储

完成对象存储的练*后,你将探索文件存储系统的层次化结构。
在文件系统中,你可能会看到像 data/employees.csv 这样的路径。这里的 data 指的是一个目录,你可以将其视为一个特殊的文件,它包含允许你访问其他文件的信息。
以下是你在文件存储部分将完成的任务:
- 使用命令行导航到
data目录,然后探索其内容和元数据。 - 你还会探索在这种存储类型中,数据是如何被就地修改的。
文件系统通常构建在块存储之上,而块存储对你来说通常是抽象的。
第三部分:探索块存储与内存缓存

为了探索实验中的一些块存储特性,你将获得一个模拟块存储行为的服务器。

以下是你在块存储部分将完成的任务:
- 连接到该服务器并向其发送一个文件。
- 服务器将通过将文件分解成块来模拟块存储如何存储数据。
最后,你将与运行实验环境的服务器的内存进行交互。本周早些时候你了解到,从内存传输数据比从磁盘传输数据更快,并且某些数据库允许你将查询结果缓存在内存中以便快速访问。
你将使用 cache-pandas 包来测试这一特性。该包提供了 timed_lru_cache 装饰器,你可以用它轻松地将函数生成的pandas数据帧缓存在内存中。这样,下次运行脚本时,它将返回缓存的数据帧,而不是再次运行该函数。
你将把这个装饰器用于一个将CSV文件读入pandas数据帧的函数。你将比较第一次读取文件所需的时间与读取存储在内存中的相同数据所需的时间。
但是,由于内存存储容量有限,每当将数据加载到内存时,你需要确保有足够的空间。为了监控内存存储容量,你将使用 htop 命令。该命令为你提供系统CPU使用率、内存和运行进程的实时概览。顶部的条形图代表系统资源(包括CPU和内存)的使用情况,下面的每一行对应一个进程,并包含CPU和内存使用信息。

总结
本节课中,我们一起学*了如何通过实验比较不同的云存储选项。你动手探索了对象存储的扁平结构和不可变性、文件存储的层次化结构,以及块存储的基本原理。你还实践了利用内存缓存来加速数据访问,并学会了使用工具监控系统资源。现在轮到你去完成这些练*,亲自探索这些存储选项的特性了。

在你尝试完实验后,我们下节课再见。下节课我们将探讨数据库如何存储数据,并了解不同类型的数据库。
146:数据库如何存储数据 🗄️

概述
在本节课中,我们将要学*数据库如何存储数据。我们将深入探讨数据库管理系统(DBMS)的存储引擎、索引的工作原理,以及内存数据库的特点。这些知识将帮助你理解数据在数据库中的物理存储方式,以及如何高效地检索数据。
数据库管理系统(DBMS)的组成

在之前的课程中提到,数据库是最常见的源系统类型之一。你将使用数据库贯穿数据工程生命周期的各个阶段。因此,在本视频中,让我们深入了解数据库如何存储数据。
数据库通常带有一个称为数据库管理系统(DBMS)的软件层,它便于你与数据库进行交互。这对于你在第2课中看到的关系型数据库以及你将在本课后面更详细探讨的非关系型数据库(如图数据库和向量数据库)都是如此。
一个DBMS由传输系统、查询处理器、执行引擎和存储引擎组成。你将在本课程的最后一周学*所有这些组件如何协同工作来处理查询。但现在,让我们专注于存储引擎。
存储引擎的作用
数据库存储引擎在将数据物理存储到磁盘时为你完成繁重的工作,包括序列化、数据排列和索引。

你可能会使用现代存储引擎,这些引擎经过优化以支持固态硬盘(SSD)的性能特性,并能处理现代数据类型和结构,如可变长度字符串、数组和嵌套数据。随着组织开始对大规模数据应用分析,现代存储引擎也已发展为分析应用提供强大的列存储支持。
当你希望通过编写查询从数据库中检索数据时,速度通常非常重要。假设你查询一个非常大的关系表,该表有数百万甚至数十亿行,并且你特别关注与某些国家相关的行。例如,你想找出在美国购买的产品的平均价格。你可以编写一个SQL查询,从我的表中选择价格列的平均值,并筛选出国家列等于“USA”的结果。
索引的作用与原理
请注意,我在这里使用SQL查询是因为我想查询一个关系数据库。在本课末尾的实验中,你将使用不同的查询语言来查询图数据库。
回到这个例子,为了执行查询,查询处理器每次都必须扫描整个表以找到满足此筛选条件的记录。事实证明,你可以通过使用一种称为索引的特殊数据结构来加速数据检索。你可以将索引视为一种在旁保留一些元数据的方式,以帮助你更有效地定位所需数据。

在大多数关系数据库管理系统中,索引通常用于主表键和外键。但你也可以将索引应用于其他列,以满足特定应用的需求。在这个例子中,你可以创建一个单独的索引表,该表由两列组成:一列包含按字母顺序排序的国家值,另一列包含引用原始表中相应行的内存地址。然后,当你执行查询以找出在美国购买的产品的平均价格时,查询处理器可以对这个索引表使用二分查找来定位国家代码为“USA”的行。这比线性扫描所有行以查找特定国家代码要快得多。
如果你熟悉计算机科学,你会看到你有效地将检索操作的时间复杂度从O(N)降低到O(log N)。如果你不熟悉这个符号,不用担心。最重要的是,你要理解从排序列表中定位特定国家代码比扫描所有行更快。
所以这是索引的一个例子,根据数据库类型和你的使用情况,还有许多其他类型的索引结构。
内存数据库简介
现在我想快速提一下使用RAM作为主要存储层的内存数据库。尽管RAM提供了出色的传输速度和低延迟,但它也极其易失。因此,内存数据库通常用于需要超快速数据检索的应用中,如缓存应用、实时竞价和游戏排行榜。但这些数据库不应用于保留或持久存储目的。
例如,你可能使用像Memcached这样的键值存储来缓存数据库查询结果或API调用,在这些情况下,如果机器重启导致数据丢失是可以接受的。你可能还会遇到一个流行的基于内存的存储系统,称为Redis,它是一个支持更复杂数据类型的键值存储。Redis有几种内置的持久化机制,包括快照和日志记录。你可以将这个键值存储用于可以容忍少量数据丢失的极高性能应用。

总结
在本节课中,我们一起学*了数据库如何存储数据。我们探讨了数据库管理系统(DBMS)的存储引擎如何工作,索引如何通过创建元数据结构来加速数据检索,以及内存数据库的特点和适用场景。理解这些存储机制对于设计和优化高效的数据管道至关重要。

在下一个视频中,我们将更详细地比较数据库中存储结构化和半结构化数据的两种常见方法:行存储和列存储。请加入我,一起探讨它们的存储模式和查询性能。
147:行存储 vs 列存储 🗂️

在本节课中,我们将要学*数据工程中两种核心的数据存储方式:行存储和列存储。我们将了解它们的工作原理、各自的优缺点,以及如何根据不同的数据访问模式来选择最合适的存储方案。
概述
作为数据工程师,您会遇到多种类型的数据库来存储和处理数据。在之前的课程中,我们已经了解了关系型数据库、键值存储和文档数据库。本周晚些时候,您还将学*图数据库和向量数据库等其他类型。本视频将重点介绍在数据工程中常用的两种存储结构化表格数据和半结构化数据的方式:行存储和列存储。您的选择将主要基于数据访问模式,即用户和系统如何访问您的数据。
行存储详解
传统的关系型数据库管理系统通常采用行存储来逐行存储数据。每一行代表一条完整的记录。




如果放大物理存储介质,您会发现每一行(对于半结构化数据,则是每个对象)在磁盘上被存储为一个连续的字节序列。这种将相关数据紧邻存储的方式,使得行存储非常适合需要低延迟读写操作的在线事务处理系统。
例如,如果您想根据ID列查询特定记录,由于该记录的所有数据都存储在一起,一旦定位到该ID,您就可以高效地读取和更新数据。
行存储在分析查询中的表现
但是,如果您想执行一个需要对整列值进行操作的分析查询呢?分析查询侧重于汇总或聚合列数据,以回答诸如“总收入是多少”、“哪种产品最畅销”或“平均数量是多少”等问题。
让我们看看这类查询在行存储上的表现。假设一个行存储包含100万行数据,每行有30列,每个条目占100字节。
假设第二列代表价格,您想计算所有价格的总和。您需要执行的查询是:
SELECT SUM(price) FROM my_table;
为了执行此查询,您需要将所有行从持久化磁盘存储逐一传输到RAM中。然后,这些行将被发送到CPU进行处理,提取每一行的价格并相加。
因此,需要传输到RAM的总数据量为:
1,000,000 行 * 30 列/行 * 100 字节/列 = 3 GB
如果您使用的磁盘数据传输速度为200 MB/秒,将所有数据读取到内存需要多长时间呢?计算如下:
3 GB (即 3000 MB) / 200 MB/秒 = 15 秒
对于短期内在小型数据集上执行分析查询来说,这不算太差,行存储模式可以胜任。但它不具备可扩展性。
行存储的扩展性挑战
想象一下,如果数据不是100万行,而是10亿行。那么您的数据大小将是3000 GB。在相同的传输速度下,将所有行及其所有列从磁盘传输到RAM将需要超过4个小时。
为了适应这种大规模的数据传输,工程师们设计了另一种存储模式。
列存储详解
这种模式就是列存储,或称列式数据库,它是NoSQL数据库的一种。当您在列存储中存储数据时,每一列的数据被集中存储在磁盘上。
因此,第一列的所有数据存储在一起,然后是第二列的所有数据,依此类推。这种方式允许您一次性读取整列数据,而不必为了获取单列数据而扫描每一行。
列存储在分析查询中的表现
让我们使用与之前相同的例子,看看列存储的分析查询性能。假设您再次想在一个包含10亿行、30列(每项100字节)的大型数据集中,计算价格列所有值的总和。
由于列存储将每列的数据集中存储,要执行此查询,您只需要将第二列的数据从磁盘传输到RAM。这意味着需要传输的数据大小是:
10亿个条目 * 100 字节/条目 = 100 GB
假设我们拥有与之前相同的数据传输速度,即200 MB/秒。那么传输需要多长时间呢?计算如下:
100 GB (即 100,000 MB) / 200 MB/秒 ≈ 8.3 分钟
与行存储所需的4个多小时相比,您可以看到,对于大型数据集的分析查询,列存储的效率要高得多。这就是为什么列式数据库更适合专注于数据分析的在线分析处理系统。
列存储的局限性
然而,恰恰由于相反的原因,列存储在事务性工作负载上表现不佳,因为您无法轻松访问单个数据行。如果您想读取特定记录,必须通过读取多个列的数据来重建该行。如果您想更新特定记录中的一个字段,则需要反序列化相关列,进行修改,然后再写回存储。
如何选择
作为数据工程师,理解行存储和列存储的工作原理差异至关重要,这样您才能为您的用例选择正确的方法。即:
- 对事务性工作负载(如销售平台的生产数据库)使用行存储。
- 对分析处理使用列存储。
后续学*

在接下来的两个可选阅读材料中,您可以了解更多关于结合了行和列存储方法的Parquet格式,以及关于宽列数据库的阅读材料。虽然Parquet是当今数据工程中流行且常见的格式,宽列数据库不那么常见,但可能非常适合某些事务性工作负载。
在之后的视频中,我们将探讨随着机器学*和生成式AI应用发展而备受关注的图数据库。
总结

本节课中,我们一起学*了数据存储的两种基本模式。我们了解到,行存储将整条记录的数据连续存放,适合需要频繁读写单条记录的OLTP场景;而列存储将同一字段的数据集中存放,能极大提升对海量数据进行聚合分析的OLAP查询效率。理解这两种模式的本质区别,是您作为数据工程师为不同应用场景选择合适存储方案的关键。
148:图数据库 🕸️

在本节课中,我们将要学*图数据库。这是一种使用节点和边构成的数学图结构来存储数据的数据库。我们将了解它的核心概念、工作原理、典型应用场景,并与传统的关系型数据库进行对比。
概述
图数据库将数据存储在由节点和边构成的数学图结构中。节点代表数据项,通常是实体,如人、产品或地点。边则代表这些数据项之间的关系或连接。在现代应用中,如果你正在为涉及数据实体间复杂连接的使用场景构建数据系统,就可能会遇到图数据库。
图数据库的核心概念
上一节我们介绍了图数据库的基本定义,本节中我们来看看其核心构成。

图数据库将关系视为一等公民。这意味着,与关系型数据库相比,使用图数据库可以非常直观地查看实体之间的关系。
- 节点:代表实体,例如用户、产品。可以表示为
节点(标签: 属性),如用户(id: 1, 姓名: “张三”)。 - 边:代表关系,例如“购买”、“是朋友”。可以表示为
边(类型: 属性),如购买(时间: “2023-10-01”)。
当你想查询图数据库中的数据时,即查询节点和边之间的关系,你可以遍历图结构。
图数据库查询示例
以下是使用图数据库进行查询的一个具体例子。
假设你想向用户1推荐其朋友购买过的产品。
- 你可以从用户1节点开始,沿着标记为“朋友”的边,找到该用户的所有朋友。
- 然后,针对每一位朋友,沿着标记为“购买”的边,找到这些朋友过去购买过的产品。
- 最后,将这些产品汇总成一个推荐列表给用户1。
如果同样的数据存储在右侧这样的关系型数据库中,那么要为用户1创建推荐列表,你需要将“好友关系表”与“购买记录表”进行连接,使连接后的结果包含用户及其朋友购买的产品行。接着,你需要过滤查询结果,只保留用户1的信息。最后,选择不重复的产品,得到推荐列表。
可以想象,如果你想向用户推荐更多产品,例如考虑其朋友的朋友购买的产品,那么查询这样的关系型数据库将需要更多的表连接操作,这会迅速变得复杂且难以控制。
图数据库的应用场景
除了产品推荐应用,图数据库还有许多其他用途。
以下是图数据库的一些典型应用场景:
- 社交网络建模
- 表示网络和IT运维关系
- 模拟供应链物流
- 追踪数据血缘关系
另一个不那么明显的用例是欺诈检测,例如在电子商务交易中。你可以构建一个图来建模实体之间的关系,如客户、他们购买的产品、用于购买的信用卡以及他们的IP地址。然后,通过将这些关系与已知的非欺诈模式进行比较,来识别可疑活动。

例如,假设你知道许多欺诈交易包含一个信用卡号,该卡号已经与一个新用户在一个新的IP地址上使用过。那么,通过分析图中用户、信用卡和IP地址之间的关系,你可以将所有使用已关联其他用户的信用卡、但来自新IP地址的用户标记为可疑。
图数据库与知识图谱
你还可以使用图数据库创建知识图谱,将来自不同来源的数据连接起来,用于各种用例,例如提高聊天机器人的准确性和可靠性。
例如,在这里,你可以创建一个知识图谱,连接一家电子商务公司的产品、客户和运输数据。当用户与聊天机器人对话时,你可以从知识图谱中检索相关信息,通过一种称为检索增强生成的技术,为底层的大语言模型提供额外的上下文。这种技术使LLM能够访问与电子商务公司本身相关且具体的新鲜数据,从而改善查询结果。

我们不会在这些课程中深入探讨特定的生成式AI主题,但这对生成式AI来说是一个非常激动人心的时代。作为一名数据工程师,我鼓励你通过查看本周课程末尾的额外资源链接来了解更多关于这些主题的知识。
主流图数据库与查询语言
鉴于图数据库有这么多潜在的应用场景,你需要积累一些使用它们的经验。如今,你可以从许多不同的图数据库中进行选择,包括 Neo4j、ArangoDB 和 Amazon Neptune。使用这些数据库时,你会用到专门的查询语言,如 Cypher、Gremlin 和 SPARQL。
在本节课结束的实验中,你将有机会体验 Neo4j 和 Cypher 查询语言。除了作为图数据库,Neo4j 还集成了向量数据库中常见的向量搜索功能。
总结



本节课中我们一起学*了图数据库。我们了解到,图数据库使用节点和边来存储数据,特别擅长处理实体间的复杂关系。我们通过推荐系统的例子,对比了图数据库和关系型数据库在查询关系时的差异。此外,我们还探讨了图数据库在社交网络、欺诈检测和构建知识图谱等多个领域的应用。最后,我们简要介绍了 Neo4j 等主流图数据库及其专用查询语言。掌握图数据库将帮助你在处理高度互联的数据时,设计出更高效、更直观的解决方案。
149:向量数据库 🧠

在本节课中,我们将学*一种随着机器学*应用兴起而日益流行的数据库类型——向量数据库。我们将了解它的核心概念、工作原理以及它如何通过相似性搜索来解决实际问题。
概述
向量数据库使你能够基于语义相似性高效地查询数据。这被称为相似性搜索,其应用范围从推荐系统到异常检测,再到文本生成。

例如,如果你想向客户推荐产品,可以查询向量数据库,以找出与客户过去购买过的产品相似的商品。或者,你可以查询向量数据库,以识别与正常交易不同的交易,从而检测异常和潜在的欺诈活动。
什么是向量数据库?
上一节我们介绍了向量数据库的应用场景。本节中,我们来看看它的定义和存储内容。
这些数据库专为存储和处理向量数据而优化。向量数据由排列在数组中的数值组成。
因此,你可以使用向量数据库存储任何以数字数组形式存在的数据。例如,一个代表一年中每天降雨量的数字数组。或者,你也可以存储可以重新排列成向量的数值数据,如图像数据,你可以将图像的RGB维度展开成一个数字数组。
然而,当今向量数据库的重要性主要在于存储和检索所谓的向量嵌入。
向量嵌入的核心概念
向量嵌入的核心思想是,获取一个项目(如文本文档或图像),并使用一个向量来捕捉其语义内容。
其工作方式是:你将原始数据(例如一段文本)输入到一个经过训练的机器学*模型中,该模型能够将文本转换为向量嵌入。然后,你可以将整个文档数据库或其他文本内容转换为这种嵌入,并将其存储在向量数据库中。
存储其他类型内容的向量嵌入表示的优势在于,基于向量表示来查找和检索相似项目,比直接比较原始数据库中的项目要容易得多,也快得多。
例如,假设你有一个项目(如一段文本),并且你想在向量数据库中找到与该文本相似的项目。要查询数据库,你首先需要计算查询项目的嵌入。然后,数据库可以测量任意两个向量之间的相似度,并返回最相似的向量。
在向量所代表的高维向量空间中,语义上相似的向量彼此会更“接*”。这里的“接*”不仅指你在这里看到的欧几里得距离(测量两个向量端点之间线段的长度),还可以通过其他类型的距离度量来确定,例如基于两向量夹角的余弦距离,或基于沿坐标轴测量的向量间距离的曼哈顿距离,以及其他度量标准。
因此,有许多算法可用于对向量嵌入数据库执行相似性搜索。
相似性搜索算法
以下是两种主要的相似性搜索算法:
K最*邻算法
让我们仔细看看其中一种更流行的算法:K最*邻算法。
假设你想找到与给定项目最相似的K个项目。KNN算法将对所有项目的所有向量嵌入进行穷举搜索,以计算这些项目与给定项目之间的距离。
你可以想象,随着向量数据库规模的增大,这种算法的效率会降低。这还涉及到所谓的“维度灾难”的挑战,即由于高维向量空间可能很稀疏,距离度量可能无法准确反映它们之间的真实距离。
*似最*邻算法
为了克服这些挑战,你可以使用另一组称为ANN的算法,它代表*似最*邻。这些算法依赖于为给定项目找到最*邻的一个良好猜测,而不是计算与所有项目的精确距离。
因此,尽管它们可能导致结果略微不那么精确,但效率要高得多。实际上,向量数据库的构建就是为了支持ANN算法,以便在存储向量嵌入时能够执行高效的相似性搜索。
在向量数据库中存储向量嵌入时,数据库会应用一种ANN算法,将你的数据表示为一种能够实现更快搜索的数据结构。然后,当你基于给定项目查询向量数据库以执行相似性搜索时,数据库会使用特定的ANN算法遍历该数据结构,以返回*似最接*的项目。
在本视频之后,我包含了一个关于流行ANN算法(称为分层可导航小世界)的可选阅读材料。如果你有兴趣了解更多,请随时阅读有关该算法的更多信息。
总结

本节课中,我们一起学*了向量数据库。我们了解到,向量数据库专为存储和处理向量嵌入而设计,能够通过相似性搜索高效地查找语义上相似的项目。我们探讨了其核心概念,并介绍了K最*邻和*似最*邻这两种关键的搜索算法,后者通过牺牲少量精度换取了在大规模数据下的高效查询能力。
在下一个视频中,我将引导你学*如何使用Cypher查询语言来查询Neo4j图数据库中的数据,为你完成实验做好准备。
150:Neo4j与Cypher查询语言(第1部分)📊

在本节课中,我们将学*图数据库Neo4j及其查询语言Cypher。我们将了解如何将数据建模为图,以及如何与图数据库进行交互,这与操作关系型数据库的方式类似。
概述
图数据库(如Neo4j)允许你将数据建模为图,并通过查询语言与之交互。在接下来的实验中,你将探索Neo4j。本节将介绍一种名为“属性图模型”的特定图模型,你可以在Neo4j中实现它。你还将学*如何使用Cypher查询语言与这样的图进行交互。
属性图模型
在关系型数据库中,你可以使用关系模型来表示数据,该模型描述了表、每张表的列名以及表之间的关系。类似地,在Neo4j中,你可以使用属性图模型来建模图数据。
请注意,下图从高层次描述了图的结构,但并未展示实际数据。该模型描述了图中存在哪些类型的节点,以及这些节点是如何链接在一起的。


在这个示例模型中,包含五种类型的节点:Customer(客户)、Order(订单)、Supplier(供应商)、Product(产品)和Category(类别)。节点的类型被称为节点标签。例如,如果一个节点代表一个产品类别,它就应该拥有Category标签。
每个节点之间的边被称为关系,每个关系都有一个类型,显示在每个箭头旁边的文本中。每个关系类型都有一个源节点和一个目标节点。例如,SUPPLIES关系的源节点是Supplier节点,目标节点是Product节点。
实际数据示例
以下是一些遵循此图模型的实际数据示例。

你可以看到五个粉色的客户节点。对于每个客户,你可以看到他们购买的订单、每个订单包含的产品、每个产品所属的类别以及每个产品的供应商。
你还可以看到与每个节点关联的附加信息,例如订单节点的ID、客户节点的CustomerId和产品节点的ProductName。这些信息被称为节点属性。
你可以为每个节点关联多个属性,以进一步描述它所代表的实体。在描述完整的图模型时指定节点属性,因此得名“属性图模型”。
以下是此模型中一些节点和关系的属性示例:
- 客户节点属性:每个客户关联一组属性,包括他们的地址、联系人姓名、客户ID等。
- 例如,客户
QUEDE的属性值可能包括:Address、ContactName、CustomerId等具体信息。
- 例如,客户
- 其他节点属性:其他节点标签(如订单、产品)也有关联的属性集。
- 关系属性:你不仅可以为节点指定属性,还可以为每个关系指定属性。
- 例如,
ORDERS关系类型(将订单映射到特定产品)拥有以下属性集:Discount(折扣)、Quantity(数量)和UnitPrice(单价)。 - 下图展示了此
ORDERS关系属性的值示例。
- 例如,

在Neo4j中创建图数据库
在Neo4j中创建图数据库有几种方法。一种方法是向Neo4j编写一组指令,指定图模型的详细信息,例如节点及其标签和属性,以及节点之间的关系及其类型和属性,并指明节点及其关系的数据来源(可能在一些CSV文件中)。
Neo4j将使用给定的数据创建实际的图。然后,你可以执行查询来与图交互并可视化查询结果。
你需要使用Cypher查询语言来创建图数据库或与Neo4j中的数据交互。
后续内容与实验
在下一个视频中,我们将通过一些示例,介绍如何使用Cypher查询语言从图数据库中读取信息。然后在实验中,你将练*更多的CURD操作来创建和修改图数据库。
在实验中,你将按照说明打开Neo4j桌面浏览器,其界面大致如下所示:

我已经按照本视频开头看到的图模型示例创建了一个数据库。如果你想了解更多关于如何创建此图数据库的信息,可以查看视频后的阅读材料。我附上了所使用的CSV文件链接以及可用于创建相同图的Cypher指令。
总结
本节课我们一起学*了Neo4j图数据库的基础概念。我们介绍了属性图模型,它由带有标签和属性的节点,以及带有类型和属性的关系构成。我们还了解了在Neo4j中创建数据库的一种方法,并知道接下来需要使用Cypher查询语言来与图数据进行交互。


现在你已经了解了属性图模型的样子,接下来请和我一起进入下一个视频,学*将在实验中用于与图数据交互的Cypher查询语句。
151:Neo4j与Cypher查询语言(第二部分)🔍

在本节课中,我们将深入学*如何使用Cypher查询语言从Neo4j图数据库中检索信息。我们将重点介绍MATCH语句,它用于在图中搜索并返回指定的模式,类似于关系型数据库中的SELECT语句。此外,我们还将学*如何过滤结果、聚合数据以及探索节点和关系的属性。
概述
上一节我们介绍了Neo4j的基本概念和图数据模型。本节中,我们将看看如何使用Cypher查询语言的核心语句——MATCH,来从图中检索所需的信息。MATCH语句允许你指定希望Neo4j搜索并返回的模式,其基本格式为:MATCH pattern RETURN result。
检索所有节点
首先,让我们从检索图中的所有节点开始。在Cypher中,我们使用圆括号 () 来表示一个节点。
以下是检索所有节点的查询语句:
MATCH (n)
RETURN n
这个语句会返回图中的所有节点。
统计节点数量
如果你想获取节点的总数,可以使用 COUNT 函数。
查询语句如下:
MATCH (n)
RETURN COUNT(n)
探索节点标签
你可以使用 LABELS 函数来查看图中存在哪些节点标签。使用 DISTINCT 关键字可以确保返回的标签不重复。
以下是查询语句:
MATCH (n)
RETURN DISTINCT LABELS(n)
在本例中,节点具有的标签与之前看到的图模型一致。
统计特定标签的节点
如果你想统计具有特定标签(例如 Order)的节点数量,可以在 MATCH 模式中指定标签名称。
查询语句如下:
MATCH (n:Order)
RETURN COUNT(n)
执行结果显示,该图包含99个 Order 节点。
探索节点属性
你可以通过在 RETURN 语句中调用 PROPERTIES 函数来查看与每种节点类型关联的属性。
例如,要查看所有 Order 节点的属性:
MATCH (n:Order)
RETURN PROPERTIES(n)
此语句返回所有 Order 节点的属性。你可以使用 LIMIT 关键字来限制返回结果的数量。
例如,只查看第一个节点的属性:
MATCH (n:Order)
RETURN PROPERTIES(n)
LIMIT 1
探索关系(边)
到目前为止,我们探索了图中节点的信息。但你也可以探索边(即节点之间的关系)的信息。
在Cypher中,使用方括号 [] 表示关系。由于关系存在于两个节点之间,表示从源节点到目标节点的有向路径的模式如下:
(source)-[r]->(target)
统计所有有向路径
如果你想统计图中所有有向路径的数量,可以编写如下 MATCH 语句:
MATCH ()-[r]->()
RETURN COUNT(r)
此查询显示图中有518条有向关系。
查看关系类型
你可以修改 RETURN 语句来查看图中不同类型的关系:
MATCH ()-[r]->()
RETURN DISTINCT TYPE(r)
指定关系类型并查看属性
你也可以通过指定关系的标签来调查特定类型的关系。例如,调查 ORDERS 关系:
MATCH ()-[r:ORDERS]->()
RETURN TYPE(r), PROPERTIES(r)
计算订单平均价格
对于 ORDERS 关系,如果你想计算订单的平均价格,可以通过将 quantity 属性乘以 unitPrice 属性来得到价格,然后求平均值。
查询语句如下:
MATCH ()-[r:ORDERS]->()
RETURN AVG(r.quantity * r.unitPrice) AS average_price
使用 AS 关键字可以为返回值创建别名,例如这里的 average_price。
按产品类别分组计算平均价格
如果你想按产品类别分组计算所有订单的平均价格,可以在 MATCH 语句中添加路径来获取类别节点。
查询模式是:匹配所有属于特定类别 c 的 ORDERS 关系 r。
以下是查询语句:
MATCH (c:Category)<-[:PART_OF]-(:Product)<-[r:ORDERS]-()
RETURN c.categoryName, AVG(r.quantity * r.unitPrice) AS avg_price_per_category
在 RETURN 语句中,我们添加了 c.categoryName,这是一个代表每个类别的名称列表。
使用 WHERE 语句过滤结果
你可以使用 WHERE 语句来过滤结果,这与SQL中的 WHERE 语句类似。
示例:检索特定类别的产品
假设你想检索属于“Meat/Poultry”类别的所有产品的产品名称和产品单价。
首先,需要指定产品节点属于类别节点的路径。注意,我为产品和类别节点分配了变量,但没有为 PART_OF 关系分配变量,因为在后续查询语句中不需要引用该关系。
接下来,指定过滤条件:类别名称属性等于“Meat/Poultry”。最后,指定要返回的产品属性。
查询语句如下:
MATCH (p:Product)-[:PART_OF]->(c:Category)
WHERE c.categoryName = 'Meat/Poultry'
RETURN p.productName, p.unitPrice
在节点括号内指定属性
除了在 WHERE 语句中指定属性,你也可以在节点括号内使用花括号 {} 来明确过滤条件。
上述查询可以改写为:
MATCH (p:Product)-[:PART_OF]->(c:Category {categoryName: 'Meat/Poultry'})
RETURN p.productName, p.unitPrice
查找客户订购的产品
假设你想检索客户ID为“QUE”的客户订购的所有产品的名称。
查询路径是:从客户节点开始,通过 PURCHASED 和 ORDERS 关系链到达产品节点。
查询语句如下:
MATCH (c1:Customer {customerID: 'QUE'})-[:PURCHASED]->()-[:ORDERS]->(p:Product)
RETURN p.productName
注意,对于 PURCHASED 关系,我不必为目标订单节点指定变量,因为在查询语句的其余部分不需要引用该变量。
查找订购相同产品的其他客户
对于同一客户“QUE”,假设你想获取订购了与“QUE”相同产品的其他客户的ID。
查询路径是:从客户“QUE”开始,通过两个 PURCHASED 和 ORDERS 关系链到达产品节点,然后通过 ORDERS 和 PURCHASED 关系使用左箭头 <- 从产品节点反向链接到另一个客户节点。
查询语句如下:
MATCH (c1:Customer {customerID: 'QUE'})-[:PURCHASED]->()-[:ORDERS]->(p:Product)<-[:ORDERS]-()<-[:PURCHASED]-(c2:Customer)
RETURN c2.customerID
检索包含至多两个产品的订单
让我们对这个图进行最后一次搜索。假设你想检索包含最多两个产品的订单。
我们可以分步思考:
- 首先,获取每个订单的产品总数。
- 然后,过滤出产品数量小于等于2的订单。

第一步的查询语句如下,它相当于使用SQL的 GROUP BY 语句按订单ID分组,然后计算每个订单ID的产品数量:
MATCH (o:Order)-[:ORDERS]->(p:Product)
RETURN o.orderID, COUNT(p) AS productCount
接下来,我们需要添加一个 WHERE 语句来过滤产品数量小于等于2的订单。为此,我们将 RETURN 语句替换为 WITH 语句,它允许你在之后访问 orderID 和 productCount 输出。
完整的过滤查询如下:
MATCH (o:Order)-[:ORDERS]->(p:Product)
WITH o.orderID AS orderID, COUNT(p) AS productCount
WHERE productCount <= 2
RETURN orderID, productCount
总结

在本节课中,我们一起学*了Cypher查询语言的核心 MATCH 语句,用于从Neo4j图数据库中检索数据。我们涵盖了如何检索节点和关系、使用函数统计和聚合数据、通过 WHERE 语句过滤结果,以及构建更复杂的查询路径来回答具体问题。这些基础技能对于操作和分析图数据至关重要。

在接下来的实验中,你将有机会使用 MATCH 语句,并学*其他如 CREATE 和 DELETE 等语句。实验将指导你在Neo4j图形界面中可视化图,但完成实验主要将在Jupyter Lab中进行,你需要在代码单元格中编写查询。这些查询将封装在Python代码中,自动连接到实验提供的图数据库。你还将学*如何不仅将Neo4j作为图数据库,还作为向量数据库进行交互。
152:图与知识图谱入门 🗺️
概述
在本节课中,我们将与专家Juan Sequeda一起探讨图与知识图谱的核心概念。我们将学*图的基本定义、图数据库与传统数据库的区别、两种主要的图模型(RDF与属性图),以及知识图谱如何为大型语言模型提供关键上下文。本课程旨在为初学者提供一个清晰、直观的理解框架。
什么是图?🔵➖🔵
上一节我们介绍了课程概述,本节中我们来看看图的基本概念。
图是一种数据结构,由节点和边组成。从集合论的角度看,节点可以看作一元关系(想象一个只有一列的表),而边则是二元关系(想象一个有两列的表)。节点是图中的“点”或“气泡”,边是连接这些点的“线”,代表它们之间的关系。
这种结构可以表示类似父子关系的语义。当你开始为边(关系)赋予具体含义时,就超越了“A连接到B”的简单表述,进入了知识层面。
以下是图的基本构成:
- 节点:代表实体或对象。
- 边:代表节点之间的关系。
从技术上讲,一个图可以只有一个节点,也可以只有一堆互不连接的节点。当边出现并连接节点时,图开始生长。图的结构特性包括:边的数量、图中是否存在环、不同节点间的路径等。
图数据库与其他数据库
了解了图的基本结构后,我们来看看图在数据库系统中是如何应用的。
数据库是数据的集合。数据库管理系统(DBMS)是管理这些数据集合的方式。传统上,我们熟悉的是关系型数据库,它使用关系模型(即表格)来组织数据。
图数据库则是一种专门为以图形式管理数据而设计的数据库管理系统。它支持对图中数据的增、删、改、查等操作。
除了关系型数据库和图数据库,还有一类被称为“NoSQL”的数据库,它们不限于SQL关系模型。这其中包括:
- 文档数据库:主要处理JSON或XML等文档。
- 对象数据库:起源于80年代,其中包含了许多图的概念。
数据库不仅存储数据,还需要提供访问数据的能力,这就是查询语言的作用。
图模型:RDF 与 属性图
上一节我们介绍了不同类型的数据库,本节中我们聚焦于两种主流的图数据模型。
就像SQL是关系型数据库的标准查询语言一样,图世界也有不同的模型和语言。主要有两种模型:
1. RDF
RDF(资源描述框架)源于万维网社区。其最初的愿景是让数据能够相互链接并描述自身含义,而不仅仅是文档之间的超链接。RDF基于三元组模型:
<主体, 谓词, 客体>
这类似于英语中的“主-谓-宾”结构。例如:“<这份文档, 由, Joe编写>”。RDF最初用于为网页添加元数据注释。用于查询RDF的标准语言是SPARQL。
2. 属性图
属性图同样由节点和边构成,但其特点是节点和边都可以关联键值对。这个模型更多是从构建图应用的角度出发,边是“一等公民”。该模型最初由Neo4j推广,其查询语言是Cypher。*年来,业界正在通过ISO组织推动属性图查询语言的标准化,即GQL。
为何选择图数据库?
我们已经了解了图数据库的模型,那么在实际应用中,为什么要选择图数据库而不是传统的关系型数据库呢?
这是一个关键问题。关系型数据库要求预先定义严谨的模式(Schema),适合需求固定、逻辑明确的应用。你可以针对已知的查询负载进行优化。
而图数据库在以下场景更具优势:
- 灵活性:图模型(三元组、节点和边)天生灵活,可以轻松添加新的节点和边,无需像关系型数据库那样频繁重构表结构。适用于需求变化频繁的场景。
- 更高的抽象层级:图(气泡和线)更贴*人类思考复杂关系的方式,有助于弥合业务含义与技术实现之间的“数据语义鸿沟”。
- 处理“图式”问题:对于需要寻找路径、分析网络、检测社群、计算中心度(如推荐系统、欺诈检测)的应用,图是天然的选择。
- 数据集成:图可以作为最小公分母,将表格、JSON、XML乃至NLP提取的实体关系转换为统一的图结构,非常适合集成来自多源、异构的数据。
简而言之,如果你的需求非常固定,可以使用关系型数据库。如果你需要集成多方数据且业务环境不断演变,那么你最终很可能会构建一个图模型——既然如此,不如从一开始就选择图数据库。
从图到知识图谱 🧠
我们讨论了图数据库的优势,现在让我们进入一个更丰富的概念:知识图谱。
图可以视为原始数据(节点和边),而知识则关乎捕获数据的含义。知识图谱在图的基础上增加了:
- 模式:定义实体类型和关系。
- 丰富的语义信息:例如,定义“一个订单只能由一个客户购买,但一个客户可以下多个订单”这样的基数约束。
- 分类体系:例如,定义“化妆品”是一个大类,“口红”是“化妆品”的一个子类。
知识图谱将所有这些语义、含义和领域知识连接起来,使其与用户对业务的理解方式对齐。
知识图谱与大型语言模型
在2024年AI浪潮的背景下,知识图谱与大型语言模型的关系尤为重要。
LLM虽然“知道”很多通用知识,但通常不了解你组织内部的特定上下文和语义。人们希望用LLM来“与自己的数据对话”。当前很多工作聚焦于让LLM理解文档或通过文本到SQL来查询数据库。
我们的研究发现,在回答基于结构化数据的问题时,如果利用知识图谱(将问题转换为SPARQL查询),其准确性比直接转换为SQL查询高出三倍。我们假设原因在于:
- LLM基于语言,而RDF三元组(主-谓-宾)本身具有语言结构。
- 图中的关系是显式的、有名称和语义的“一等公民”,而在关系型数据库中,关系隐含在外键中,且列名可能不够描述性。
因此,知识图谱为LLM提供了理解你企业数据的必要上下文。如果你想为关系型数据库添加所有这些上下文,本质上你就是在构建一个知识图谱。
总结与建议
本节课中,我们一起学*了图与知识图谱的核心知识。
最后,给初学者的建议是:
- 拥抱范式转变:图是一种不同的思维方式。跳出表格的舒适区,尝试新的视角。
- 尊重历史:图和知识图谱的概念有深厚的历史渊源,并非一时的新发明。我们应该站在巨人的肩膀上,避免重复造轮子。
课程总结
在本节课中,我们与Juan Sequeda一起探讨了:
- 图的基本概念:由节点和边组成的数据结构。
- 图数据库:专门管理图数据的系统,区别于关系型数据库。
- 两大图模型:基于三元组的RDF和具有键值对的属性图。
- 图数据库的应用优势:灵活性、高抽象性、擅长处理关联关系和集成异构数据。
- 知识图谱:在图的基础上融入了丰富的语义和业务规则。
- 知识图谱与AI:知识图谱能为大型语言模型提供关键的业务上下文,显著提升其处理企业结构化数据问答的准确性。
希望本教程能帮助你建立起对图与知识图谱清晰而直观的理解。
153:第1周总结 📚

在本节课中,我们将回顾第一周课程的核心内容。我们重点学*了存储层次结构的前两层:原始存储介质和构建于其上的存储系统。同时,我们也深入探讨了数据库的基础知识,包括存储引擎、索引以及不同的数据存储格式。
🧱 原始存储介质与存储系统
上一节我们介绍了课程的整体框架,本节中我们来看看存储层次结构的基础层。
我们比较了多种原始存储介质的成本与性能。
以下是主要的存储介质类型及其特点:
- 机械硬盘:成本较低,但读写速度相对较慢。
- 固态硬盘:读写速度快,但单位存储成本高于机械硬盘。
- 内存:速度最快,用于临时存储和处理数据,但成本最高且断电后数据会丢失。
在理解了这些基础组件后,我们探讨了构建于其上的存储系统。你基于先前关于对象存储和分布式存储系统的知识,通过实践练*探索了文件、块和对象存储之间的区别。
尽管对象存储可能是当今数据工程领域中最主要的文件存储和检索机制,但你仍需准备好评估每种云存储选项的性能,以便为组织的具体用例选择最佳方案。
🗃️ 数据库基础
在了解了基础存储系统后,本周第二课的重点转向了数据库。

数据库存储引擎负责在磁盘上物理存储和组织数据。通过探索各种示例,你学*了如何使用索引来提升查询性能。


索引的核心作用可以用一个简单的类比理解:就像一本书的目录,它能帮助你快速找到所需内容,而无需逐页翻阅。在数据库中,索引通过创建额外的数据结构来加速数据检索。

接着,我们深入探讨了行存储与列存储的细节,并了解了每种存储格式适用的不同数据工程用例。
以下是两种存储格式的简要对比:
- 行存储:将一整行数据连续存储。适合需要频繁进行整行读取或写入的事务处理场景。
- 列存储:将每一列的数据连续存储。适合需要快速对特定列进行聚合和分析的查询场景。
最后,我们概览了一些随着生成式AI兴起而流行的数据库。你学*了图和向量数据库如何存储和检索数据,并有机会使用Neo4j图数据库及其Cypher查询语言进行实践。
Cypher查询语言示例:
MATCH (p:Person)-[:LIVES_IN]->(c:City)
WHERE c.name = '北京'
RETURN p.name
📈 总结与展望
本节课中,我们一起学*了存储系统的基石——从物理介质到数据库引擎。我们比较了不同存储介质的特性,分析了文件、块、对象存储的差异,并深入理解了数据库索引以及行、列存储格式的应用场景。

下周,我们将沿着存储层次结构向上,讨论存储抽象。你将看到存储架构和框架如何随着数据仓库、数据湖乃至数据湖仓的出现而演变,并深入探索每种架构的细节。


期待下次再见。
154:数据工程(导论,源系统、数据摄取和管道,数据存储和查询|1-2-3课) - 第2周概览 🗂️

在本节课中,我们将要学*数据存储的抽象层次。我们将从数据仓库架构开始,探讨其向现代云数据仓库的转变,然后深入了解数据湖的兴起及其挑战,最后探索旨在结合两者优势的数据湖仓架构。
上周我们探讨了存储原始组件的细节。你看到了作为数据工程师,理解不同存储介质和流程的特性、性能和成本,如何帮助你更好地评估存储解决方案决策中的权衡。
然后我们探索了不同的存储系统,包括对象存储和常见类型的数据库。
本周我们将沿着存储层次向上移动,探索不同的存储抽象。
数据仓库架构的演变 🏢

上一节我们介绍了基础的存储系统,本节中我们来看看数据仓库架构。
我们将首先审视数据仓库架构,以及其向现代云数据仓库的变革性转变。
数据湖的兴起 🌊
在了解了数据仓库之后,本节我们将探讨数据湖。
我们将深入探讨数据湖的兴起,这是对数据量、数据类型和用例方面不断增长的存储需求的回应。我们也将审视与此架构相关的挑战。
以下是数据湖兴起的主要驱动因素:
- 数据量的爆炸式增长。
- 数据类型的多样化,包括非结构化数据。
- 支持更广泛的分析用例的需求。
数据湖仓架构:融合优势 🏢🌊
在分别探讨了数据仓库和数据湖之后,本节我们来看看结合两者优势的架构。
最后,我们将审视数据湖仓架构,其目标是结合数据仓库和数据湖两者的优势。
我将本周内容设置为一次穿越数据存储抽象历史的旅程。当我们探讨每一种范式时,你将思考其各自的优点、缺点和可能的用例。这里的目的是让你对每种架构有足够的理解,以便你能根据你的用例选择最合适的存储解决方案。
在本周的实验练*中,你将使用 AWS Glue 和 Athena 在数据湖中进行高效的数据检索。然后,你将有机会尝试使用 AWS Lake Formation 和 Apache Iceberg 表,通过一种称为“奖牌架构”的方式来创建数据湖仓。


在我们深入探讨每一种存储抽象范式的细节之前,我想给你一个机会,听听被广泛认为是数据仓库之父、该领域知识渊博的专家之一——Bill Inmon 的见解。下一个视频是可选的,如果你更想直接跳转到数据仓库架构的细节,可以自由跳过。否则,请享受接下来与 Bill Inmon 的对话。之后我将与你再次会面,更深入地探讨数据仓库。


本节课中我们一起学*了数据存储的三种主要抽象范式:数据仓库、数据湖和数据湖仓。我们了解了每种架构的演变背景、核心特点以及适用场景,为根据具体用例选择合适的存储解决方案奠定了基础。
155:与Bill Inmon的对话 🎙️

在本节课中,我们将与数据仓库之父Bill Inmon进行对话,了解数据仓库的起源、ETL技术的发展历程以及数据工程领域的早期故事。通过他的亲身经历,我们可以更好地理解现代数据基础设施的演进背景。
数据仓库的诞生 🏗️
上一节我们介绍了数据工程的基础概念,本节中我们来看看数据仓库的起源。Bill Inmon是数据仓库概念的创建者,也可以说是现代数据行业的奠基人。
Bill Inmon于1965年在新墨西哥州的白沙导弹靶场编写了他的第一个程序。他回忆道,偶尔在傍晚时分,大家会走到阳台上观看从犹他州发射到白沙导弹靶场的导弹。他表示,如果不从事计算机行业,自己无法成为一名医生,也不想成为律师,因此不确定生活会走向何方。但编写第一个计算机程序后,他便爱上了计算。
随后,他提出了数据仓库的概念。
什么是数据仓库? 📊
那么,什么是数据仓库?一个简单的单句定义是:数据仓库无非是公司数据,即代表公司所有方面的数据。
为了理解数据仓库,一个好的起点是了解数据仓库出现之前的世界。在那个时代,我们拥有应用程序。每个应用程序设计师都为使用该应用程序的人构建应用程序,这似乎很合理。但问题是,随着时间的推移,我们开始拥有大量应用程序。每个应用程序都是独立且不同的。因此,实际情况是,除了应用程序用户之外,公司中还有其他人需要使用应用程序数据。
公司中有市场营销、销售、财务、管理等各个部门,这些组织都需要所谓的公司信息视图。问题在于,你无法真正从应用程序中获得数据的公司视图,因为每个应用程序都是特定和定制化的。因此,当会计和营销部门的人员想要查看公司中的所有数据时,他们无法做到。
所以,数据仓库的一个简单定义是公司数据。它是跨越公司范围的数据。当谈论数据仓库时,通常会涉及数据转换,即从应用程序基础到公司基础的数据转换。
ETL技术的起源与发展 ⚙️
上一节我们定义了数据仓库,本节中我们来看看数据如何进入仓库。典型情况下,这种转换是通过称为ETL(提取、转换、加载) 的技术完成的。ETL技术已经存在很长时间,Bill Inmon也是ETL的创始人之一。
在数据仓库的早期,人们围坐讨论如何将数据导入数据仓库。早期的做法是手动编写程序,使用PL/1、COBOL或类似的FORTRAN等语言。他们会编写这些程序来查找数据、转换数据并将其放入数据仓库。
但很快,他们发现构建这些程序是一项非常繁重的任务,既耗时又枯燥。此外,他们还发现逻辑一遍又一遍地重复。编写ETL程序的知识性刺激在最初的30秒内就消失了,因为你是在重复编写相同的程序。
因此,Bill Inmon和Prison Solutions的几位创始人提出:“我们真正需要的是自动化技术,可以进入数据世界,找到必要的数据,进行转换并将其导入数据仓库。”这就是ETL的起源。
早期挑战与行业故事 📜
Bill Inmon在行业中工作了很长时间,可以说他创建了这个行业。他有一些有趣的故事和轶事想与学生分享。
他可以谈谈数据仓库的早期日子,他认为这很有趣,否则可能没人会听到这些故事。但他必须警告,他将涉及一个供应商,因为当时有另一个供应商竭尽全力压制数据仓库,那就是IBM公司。
在数据仓库开始时,IBM是主导供应商。这实际上正是微软开始进军世界的时候。在当时,任何技术都是IBM的,IBM在公司的地位既是顾问又是销售人员,这对公司来说是危险的。
当数据仓库出现时,IBM竭尽全力反对。在那个时代,成为IBM的反对者很困难,就像大卫对抗歌利亚。而他当然不是歌利亚。
他们开始构建数据仓库。当时他恰巧是《Comp World》杂志的记者,并开始撰写文章。他指出,那篇惹恼IBM的文章在今天看来很有趣,但当时并不好笑。他提出建议,认为数据可以用于事务处理以外的用途。
这激怒了IBM及其盟友,他们有一种奇特的观点,认为数据只应用于事务处理,说其他任何话都是异端邪说。他唯一的平台就是他在《Computer World》上发表的文章。你应该看到一些回复和读者来信。他记得其中一封说:“这个人是个无政府主义者。”另一封说:“他不应该再被允许公开讲话。”还有一些含有脏话的信件,他也收到了很多。无论如何,这在学术界和IBM世界中引起了强烈的本能反应。
有趣的是,在早期,世界上的技术人员根本不支持数据仓库。他们将数据仓库卖给营销组织。感谢营销组织,如果没有营销人员,数据仓库今天就不会存在。
持续的动力与行业先驱 👨💼
最后,是什么让Bill Inmon在数据领域坚持了这么多年?他的真正方向是什么?
有时早上起床,他也会问自己同样的问题。当他看到一些他认为根本不对的事情时,就会促使他采取行动。他看到的一件不对的事情是文本在公司中没有得到利用,这促使他构建了称为文本ETL的技术。
另一件他看到不对的事情是,有一天他在一个会议上与其他计算机专业人士在一起,他提到Ed Yourdon去世了。令他惊讶的是,桌上没有一个人知道Ed Yourdon是谁。他感到惊讶,因为Ed Yourdon和其他三、四个人对我们的行业产生了惊人的影响。如果没有他们,我们的行业不会像今天这样,然而我们的行业却忘记了所有这些人。
以下是关于Ed Yourdon的介绍:
在很早的时候,当你是一名程序员时,结果总是说我们需要构建一个新系统,带上你的编码本。没有设计工作,什么都没有,最终用户认为他们想要什么,让我们今天就开始编码。在那个时代,编码就像狂野的西部,你只是开始写代码。
Ed Yourdon出现了,并看到了这一点。他说:“天哪,我们需要一种更有条理的方式来组织我们的专业,我们编写代码的方式,我们进行设计的方式。”Ed Yourdon开始了称为结构化设计与分析的工作。简化版本的结构化设计与分析表示,我们需要一种有组织、有条理、经过深思熟虑的方式来布局这些程序。今天,我们做到了这一点,但在早期,我们没有。
在开发完成的方式、应用程序设计的方式方面,都要感谢Ed Yourdon。然而在他参加的这次会议上,甚至没有人知道他的名字。
总结 📝
本节课中,我们一起学*了数据仓库之父Bill Inmon的见解。我们探讨了数据仓库的定义与价值,回顾了ETL技术的起源与发展,并聆听了数据工程早期与行业巨头抗争的故事。这些历史背景帮助我们理解,现代数据基础设施的建立并非一帆风顺,而是源于解决实际业务需求、挑战传统观念并持续创新的过程。Bill Inmon对行业先驱的铭记也提醒我们,在快速发展的技术领域中,尊重历史与 foundational work 同样重要。
156:数据仓库关键架构理念 🏗️

在本节课中,我们将要学*数据仓库的核心概念、其定义、传统架构以及向现代云数据仓库的演进过程。理解这些理念对于构建高效、可靠的数据分析平台至关重要。
数据仓库的起源与定义
在数据工程师的工作中,你会从许多不同的源系统摄取数据。一个非常常见的来源是作为OLTP系统一部分的数据库,其数据以优化事务性工作负载的方式进行结构化。

OLTP系统已经存在了几十年。在数据分析的早期,团队直接在生产的OLTP数据库上运行分析查询的情况并不少见。
正如之前多次提到的,在生产数据库上运行分析查询可能带来灾难性后果。此外,直接在基于行的事务性数据上进行数据分析可能非常低效且成本高昂。
早在20世纪80年代末,Bill Inmon提出了数据仓库的概念来解决这个问题。他将数据仓库描述为:一个面向主题的、集成的、非易失的、随时间变化的数据集合,用于支持管理决策。这个基础定义强调了数据仓库作为中央数据存储库的角色,旨在促进报告和分析。
详解数据仓库定义
上一节我们介绍了数据仓库的起源,本节中我们来详细拆解其定义。
以下是Bill Inmon定义中四个关键特征的解析:
- 面向主题:数据仓库围绕业务的关键主题或领域(如客户、产品、销售或财务)组织和存储数据。其重点在于建模数据以支持决策,而非事务处理和记录。
- 集成:数据仓库汇集来自不同来源的数据,并确保其以预定义模式一致地存储。
- 非易失:数据仓库中的数据是只读的,通常意义上不能被删除或更新。这对于历史数据分析非常有用。非易失性原则要求数据仓库在从源系统初始加载数据时,将数据作为快照捕获并加载。当源系统发生后续更改时,要么将数据的新快照加载到数据仓库,要么仅加载更改。无论如何,数据的现有快照不会被删除或更改,而是保留在数据仓库中。
- 时变:数据仓库存储当前数据和历史数据。数据用户可以通过查看这些历史数据来观察多个主题的趋势,以支持其业务决策。这是OLTP源系统通常无法做到的,因为它们通常不支持保留历史数据或进行历史数据分析。

尽管数据仓库的技术层面已发生重大演变,但这个原始定义至今仍然适用。
传统数据仓库架构:ETL与数据集市
理解了数据仓库的核心特征后,我们来看看如何将数据加载到其中。
传统上,你会使用ETL管道从各种来源将数据加载到数据仓库。ETL即提取、转换、加载的摄取模式。典型流程如下:首先将提取的数据移动到数据仓库外部的暂存区(例如S3对象存储)。在那里,你将应用转换来清理和标准化数据。这也是你根据特定模型构建数据的地方,以使数据对下游用户有用。我们将在下一门课程中详细讨论数据建模。接下来,你将转换后的数据加载到数据仓库中。
数据仓库旨在为更广泛的组织服务,但你也可以通过将数据加载到所谓的数据集市来服务于特定用户群。你可以将每个数据集市视为数据仓库的一个更精细的子集,旨在满足单个部门或业务功能(如销售、营销或财务)的特定需求。与数据仓库的综合模式不同,数据集市中的数据通常遵循更简单的反规范化模式,仅提供特定于某个部门的、更聚焦的数据子集视图。
借助数据集市,你还可以在初始ETL管道提供的转换之外,执行额外的转换阶段,这可以提高需要复杂连接和聚合的分析查询的性能。
ETL过程通常用于使数据仓库中的数据与生产数据库保持同步,因为这些源数据库会持续更新。当你从生产数据库提取数据时,可以不用提取所有数据,而是使用变更数据捕获或CDC过程来识别和捕获仅变更事件(如插入、更新或删除),并将这些变更传送到你的数据仓库。通过仅提取增量变更,你可以最大限度地减少对源系统性能的影响。

从OLTP到OLAP:数据仓库的演进
上一节我们介绍了如何通过ETL将数据加载到仓库,本节中我们来看看数据仓库带来的核心转变。
因此,数据仓库是对传统OLTP系统的背离。通过从生产数据库中提取数据,将其建模以支持分析工作负载,然后将其加载到单独的数据仓库中,你可以将负载从生产系统转移开,并以改进的分析查询性能提供更好的最终用户体验。这使得数据仓库成为在线分析处理或OLAP数据架构的标准。
数据仓库的最早实现基于单一的整体式服务器,这限制了其性能。随着整个20世纪90年代数据量的稳步增长,传统数据仓库无法跟上。随后,大规模并行处理或MPP系统的出现使数据仓库能够扩展。实现了MPP的数据仓库能够并行扫描大量数据,实现高性能的分析查询。但这些系统复杂且固定,需要付出精力和时间来维护。
在21世纪10年代初,现代云数据仓库(如Amazon Redshift、Google BigQuery和Snowflake)出现,代表了与过去本地数据仓库架构的重大演变。现代云数据仓库架构将计算与存储分离,并扩展了MPP系统的能力。这使得大规模数据集的处理具有可扩展性和高效性,并使数据分析对小型组织而言更易于访问且更具成本效益。
总结

本节课中我们一起学*了数据仓库的关键架构理念。我们从其起源和Bill Inmon的经典定义开始,详细解析了其面向主题、集成、非易失和时变的特征。接着,我们探讨了传统的ETL数据加载流程以及服务于特定部门的数据集市概念。最后,我们回顾了数据仓库如何从OLTP系统中分离出来,成为OLAP的标准,并最终演进为将计算与存储分离的现代云数据仓库架构。理解这些核心理念是设计和构建有效数据工程解决方案的基础。
157:现代云数据仓库 🏢

在本节课中,我们将学*现代云数据仓库的核心概念。我们将探讨云数据仓库相比传统本地数据仓库的优势,并深入了解其架构特点,包括大规模并行处理、列式存储以及计算与存储分离等关键特性。
作为数据工程师,你很可能会接触到云数据仓库。在本视频中,我们将详细探讨云数据仓库相比传统本地数据仓库具备更强处理能力的因素。理解这些因素将帮助你设计更高效的数据仓库,并更好地管理扩展、性能和成本。
正如上一节视频所提到的,数据仓库通常采用大规模并行处理架构。这种架构使用多个处理器来处理海量数据。对于云数据仓库,你无需预先精确配置MPP系统,也无需花费数百万美元的前期投入来建立系统。你可以按需启动计算集群,随着数据和分析需求的增长逐步扩展,或在不再需要时删除集群。

接下来,让我们花点时间看看亚马逊Redshift的具体MPP架构。其他云数据仓库,如Google BigQuery和Snowflake,也使用类似的结构,但实现细节有所不同。
在Redshift中,计算资源的集合被称为一个集群。每个集群由一个或多个计算节点组成,这些节点由一个领导者节点管理。这些节点拥有自己的CPU、内存和磁盘空间。一个计算节点进一步划分为多个节点切片,每个切片包含节点CPU、内存和磁盘空间的一部分。
当你将数据加载到Redshift时,领导者节点管理数据如何在节点切片之间分布。当客户端应用程序向数据仓库发送查询请求时,领导者节点将请求解析为一系列步骤,并形成一个执行计划。然后,基于该计划,领导者节点编译代码并将其分发给包含与查询相关数据的相应计算节点切片。这些切片并行工作以完成工作负载。接着,计算节点将中间结果发送回领导者节点。最后,领导者节点聚合结果,并将最终结果发送回客户端应用程序。
随着工作负载的增加,你可以启动更多计算节点,或将节点类型升级为具有更高计算能力的类型。从这个意义上说,云数据仓库扩展了MPP系统的能力,使你能够轻松扩展数据基础设施,以处理单次查询中高达PB级别的数据。
随着MPP带来的处理能力提升,云数据仓库还可以支持ELT提取、加载和转换的摄取模式。从存储系统提取数据后,你无需在数据仓库外部转换和建模数据,而是可以将原始的、未经处理的数据直接加载到数据仓库内的暂存区域。然后,你可以利用云数据仓库的巨大计算能力来转换数据。这带来了更快的摄取速度,使你能够快速为下游利益相关者提供数据。
我们在云数据仓库中看到的另一个变化是从行式架构向列式架构的转变。正如上周所见,列式存储与数据压缩相结合,促进了大规模分析查询的更高性能。


最后,在许多云数据仓库中,数据存储在对象存储中,这提供了几乎无限的存储空间。这意味着你可以分离计算和存储,允许你独立管理和扩展这些资源,以优化成本和性能。
现在,云数据仓库仍然具备传统数据仓库的所有属性,即你存储的数据可以是高度结构化和建模的,以支持分析查询。将这些属性与MPP、列式存储以及计算与存储分离所带来的高处理能力相结合,使得云数据仓库在存储和处理大规模分析工作负载的数据时非常高效。


那么,如果你的公司想要存储和查询非结构化数据,比如文本、图像、音频文件或视频,该怎么办呢?现代数据应用不再局限于分析和报告。它们通常涉及机器学*或探索性分析等用例,这些用例需要直接访问各种非结构化数据,而不仅仅是运行SQL查询访问的数据。这正是数据湖存储架构发挥作用的地方。
本节课中,我们一起学*了现代云数据仓库的关键特性,包括其基于MPP的弹性扩展能力、对ELT模式的支持、列式存储的优势以及计算与存储分离的架构。这些特性共同构成了云数据仓库高效处理大规模分析工作负载的基础。
158:数据湖关键架构理念 🏞️

在本节课中,我们将要学*数据湖这一核心数据架构理念。我们将了解其基本概念、第一代数据湖(Data Lake 1.0)的贡献与局限性,以及它为何对许多组织而言既是机遇也是挑战。
想象你是一家电子商务公司的数据工程师,你的任务是将来自销售订单数据库的结构化数据、来自客户关系管理系统的半结构化客户记录,以及文本、视频和音频文件形式的客户评论整合在一起。你最初可能从数据仓库入手,但很快会发现半结构化和非结构化数据无法适应固定的模式,并且数据量非常庞大。
那么,与其对数据施加严格的结构限制,为什么不简单地将所有数据(无论是结构化的还是非结构化的)都导入一个中央存储库呢?这正是数据湖的概念,它在21世纪初至2010年代早期兴起。“数据湖”这个名字出现得稍晚一些,但存储海量结构化和非结构化数据的中央存储库理念,是这一新范式的驱动力。
与数据仓库不同,数据湖不要求你提前决定固定的模式或预定义一组转换。相反,数据湖遵循“读时模式”模式,即由读取者在读取数据时确定模式。
第一代数据湖(Data Lake 1.0)的贡献
上一节我们介绍了数据湖的基本理念,本节中我们来看看其最初的具体实现。第一代数据湖,我称之为Data Lake 1.0,通过结合不同的存储和处理技术,为实现上述承诺做出了扎实的贡献。
以下是其核心组成部分:
- 存储方面:Data Lake 1.0始于HDFS。但随着云计算的普及,基于云的对象存储(如Amazon S3)上构建数据湖变得更加常见。这种极其廉价且几乎无限的存储容量,允许你存储任何大小和任何类型的大量数据,为组织中的所有数据创建一个单一的真相来源。
- 处理方面:当你需要转换或查询数据时,可以从许多不同的技术中进行选择,包括MapReduce、Apache Pig、Spark、Presto和Hive等。
Data Lake 1.0的严重缺陷


尽管前景广阔且备受炒作,Data Lake 1.0存在许多严重的缺陷。最大的缺点是,1.0时代的数据湖常常变成了“数据沼泽”——一个组织倾倒数据却没有适当数据管理的地方。
以下是导致数据沼泽的几个关键问题:
- 缺乏数据管理:没有数据目录和数据发现等工具,用户很难找到所需的数据,也难以理解不同数据之间的关系。
- 数据质量无保障:即使能找到数据,也无法保证数据的完整性或质量。你无法判断数据是否是最新的或准确的。
- 数据操作困难:原始的数据湖概念本质上只支持写入。在SQL中常用的简单数据操作语言操作(如删除或更新行)实现起来非常痛苦,通常需要用户创建全新的表。这使得组织很难遵守GDPR等数据法规,因为这些法规要求组织在收到请求时能够删除用户记录。
- 查询性能不佳:没有模式管理和仔细的数据建模,处理存储在数据湖中的数据也非常具有挑战性。数据没有像数据仓库中的结构化数据那样为查询进行优化。例如,像连接这样的常见数据操作,编码成MapReduce作业非常头疼。
Data Lake 1.0的价值与挑战

即使Data Lake 1.0有所有这些缺点,许多组织,特别是像Netflix和Facebook这样高度以数据为中心的科技公司,仍然在数据湖中发现了巨大价值。这些公司拥有资源来建立成功的数据实践,并创建自己的定制工具来处理数据。
然而,对于许多组织来说,Data Lake 1.0是一次代价高昂的失望。好消息是,*年来出现了许多工具和实践,可以帮助企业更好地组织和查询存储在数据湖中的数据。
本节课中我们一起学*了数据湖的核心架构理念,回顾了Data Lake 1.0的贡献与主要缺陷。下一节视频,我们将共同探索下一代数据湖的特性。
159:下一代数据湖 🏞️

在本节课中,我们将要学*如何改进传统数据湖的不足,探索数据分区、数据目录等关键技术,并了解它们如何共同作用,以更高效地管理和查询海量数据。
上一节我们介绍了传统数据湖1.0版本的一些局限性。本节中,我们来看看工程师们为更高效地管理和查找数据湖中的数据而开发的一些方法。
具体来说,我们将探讨数据分区、数据分区和数据目录。
为了更好管理存储在数据湖中的数据,你可以将其组织到不同的区域中。每个区域存放着经过不同程度处理的数据。虽然没有关于区域数量或命名的固定规则,但一个常见的设计模式是拥有三个区域。
以下是三个常见的数据区域:
- 着陆区或原始区:当你将原始数据加载到数据湖时,它首先进入此区域。这样,你可以永久记录从源系统摄取的所有原始数据。
- 清洗区或转换区:在你对原始数据应用转换(如清洗、验证、标准化,以及移除或屏蔽任何个人身份信息)后,转换后数据的副本将被写入此区域。
- 策展区或丰富区:接下来,你通过施加业务逻辑并应用进一步的转换来对数据进行建模。然后,你将转换后的数据写入此区域。该区域的数据应符合组织的标准,并已准备好供消费使用。
你通常使用开放文件格式(如 Parquet、Avro 或 ORC)将数据存储在清洗区和策展区。这些格式使磁盘存储更高效。由于它们是开源的,也允许广泛的分析引擎和机器学*系统直接访问数据。
正如我所说,这些区域的数量和命名可以变化。你可能设计一个只有原始区或策展区的数据湖。或者,你可能需要执行更复杂的转换以符合严格的法规,在这种情况下,你可能需要四五个或更多的区域来处理中间存储阶段。
无论如何,将数据组织到不同的区域,允许你对每个区域应用适当的数据治理策略,并确保数据用户根据其特定需求,消费具有适当质量和准备度的数据。
现在,为了提高数据湖的查询性能,你通常希望从清洗区或策展区获取数据,并将其存储为分区数据。
数据分区是一种基于某些标准(如数据中记录的时间、日期或位置)将数据划分为更小、更易管理的部分的技术。这样,当你查询数据时,查询引擎只需要扫描包含与查询相关数据的那些分区,从而获得更快的查询性能。
最后,为了解决数据湖中数据可发现性的挑战,你可以创建一个数据目录。
数据目录是有关数据的元数据集合。这种集中式的元数据允许数据用户根据数据所有者、数据源、分区信息、列的业务定义等进行数据搜索。目录还记录和维护数据的模式,包括随时间的变化。因此,数据目录是一个关键特性,它为组织中的每个人提供了对数据结构和含义的共同理解。
通过这些增强的数据管理功能和搜索能力,你可以使用数据湖来存储、管理和处理大量不同类型的数据。

尽管人们努力使数据湖更有组织性和可搜索性,但历史上,组织仍然需要多个存储系统来满足其业务需求。他们希望利用数据湖的低成本存储来存储大量数据以用于机器学*应用,同时也希望利用数据仓库的卓越查询性能来支持分析用例。
因此,他们首先会在数据湖中摄取和处理数据,以便为所有数据建立一个单一的事实来源。然后,他们会将需要频繁查询的数据子集加载到数据仓库中,以支持低延迟的查询性能。
但这种解决方案成本高昂,因为你必须通过ETL管道持续地将数据从数据湖移动到存储成本更高的数据仓库中。并且ETL过程的每一步都可能引入错误或故障,导致数据质量、重复性和一致性问题。
为了解决这些挑战,一种名为“数据湖仓”的新存储架构被创建出来。这种新架构旨在将数据仓库和数据湖的优势结合到一个统一的架构中。
在我们深入了解这种新架构之前,我将引导你完成接下来的实验。在实验中,你将获得一些动手实践,对数据进行分区并创建数据目录,以提高从数据湖中检索数据的效率。
然后,在实验之后,请加入下一节视频,我们将更详细地探讨数据湖仓架构。

本节课中,我们一起学*了如何通过数据分区、数据目录等技术来优化数据湖的管理与查询性能,并了解了传统多系统架构的局限性,为引入下一代数据湖仓架构做好了铺垫。
160:使用 AWS Glue 构建简单数据湖(第1部分)🏗️

概述
在本节课中,我们将学*如何使用 AWS Glue 构建一个简单的数据湖。我们将处理存储在 Amazon S3 中的原始 JSON 文件,将其转换为 Parquet 格式,并使用 AWS Glue 爬虫和 Amazon Athena 来查询处理后的数据。本部分将重点介绍数据转换函数的定义以及通过 Terraform 定义相关 AWS 资源。
实验简介与目标
在本次实验中,你将操作一个使用 Amazon S3 作为主要存储的简单数据湖。实验提供了一个包含原始 JSON 文件的 S3 存储桶,这些文件代表某些亚马逊产品的评论和元数据。
你的任务是处理和转换这些文件为 Parquet 格式,并将其存储回同一个存储桶。为了处理数据,你将使用 Terraform 定义 Glue ETL 作业,然后使用 Glue 爬虫将处理后的数据填充到数据目录中。这使你和其他利益相关者能够使用 Amazon Athena 通过 SQL 查询来查询 S3 存储桶中的处理数据。
实验末尾有一个可选部分,你将探索在 S3 中存储数据时,压缩和分区技术对存储容量和数据检索性能的影响。
在这一系列实验演练视频中,我将概述你将应用于 JSON 文件的转换步骤,讲解如何在 Terraform 中定义 Glue 作业,并展示如何使用 Glue 爬虫和 Amazon Athena 来查询你的数据湖。
第一部分:定义数据转换函数
在实验的第一部分,我们将完成两个用于处理原始 JSON 文件的函数。这些文件包含产品评论和元数据。
以下是每个数据文件的结构和处理目标。
评论数据处理
每个评论条目包含以下信息:
- 评论者ID和姓名
- 产品ID
- 评论文本及其摘要
- 产品评分
- 评论时间
- 一个“helpful”字段,包含两个数字:认为该评论有帮助的用户数量,以及对该评论有用性进行评分的用户总数。
你将把这个评论数据导入到一个表格数据框架中,并进行如下处理:
- 从时间戳中提取
年份和月份。 - 将
helpful列拆分为两列。
之后,你将使用年份和月份列在 S3 存储桶中对数据进行分区。
元数据处理
第二个 JSON 文件中的元数据项示例如下。每个项目包含:
- 产品ID
- 产品相关信息
- 相关产品列表
- 销售类别和销售排名等。
你同样需要将这些数据导入表格形式,并保留相关列。具体处理步骤如下:
- 展开
sales rank列,将其拆分为两列:sales_category和sales_rank。 - 删除数值列中包含空值的记录。
- 将其他列中的空值替换为空字符串。
使用 Terraform 定义 AWS 资源

定义完上述两个函数后,你将使用这些代码,通过 Terraform 为转换任务定义 Glue 作业。
在 terraform 文件夹下,你可以找到定义实验所需所有资源的 Terraform 文件,例如 S3、Glue、允许 Glue 作业与 S3 存储桶交互的 IAM 角色和策略,以及输入变量和输出值。虽然你只会直接与 glue.tf 文件交互,但让我们浏览一下其他一些文件,以便全面了解实验中使用的资源。
S3 存储桶配置
在 s3.tf 文件中,提供的“数据湖”存储桶被定义为一个数据块。当你运行 Terraform 时,将创建另一个存储桶,用于存放 Glue 作业的转换脚本。
这里的第三个资源块确保你创建的脚本存储桶不允许公共访问。虽然你可以手动上传脚本到存储桶,但也可以通过定义 aws_s3_object 资源类型,使用 Terraform 将脚本上传到存储桶。
在这些资源块中,你可以找到目标存储桶的名称、脚本加载到 S3 存储桶时将分配的键(Key),以及脚本的本地路径(位于 assets 文件夹下)。
IAM 角色与策略
为了允许 Glue 作业访问 S3 数据湖,你需要创建一个 Glue 作业可以担任的角色。然后,你将向该角色附加一个权限策略,详细说明对 S3 存储桶允许的操作。
在 iam_roles.tf 文件中,你会看到定义 IAM 角色的 aws_iam_role 块,以及概述附加到该角色的权限策略的 aws_iam_role_policy 块。角色和权限策略的详细信息在单独的 policies.tf 文件中定义。
policies.tf 文件中的第一个块生成一个“信任关系”策略,你可以在其中列出可以代表你调用 AWS 服务的受信任实体(在本例中是 AWS Glue)。第二个块为被担任的角色生成权限策略,你可以在其中列出资源以及允许对这些资源执行的操作。可以看到,列表包括了 S3,并且允许对 S3 的所有操作。
Glue 作业定义
现在让我们查看 glue.tf 文件。这里你可以看到两个类型为 aws_glue_job 的资源块。每个块定义一个你需要运行的 Glue 作业,分别用于处理评论数据和元数据。
对于每个 Glue 作业,你需要定义:
- 作业名称
- 附加到作业的角色
- 指定转换脚本位置的命令块
default_arguments 块包含转换脚本期望的参数,以及 Glue 自身的参数。
以下是转换脚本期望的参数:
--S3_bucket--source_path--target_path--compression--partition_columns
这些参数定义了提取原始数据的源路径、存储处理数据的目标路径、用于存储处理数据的压缩算法,以及用于数据分区的列名。
其余参数都是可选的,由 AWS Glue 用于设置你的作业。有关这些参数的更多信息,请随时查阅 AWS Glue 文档。
在 default_arguments 块之后,你会看到 timeout 属性,你可以在此指定 Glue 作业在被终止之前允许运行的分钟数。这有助于防止 Glue 作业因某些代码错误或数据异常而运行时间超出预期。
对于此块中的最后一个参数,AWS Glue 在幕后使用一个名为 Spark 的分布式框架,因此你可以指定 Spark 将用于运行 Glue 作业的工作节点的数量和类型。
输出定义
最后,在 outputs.tf 文件中,你可以看到运行 Terraform 后可以使用的输出值列表。这些输出包括 Glue 作业的名称和 IAM 角色。稍后,你将使用这个 IAM 角色来创建 Glue 爬虫。
总结
在本节课中,我们一起学*了实验的第一部分内容。我们明确了实验目标:构建一个基于 S3 的数据湖,处理 JSON 数据为 Parquet 格式。我们详细定义了两个核心的数据转换函数,分别用于处理产品评论和元数据。我们还系统性地了解了如何通过 Terraform 代码定义所需的 AWS 资源,包括 S3 存储桶、IAM 角色策略以及最重要的 Glue 作业配置。

下一节视频中,我们将具体讲解如何在 Terraform 中定义你的 Glue 作业。我们下节课再见。
161:实验演练 - 使用AWS Glue构建简单数据湖(第2部分) 🧪

在本节课中,我们将学*如何完成AWS Glue数据转换脚本,运行Glue作业,并最终通过AWS Glue数据目录和Athena查询处理后的数据。我们将详细解析提供的转换脚本,并了解整个数据处理流程。
概述
上一节我们介绍了对JSON文件应用的基本转换类型。本节中,我们将详细查看在Terraform资产文件夹下提供的两个转换脚本,并学*如何运行它们以构建数据湖。
转换脚本解析
当运行Terraform时,脚本将从本地目录复制到脚本存储桶。我们将一起查看评论转换脚本,元数据转换脚本的结构与此非常相似。
以下是提取在Glue作业中定义的参数以便在脚本中使用的方法:
# 示例:从Glue作业参数中提取值
args = getResolvedOptions(sys.argv, ['JOB_NAME', 'input_path', 'output_path'])
如前所述,AWS Glue ETL在底层使用Spark。我们将在下一课程中详细学*Spark,这里仅概述此脚本与Spark框架交互的过程。
要使用Spark框架,首先需要创建一个名为GlueContext的对象。该对象允许你初始化Glue作业、连接到S3存储桶源、将数据从源提取到数据帧中,并最终将处理后的数据存储回S3存储桶。完成后,需要调用commit方法来结束Glue作业。
在实验中,你将完成这个转换函数来处理评论数据集。该函数期望一个Pandas数据帧作为输入,并返回另一个包含处理后数据的Pandas数据帧。
数据提取与转换流程
GlueContext的create_dynamic_frame方法允许你连接到S3存储桶以提取原始数据。以下是存储桶内CSV文件的路径示例。此方法将读取CSV文件并将其导入到Glue数据帧中。
你可以直接使用这个Glue数据帧来转换数据。但为了本次练*,我们将其转换为Pandas数据帧,以便在其上调用转换函数。在下一课程中,你将有机会与Spark和Glue数据帧进行交互。
包含处理后数据的返回Pandas数据帧随后被转换回Glue数据帧。这是因为下一个方法write_dynamic_frame(用于将处理后的数据存储到目标位置)需要一个Glue数据帧作为输入。
数据存储配置
在write_dynamic_frame方法中,你需要指示连接到S3存储桶,指定希望数据以Parquet格式存储,提供处理后数据的路径,并指定要使用的压缩算法。
查看处理后数据的路径,其键名将以processed_data开头,后跟压缩算法的名称,然后是分区状态。分区功能被启用。你还需要将分区列作为脚本参数传递。
这种包含压缩算法名称和分区状态的键名格式,在实验的可选部分会非常有用,届时你将尝试这些数据格式化选项。
运行实验步骤
完成两个转换脚本中的转换函数后,你需要从终端运行Terraform来创建资源。脚本存储桶应该被创建成功。


你将获得Glue作业和Glue角色的名称。



然后,从终端使用这些名称来运行Glue作业。



监控作业与验证结果
你可以从控制台检查每个作业的状态,当然也可以在终端中完成此操作。在搜索栏中,我将输入“glue”然后打开此服务。


在左侧,点击“ETL作业”。这里列出了两个Glue作业。点击第一个作业,然后点击“运行”选项卡。你将看到运行此Glue作业的所有尝试的状态。一段时间后,你会看到两个作业都已成功运行。
让我们查看S3存储桶中的处理数据。它以processed_data开头。然后是snappy,这是所使用的压缩算法的名称。接着你会看到数据存储时使用了分区。在toys_reviews目录内,可以看到数据按年份然后月份进行分区,最终数据以Parquet格式存储。
使用Glue数据目录与Athena查询
现在,假设你的最终用户希望从S3存储桶查询处理后的数据。你需要首先使用AWS Glue数据目录创建一个包含处理后数据元数据的表。
AWS Glue数据目录是一个中央存储库,用于存储跨各种数据源的所有数据资产的元数据。在Glue数据目录内,你可以创建元数据库,其中可以包含许多表,每个表存储基本的元数据,如列名、数据类型和分区键。
要填充你的目录数据库,可以使用AWS Glue爬虫程序自动从数据存储中发现和提取元数据,然后相应地更新Glue数据目录。
数据目录中的表设置完成后,你的最终用户就可以使用Amazon Athena通过常规SQL查询来查询数据。
实验中的具体操作
在实验中,为了为处理后的数据创建元数据库并使用Athena查询数据,你将使用AWS Wrangler。AWS Wrangler是建立在Pandas和Boto3等开源库之上的AWS SDK。它扩展了Pandas的功能以支持AWS。
以下是具体步骤:
首先,你将在Glue目录中创建一个数据库,用于包含处理后数据的元数据。
# 使用Boto3创建Glue客户端对象
import boto3
glue_client = boto3.client('glue')
然后,你可以在此Glue客户端上调用create_crawler方法来创建Glue爬虫程序。你需要指定爬虫程序的名称,将其附加到通过Terraform创建的角色,指定Glue目录的数据库名称以及处理后数据的路径。
之后,你可以在Glue客户端上调用start_crawler方法来启动Glue爬虫程序。可能需要等待几分钟才能创建表。
表创建后,你将使用AWS Wrangler通过Athena查询数据。你将使用read_sql_query方法,该方法期望将SQL查询作为字符串和目录数据库的名称。然后它执行查询并将结果作为Pandas数据帧返回。
可选实验部分
至此,你已经准备好尝试这个实验。但如前所述,在实验的最后有一个可选部分,你将在其中探索在S3中存储数据时压缩和分区的效果。如果你有兴趣尝试这个可选部分,可以观看下一个视频,我将引导你完成那些可选实验,或者你也可以直接开始实验。

总结

本节课中,我们一起学*了如何完成并理解AWS Glue数据转换脚本,运行Glue ETL作业处理数据,以及如何利用AWS Glue数据目录和Amazon Athena使得处理后的数据可供查询。我们涵盖了从脚本编写、作业执行到元数据管理和SQL查询的完整数据湖构建流程。
162:使用 AWS Glue 构建简单数据湖(第 3 部分,可选)🏗️

在本节课中,我们将通过四个实验,探索 AWS Glue 作业中不同配置(特别是压缩与分区)对数据存储和处理性能的影响。我们将分析压缩算法的选择以及分区键的设计如何优化存储成本与查询效率。
实验概述
在实验的第一部分,我们创建了两个 Glue 作业来处理评论和元数据数据集。在作业中,我们选择了 Snappy 作为压缩算法,并为每个数据集指定了分区列。本可选部分将进行四项实验,以探索不同的 Glue 作业配置,帮助我们理解压缩和分区对存储的影响。
实验一:探索压缩效果
首先,我们将通过更改 Glue 作业中的压缩参数来探索压缩效果,此实验不进行数据分区。
以下是操作步骤:
- 首先处理元数据,并为压缩参数选择 未压缩 选项。
- 然后再次处理数据,但这次为压缩算法选择 Snappy。
完成两次实验后,您可以使用以下命令(带 summarize 选项)来显示给定 S3 路径下的对象数量和总大小信息:
# 示例命令,用于汇总S3路径信息
aws s3 ls --summarize --human-readable s3://your-bucket/path/
您将观察到,启用压缩后,对象占用的存储空间更少。尽管没有指定分区键,但仍会生成多个 Parquet 文件,这是因为 AWS Glue 底层处理框架会自动尝试对数据进行分区。
实验二:比较压缩算法
接下来,我们将比较两种压缩算法:第一个实验中已使用的 Snappy 和本实验中将使用的 Gzip。
您会注意到,使用 Gzip 压缩时,总文件大小比 Snappy 更小。Gzip 和 Snappy 都是流行的压缩算法,Gzip 通常能实现更高的压缩率,而 Snappy 的处理速度通常比 Gzip 更快。
实验三:探索分区效果
在第三个实验中,我们将通过比较两种数据处理结果来探索分区的影响:
- 使用 Snappy 压缩但未分区的处理后的评论数据。
- 来自实验第一部分的数据,其中我们通过指定分区键,按年份和月份对评论进行了分区。
您可以观察到,进行分区后,生成了 556 个 Parquet 文件,每个文件对应特定的年份和月份组合。而未分区时,数据被自动分区为 4 个 Parquet 文件。
当对数据进行分区时,需要选择一个合适的分区键,将数据组织成与您的查询模式相匹配的有意义的文件。这是因为当您在 WHERE 子句中指定分区条件时,Athena 只会扫描该分区的数据,从而限制每次查询扫描的数据量,提升性能并降低成本。
实验四:不当分区键的影响
一个糟糕的分区键会将数据分割成过多的小文件,这可能增加存储成本并使数据处理速度变慢。
例如,在最后一个实验中,我们选择 ASIN 列(即评论标识符)作为分区键。使用 ASIN 列对数据进行分区将耗时超过 15 分钟,并导致作业超时。
这个实验表明,选择不当的分区键(如高基数列)会导致极低效的数据布局。

课程总结
本节课中,我们一起学*了 AWS Glue 中压缩与分区配置的实践影响。我们了解到:
- 压缩可以节省存储空间,不同算法在压缩率和速度上各有权衡。
- 分区能大幅提升查询效率,但分区键的选择至关重要,应贴合查询模式并避免产生过多小文件。


感谢您坚持完成这些实验演练。现在轮到您动手尝试了。当您进行到末尾的可选部分时,可以自由选择完成或跳过这些实验。我们将在下一课再见,探讨数据湖仓架构。
163:数据湖仓架构 🏔️🏠
在本节课中,我们将要学*数据湖仓架构。这是一种结合了数据湖和数据仓库优势的新型数据架构,旨在为数据分析、机器学*和商业智能提供一个统一、高性能且易于管理的平台。
什么是数据湖仓?🤔
你可以将数据湖仓架构视为一个内置了额外功能的数据湖,这些功能旨在创造一种类似于数据仓库的使用体验。它的目标是将数据湖灵活、低成本的存储优势,与数据仓库卓越的查询性能和强大的数据管理能力结合起来。这使得它能够支持分析和报告应用,以及机器学*和大数据处理等用例。
上一节我们介绍了数据湖仓的基本概念,本节中我们来看看它的核心架构组件和特性。
核心架构与存储层 🏗️
在其核心,数据湖仓与数据湖非常相似。它使用一个构建在对象存储之上的单一存储层,来存储任何类型的大量数据。
你可以像在前一个视频中看到的那样,将存储层组织成不同的区域,以促进数据治理并确保更好的数据质量。
以下是数据湖仓存储层的一个常见组织方式,被称为“奖牌架构”:
- 青铜区:存储原始数据。
- 白银区:存储经过清洗的数据。
- 黄金区:存储经过建模和丰富处理的、可直接用于分析的精选数据。
经过转换的数据存储在白银区和黄金区,并以开放的文件格式(通常是 Parquet)写入,以实现更高效的存储,并允许各种分析和查询引擎直接访问数据。
数据管理特性 📊
除了数据湖的特性,湖仓还包含了数据仓库中常见的数据管理功能。
它们在存储级别强制执行模式,以确保你加载的数据符合指定的格式和质量标准,并且它们也支持模式演进。
数据湖仓通常遵循 ACID 原则,这意味着事务具有原子性、一致性、隔离性和持久性。这使得你的数据用户可以并发地读取、插入、更新和删除数据,同时确保数据对于分析过程是可靠的。

治理、安全与版本控制 🔒
湖仓还具有内置的数据治理和安全功能,例如强大的访问控制、数据编目和数据血缘跟踪。
你还可以使用连接器 API 连接到数据湖仓,然后使用 SQL 对你的数据集执行增量更新和删除操作。
这些是实现数据法规和隐私规则合规性的关键功能。并且,由于湖仓保留了文件的旧版本和元数据,你也可以根据需要回滚或访问任何版本的历史数据。
总结与展望 📈
通过整合数据仓库和数据湖的最佳能力,数据湖仓提供了一个统一的架构,支持从 SQL 应用到商业报告再到机器学*的各种工作负载。
自数据湖仓概念诞生以来,各种云和软件供应商以及开源组织一直在创建新产品,以帮助组织向数据湖仓架构迁移。

在本节课中,我们一起学*了数据湖仓架构的定义、核心组件(如奖牌架构)、关键特性(如ACID事务、模式管理)以及其带来的统一优势。下一节视频,我们将更深入地探讨数据湖仓实现的一些细节。
164:数据湖仓实施 🏗️

在本节课中,我们将学*数据湖仓(Lakehouse)的概念及其实现方式,特别是通过开放表格式(Open Table Formats)来融合数据仓库和数据湖的优势。
自数据湖仓概念诞生以来,我们见证了云数据仓库与数据湖之间发生的有趣融合。云数据仓库提供商已开始集成通常与数据湖相关的功能。与此同时,数据湖技术也开始拥抱数据仓库的典型特性,例如强制执行和管理模式以及SQL功能。在本视频中,我们将探讨如何使用开放表格式实现数据湖仓。在下一个视频中,Morgan将引导您了解如何在AWS上实现湖仓。
开放表格式简介
上一节我们介绍了数据湖仓的融合趋势,本节中我们来看看实现这一目标的关键技术:开放表格式。

在湖仓实施方面,已经开发出多种开放表格式来支持更具事务性的数据湖理念。这些开放表格式包括:
- Databricks Delta Lake
- Apache Iceberg
- Apache Hudi(代表Hadoop Upserts Deletes and Incrementals)
这些开放表格式是专门的存储格式,为您的数据湖仓添加了事务性功能。这使得您可以在构建于对象存储数据湖之上的存储层中,轻松更新和删除单个记录,同时支持传统数据仓库中的ACID原则。
开放表格式的工作原理
了解了开放表格式是什么之后,我们来看看它们具体是如何工作的。
简而言之,它们在您的存储数据之上提供了一个逻辑抽象层。当您对数据表执行操作(例如插入、更新或删除记录)时,开放表格式会跟踪这些更改,并将其存储为一系列反映数据在特定时间点状态的快照。

以下是这些快照支持的核心功能:
- 时间旅行:您可以通过指定时间戳来查询表的任何先前版本。
- 回滚:可以将表回滚到先前的版本,以恢复对表所做的任何错误更改。
- 模式和分区演进:即使您进行了模式更改(如添加或删除列)或更改了数据集的划分方式,您仍然能够查询数据。
由于开放表格式是开源的,它们还支持不同的查询引擎访问存储在数据湖仓中的数据。因此,您可以使用任何适合您用例的处理工具,而无需复制数据并将其重组为另一种格式。
主流开放表格式对比
在您作为数据工程师的工作中,可能会遇到Databricks Delta Lake、Apache Iceberg和Apache Hudi。这些技术都提供模式演进和时间旅行等相同功能,但它们通常在底层实现细节上有所不同。
例如,以下是Iceberg的工作原理:
- 与数据湖类似,有一个数据目录和一个数据存储层(包含以Parquet格式写入的文件以实现高效存储)。
- 但在目录和存储层之间,存在一个元数据层。
- 每当您更新或创建数据文件时,Iceberg会创建一个新的清单文件来跟踪这些数据文件以及每个文件元数据的附加细节。
- 然后创建一个新的清单列表,用于跟踪有关清单文件位置、每个清单文件所属的快照以及分区信息的信息。
- 最后,创建一个以JSON格式编写的新元数据文件,其中包含指向新清单列表的新快照。这些文件包含诸如当前表模式、分区信息、快照以及哪个快照是当前快照等信息。
在Iceberg目录中,有一个指针指向存储在湖仓中的每个表,该指针引用表的最新元数据文件。因此,每当创建新的元数据文件时,该指针都会更新。
当您运行查询时:
- 目录中的指针根据正在查询的表告诉查询引擎哪个元数据文件是当前的。
- 查询引擎然后从元数据文件中检索当前快照的清单列表。
- 接着检索相关的清单文件。
- 最后检索相关的数据文件。
这个元数据层帮助Iceberg确定需要读取哪些数据文件,并忽略与查询无关的文件,从而显著加快查询性能。

如何选择存储架构
了解了具体技术后,我们来探讨一个实际问题:如何在不同的存储架构间做选择。
在数据仓库、数据湖或数据湖仓之间进行选择,实际上是为支持组织的需求而选择正确的存储抽象。
以下是选择时需要考虑的因素:
- 早期公司/简单需求:如果您是一家处于早期阶段的公司,只需要处理少量结构化数据进行分析和报告,您或许可以直接将BI工具连接到生产数据库的只读副本。
- 数据量增长/多源整合:随着数据量和数据源的增长,您会希望使用云数据仓库来整合来自多个源的结构化和半结构化数据,并允许您的数据用户查询当前和历史数据以进行分析和报告,而不会给生产数据库增加太多额外负载。
- 海量数据/非结构化数据:如果您的组织需要处理海量数据,尤其是非结构化数据(例如用于机器学*应用),那么您可能需要考虑实施数据湖架构以节省存储成本。在这种情况下,您可以选择通过添加数据管理和可发现性功能,将存储架构演进为数据湖仓,以同时支持机器学*应用和低延迟分析查询。
总结与展望
正如您所看到的,云数据仓库和数据湖的技术架构已经开始融合。我认为这种融合趋势只会继续下去。数据湖和数据仓库仍将作为不同的架构存在,但在实践中,它们的功能将融合在一起。

因此,在未来,您将无需在仓库或湖之间做出选择,而是可以根据您的具体情况和数据用例,选择融合的数据平台。
接下来,Morgan将引导您了解如何使用AWS Lake Formation在AWS上实现数据湖仓。之后,我将带您预览即将进行的实验,您将有机会创建自己的数据湖仓架构。
本节课中我们一起学*了:数据湖仓作为融合数据仓库和数据湖优势的架构,其核心实现技术是开放表格式(如Delta Lake、Iceberg、Hudi)。这些格式通过在数据存储之上添加事务性元数据层,实现了ACID事务、时间旅行、模式演进等功能,从而支持高效的分析查询和灵活的数据管理。最后,我们讨论了如何根据组织的数据规模、类型和用例,在数据仓库、数据湖和数据湖仓之间做出合适的选择。
165:AWS上的湖仓架构 🏗️

在本节课中,我们将学*如何在AWS上构建一个数据湖仓架构。我们将了解AWS Lake Formation如何简化数据湖的构建和管理,并探讨一个集成了多种AWS服务的典型湖仓架构。
概述
你已经从Joe那里学到了数据湖、数据仓库和数据湖仓之间的区别,并且完成了使用AWS Glue和Amazon S3建立简单数据湖的实验。许多组织通常从这样一个简单的数据湖开始,然后逐步演进到使用更成熟的解决方案,如数据湖仓。现在,我们将讨论如何使用AWS服务(包括AWS Lake Formation和Amazon Redshift Spectrum)来架构一个数据湖仓。
AWS Lake Formation 简介
AWS Lake Formation的核心设计目标是简化构建和管理数据湖的过程。传统上,设置数据湖或湖仓涉及大量手动步骤:定义存储、设置访问控制、编录数据以及管理数据资产的权限。这个过程可能复杂且耗时。Lake Formation自动化了其中一些任务,使其变得简单,便于你快速开始。

以下是它的工作原理:
- 首先,识别你现有的数据源,例如Amazon S3或关系型及NoSQL数据库。
- 然后,使用Lake Formation将这些数据移入你的数据湖。
- 之后,使用Lake Formation爬取数据、进行编录,并使其准备好进行分析。
- 最后,你可以授予用户安全的自助服务访问权限,让他们使用自己偏好的分析工具访问这些数据。
这是一种简化的方式,确保组织中的每个人都能轻松找到并使用他们需要的数据。
你可能发现其中一些任务与你之前使用AWS Glue完成的任务类似。这是因为Lake Formation实际上是构建在AWS Glue之上的。它利用了你已经熟悉的Glue功能,如Glue作业、工作流和爬取程序来执行这些任务。当你使用Lake Formation时,你可以创建工作流等,也可以直接在Glue中管理这些功能。
湖仓架构详解
在典型的数仓或湖仓架构中,有许多AWS服务相互交互,同时终端用户访问不同的数据集。随之而来的是管理权限的大量开销。Lake Formation帮助自动化数据湖创建的一部分工作,就是管理复杂的细粒度权限。Lake Formation还对存储在S3中的数据以及数据目录中的元数据提供细粒度访问控制。因此,你可以集中管理权限和IAM策略,以简化在内部和外部为分析和机器学*应用程序治理和共享数据的过程。
现在你已经对Lake Formation有了高层次的理解,让我们回顾一个使用AWS服务架构的数据湖仓示例图。随着课程的深入,我们将更深入地探讨这个架构的各个方面。

以下是该架构的各个层次:
数据源层
从数据工程师的角度来看,数据源通常是你无法控制的。这些包括数据库、文件共享、SaaS应用程序等。
数据摄取层

摄取机制将数据摄入到数据湖仓中。正如你在之前的课程中学到的,有多种服务可用于数据摄取,包括:
- Amazon Kinesis Data Streams
- Amazon Data Firehose
- AWS DataSync
- AWS Data Migration Service
- Amazon AppFlow
此外,AWS Lake Formation可以通过AWS Glue管理一些数据摄取任务。
存储层
所有摄入的数据都需要存储在某个地方。因此,在摄取层旁边是存储层,它使用Amazon Redshift和Amazon S3。
处理层
存储层之上是处理层。在这里,你将从湖仓存储层读取数据,并为下游消费者进行转换。你会使用以下服务:
- Amazon EMR
- AWS Glue
- Amazon Managed Service for Apache Flink
- 或者在Amazon Redshift上进行SQL数据处理。
目录层
目录层使用Lake Formation提供一个中央目录,用于存储和管理存储层中所有数据集的元数据。在这一层,你还可以使用Lake Formation管理权限并提供细粒度的访问控制。
消费层
湖仓架构最右边的层是消费层。它提供了你可能用来消费数据的AWS服务,包括但不限于:
- Amazon SageMaker:用于机器学*用例。
- Amazon QuickSight:用于商业智能和数据可视化。
- Amazon Athena 和 Amazon Redshift Spectrum:用于查询湖仓中的数据。
我们将在下一个视频中花更多时间探索Amazon Redshift Spectrum。
总结

本节课我们一起学*了AWS上的湖仓架构。我们了解了AWS Lake Formation如何作为核心服务,通过自动化任务和集中管理权限来简化数据湖的构建。我们还详细剖析了一个集成了数据源、摄取、存储、处理、目录和消费各层的完整湖仓架构示例。由于你已经学*了很多关于数据源和摄取用例的知识,我们现在不再重点讨论这些。我邀请你加入下一个视频,我们将更深入地探讨这个数据湖仓架构的存储、处理、目录和消费层。
166:在AWS上实施湖仓架构

在本节课中,我们将学*如何在AWS上构建一个数据湖仓架构。我们将重点探讨其核心的存储层、目录层和消费层,并了解如何利用AWS服务(如S3、Redshift、Lake Formation、Glue、Athena和Redshift Spectrum)将这些层有效地整合在一起。
架构概述
在上一节视频中,我们宏观地概述了如何将各种AWS服务组合成数据湖仓架构中的一系列层级。
作为回顾,该架构的概览如下:左侧是源和摄取层,中间是存储、处理和目录层,右侧则是消费层。接下来,我们将从存储层和目录层开始深入探讨。
存储层 🗄️
上一节我们介绍了架构的整体分层,本节中我们来看看具体的存储层实现。
在数据湖和数据湖仓中,使用S3进行存储非常普遍。对于湖仓,通常同时使用S3和Redshift作为存储层。
- S3通常为结构化、半结构化和非结构化数据提供存储。
- Amazon Redshift则存储经过高度整理、符合预定义模式的结构化或半结构化可信数据。
这种双重存储方法结合了S3在处理大规模结构化和非结构化数据时的成本效益和可扩展性,同时利用Redshift对更结构化数据进行高性能分析。
创建数据湖仓的部分原因,是希望能够同时分析存储在S3和Redshift中的数据。当然,你可以编写定期将数据从S3移动到Redshift的ETL作业,但长期来看,为此创建数据管道可能成本高昂,并导致数据冗余。此外,每次移动和转换数据时,都可能引入错误或问题,从而影响数据质量和可用性。
因此,如果能以原生方式将数据湖与数据仓库集成起来,将会非常理想。这正是Amazon Redshift Spectrum的用武之地,它充当了S3和Redshift之间用于查询数据的集成桥梁。它在架构图中属于存储层,但也是AWS上数据湖仓消费层的关键部分。
Redshift Spectrum允许你直接查询存储在S3中的数据,而无需先将其加载到Redshift中。这非常棒,因为它消除了在数据湖和数据仓库之间移动数据的复杂ETL管道的需求。通过集成这两个数据存储系统,它帮助你实现了数据湖仓的构想。
所以,使用像Redshift Spectrum这样的工具来同时查询数据湖存储和数据仓库存储中的数据,无疑是比通过ETL流程将数据移出S3再导入Redshift进行查询更可取的方法。关于消费层的更多细节,我们稍后会详细讨论。
目录层 📇
接下来,我们将讨论存储层之上的目录层。
中央数据目录用于在单一位置为湖仓中的所有数据集提供元数据,并使其易于搜索。这对于湖仓中数据的自助服务发现极其重要。你之前学*过“数据沼泽”的概念,你肯定不希望数据使用者在浑浊的水中艰难跋涉。相反,你希望能够清晰地了解湖仓中的数据。
在本案例中,我们使用Lake Formation,它在后台使用Glue来创建数据目录,以存储湖仓中托管的所有数据集的元数据。Lake Formation协调Glue爬虫程序来识别数据,然后将元数据(包括模式信息、分区信息和数据位置)持久存储在Glue数据目录中。
需要记住的重要一点是,存储层中的数据集通常会随着时间推移而模式不断演变,数据分区不断增加。因此,填充元数据目录不是一劳永逸的工作,它必须得到维护和更新。
为了自动保持目录的最新状态,你可以配置AWS Glue定期爬取湖仓存储层,以发现新的或更新的数据集并提取其元数据,然后将其存储在目录的一个表中。
虽然Lake Formation和Glue非常适合管理和编目你的数据,但高效处理不断演变的模式和大数据集正是Apache Iceberg表可能发挥作用的地方。你在之前的视频中学*过Iceberg表,它们如何让你更容易地更改数据模式,而不会破坏现有流程或底层数据。这部分是通过模式和数据的版本控制实现的,它允许用户跟踪数据随时间的变化。借助版本控制,你可以使用“时间旅行”功能来访问和查询数据的历史版本,并分析数据在更新和删除之间的变化。
Lake Formation也支持Iceberg表,你可以在AWS Glue数据目录中创建使用Parquet格式的Iceberg表。
消费层 🍽️
现在,让我们进入消费层,我想花更多时间介绍Redshift Spectrum和Amazon Athena。你将在接下来的实验中有机会使用Athena。虽然你不会使用Redshift Spectrum,但它在AWS的数据湖仓中很常用,因此你应该了解其基础知识。
Redshift Spectrum使Redshift能够为数据消费者提供一个统一的SQL接口,该接口可以接受和处理SQL语句,其中同一个查询可以引用和组合存储在数据湖(S3)以及数据仓库(Redshift)中的数据。这意味着,通过使用Redshift Spectrum,你可以减少数据延迟。换句话说,通过就地查询数据,你可以更快地获得洞察,而无需等待数据移动或转换。
Redshift Spectrum查询使用大规模并行处理来针对大型数据集运行查询,并且大部分处理发生在Redshift Spectrum层。这意味着在你定义了Redshift Spectrum表之后,大部分数据仍保留在Amazon S3中。你可以像查询任何其他Amazon Redshift表一样查询和连接这些表。
多个Redshift集群也可以同时查询Amazon S3中的同一份数据,而无需为每个集群复制数据。
使用Redshift Spectrum,你可以做很多事情,例如:
- 将大量历史数据保留在数据湖中,并将几个月内的热数据摄取到数据仓库中。
- 通过同时处理来自Redshift的热数据和来自S3的历史数据来创建丰富的数据集,而无需在任一方向移动数据。
- 更轻松地将大量历史数据从数据仓库卸载到S3中,S3提供了更具成本效益的数据湖存储,同时仍然能够作为Amazon Redshift查询的一部分轻松查询这些数据。
然后是Amazon Athena。Athena使得能够直接使用标准SQL查询S3中的数据。因此,无需将数据加载到另一个系统中即可使用SQL进行查询。相反,你可以使用Athena创建表并直接查询。Athena是无服务器的,因此无需设置或管理基础设施,你只需为查询扫描的数据量付费。你将在接下来的实验中尝试这一点。
Athena还支持称为联合查询的功能,允许你查询S3之外的数据。它支持广泛的数据源进行联合查询,包括Redshift。Amazon Athena Redshift连接器使Athena能够访问你的Amazon Redshift表,因此你可以编写从数据仓库中提取数据的查询。
所以,对于使用SQL的消费,你可以使用Athena和/或Redshift Spectrum来查询S3和Redshift中的数据集。这两者都可以使用存储在Lake Formation目录中的模式,并遵循你在课程早期从Joe那里学到的“读时模式”方法来应用它。
总结
本节课中,我们一起学*了在AWS上构建数据湖仓架构的示例,该架构利用了AWS Lake Formation及其他服务,包括Amazon Athena和Amazon Redshift Spectrum。我们探讨了如何通过S3和Redshift构建双重存储层,如何使用Lake Formation和Glue管理元数据目录以应对模式演变,以及如何通过Redshift Spectrum和Athena实现统一、高效的SQL查询消费。在接下来的实验中,你将有机会亲手操作其中一些服务。祝你实验愉快,我们很快再见。
167:使用AWS Lake Formation和Apache Iceberg构建数据湖仓 🏗️💾

在本节课中,我们将学*如何利用AWS服务(如S3、Lake Formation)和开源格式(如Apache Iceberg)来构建一个具有“奖牌”架构的数据湖仓。我们将从原始数据摄取开始,经过处理和转换,最终创建可供分析和机器学*使用的数据表。
概述
实验将指导您使用Amazon S3、Apache Iceberg和AWS Lake Formation,实现一个具有类似“奖牌”架构的数据湖仓。您将获得一个已注册到Lake Formation的S3存储桶作为数据湖仓的底层存储,从而探索如何为数据湖中的数据建立治理和细粒度权限控制。
数据湖仓架构与数据流转
上一节我们介绍了实验的整体目标,本节中我们来看看数据在湖仓各层(着陆区、整理区、展示区)中的具体格式和流转过程。
着陆区:原始数据摄取
首先,您需要将原始数据从两个源系统摄取到数据湖存储桶的着陆区。
以下是数据摄取的具体步骤:
- 从MySQL源数据库提取数据:提取每个表,并将其保存为着陆区中的CSV文件。这意味着您将创建八个CSV文件,每个文件对应一个表。
- CSV文件命名规则:S3对象键的格式为:
landing-zone/rds/<表名>。 - 从S3源提取JSON数据:提取包含客户产品评级的JSON文件。该文件是一个JSON对象列表,每个对象包含客户编号、产品代码和该客户对给定产品的评级。
- 处理JSON数据:将JSON文件作为数据帧摄取,添加表示文件摄取时间戳的字段
ingest_ts,最后将数据帧作为JSON文件存储在着陆区。 - JSON文件命名规则:S3对象键的格式为:
landing-zone/json/ratings。
整理区:数据处理与转换
将原始数据传输到着陆区后,您将提取数据,对其执行三次转换,然后将处理后的数据存储在整理区。
以下是三次转换的概述:
-
第一次转换:处理CSV文件
- 从着陆区提取所有八个表,并将每个表转换为数据帧。
- 为每个表添加两个元数据列:
ingest_ts(表示数据在整理区的摄取时间戳)和source(表示源数据库的名称)。 - 强制执行预定义的模式,将数值列转换为预期类型。
- 最后,使用Snappy作为压缩算法,将每个表存储为Parquet文件。
- S3路径格式:
curated-zone/<表名> - 目录关联:在Glue数据目录中名为“curated-zone”的数据库内,为整理区创建的每个对象关联一个对应的目录表。
-
第二次转换:为机器学*准备数据
- 通过结合最新的评级数据与来自着陆区CSV表的客户和产品信息,创建机器学*团队所需的数据。
- 从着陆区提取CSV表和最新的JSON评级文件,并将它们各自转换为数据帧。
- 创建一个新的数据帧,其中包含来自客户表的部分客户信息、来自产品表的部分产品信息以及评级数据中的评级。
- 向此数据帧添加一个包含数据处理时间戳的附加列。
- 最后,通过指定以
curated-zone/ratings-for-ml/iceberg开头的S3键,使用Iceberg格式将数据帧存储在数据湖存储桶的整理区。 - 目录关联:将处理后的数据与其在Glue数据目录“curated-zone”数据库中的对应目录表关联。

- 第三次转换:存储最新评级数据
- 专注于提取最新评级,并使用Iceberg格式将其存储在数据湖存储桶的整理区。
- S3路径格式:
curated-zone/ratings/iceberg - 数据更新逻辑:如果整理区中的评级表已包含某客户对某产品的评级,则在摄取新数据时,将提取新的客户-产品对并更新已存在对的评级。
- 目录关联:将评级数据与其在Glue数据目录“curated-zone”数据库中的目录表关联。
使用Glue ETL和Terraform执行转换
您将使用Glue ETL通过为着陆区和整理区定义ETL作业来执行这些转换,这些作业使用Terraform进行配置。

以下是Terraform配置的关键组件:
- 模块结构:在Terraform文件下,您会找到三个模块。
landing-etl和transform-etl模块包含用于着陆区和整理区对应ETL作业的配置文件。 - 着陆区ETL作业:在
landing-etl模块的Glue配置文件中,可以找到将原始数据摄取到数据湖存储桶着陆区的Glue作业。还包括定义连接到RDS数据库所需信息的代码块。 - 转换ETL作业:在
transform-etl模块下,可以找到用于处理着陆区原始数据并将其存储在整理区的三个Glue作业的配置文件。 - Python脚本:在
assets文件夹中,可以找到包含每次转换的Python脚本的文件夹。每个脚本包含三个部分:从源提取数据、处理数据、将数据存储到目标位置。batch_transform.py:对应处理着陆区CSV文件、对每个表强制执行模式,然后将处理后的数据作为Parquet文件存储在整理区的作业。在此文件中,可以找到每个表的模式定义,定义为StructType。# 示例:定义表模式的StructType from pyspark.sql.types import StructType, StructField, StringType, IntegerType schema = StructType([ StructField("customerNumber", IntegerType(), True), StructField("customerName", StringType(), True), # ... 其他字段定义 ])- 在其他两个脚本中,您将从JSON文件提取原始数据并对其进行转换,以创建存储在Iceberg格式中的
ratings-for-ml和ratings数据。
- Iceberg配置:在脚本中,您会找到用于为AWS Glue启用Iceberg的配置设置。通过设置这些配置,您可以使用AWS Glue对Amazon S3中的Iceberg表执行读写操作,或使用AWS Glue数据目录处理Iceberg表。
# 示例:在Glue作业中启用Iceberg的配置 spark.conf.set("spark.sql.catalog.glue_catalog", "org.apache.iceberg.spark.SparkCatalog") spark.conf.set("spark.sql.catalog.glue_catalog.warehouse", "s3://your-data-lake-bucket/") spark.conf.set("spark.sql.catalog.glue_catalog.catalog-impl", "org.apache.iceberg.aws.glue.GlueCatalog") spark.conf.set("spark.sql.catalog.glue_catalog.io-impl", "org.apache.iceberg.aws.s3.S3FileIO")
展示区:创建最终分析表
在整理区准备好所有处理后的数据后,您将在展示区创建额外的表,这些表将与最终用户共享。
以下是创建展示区表的方法:
- 表类型:
- 为分析最终用户创建两个表:一个包含按年月分组的平均销售额,另一个包含每个产品的平均评级。
- 创建一个代表您在整理区创建的
ratings表的附加表。 - 为机器学*最终用户创建一个代表您在整理区创建的
ratings-for-ml表的表。
- 使用Athena创建表:虽然可以使用Glue ETL在展示区创建这些表,但您将改用Athena。由于您已将目录表与整理区中的数据关联,因此可以将Athena用作处理工具。
- SQL查询示例:以下是一个使用Athena在展示区创建评级表的SQL查询示例。
CREATE TABLE presentation_zone.ratings WITH (format = 'ICEBERG', location = 's3://your-data-lake-bucket/presentation-zone/ratings/') AS SELECT * FROM curated_zone.ratings; - 执行过程:编写此查询后,将其传递给AWS Wrangler包中的
start_query_execution方法,同时指定要与此表关联的目录数据库名称(本例中为presentation_zone)。执行该语句后,将在S3存储桶中创建实际数据及其在Glue数据目录中的目录表。 - 存储格式:对所有表重复相同的过程,并将它们全部以Iceberg格式存储在展示区。
总结

本节课中,我们一起学*了构建数据湖仓实验的完整流程。我们概述了数据在着陆区、整理区和展示区的格式与流转,包括如何使用Glue ETL和Terraform进行数据处理,以及如何利用Athena和Iceberg格式创建最终的分析表。在接下来的视频中,我们将深入探讨Iceberg格式的细节以及Lake Formation服务的治理功能。
168:使用AWS Lake Formation和Apache构建数据湖仓 🧪

在本节课中,我们将学*如何在实验中将处理后的数据以Iceberg格式存储,并深入了解Iceberg文件在S3存储桶中的组织结构。我们还将探索Iceberg的架构演进和时间旅行特性,并学*如何使用AWS Lake Formation为数据湖应用精细的权限控制。
Iceberg格式与S3存储结构
上一节我们介绍了如何在实验中将数据以Iceberg格式存储。本节中,我们来看看这些文件在S3存储桶中是如何组织的。
我们以在“精炼区”创建的ratings数据为例。当你将ratings数据导入精炼区时,你会在S3存储桶中指定一个路径。如果进一步检查带有iceberg前缀的文件,你会看到两个额外的前缀:metadata和data。
metadata前缀代表元数据层,它包含我们在之前视频中讨论过的元数据清单列表和清单文件。data前缀代表存储层,它包含存储在Parquet文件中的实际数据。

以下是创建数据后,元数据层的内容示例:
.json文件代表元数据文件,它包含表结构信息、表在S3中的存储位置、表最后更新的日期时间以及当前快照的UUID(每次表内容更新时都会创建一个新的快照)。- 每次对表的元数据进行更改时,都会创建另一个元数据文件。
- 以
Snap开头的.avro文件是另一个元数据文件,代表对应一个快照的清单列表文件。它指向包含该快照详细元数据的清单文件列表。 - 这个清单列表文件指向另一个
.avro格式的清单文件。
以下是存储层或数据层的内容,它包含Parquet数据文件。
需要记住的是,在元数据层和存储层之上,是目录层。目录层指向当前的元数据,并帮助确定在给定表中读取或写入数据的位置。在实验中,这个目录层是通过Glue数据目录实现的,它会为你在精炼区和展示区创建的每个Iceberg文件创建一个目录表。这些目录表被组织到curated_zone和presentation_zone数据库中,正如我之前提到的。
探索Iceberg高级特性
在实验的可选部分,你将探索Iceberg的架构演进特性。系统会要求你向ratings表添加一个新列,以适应输入数据架构的变化。
从源存储桶中,你将使用第三个模块Al_table在Terraform中应用转换。当你向ratings表添加新列时,只有元数据文件会被更改,你无需重写或更新任何数据文件。
你还将探索Iceberg的时间旅行特性,并查看如何同时查询ratings表的新版本和旧版本。
使用Lake Formation管理数据湖权限
最后,你将探索如何使用Lake Formation为你的数据湖应用精细的权限控制。正如我已经提到的,提供给你的数据湖已在Lake Formation中注册,你将扮演数据湖管理员的角色。我在资源部分包含了AWS文档的链接,向你展示如何设置Lake Formation并将其与你的数据湖关联。

Lake Formation允许你在两个级别强制执行权限:

- 元数据级权限:针对数据目录资源(如数据库和表)的权限。
- 存储访问权限:针对底层存储数据的权限。
Lake Formation使你(数据湖管理员)能够向IAM用户或角色授予对数据、数据库、表、列、行和单元格的精细权限。当你使用Lake Formation管理对底层数据的访问时,它会向集成的分析引擎(如Amazon Athena或AWS Glue)提供临时访问权限,以访问S3数据。这样,你无需编写详细的IAM策略来授予数据湖用户直接与底层S3对象交互的权限。
然而,你使用Lake Formation授予数据湖用户的权限旨在补充常规的IAM权限,而不是取代它们。数据湖用户仍然需要附加一个IAM策略,该策略授予他们访问AWS Glue服务、Lake Formation服务和Amazon Athena的权限。其工作方式是:通过IAM策略,你向用户或角色应用广泛的权限;然后,通过Lake Formation,你应用精细的权限,授予他们访问特定S3对象的权限。
在实验中,系统为你提供了Cloud9实例和Glue资源所承担的角色,以及一个代表机器学*团队成员的用户。这些IAM实体的广泛权限已在实验中为你定义。你将使用Lake Formation向数据湖表应用精细权限。具体来说,你将:
- 授予Cloud9实例承担的角色访问所有目录表及其底层存储数据的权限。
- 仅授予机器学*用户访问展示区中
ratings_for_ml表的权限。 - 然后验证他们无法访问其他表。
总结
我认为你已经准备好尝试这个实验了。这个实验可能有点长,所以如果你时间紧张,可以跳过或仅浏览可选部分。完成实验后,我将在这里与你见面,对本周内容进行快速总结。

本节课中,我们一起学*了Iceberg表格式在S3中的具体组织结构,包括其元数据层、存储层和目录层。我们还实践了Iceberg的架构演进和时间旅行两大核心特性。最后,我们探讨了如何使用AWS Lake Formation在元数据和存储两个层面,为数据湖实施精细的访问权限控制,从而安全地管理数据资产。
169:数据工程(导论,源系统、数据摄取和管道,数据存储和查询|1-2-3课) - 第2周总结 🗂️


在本节课中,我们将回顾第2周的核心内容,重点梳理从传统数据仓库到现代数据湖仓的存储架构演变。我们将理解每种架构的关键概念、优缺点,并学*如何根据组织需求选择合适的存储方案。
存储架构的演变 🏗️
上一节我们介绍了数据工程的基础,本节中我们来看看数据存储架构的发展历程。
本周我们探讨了存储抽象概念的演变过程,从传统数据仓库到现代云数据仓库,再到数据湖,最后到数据湖仓。
你看到了数据湖仓架构如何旨在结合数据仓库和数据湖两者的优势,以支持许多组织日益增长的数据需求。
理解每种架构的关键概念,使你能够根据组织的需求选择最合适的存储解决方案。
核心架构对比 ⚖️
以下是三种主要存储架构的核心特点与权衡。
- 现代云数据仓库:可用于存储分析工作负载和报告用例的数据。它们通过利用云计算的大规模并行处理能力,实现低延迟查询性能。但数据仓库通常伴随较高的存储成本。
- 核心优势公式:
低延迟查询 = 大规模并行处理(MPP)
- 核心优势公式:
- 数据湖:构建在低成本对象存储之上,用于存储大量结构化和非结构化数据。支持需要海量数据的应用,如机器学*和大数据处理。但若缺乏适当的数据管理功能或数据发现工具,你的数据湖很容易变成无法使用的“数据沼泽”。
- 核心风险:
数据湖 - 管理工具 = 数据沼泽
- 核心风险:
- 数据湖仓:结合了数据湖的可扩展、低成本、灵活存储能力,以及数据仓库的结构化查询和数据管理功能,提供了一个统一的平台,同时支持低延迟分析工作负载和机器学*。
实践与应用 🛠️
理解了理论概念后,我们来看看如何在实践中应用这些知识。



在本周的第一个实验中,你看到了如何通过为存储在数据湖中的数据集创建数据目录,并对数据进行分区以提高数据检索效率,来缓解“数据沼泽”的挑战。
在实验作业中,你使用 Lake Formation 和 Iceberg 表 创建了一个数据湖仓。

# 示例:创建Iceberg表(概念性代码)
CREATE TABLE sales_iceberg (
transaction_id BIGINT,
product_id INT,
sale_amount DECIMAL(10,2),
sale_date DATE
)
USING iceberg
PARTITIONED BY (sale_date);

未来趋势与下周预告 🔮
正如我之前所说,现有的数据仓库技术正越来越多地融入使其也能像数据湖一样运作的功能,而数据湖技术也正在融入使其能像数据仓库一样运作的功能。
因此,在你未来作为数据工程师的工作中,我认为你很可能会看到数据湖、数据仓库和数据湖仓之间的界限开始模糊,取而代之的是一套工具集,它们让你能够灵活地根据组织需求优化存储解决方案。
接下来的一周,我们将深入探讨查询。你将了解查询在底层是如何工作的,并探索提升查询性能的策略。我们下周见。
本节课总结:本节课我们一起学*了数据存储架构的演变,对比了数据仓库、数据湖和数据湖仓的核心特点与适用场景,并通过实验了解了构建数据目录、数据分区以及使用现代工具(如Lake Formation和Iceberg)创建数据湖仓的具体方法。理解这些架构有助于你为不同的业务需求设计最有效的数据存储解决方案。
170:数据工程(导论,源系统、数据摄取和管道,数据存储和查询|1-2-3课)|第3周概览 🗺️

在本节课中,我们将要学*数据工程课程的第三周,也是最后一周的内容。我们将探讨数据存储与管理方式如何直接影响数据检索速度,以及查询如何影响存储系统本身的性能。作为数据工程师,理解查询的内部工作机制至关重要。
在前几周,我们学*了数据如何存储在数据库和对象存储等存储系统中,以及存储抽象如何在存储系统之上添加额外的管理层。
本节中,我们来看看数据存储和管理的方式如何直接影响数据检索的速度,即查询数据的速度,以及查询如何影响存储系统本身的性能。
在你的数据工程师工作中,你将编写查询以从内部和外部系统提取数据,并设置可供利益相关者直接查询的数据存储解决方案。因此,你需要理解你的数据存储和管理选择如何影响查询性能和系统性能。
要做到这一点,你需要详细了解查询的实际工作原理。查询是你用特定查询语言编写的语句,用于检索数据或对数据执行操作。

例如,在之前的课程中,你编写了SQL语句来与关系数据库管理系统(RDBMS)交互。
但查询不仅限于表格数据。在那门课程的另一个实验中,你使用了类似SQL的语句从亚马逊对象存储中检索数据。在本课程的第一周,你使用了Cypher语言从Neo4j图数据库中查询关系和节点属性。
查询语言是声明性语言。这意味着当你编写查询时,你只需向DBMS描述你想要检索什么数据或想对数据做什么,而无需担心执行查询所需的确切步骤。这些细节对你来说是抽象的,并由DBMS处理。
既然DBMS处理了这些细节,你可能会认为不必确切理解查询在幕后是如何处理的。


但如果你不真正理解查询的工作原理,有一天你可能会运行一个查询,导致关键数据库宕机数天甚至更久。相信我,这绝不是好事。

即使你自己已经擅长编写高效的查询,理解查询的处理过程也能帮助你建模数据,使其更易于被利益相关者检索且速度更快。
因此,本周我们将探索查询从编写到执行所经历的旅程:从你编写查询的那一刻起,到它被解析,再到创建和执行执行计划,最后到结果返回或所需操作被执行。
然后,我们将介绍可用于提高SQL查询性能的技术,例如创建数据库索引,这有助于优化对数据库中特定记录的搜索。
本周我们将重点讨论SQL,因为它是一种极其流行且成熟的语言,并且我们将介绍的许多技术也适用于其他查询语言。
我们还将研究聚合操作,重新讨论行存储与列存储的对比,并讨论流数据上的查询。
在本周的实验中,你将获得以下实践经验:
以下是本周实验你将获得的实践经验:
- 使用高级SQL语句。
- 比较在行存储与列存储上执行分析查询的执行时间。
- 最后,使用亚马逊Apache Flink托管服务对流数据执行基于时间的窗口查询。
在下一个视频中,请与我一起深入探究查询的生命周期。

本节课中我们一起学*了第三周的课程概览。我们明确了理解查询内部工作原理的重要性,概述了查询从编写到执行的完整旅程,并预告了本周将学*的核心技术与实践内容,包括查询性能优化、存储格式对比以及流数据处理。
171:查询的生命周期 🔍

在本节课中,我们将学*数据库管理系统执行一个查询的完整生命周期。虽然运行查询看起来只是编写代码、执行并获取结果的简单任务,但其背后涉及多个组件的协同工作。我们将详细解析从提交查询到返回结果的每一个步骤。
查询处理的架构概述
上一节我们介绍了数据库系统的基本概念,本节中我们来看看一个典型数据库管理系统的内部架构。下图展示了一个通用架构:

本课程第一周已详细讨论过存储引擎,因此本节将聚焦于架构中的其他核心组件。
查询生命周期的阶段
当你向数据库发送查询请求时,该请求会经历一系列有序的阶段才能最终被执行。
以下是查询处理的主要阶段:
-
传输系统接收查询
你的查询请求首先通过传输系统抵达数据库。 -
查询处理器解析
传输系统将查询交给查询处理器。处理器包含两个主要部分:查询解析器和查询优化器。 -
解析与验证
查询解析器将查询语句分解为查询令牌,这些是SQL查询的基本构建块,包括SELECT、FROM等关键字、表名、属性名、操作符等。
接着,解析器检查语法是否正确,并通过验证引用的所有表和属性名是否真实存在于数据库中来确认查询有效性。
同时执行控制检查,以确保运行查询的用户拥有访问这些属性的适当权限。 -
生成字节码
验证通过后,查询解析器将SQL代码转换为字节码。字节码以一种高效的、机器可读的格式表达了执行查询所需的步骤。
公式表示:SQL 语句 -> 解析 -> 字节码 -
查询优化
生成的字节码随后传递给查询优化器。优化器分析查询,并制定从存储层检索结果的执行计划。
由于一个查询可以有多种执行方式,查询优化器会尝试找到一种能最高效利用可用资源的合适策略。
为此,优化器会根据所需操作类型、数据中是否存在索引、扫描数据量大小等因素生成多种可能的执行计划。
然后,它为每个计划计算一个成本值。成本可能包括多个组成部分,例如将数据从磁盘传输到内存的I/O成本,以及计算和内存使用成本。
最终,查询优化器选择成本最低的计划。
代码逻辑示意:plans = generate_plans(query) costs = calculate_cost(plans) chosen_plan = select_plan_with_minimum_cost(costs) -
执行引擎运行
一旦执行计划创建完毕,执行引擎便按照计划中概述的操作序列执行,并产生最终的查询结果。
理解执行计划
虽然执行查询的所有细节通常对你来说是抽象的,但你可以访问任何查询语句的执行计划,以便在执行前理解其性能,或在执行后排查慢查询的原因。
例如,在关系型数据库中,你可以在SQL语句前添加EXPLAIN命令,以显示数据库为执行该查询将采取的步骤序列。这还会展示各个查询阶段的各种资源消耗和性能统计信息。
让我们看一个例子。
以下是你在之前课程实验中见过的DVD租赁数据库的客户表。假设我将这些数据存储在Postgres数据库中,并且想从客户表中选择所有记录。
我可以在简单的SELECT语句前添加EXPLAIN命令,以获取Postgres查询优化器创建的执行计划。

EXPLAIN SELECT * FROM customer;

返回的计划指明它将执行顺序扫描,即全表扫描。它还显示两个成本值:第一个是输出结果前所需任何处理的启动成本,第二个是检索查询结果的总执行成本。此外,计划还输出预计返回的行数以及预期的行宽度(字节数)。
在此示例中,全表扫描的启动成本为0个成本单位,但返回599行的总成本为14.99个成本单位。
现在,假设你想再次运行SELECT查询,但这次决定使用WHERE子句来过滤记录,以便只返回客户ID等于3的记录。
EXPLAIN SELECT * FROM customer WHERE customer_id = 3;

现在返回的计划指明它将使用客户ID列上的索引来查找匹配WHERE条件的指定行,而不是扫描整个表。回顾第一周的内容,索引是一种你创建的特殊数据结构,作为一种保存额外元数据的方式,以帮助更高效地定位所需数据。

你会注意到,使用这种基于索引的策略,估计的总成本低于全表扫描的成本。我们将在另一个视频中详细讨论数据库索引。
因此,每当你想要理解查询性能时,都可以使用这个EXPLAIN功能。并且,该功能并非关系型数据库独有,你也可以在NoSQL数据库、数据仓库或数据湖屋中使用它。
总结
本节课中,我们一起学*了查询在数据库管理系统中的完整生命周期。我们从查询通过传输系统进入开始,逐步了解了查询处理器(包括解析器和优化器)如何将SQL语句解析、验证、优化为成本最低的执行计划,最终由执行引擎执行并返回结果。我们还学*了如何使用EXPLAIN命令来查看和理解查询的执行计划,这对于性能分析和优化至关重要。在接下来的视频中,我将带你快速了解本周的第一个实验。
172:高级SQL查询(第1部分) 🗂️

概述

在本节课中,我们将学*一系列高级SQL查询技术。这些技术包括使用SELECT DISTINCT、字符串和日期操作函数、CASE语句、布尔表达式等,以更高效、更灵活地从关系型数据库中提取和处理数据。
回顾基础SQL操作
在上一门课程的第一个实验中,你使用SQL查询对关系型数据库执行了CRUD操作。CRUD代表创建、读取、更新和删除。
你学*了如何创建表和新的记录,使用SELECT语句读取一组记录,以及更新和删除现有记录。你还学*了如何使用WHERE子句应用谓词来过滤数据,使用JOIN连接不同表的数据,并应用聚合函数,如COUNT、SUM、AVG、MIN和MAX。

引入高级SQL语句
在接下来的实验中,你将使用更高级的SQL语句。这些语句包括SELECT DISTINCT、用于操作字符串和日期的SQL函数、CASE语句、SQL布尔表达式、公共表表达式(CTE)、子查询和SQL窗口函数。
在开始实验之前,让我们先了解一下这些高级SQL语句。
数据模型:星型模式
以下是我们将要使用的数据的实体关系图(ERD)。它包含与你在课程2中使用的DVD租赁数据库相同的信息,但在这里它被组织成所谓的星型模式。你将在下一课程中了解更多关于数据模型的知识。
中间的事实表名为 fact_rental,它包含了客户每次租赁交易的详细信息,例如租赁日期、归还日期、支付金额、租赁的电影ID、电影类别ID、服务客户的员工ID等。
周围的其他维度表则包含了关于客户、电影、电影类别、演员以及商店和员工的更详细信息。
为了讲解这些高级SQL语句,我们将只关注租赁事实表以及客户、员工、电影和电影类别的维度表。

使用 SELECT DISTINCT 去重
假设你想从 fact_rental 表中了解哪位员工服务了哪位客户。你可以选择 staff_id 和 customer_id。
SELECT staff_id, customer_id FROM fact_rental;
这个查询返回所有员工和客户ID的组合。但由于同一个客户可能被同一位员工服务多次,结果中可能包含重复的员工-客户ID对。
你可以向SELECT语句中添加SQL关键字DISTINCT,以确保结果只包含唯一的员工-客户ID对。
SELECT DISTINCT staff_id, customer_id FROM fact_rental;
连接表与字符串函数
现在,让我们包含员工的名字和姓氏,这些信息可以在员工维度表 dim_staff 中找到。因此,我将基于 staff_id 列将 fact_rental 表与 dim_staff 表连接起来。
我将把员工的名字和姓氏添加到SELECT语句中。你可以将名字和姓氏连接成一个字符串。根据数据库管理服务器的不同,字符串连接的语法可能有所不同。这里我使用的是MySQL数据库,可以使用CONCAT函数来组合名字和姓氏。
SELECT DISTINCT
f.staff_id,
f.customer_id,
CONCAT(s.first_name, ' ', s.last_name) AS staff_name
FROM fact_rental f
JOIN dim_staff s ON f.staff_id = s.staff_id;
这个CONCAT函数将返回员工的全名,但名字之间没有空格。为了使其更易读,让我们在名字和姓氏之间添加一个空格。
除了连接两个字符串,你还可以应用其他字符串操作函数,例如LOWER将字符串转换为小写,或UPPER将其转换为大写。
你也可以使用SUBSTRING函数来提取字符串的一部分。例如,要返回姓氏的第一个字母,我将对 staff_last_name 应用SUBSTRING函数。
SELECT DISTINCT
f.staff_id,
f.customer_id,
CONCAT(s.first_name, ' ', SUBSTRING(s.last_name, 1, 1)) AS staff_name_initial
FROM fact_rental f
JOIN dim_staff s ON f.staff_id = s.staff_id;
这个函数需要两个参数:起始位置和要提取的字符数。由于我只想要第一个字母,起始位置和字符数都将是1。
使用 CASE 语句创建条件列
现在,假设你想检查客户是否按时付款,即他们在归还DVD之前支付了DVD租赁费用。在 fact_rental 表中,你可以比较单个记录的 payment_date 和 return_date 列。
但为了使其更容易,让我们使用SQL CASE语句创建一个列,如果付款日期在归还日期之前,则该列包含1,否则为0。
该语句以CASE关键字开始,以END关键字结束。在这两个关键字之间,你可以使用WHEN关键字指定条件,使用THEN关键字指定与该条件关联的结果。列出所有条件后,你可以使用ELSE关键字指定如果列出的条件均未满足时要返回的结果。
让我们使用该语句从 fact_rental 表创建指示列。
SELECT
customer_id,
rental_id,
CASE
WHEN payment_date < return_date THEN 1
ELSE 0
END AS on_time_payment
FROM fact_rental
LIMIT 5;
我将此列标记为 on_time_payment。让我们限制此查询仅显示结果的前五行。
以下是此查询的结果。所有这五位客户的 on_time_payment 列中都是0,这意味着他们在归还DVD之后才支付了DVD租赁费用。
使用 WHERE 子句和布尔表达式过滤结果
让我们过滤这些结果,以便你只能看到位于美国和加拿大的客户的结果,以及发生在2005年5月24日至2005年7月26日之间的任何租赁的结果。
要获取客户的国家/地区,我将基于 customer_id 将 fact_rental 表与客户维度表 dim_customer 连接起来。
你需要使用WHERE语句根据国家和日期过滤结果。

首先,检查客户的国家是美国还是加拿大。或者,你可以使用IN运算符编写此表达式,并检查客户的国家是否在包含美国和加拿大的列表中。
SELECT
f.customer_id,
f.rental_id,
CASE
WHEN f.payment_date < f.return_date THEN 1
ELSE 0
END AS on_time_payment
FROM fact_rental f
JOIN dim_customer c ON f.customer_id = c.customer_id
WHERE c.country IN ('United States', 'Canada')
AND f.rental_date BETWEEN '2005-05-24' AND '2005-07-26';
这里我选择使用IN运算符,当你有两个以上的选项时,它会很方便。
接下来检查日期,你可以使用BETWEEN运算符检查租赁日期是否在2005年5月24日(即2005-05-24)和2005年7月26日(即2005-07-26)之间。我在这里的这两个布尔表达式之间写AND,因为我希望国家和日期条件都为真。
现在运行查询以查看结果。
总结

本节课中,我们一起学*了SELECT DISTINCT语句、一些SQL字符串函数、布尔表达式和CASE语句。这些高级SQL技术能帮助你更精确地查询和转换数据。在下一个视频中,我们将继续探讨实验中会出现的更多高级SQL技巧。
173:高级SQL查询(第2部分)📊

在本节课中,我们将学*几种高级SQL技术,包括公共表表达式、子查询和窗口函数。我们将通过具体的DVD租赁数据库示例,了解如何应用这些技术来执行更复杂的数据分析和计算。
在上一节视频中,我们学*了如何使用 SELECT DISTINCT 语句和SQL字符串函数来查询DVD租赁数据库中员工与客户的唯一配对。我们还使用 CASE 语句创建了一个指示客户是否按时支付租金的列,并通过 WHERE 子句中的布尔表达式过滤了结果。
本节中,我们将看看如何将一些高级SQL技术应用到查询中。
使用公共表表达式(CTE)📝
有时,我们可能需要在先前查询结果的基础上执行额外的计算,但又不希望将这些结果存储在单独的表中。这时,我们可以使用公共表表达式来定义临时的结果集,以便在查询的其他部分引用。

以下是定义和使用CTE的步骤:

- 使用
WITH关键字开始。 - 为CTE指定一个名称。
- 使用
AS关键字。 - 将代表临时结果的查询用括号括起来。
让我们通过两个例子来具体说明。
示例一:计算每位员工服务的客户总数
首先,我们定义一个名为 staff_customer_pairs 的CTE,它包含了上一课中获取的唯一员工-客户配对查询。
WITH staff_customer_pairs AS (
-- 获取唯一员工和客户配对的查询
SELECT DISTINCT staff_id, customer_id
FROM rental
)
定义好CTE后,我们就可以像查询普通表一样查询它。以下查询从CTE中选择员工ID并统计客户数量,然后按员工ID分组。

SELECT staff_id, COUNT(customer_id) AS total_customers
FROM staff_customer_pairs
GROUP BY staff_id;
示例二:计算每位客户的按时支付百分比
接下来,我们定义一个名为 customer_payment_info 的CTE,它包含了计算按时支付指示列的查询。
WITH customer_payment_info AS (
-- 计算按时支付指示列的查询
SELECT customer_id,
CASE WHEN return_date <= rental_date + INTERVAL '7 days' THEN 1 ELSE 0 END AS on_time_payment
FROM rental
)
然后,我们可以从这个CTE中查询,计算每位客户的按时支付平均值(即百分比)。

SELECT customer_id, AVG(on_time_payment) * 100 AS percent_on_time
FROM customer_payment_info
GROUP BY customer_id;
为了验证所有客户的按时支付百分比,我们可以定义第二个CTE,并从中找出最大百分比值。
WITH customer_payment_info AS (...),
customer_percent_on_time AS (
SELECT customer_id, AVG(on_time_payment) * 100 AS percent_on_time
FROM customer_payment_info
GROUP BY customer_id
)
SELECT MAX(percent_on_time) AS max_percent_on_time
FROM customer_percent_on_time;
使用子查询🔍
除了CTE,我们还可以在主查询内部使用子查询来合并临时结果。子查询是嵌套在另一个SQL语句中的查询。
让我们以电影维度表为例。假设我们想找出长度大于平均长度的电影ID。
首先,我们需要一个查询来获取电影的平均长度:
SELECT AVG(length) FROM dim_film;

然后,我们可以将这个查询作为子查询嵌入到主查询的 WHERE 条件中:
SELECT film_id, length
FROM dim_film
WHERE length > (SELECT AVG(length) FROM dim_film);
使用SQL窗口函数🪟
最后,我们来探讨SQL窗口函数。这类函数允许你在一个特定的“窗口”或行集上应用聚合或排名函数。它与使用 GROUP BY 进行聚合类似,但不同之处在于,窗口函数将聚合应用于行的子集,并且不会将多行合并为单行输出,每一行都保持独立。
要定义窗口,需要使用 OVER() 子句,它需要两个信息:按哪一列对行进行分区,以及按哪一列对行进行排序。

排名函数示例
假设我们有一个查询(可以定义为CTE),用于计算每位客户在每个电影类别上的平均租赁天数。
WITH customer_info AS (
SELECT r.customer_id,
c.name AS category_name,
AVG(DATEDIFF(r.return_date, r.rental_date)) AS avg_rental_days
FROM fact_rental r
JOIN dim_category c ON r.category_id = c.category_id
GROUP BY r.customer_id, c.name
ORDER BY r.customer_id, avg_rental_days DESC
)

现在,我们想为这个结果添加一列,显示对于每位客户,每个类别基于租赁天数的排名。
我们可以使用 RANK() 窗口函数:
SELECT customer_id,
category_name,
avg_rental_days,
RANK() OVER (PARTITION BY customer_id ORDER BY avg_rental_days DESC) AS rank_category
FROM customer_info
ORDER BY customer_id, rank_category;
RANK() 函数在遇到并列情况时会分配相同的排名。如果想在并列时分配不同的排名,可以使用 ROW_NUMBER() 函数。
聚合函数示例
同样在窗口函数中,你也可以使用聚合函数,如 SUM()。以下查询会计算每位客户在每个类别上的平均租赁天数的累计和。
SELECT customer_id,
category_name,
avg_rental_days,
SUM(avg_rental_days) OVER (PARTITION BY customer_id ORDER BY avg_rental_days DESC) AS running_sum
FROM customer_info;
还有其他窗口函数,如 LEAD() 和 LAG(),可以在本实验的可选部分进行探索。
总结📚

本节课中,我们一起学*了三种高级SQL查询技术:
- 公共表表达式:用于创建可重用的临时结果集,使复杂查询的结构更清晰。
- 子查询:允许将一个查询的结果嵌套在另一个查询中,用于条件过滤或计算。
- 窗口函数:能够在保留各行独立性的同时,在指定的行窗口上执行排名或聚合计算,非常适合进行高级数据分析。
掌握这些技术将极大地增强你处理复杂数据查询和分析任务的能力。接下来,我们将在后续视频中探讨这些SQL语句在后台是如何被处理的,并学*一些可用于提升其性能的策略。
174:索引深入探讨 🔍


在本节课中,我们将要深入学*数据库索引的内部结构和工作原理。理解索引的实现方式有助于你设计更优的索引结构,从而提升SQL查询的性能。
概述
索引是一种独立的数据结构,拥有自己的磁盘空间,并存储指向实际表中数据的信息。它存储一个或多个列的数据,并按照明确的顺序排列。就像使用书籍末尾的字母索引来快速定位特定主题的页码,而不是翻阅整本书一样,数据库管理系统可以通过搜索有序的索引来查询数据,而非扫描整个表,从而更快地返回结果。
索引的基本概念与结构


在第一周的学*中,你已经了解到可以在关系型数据库中创建索引来帮助特定查询运行得更快。实际上,当查询优化器分析一个查询时,它会考虑是否存在索引,以及使用基于索引的计划是否能降低查询成本。
以下是索引结构的一个示例:


在这个例子中,country列中的条目按字母顺序存储在索引结构中。当你想查询发生在特定国家的订单时,例如,你想从order表中选择country为USA的所有记录,数据库可以对索引执行二分查找,以定位country列中包含USA的实际订单表中的行。
索引的物理实现
上一节我们介绍了索引的逻辑概念,本节中我们来看看索引在物理上是如何实现的。
在上述示例中,我以表格形式展示索引条目来解释索引的概念。然而,索引中的数据实际上并非像表一样顺序存储。它被划分为多个数据块,这些数据块通过双向链表连接在一起,以便从任何数据块进行前向和后向读取。每个数据块内部的数据是排序的,然后索引块以保持整个索引逻辑顺序的方式链接在一起。此外,数据块的位置并不重要,因为它们被正确地链接在一起。这种结构便于在插入新数据或删除旧数据时更新索引。
例如,假设向表中添加了一个来自泰国的订单。泰国在字母顺序上位于墨西哥和美国之间。你会将其添加到此处看到的第三个索引块中,并相应地移动其余数据。如果该记录被删除,那么你将从其索引块中移除相应的国家。整个过程,索引块始终保持双向链接。
B树:高效定位索引块
为了高效地定位这些索引块,在索引块之上会构建另一种称为平衡搜索树或B树的结构。索引块代表树的叶节点。从这些叶节点向上构建,你拥有内部节点(也称为分支节点),它们充当叶节点组的父节点。
例如,这个内部节点是这三个叶节点的父节点。内部节点存储三个条目:Canada、Mexico和USA,它们分别代表每个叶节点中按字母顺序排序的最后一个国家。这样,如果数据库要查找名称在Canada和Mexico之间的国家,它将遍历到这里的第二个叶节点。如果名称在Mexico和USA之间,它将遍历到第三个叶节点。
这种节点分组和链接的模式在树中向上重复,直到到达树的第一个节点或根节点。
假设你想查询在加拿大下的订单。为了定位这些行,数据库从根节点开始,然后查找国家Canada。Canada不在根节点中,但由于它在字母顺序上位于Brazil和USA之间,数据库选择第二个内部节点,你知道该节点将包含字母顺序在Brazil和USA之间的国家。数据库在此内部节点中搜索Canada,并发现它是第一个条目,因此数据库选择第一条路径并到达一个叶节点,在那里找到代表在加拿大下订单的所有记录。由于country列中的条目不是唯一的,数据库还需要水平遍历叶节点以找到所有与Canada对应的条目。
索引查询的成本分析
总结一下,要检索具有索引结构的数据,数据库需要首先遍历B树。由于树被维护为平衡的,意味着子节点的数量在父节点之间均匀分布,一直到树的根节点,因此遍历树始终是一个高效的操作,时间复杂度为 O(log n)。
但是,如果索引不包含唯一元素,一旦数据库定位到适当的叶节点,它就需要水平遍历一系列叶节点以检索所有具有所需索引值的行。如果存在大量重复值,遍历节点链最终可能几乎像扫描整个表一样,在这种情况下,查询优化器将选择扫描整个表而不是使用索引。
因此,当你创建索引时,需要仔细选择合适的列来构建索引。一般策略是创建能够提高你最关注性能的查询性能的索引结构。你也不希望用太多索引使表过载,因为每当数据更新时,维护许多树结构的平衡实际上可能会降低数据库的性能。
索引实践:示例分析

为了更好地理解索引如何影响查询成本,让我们以本周第一个实验中所见的VD租赁数据库的payment表为例。
首先,让我们检查一个不涉及索引的SQL查询的执行计划。这里,我将从payment表中选择rental_id为1的记录。你可以通过在查询前添加EXPLAIN关键字来获取查询计划。
EXPLAIN SELECT * FROM payment WHERE rental_id = 1;
从返回的计划中,你可以看到查询优化器选择了顺序扫描,即全表扫描。
现在,让我们为rental_id列创建一个索引。我将以关键字CREATE INDEX开始,并给这个索引命名为rental_id_idx。我想在payment表的rental_id列上创建这个索引结构。
CREATE INDEX rental_id_idx ON payment (rental_id);

然后,我在之前的相同查询前添加EXPLAIN关键字以检查执行计划。
EXPLAIN SELECT * FROM payment WHERE rental_id = 1;
这次,查询优化器识别到索引的存在,并选择了基于索引的策略,因为其成本要低得多。通过添加索引,我能够将查询时间减少超过30倍。
在视频之后的阅读材料中,我包含了更多关于索引的示例。请务必查看这些内容,以更好地理解索引如何真正提高你的查询性能。
列式存储中的索引概念
到目前为止,我们一直在讨论传统关系型数据库的索引概念,但相同的概念也存在于列式存储中。
例如,当你在Amazon Redshift中创建表时,可以将其一个或多个列声明为排序键。然后,无需创建单独的数据结构,Redshift会根据排序键直接对数据的行进行排序,然后在磁盘上存储排序后的数据。
例如,当你将country列声明为此表的排序键时,表的所有行将根据country列重新组织,就像这样:



这类似于在电子表格中按一列或一组列排序。每个列重新组织后的版本随后存储在磁盘上。顺便说一下,其他云数据仓库,如BigQuery,将排序键称为集群键,但这是完全相同的概念。



通过在行式数据库中正确创建索引,或为列式存储指定排序键或集群键,你可以通过减少需要扫描的行数来增强特定查询的性能。
总结
本节课中我们一起学*了数据库索引的深入知识。我们探讨了索引的基本概念、物理实现方式(如双向链表和B树结构),以及索引如何影响查询性能。我们还通过实际示例分析了创建索引前后的查询计划变化,并了解了索引概念在列式存储(如排序键)中的应用。理解这些原理将帮助你设计更有效的数据库结构,优化查询,从而提升整体数据工程管道的效率。
在查看下一个阅读材料中的额外索引示例后,请加入后续视频,学*查询数据的另一个最佳实践:只查询和检索你实际需要的数据。


175:只检索所需数据 📊

在本节课中,我们将学*如何通过优化查询来只检索所需数据,从而避免不必要的性能开销和额外成本。我们将探讨几种“剪枝”技术,包括行剪枝、列剪枝和分区剪枝,以提升查询效率。
在上一节视频中,我们了解到为表创建合适的索引可以避免代价高昂的全表扫描。然而,实际上存在比全表扫描更糟糕的情况,那就是编写一个不仅扫描整个表,而且返回所有数据的查询。
当运行不带任何谓词(即没有 WHERE 子句来过滤结果)的 SELECT * 时,数据库管理系统需要扫描整个表并检索每一行和每一列。这对于源数据库来说代价高昂,因为需要从磁盘传输大量数据,并且数据可能还需要进一步处理。

我记得有一次,在我咨询的一家大型连锁超市,一位新分析师在生产数据库上运行了一条 SELECT * 命令,导致整个关键的库存数据库宕机了整整三天。公司不得不花费大量资金来解决这个问题,而那位可怜的分析师处境也不妙。
在按使用量付费的云数据库或数据仓库上运行 SELECT * 也可能非常昂贵。您将需要为从整个表读取的所有字节以及查询运行时使用的任何计算资源付费。
因此,一般来说,您应该避免运行不带 WHERE 子句来过滤结果的 SELECT *。作为一个经验法则,您应该只查询需要的数据。如果您想探索数据,请考虑使用一种称为“剪枝”的技术,从查询扫描中排除不相关的数据。
以下是几种常见的剪枝技术:
行剪枝 是最常见的剪枝技术之一,即过滤掉不满足 WHERE 条件的行。例如,您可以像之前看到的那样,从 payments 表中选择 rental_id 列为 1 的所有记录。在过滤结果时,您可以通过在传统的行式数据库中使用索引,或在列式存储(如 BigQuery 或 Amazon Redshift)中使用排序键或集群键来进一步提高查询性能。正如上一视频所见,您可以在 payments 表的 rental_id 列上创建一个名为 rental_idx 的索引来加速此查询。
列剪枝 技术包括在查询语句中仅指定需要的列。例如,您可以选择仅从 payments 表中查询 customer_id 和 rental_id 列,而不是选择所有记录。这样,数据库就不必扫描所有其他不相关的列。
分区剪枝 是指仅扫描包含相关数据的特定分区,而不是扫描整个表。当您使用的数据存储允许您基于分区键(例如日期或位置)对数据进行分区时,这种剪枝就成为可能。例如,在 BigQuery 中,您可以将这个未分区的表基于 order_date 对记录进行分区,然后进一步按 country 对每个分区进行排序。
假设用户查询数据,并按特定订单日期(4月1日)和国家(美国)进行过滤,数据库只需扫描 4月1日 分区中的记录,然后查找国家为美国的记录。
因此,为了避免产生意外费用或降低源数据存储的性能,您应始终确保只读取需要的数据。
另一个对查询性能有巨大影响的因素是连接不同表中数据的方式。我们将在下一个视频中讨论表连接带来的挑战。我们下节课见。

本节课中,我们一起学*了如何通过避免使用 SELECT * 和运用行剪枝、列剪枝及分区剪枝等技术,来优化查询并只检索所需数据,从而提升性能并控制成本。
176:JOIN语句详解 🔗

在本节课中,我们将学*SQL中JOIN语句的工作原理、常见实现方法及其对查询性能的影响。理解JOIN是设计高效数据管道和优化数据模型的关键。
概述
JOIN是组合数据集最常用的方法之一。它允许你在数据管道中转换数据并创建新的数据集。此外,最终用户也可能使用JOIN来组合你提供的数据。然而,JOIN是最耗时的查询操作之一,因此在数据建模时,理解最终用户如何通过JOIN组合数据至关重要。
JOIN的工作原理
为了回顾JOIN的工作原理,我们考虑以下两个表。orders表包含一家电子商务公司每个订单的信息,customer表包含每个客户的信息。这两个表通过客户ID相互关联,属于一个规范化模型,该模型将数据存储在单独的表中以减少冗余。

为了简化查找订单及其下单客户信息的过程,你可以使用SQL JOIN语句组合orders表和customer表的数据。你将选择orders表中的所有记录,这些记录通过customer表的ID列和orders表的customer_id列与customer表连接。这样,基于客户ID,customer表中相应的客户信息将与订单信息组合。
例如,对于这三个客户ID均为1的订单,你将附加ID为1的客户信息。然后,对于下一个客户ID为2的订单,你将附加ID为2的客户信息,依此类推。这种类型的JOIN称为内连接,它只组合两个表中共享匹配客户ID的行。
JOIN的实现方法

为了帮助你理解为什么JOIN操作是最耗时的查询操作之一,我们介绍三种常见的JOIN实现方法。大多数数据库查询优化器在制定JOIN语句的执行计划时会使用其中一种方法。
嵌套循环连接
默认方法是嵌套循环连接,其工作原理类似于嵌套的for循环。从orders表的第一行开始,数据库记录下customer_id,然后扫描customer表中的每一行,仅检索具有此匹配customer_id的行。它将orders表该行的信息与检索到的客户信息行组合。对orders表中的每一行重复此过程,最后返回组合结果。
基于索引的嵌套循环连接
第二种方法是基于索引的嵌套循环连接,这是第一种方法的变体。当至少一个连接属性存在索引时,可以使用此方法。在本例中,索引可以是customers表中的ID列或orders表中的customer_id列。
假设customers表的ID列存在索引。你可能有一个B树结构,包含根节点、内部节点和叶节点。要执行此连接,数据库从orders表检索第一行,然后使用ID索引定位customer表中所有具有匹配ID为1的行。然后,数据库从customer表检索该行的数据,并将其与orders表的第一行连接。对orders表中的每一行重复此过程,然后返回组合结果。
哈希连接
最后一种方法是哈希连接。此方法使用哈希函数将每个表的行映射到桶空间,映射依据是连接属性的值(在本例中是客户ID)。
使用此方法,数据库首先扫描较小表(本例中是customers表)的所有行,并将每一行发送到特定的桶。然后,数据库扫描较大orders表的行,根据相同的哈希函数将每一行发送到一个桶。最后,在每个桶内,数据库组合customers表和orders表中共享匹配客户ID的行。最终返回组合结果。
这种方法可能快得多,因为并行扫描较小的桶比扫描整个表要快得多。在所有这些方法中,JOIN操作要求数据库扫描每个表中相当数量的行,并且可能发生多次。这就是JOIN操作成为最耗时查询操作之一的原因。

数据建模与JOIN
作为一名数据工程师,除了能够自己编写高效的JOIN查询外,还应该以能够使最终用户在需要时轻松连接数据的方式建模和提供数据。你选择的数据模型和模式会影响最终用户为获取所需数据而需要执行的JOIN数量。
通常,规范化模式会导致数据冗余较少,但需要更复杂的JOIN语句来组合数据。以下是你在专项课程第一个实验中看到的两种模式。
第一种是你摄入管道的输入数据的规范化模式。然后,你运行一个Glue作业,将数据转换为星型模式,再提供给数据分析师。假设数据分析师有兴趣计算每个国家/地区销售的产品总数。
如果你将数据保持在其原始的规范化模式中,那么数据分析师需要将customer表与orders表连接,然后将orders表与orders_details表连接。另一方面,在星型模式中,数据分析师只需通过组合事实表orders和维度表dim_locations执行一次JOIN。
另一种选择是将相关属性组合成一个大表,那么数据分析师就根本不需要执行任何JOIN。如果数据建模对你来说是新的,请不要担心,我们将在下一课程中更详细地介绍数据建模以及每种方法的优缺点。
多对多关系与行爆炸


除了数据建模之外,在使用JOIN时你可能遇到的另一个挑战是当两个表具有多对多关系时。例如,这里显示的payments表和orders表具有多对多关系:一个支付可以与多个订单关联,一个订单可以通过多次支付完成。
每个支付都与一个客户关联,假设客户1进行了五次不同的支付。每个订单也与一个客户关联,假设客户1下了五个不同的订单。因此,你可以基于客户编号连接payments表和orders表以获得此表。
这听起来很简单,对吧?问题在于,这个表可能并不像你第一眼认为的那样。你可能认为这个表显示了支付信息及其关联的订单,但实际上这里的连接逻辑存在错误。通过基于客户编号连接表,你盲目地将payments表与orders表连接,而没有考虑给定的支付是否正确映射到其对应的订单。
由于这个错误,payments表中与客户1关联的每一行都映射到orders表中同样与客户1关联的每一行。这在输出中创建了5乘以5,即25行。现在假设客户编号列中还有许多其他重复项。这会导致一种称为行爆炸的情况,即查询返回的行数比预期的多。


行爆炸可能产生足够多的输出行,消耗大量数据库资源,甚至偶尔可能导致查询失败。为了避免这个问题,请确保检查你的查询计划,看它是否正确描述了你希望JOIN执行的操作。如果此查询将频繁运行,那么考虑在你的模型中添加一个正确映射支付到其对应订单号的表。
总结
在本节课中,我们一起学*了JOIN语句的核心概念、三种主要实现方法(嵌套循环连接、基于索引的嵌套循环连接、哈希连接),以及数据建模如何影响JOIN的复杂度。我们还探讨了多对多关系可能引发的行爆炸问题及其规避方法。理解JOIN的处理过程可以帮助你设计更高效的JOIN查询,并为最终用户正确地建模数据。
177:聚合查询 📊

在本节课中,我们将要学*聚合查询。聚合查询是分析型工作负载中的核心操作,用于从大型数据集中计算汇总值。我们将探讨其在行式存储和列式存储数据库中的执行方式与性能差异。
构建用于分析工作负载的系统时,必须支持对大型数据集进行聚合操作。
聚合查询用于计算某一列的汇总值,例如该列值的总和、平均值、最大值、最小值以及计数。以下是一个查询示例:从订单表中选择最低价格。在行式数据库中,此类聚合查询可以通过全表扫描来计算,即扫描表中的每一行以查找价格列中的最小值。如果可用,也可以通过使用索引结构来加速此查询。
例如,如果在价格列上存在一个B树索引,查询优化器可以决定使用该索引,并遍历B树以到达最左侧的叶节点,从而返回最低价格。
处理聚合查询时,还可以使用 GROUP BY 子句按特定列对查询结果进行分组,并返回每个组内的汇总值。例如,可以在查询中添加 GROUP BY country,以获取每个国家订单的最低价格。在这种情况下,表必须首先被分区成多个组。






每个组仅包含一个国家,然后为每个组计算最低价格。分区通常使用排序算法或哈希函数执行。如果分组属性(本例中是国家列)上存在索引,则可以避免这种分区操作。无论如何,聚合查询执行的是对列而非行的操作。
请记住,在行式数据库中,同一行的所有值在磁盘上是彼此相邻存储的。这意味着要从每一行获取价格值,必须将整行数据从磁盘传输到内存。因此,最终传输的数据量会超过执行分析查询实际所需的数据量。对于小型数据集,这可能没有问题。
但对于大型数据集,在行式存储中执行分析查询会变得非常缓慢。另一方面,列式存储在磁盘上将同一列的所有值相邻存储。

因此,在这种情况下,如果需要价格列的所有值,只需传输从第一个价格值到最后一个价格值之间存储的数据。在列式存储上执行分析查询效率要高得多,因为只需将分析查询相关的列数据从磁盘传输到内存。

在接下来的实验中,你将有机会比较行式存储与列式存储的查询性能。你将在托管于Amazon RDS的行式数据库上运行一个分析查询,然后在Amazon Redshift(一个利用列式存储的云数据仓库)上运行相同的分析查询,最后比较这两个查询的执行时间。
在下一个视频中,Morgan将带你详细了解Amazon Redshift。

之后,我将为你快速讲解实验步骤。

本节课中,我们一起学*了聚合查询的概念及其在行式与列式存储数据库中的执行机制。关键点在于,聚合查询针对列进行计算,而列式存储因其数据组织方式,在处理此类分析查询时具有显著的性能优势。接下来的实验将让你亲身体验这种差异。
178:Amazon Redshift云数据仓库 🚀

在本节课中,我们将学*影响Amazon Redshift数据仓库工作负载查询性能的架构因素。我们将探讨Redshift如何查询数据,以及为了优化查询性能,在表设计时需要考虑哪些关键点。
上一节我们介绍了查询、索引以及编写高效SQL查询的各种策略和技巧。本节中,我们来看看一些影响在Amazon Redshift上运行的数据仓库工作负载查询性能的架构因素。
这里我们将探讨Redshift如何查询数据,以及为了优化查询性能,在表设计时需要牢记的一些考虑因素。
Redshift的设计与架构 🏗️
Redshift被设计为一个高效的数据仓库解决方案。

它通过结合多种内部架构特性来实现这一目标,包括列式数据存储、大规模并行处理(MPP)以及数据压缩编码方案。
Redshift是一个列式数据库,这意味着它将数据按列(而非按行)一起存储在磁盘上。这种存储方式对于需要跨多行聚合数据,但任何特定查询只需访问少数几列的分析查询和OLAP工作负载尤其高效。通过这种列式存储方式,Redshift可以快速扫描和检索必要的数据,从而显著提升查询性能。这也是Redshift特别适合数据仓库和大规模数据分析的部分原因,在这些场景中,对大数据集的快速查询性能和成本效益至关重要。
列式存储还允许更好的数据压缩。当你运行查询时,Redshift将压缩数据读入内存,并按需解压。这意味着它可以利用更多内存来实际分析数据,从而使你的查询运行得更快。因此,你可以节省存储空间,并减少从磁盘读取的数据量。
Redshift还使用大规模并行处理(MPP),这个概念你上周已经和Joe学*了一些。让我们快速回顾一下。
Redshift由一个包含多个计算节点和一个领导节点的集群组成。与工作负载相关的数据分布在这些计算节点上,每个节点负责存储一部分数据,并处理对该数据的查询。计算节点被划分为称为“切片”的部分。一个切片使用计算节点的一部分内存和磁盘空间来处理分配给该节点的一部分数据。


通过MPP,这些计算节点协同处理查询,每个切片在不同部分的数据上运行查询。当你向Redshift提交查询时,领导节点会解析查询、制定执行计划并生成一系列必要步骤。然后,它编译执行任务所需的代码,并将其分发给计算节点执行。
每个切片并行处理其分配的数据部分。
一旦计算节点完成工作,它会将结果发送回领导节点,领导节点随后将结果聚合成最终的结果集。
这种并行方法确保了查询的快速执行。
然而,你的查询性能也可能取决于集群中的节点数量或节点类型。
表设计的关键因素 📊
现在,尽管有上述内置因素,但为了优化效率和性能,你不能仅仅依赖它们。
与表设计相关的多个关键因素需要考虑。当你创建表时,可以选择性地定义排序键和分布样式,这将极大地影响整体查询性能。
所以,让我们首先深入探讨分布样式的细节。
在我们讨论MPP如何在Redshift中工作时,我已经提到过这一点。数据在计算节点之间划分,而划分的方式是通过为表定义分布样式来控制的。

定义合适的分布样式有两个主要目标。
第一个目标是实现数据在节点间的均匀分布。
不均匀的分布(也称为数据分布倾斜)可能导致某些节点比其他节点做更多的工作。由于你的查询需要等待一个节点处理大量数据,这会导致性能瓶颈。像这样数据分布不均匀意味着你无法充分利用Redshift提供的大规模并行处理能力。
第二个目标是尽量减少节点间的数据移动。
如果在节点上运行的查询涉及连接表或聚合分布在多个其他计算节点上的数据,那么部分数据可能需要通过网络在节点之间重新分布。这种跨节点的数据移动会导致网络流量增加,进而可能减慢查询性能并增加查询成本。为了最小化这种情况,仔细为你的表选择分布样式非常重要。
节点间合理的数据分布确保相关数据位于同一节点上,减少了这种跨节点通信的需求。这种优化有助于平衡工作负载,并通过尽可能将处理本地化到每个计算节点来提高查询效率。
分布样式详解 🎯
因此,当你创建表时,可以从以下分布样式中选择:AUTO、EVEN、KEY 或 ALL。
KEY 样式允许你选择一个特定的列,然后使用该列的值在节点间分布数据行。领导节点会将具有相同键值的行分布到同一个节点。你可能想为你创建的每个表都定义一个特定的键,但这需要对数据进行彻底的分析,并且你可能无法确切知道哪个列最合适。在这种情况下,你可能希望使用 AUTO,这将让Redshift根据表数据的大小分配一个最佳的分布样式。如果你不提供分布样式的值,它将默认为 AUTO。
或者,你可以使用 EVEN 分布样式。Redshift会让领导节点使用轮询方式在节点间分布数据行,而不考虑任何特定列中的值。当表的数据集不太需要运行连接操作时,均匀分布是最合适的。

此外还有 ALL 选项。使用 ALL 时,整个表的完整副本会被分发到每个节点。当使用 EVEN 或 KEY 时,Redshift将表的一部分行放在每个节点上。但当你使用 ALL 时,Redshift确保该表参与的每次连接中,每一行都是共位的。这对于你经常将较小的表与非常大的表连接的情况很有用。通过在每个节点上拥有小表的完整副本,你消除了连接操作期间跨节点数据混洗的需要。
然而,ALL 分布将存储表数据所需的存储空间乘以集群中的节点数,因此向多个表加载、更新或插入数据所需的时间要长得多。因此,使用 ALL 分布仅适用于相对变化缓慢的表。
排序键的影响 ⚡
现在让我们继续讨论排序键及其如何影响查询性能。
Redshift根据你定义为排序键的内容,以排序顺序将数据存储在磁盘上。当你向Redshift提交查询时,查询优化器使用排序顺序来确定最优的查询计划。
你为表选择的排序键会影响查询性能,因为它决定了数据在磁盘上的物理组织方式。当你的查询基于排序键过滤或连接数据时,Redshift可以更有效地定位相关数据,减少需要从磁盘扫描的数据量。因此,选择合适的排序键可以最小化磁盘读取操作,并加快整体查询执行速度。
例如,如果你经常按订单日期查询销售表,将订单日期定义为排序键允许Redshift高效地仅扫描表中与查询中日期范围匹配的必要部分。
同样,如果你经常按客户ID过滤,将客户ID设置为排序键可以优化这些查询。你可以将其理解为OLTP数据库如何使用索引来加速查询,类似地,像Redshift这样的OLAP数据库使用排序键来加速查询。
以上就是表设计时需要牢记的一些考虑因素。
总结 📝
本节课中,我们一起学*了影响Amazon Redshift查询性能的核心架构因素。我们了解到Redshift通过列式存储、大规模并行处理和数据压缩来实现高效的数据仓库操作。在表设计方面,我们深入探讨了分布样式(KEY、EVEN、ALL、AUTO)的选择策略,以及如何通过定义合适的排序键来优化数据在磁盘上的物理组织,从而显著减少I/O操作并提升查询速度。这些设计决策对于在Redshift上构建高性能、可扩展的数据分析解决方案至关重要。
接下来,Joe将带你进行即将到来的实验,在那里你将比较行式数据库和列式数据库之间的性能差异。我们很快会再见面。
179:比较行存储与列存储的查询性能 🚀

在本节课中,我们将通过一个动手实验,探索基于行的数据库与基于列的数据库在查询性能上的差异。我们将对两种存储类型执行分析查询、更新和删除操作,并比较它们的执行时间。
概述
实验将使用基于特定实体关系图的基准测试数据。该数据同时存储在一个代表行式存储的 PostgreSQL 数据库和一个代表列式存储的 Redshift 数据仓库中。数据内容涉及订单、订单项、客户以及供应商信息。
我们将运行五组分析查询(即TPC-H基准测试),以模拟基本业务场景,评估不同数据库系统处理复杂查询的性能。此外,我们还将完成一个向lineitem表写入50行随机数据的函数,并比较其在两种数据库上的执行时间,随后删除这些行并再次比较删除操作的性能。
实验数据与设置
在开始实验前,你需要首先建立到 Redshift 数据仓库的连接并执行一些查询。你会发现,与数据仓库的交互方式与操作常规数据库非常相似。
以下是实验中将要使用的数据实体关系示意图:

分析查询性能对比
上一节我们介绍了实验的总体设置,本节中我们来看看分析查询的具体性能结果。
我已分别在两种数据库上运行了TPC-H基准测试中的五组分析查询,并得到了以下结果。在标准的基准测试中,理想情况下应多次运行查询以获取平均结果,但本次演示为了节省时间和成本只运行了一次。在实验中,你只需要运行第一组查询,其余查询为可选。
以下是查询执行时间的对比结果:


关键发现:
- 在行式数据库上,所有分析查询都需要数分钟才能完成。
- 在列式数据库上,所有分析查询仅需毫秒或数秒即可完成。
结论: 在列式数据库上执行分析查询的速度远快于在行式数据库上执行。
写入与删除操作性能对比
分析完查询性能后,我们接下来比较两种数据库在数据写入和删除操作上的表现。
以下是向lineitem表写入50行随机数据并随后删除这些行的操作时间对比:



关键发现:
- 在行式数据库中写入和删除50行数据的速度,比在列式数据库中执行相同操作要快得多。
结论: 对于写入和删除这类操作,行式数据库的性能优于列式数据库。
总结
本节课中我们一起学*了行式存储与列式存储的核心性能差异。通过实验我们明确:
-
列式数据库在分析查询(如大规模数据扫描、聚合)上具有显著性能优势,其执行时间通常以毫秒或秒计。
- 核心概念:列存储将同一列的数据连续存放,利于压缩和批量读取分析所需的特定列。
- 适用场景:数据仓库、商业智能、复杂分析。
-
行式数据库在联机事务处理(如单行插入、更新、删除)上表现更佳。
- 核心概念:行存储将同一行的所有数据连续存放,便于快速读取和修改整行记录。
- 适用场景:高并发的业务系统、订单处理、用户账户管理。

现在,你可以亲自尝试实验,在 PostgreSQL 和 Redshift 数据库上运行这些测试。完成后,请继续学*下一课,我们将探讨处理复杂查询的更多策略。
180:额外的查询策略 🚀


概述
在本节课中,我们将要学*几种提升查询性能的策略。除了了解查询在后台的处理机制,掌握处理复杂查询的策略(如查询缓存和公共表表达式)以及其他数据库维护技术(如清理),都能帮助你优化查询效率。
查询缓存策略
上一节我们介绍了查询的基本处理过程。本节中我们来看看如何避免重复执行高成本查询。
假设你正在使用之前课程中见过的DVD租赁数据库,并希望计算三个电影类别(家庭、剧情和喜剧)的总消费金额。你可以从选择支付表中的支付金额总和开始。
为了从类别表中获取电影类别名称,你需要进行多次连接操作。
以下是实现此查询所需的连接步骤:
- 基于租赁ID,将支付表与租赁表连接。
- 基于库存ID,将上一步结果与库存表连接。
- 基于电影ID,将上一步结果与电影表连接。
- 再次基于电影ID,将上一步结果与电影类别表连接。
- 最后,基于类别ID,将上一步结果与类别表连接。
完成所有这些连接后,你就能选择类别名称。由于你只关心家庭、剧情和喜剧类别,你需要使用WHERE子句过滤结果。然后,按类别名称对结果进行分组,以便计算每个电影类别的聚合总消费。你还可以按金额对结果排序,将总消费从低到高排列。

在包含此数据的大型数据库上频繁运行此查询成本可能非常高。为了避免重复运行相同查询并在许多数据库(尤其是云数据库)上产生高昂费用,你可以利用查询缓存。

大多数应用数据库允许你缓存查询结果,以便后续即时检索。通过利用查询缓存,你可以减轻数据库负载,并提升频繁执行查询的用户体验。
使用公共表表达式提升可读性
除了缓存,编写复杂查询时,另一个建议是优先考虑可读性。就像编写任何代码一样,可读性高的查询更不容易出错,调试更简单,协作也更容易。
你可以通过使用公共表表达式来提升查询的可读性。CTE用于创建一个临时结果集,你可以在查询的其他地方引用它。这是你在本周第一个实验中练*过的概念。
例如,假设你想获取出演电影《Rocky War》的演员姓名。你可以创建一个名为 selected_film 的CTE,从电影表中选择电影标题为“Rocky War”的电影ID。

然后,你可以创建另一个名为 film_actors_id 的CTE,从电影演员表中选择演员ID,条件是电影ID等于从 selected_film CTE中获取的ID。

最后,你可以编写一个主查询,从演员表中选择名字和姓氏,条件是演员ID来自 film_actors_id CTE。
与编写许多嵌套子查询相比,CTE可以帮助你以更易读的方式构建复杂查询,从而更容易理解查询的逻辑流程。
数据库维护:清理操作
在优化查询本身的同时,你还需要优化数据库管理系统资源的使用,以尽可能高效快速地执行查询。
某些数据库的设计允许在数据更新时并发访问数据。当你在这些数据库中删除或更新记录时,它们会创建新记录,同时在物理磁盘上保留过时的数据作为指向数据库最后状态的指针。这也有助于在发生故障时将事务回滚到之前的状态。

然而,随着这些过时的记录不断累积且不再需要被引用,它们可能导致表膨胀。这就是数据库在物理磁盘上占用的空间远超实际数据大小的情况。
除了浪费磁盘空间,数据库还必须跳过许多数据块来检索所需数据,从而拖慢查询速度。由于查询优化器依赖于磁盘上数据的内部统计信息来生成查询执行计划,过时的记录也可能导致生成次优或不准确的计划。
同样,索引也可能因累积了过时数据的条目而变得低效。因此,为了为新记录释放空间并实现更好的查询和索引性能,你应该使用一个称为“清理”的过程来移除这些死记录。
你可以清理单个表、多个表或数据库中的所有表。清理对于Postgres和MySQL等关系型数据库更为关键,因为大量的事务操作会导致死记录的快速累积。当你在这些系统中工作时,需要熟悉清理的细节和影响。

总结
本节课中我们一起学*了多种优化查询性能的策略。你现在掌握了更多策略来优化查询性能。



我们在批处理数据查询方面涵盖了很多内容。下一课我们将探讨流式数据的查询。
181:流数据查询 📊

概述
在本节课中,我们将要学*如何查询流数据。我们将探讨流数据处理的核心概念,特别是如何通过“窗口查询”来聚合和分析实时到达的数据流。课程将介绍三种常见的窗口类型,并解释如何连接多个数据流或流数据与批处理历史数据。
之前我们讨论了如何查询批处理数据。随着流数据变得越来越普遍,在查询流数据时,您可能也需要对数据进行聚合和连接操作。您必须采用能反映数据实时特性的查询模式。
假设您希望从流系统中摄取数据,并在收到数据后立即处理数据流。您可以使用诸如 Apache Flink 和 Spark Streaming 这样的流处理系统。这些系统使您能够对数据流持续应用 SQL 查询,甚至是复杂的查询。
像 Kafka 这样的流平台也支持查询 Kafka 流中的数据。使用这些系统,您可以通过应用一种称为“窗口查询”的技术来持续聚合流数据。窗口查询允许您使用一个窗口来限定查询范围,然后在该窗口上应用诸如聚合、添加或删除数据等操作。

让我们来看看三种常见的窗口类型。
以下是三种主要的窗口类型:
- 会话窗口:适用于处理不规则时间到达的事件。
- 固定时间窗口:也称为滚动窗口。
- 滑动窗口:允许窗口重叠。
会话窗口
会话窗口非常适合处理不规则时间到达的事件。它将相似时间发生的事件分组,并过滤掉没有事件的时段。使用这种窗口时,您需要指定事件之间允许的最大时间间隔,以确定一个会话何时结束、另一个会话何时开始。
例如,假设我们正在分析每个用户的网站点击行为,并决定将用户不活动的时间间隔设置为五分钟或更长时间来划分会话窗口。那么,这里将会有三个会话窗口,因为它们各自被五分钟或更长的用户不活动时间隔开。
请注意,会话窗口对每个键(例如用户ID)是唯一的。因此在本例中,每个用户都有自己的一套会话窗口。对这些窗口进行分析,例如,可以让分析师采取后续行动,比如向用户发送一封包含优惠券的电子邮件,该优惠券针对用户在上一个会话窗口中浏览过的产品。
为了确定会话边界,处理系统在第一个事件发生时(本例中是用户的第一次网站点击)启动一个新的会话窗口。然后,只要新事件在前一个事件的五分钟内到达,系统就会继续为该用户累积到达的事件。一旦出现五分钟的不活动期,系统就会关闭窗口,将任何指定的聚合结果(如最大值、最小值或平均值)发送给消费者,然后刷新数据。如果之后该用户没有事件到达,系统将启动一个新的会话窗口。
因此,对于会话窗口,只要事件持续紧密地到达,窗口可以扩展到任意大小。
固定时间窗口
或者,您可以在固定大小的窗口上聚合事件数据,这被称为固定时间窗口或滚动窗口。
例如,这里有三个固定时间窗口,每个持续20秒。系统处理每个窗口内到达的所有数据,然后在窗口关闭后立即发送聚合结果。如果您想计算例如每20秒内发生的点击总数,这会很有用。这类似于传统的批处理ETL处理,您可能每天或每小时运行一次数据更新作业。然而,流处理系统允许您更频繁地生成窗口,并以更低的延迟交付结果。
滑动窗口
在会话窗口和固定时间窗口中,窗口是不重叠的。但对于滑动窗口,您可以在固定时间长度的窗口中分组事件,并且这些窗口可以重叠。
例如,这里有三个60秒的重叠窗口,每30秒生成一个。这种类型的窗口化可以帮助您计算诸如时间间隔内的移动平均值等数据。
连接数据流
除了聚合数据流,您还可以连接多个数据流,或将一个数据流与批处理历史数据相结合。
连接多个数据流的传统方法是将每个流转换为一个表,然后在数据库中对这些表进行连接。但流处理系统正越来越多地支持直接的流到流连接。

例如,您可能希望将网络浏览数据流与来自广告平台的流数据连接起来。由于这些流可能以不同的事件速率产生并具有不同的延迟,典型的流连接架构依赖于流缓冲区,这些缓冲区可以在一定时间内保留这些事件。来自各个流的事件在缓冲区中被连接,并在缓冲区的保留期过后最终被发出。
除了连接两个数据流,您可能还希望将流数据与存储在数据库或对象存储中的批处理历史数据连接起来,以产生一个经过丰富的事件流。
例如,您可能希望用产品详情和用户人口统计信息来丰富来自电子商务网站的产品浏览事件。为此,您可以使用无服务器函数或处理系统在内存数据库或对象存储中查找产品和用户信息,然后将所需信息添加到事件中,最后将增强后的事件输出到另一个流。
在本周最后一个实验中,您将处理在课程1中见过的流数据。但现在,您将应用基于时间的窗口查询来处理这些数据。在下一个视频中,Morgan 将概述我们将用来完成此任务的 Amazon 托管服务 Apache Flink。现在,我将带您了解接下来的实验。

总结
本节课中,我们一起学*了流数据查询的核心概念。我们了解到,处理实时数据流需要使用特殊的窗口查询模式,包括会话窗口、固定时间窗口和滑动窗口。我们还探讨了如何连接多个流数据或将流数据与历史批处理数据相结合,以生成更丰富、更有价值的数据流,为实时分析和决策提供支持。
182:使用Amazon托管服务部署Apache Flink应用 🚀

概述
在本节课中,我们将学*如何在AWS上使用Amazon Managed Service for Apache Flink来部署和管理Apache Flink流处理应用。我们将了解托管服务的优势,并通过一个实际演示,学*如何创建一个处理实时股票数据的Flink应用,以及如何通过Studio Notebook进行交互式数据探索。
1. Apache Flink在AWS上的部署选项
上一节我们介绍了Apache Flink用于查询流数据。本节中我们来看看在AWS上运行Apache Flink时可选择的几种方式。
在AWS上运行Apache Flink时,您有多种选择。
- 您可以在Amazon EMR上作为YARN应用程序运行Apache Flink。
- 您可以使用Amazon Elastic Kubernetes Service或Amazon Elastic Container Service在容器化环境中自行托管Apache Flink。
这些可以称为“自己动手”选项。但您也可以选择使用托管服务,例如Amazon Managed Service for Apache Flink,这正是我接下来要介绍的内容。

2. 认识Amazon Managed Service for Apache Flink
Amazon Managed Service for Apache Flink在AWS上运行Apache Flink。它为您的Apache Flink应用程序提供底层基础设施,并创建一个托管的无服务器环境供其运行。
它为您处理了许多繁重的工作,包括:
- 供应和配置计算资源
- 为弹性设置和管理Zookeeper故障转移
- 自动扩展
- 应用程序备份
为了让大家了解其工作原理,我将通过一个演示来介绍如何设置Amazon Managed Service for Apache Flink,并在此过程中讲解一些核心概念。
3. 演示:创建流处理应用程序

现在,我位于AWS管理控制台。我将在搜索栏中输入“Flink”,然后选择“Amazon Managed Service for Apache Flink”。


Amazon Managed Service for Apache Flink为您创建托管环境以运行Apache Flink应用程序,但您需要像其他编程项目一样,在本地使用Apache Flink框架编写应用程序。
在“开始使用”下,我可以选择创建应用程序或选择Studio Notebook。
以下是两种模式的主要区别:
创建应用程序:如果您希望托管Apache Flink应用程序并在生产环境中运行它,则应选择此选项。这涉及定义必要的资源、配置应用程序设置并部署您的Flink作业。AWS随后会处理底层基础设施、扩展和运维方面的工作,让您可以专注于应用程序逻辑。
Studio Notebook:非常适合开发和交互式数据探索。它提供了一个基于浏览器的界面(由Apache Zeppelin提供支持),该界面与Apache Flink集成,允许您使用标准SQL、Python和Scala运行流处理应用程序。使用这种交互式方法,您可以试验Flink代码、测试不同场景并快速交互式地可视化结果。这在开发阶段或进行临时数据分析任务时特别有用。
在本演示的第一部分,我将创建一个流处理应用程序。稍后,我将创建一个Studio Notebook。
在下一页,您需要选择是从头开始还是从蓝图开始。我将选择一个蓝图,该蓝图将使用AWS CloudFormation创建您入门所需的所有资源。
它将设置一个Amazon Kinesis Data Stream作为我们要分析的源,然后设置将演示数据发送到流中所需的资源,并部署一个将从流中读取数据、处理数据,然后将处理后的数据发送到Amazon S3进行存储的应用程序。


我将选择“在CloudFormation中部署蓝图”。CloudFormation现在将部署必要的资源。这需要几分钟才能完成,因此我们将在完成后返回。
4. 演示应用解析
现在,CloudFormation模板已完成部署,我们的演示应用程序正在运行。
这个演示应用程序通过Kinesis数据流发送股票代码价格的样本数据,模拟实时传入的股票市场数据,然后部署一个Flink应用程序,该程序执行简单的数据转换,然后将数据写入S3。
该蓝图提供了一个指向GitHub仓库的链接,您可以在其中探索要部署的Apache Flink应用程序。这个应用程序是用Java编写的。
以下是应用程序核心逻辑的说明:
// 此方法设置了从Kinesis读取数据的源,并运行转换逻辑
public void runAppWithKinesisSource() {
// 设置源为Amazon Kinesis Data Streams
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
DataStream<String> sourceStream = env.addSource(new FlinkKinesisConsumer<>(...));
// 转换逻辑:过滤价格低于1美元的股票
DataStream<String> filteredStream = sourceStream
.flatMap(new StockPriceParser())
.filter(stock -> stock.getPrice() >= 1.0);
// 将过滤后的数据写入S3
filteredStream.addSink(new FlinkS3Writer(...));
env.execute("Kinesis to S3 Streaming Job");
}
这段代码从Amazon Kinesis流中将股票数据读入Flink数据流,过滤数据以仅保留价格在1美元或以上的股票,然后将过滤后的数据写入S3文件。
5. 监控Flink作业
了解了应用程序的功能后,让我们回到AWS控制台,选择“打开Apache Flink仪表板”按钮。
这将打开Apache Flink仪表板,其中有一个作业正在运行。如果在导航中选择“Running Jobs”,会看到一个名为“KinesisDataStreamsToS3FlinkStreamingApp”的蓝图作业。
点击它以查看更多详情,我们可以看到为此作业定义的算子图。我们正在从流中读取股票数据,使用一个flatMap算子来过滤掉价格低于1美元的股票,然后将过滤后的数据写入S3文件。

该图直观地表示了数据通过这些算子的流动,使得更容易理解处理步骤以及数据如何被转换和存储。
如果我选择这里的这个算子,您可以看到已经处理了10,000条记录。

6. 总结与下节预告
本节课中我们一起学*了如何使用Amazon Managed Service for Apache Flink部署一个数据处理和分析作业,该作业从Amazon Kinesis Data Streams拉取数据。
正如我之前提到的,在AWS上使用Flink的另一种方式是通过Studio Notebook,这对于数据探索或临时分析非常有用。这就是我接下来想向大家展示的内容。
请继续观看下一个视频,学*如何使用Amazon Managed Service for Apache Flink部署一个Studio Notebook。
183:使用Amazon托管服务部署Apache Flink Studio笔记本 🚀

概述
在本节课中,我们将学*如何使用Amazon Managed Service for Apache Flink来部署一个Studio Notebook。我们将了解Flink如何通过连接器与不同系统交互,并实际操作一个基于Zeppelin的交互式笔记本,用于实时处理来自MSK主题的股票行情数据。
上一节我们介绍了如何将Flink应用程序部署到Amazon Kinesis数据流。本节中,我们来看看如何使用Studio Notebook进行类似的部署。
首先,我们需要了解Flink在幕后是如何工作的。Flink能够连接到Kinesis数据流并将数据写入S3,是通过使用连接器实现的。连接器提供了与各种系统交互的代码,这些系统包括数据库、消息队列和云存储服务。
例如:
- 你可以连接到Amazon DynamoDB来处理NoSQL数据。
- 可以使用Amazon Kafka连接器来处理Apache Kafka主题的流数据。
- Flink连接器还通过JDBC支持关系型数据库,允许与运行在Amazon RDS上的MySQL或PostgreSQL等数据库集成。

这些连接器使Flink能够与不同的数据源和目的地交互,帮助你在不同平台和服务之间构建实时数据处理管道。

现在,让我们使用Amazon Managed Service for Apache Flink创建一个Studio Notebook,以便了解部署笔记本与部署应用程序之间的区别。
在AWS控制台中,我位于Managed Apache Flink仪表板上。这次我将选择“Studio notebook”,然后点击“创建”。
我将再次使用一个蓝图。这个蓝图会将演示数据发送到Managed Streaming for Apache Kafka(MSK)主题,然后由Managed Apache Flink读取。我们将使用Studio Notebook与这些数据进行交互。
部署蓝图后,当部署完成时,演示笔记本就可以供我们与MSK主题进行交互了。
这个演示将股票行情价格的演示数据发送到MSK主题,我们可以使用Flink实时与这些数据交互。
要打开笔记本,我可以选择“在Apache Zeppelin中打开”。这是一个基于浏览器的笔记本,支持协作式交互式数据分析。Zeppelin支持用SQL、Python和Scala等语言编写代码,你可以用表格和图表等不同格式可视化数据,还可以与Flink等工具和框架集成。这是数据科学家、分析师和工程师用来协作开发和分享数据见解的流行工具。
这就是由蓝图创建的Zeppelin笔记本。
在Zeppelin笔记本中,你使用段落来定义工作单元。
每个段落可以执行诸如运行代码、显示文本或执行数据可视化等操作,并且它们可以独立执行。这允许你将数据分析或数据处理任务分解为更易于管理的步骤,从而更轻松地开发、测试和调试工作流。
你可以在这些段落中使用不同的解释器来执行操作,例如运行SQL查询、执行Python脚本或与Apache Flink和Spark等大数据框架交互。
以下是笔记本中的关键段落及其功能:
-
第一个段落创建了一个用于生成股票行情数据的用户自定义函数。
- 第一行
%flink指定代码将使用Flink解释器执行。 - 随后的代码定义并注册了一个名为
random_ticker_udf的自定义Flink函数。该函数从一个预定义的列表中返回一个随机的股票代码符号,并为该行情价格提供一个随机值。然后,此函数可以在Flink SQL查询中用于生成随机的行情数据。
- 第一行
-
第二个段落使用MSK主题的连接器定义了一个源表。
- 还有一个查询对该表执行
SELECT *并显示结果。我们也可以将此显示更改为其他类型的可视化,如折线图或条形图。
- 还有一个查询对该表执行
-
最后一个段落允许你通过运行之前定义的函数,再次运行初始数据生成。
- 这是为了让你可以执行基于时间窗口的查询。因为如果数据生成已经发生,并且当前没有数据流经流,你将得到空结果。所以你可以运行此段落来再次生成样本数据,以测试基于时间的查询。你将在接下来的实验课中看到使用基于窗口查询的示例。
在幕后,系统使用AWS Glue数据库来存储有关脚本正在使用的数据源和目的地的信息。
我们使用了蓝图,因此该数据库的创建和连接信息是由CloudFormation模板设置的。然而,在实际操作中,当你创建自己的Studio Notebook时,你需要指定包含数据源和目的地连接信息的AWS Glue数据库。
然后,当你想访问数据源和目的地时,你需要指定该数据库中包含的相关Glue表。这些表提供了对Glue连接的访问,这些连接定义了数据源和目的地的位置、模式和参数。
以上就是我们对Amazon Managed Service for Apache Flink的快速介绍。

接下来,你将在实验课中充分运用所有这些知识。一如既往,祝你学*愉快,我们稍后见。
184:数据存储与查询 🗄️

在本节课中,我们将对数据工程专项课程的第三部分——“数据存储与查询”进行总结。我们将回顾本课程涵盖的核心内容,包括存储层次结构、存储系统的演进以及查询处理的生命周期。
恭喜你完成数据工程专项课程的第三部分。这意味着我们已经完成了三门课程,只剩最后一门。本课程我们深入探讨了数据工程生命周期中最复杂的阶段——数据存储,大家做得非常出色。
在第一周,我们探讨了存储层次结构中的前两层:原始存储组件以及由这些组件构建的存储系统。在实验环节,你比较了文件、块和对象云存储选项,并有机会实践了图数据库的操作。
以下是第一周的核心要点:
- 原始存储组件:如硬盘、SSD等物理或逻辑存储单元。
- 存储系统:基于原始组件构建的系统,例如文件系统、数据库。
- 云存储比较:文件存储(如NFS)、块存储(如AWS EBS)和对象存储(如AWS S3)的适用场景与差异。
- 图数据库实践:用于处理高度连接关系的数据,其核心查询语言通常是
Cypher或Gremlin。

上一节我们介绍了基础的存储组件与系统,在第二周,我们着眼于存储抽象概念的演进:从数据仓库到数据湖,最终到湖仓一体。你为数据湖设置了分区和数据目录,并获得了使用AWS Lake Formation和Apache Iceberg创建湖仓一体的实践经验。
以下是第二周的核心要点:
- 数据仓库:为结构化数据分析而优化的集中式存储库,通常采用星型或雪花型
Schema。 - 数据湖:存储原始、各种格式(结构化、半结构化、非结构化)数据的存储系统。
- 湖仓一体:结合数据湖的灵活性与数据仓库的管理和性能优势的新型架构。
- 实践内容:在数据湖上配置
PARTITION BY,使用AWS Glue建立数据目录,并利用Apache Iceberg表格式构建湖仓一体。
在了解了数据存储的形态之后,第三周我们深入探讨了查询的生命周期细节,包括筛选、连接和聚合查询在后台是如何被处理的。你通过高级SQL语句获得了实践经验,比较了在行式存储与列式存储上执行分析查询的时间,最后使用Amazon Managed Service for Apache Flink对流数据执行了基于时间窗口的查询。
以下是第三周的核心要点:
- 查询生命周期:从解析SQL语句到生成执行计划,再到从存储中读取和处理数据的过程。
- 行式 vs 列式存储:行式存储(如MySQL)适合事务处理,列式存储(如Amazon Redshift)适合分析查询,因其查询公式可表示为
SELECT column_a, column_b FROM table WHERE condition,仅需读取特定列。 - 流处理窗口查询:使用Apache Flink对无界数据流进行聚合,例如计算每分钟的销售额:
SELECT TUMBLE_START(rowtime, INTERVAL '1' MINUTE), SUM(amount) FROM orders GROUP BY TUMBLE(rowtime, INTERVAL '1' MINUTE)。
到目前为止,通过完成三门课程,你已经掌握了成为一名成功的数据工程师所需的许多核心技能。在最后一门课程中,我们将重点学*如何为分析和机器学*用例建模并提供数据。我们下一门课再见。


本节课总结:
本节课我们一起回顾了“数据存储与查询”课程的核心内容。我们从存储的基础组件和系统学起,探索了从数据仓库到湖仓一体的架构演进,最后深入了解了查询处理的内部机制及不同存储格式对性能的影响。这些知识构成了构建高效、可靠数据平台的基石。

浙公网安备 33010602011771号