当我们在数据湖上进行批量摄取用例时,我们主要处理文件的更新。在设计基于云的原生数据平台和利用现有框架时,人们总是关心如何减少实施基于文件的框架和通知机制的繁重工作。如果在云端原生存储--S3、ADLS和基于PaaS的数据服务--Databricks之间进行原生整合,提供完整的解决方案,那么为文件生命周期实施自己的自定义框架就是 "重新发明轮子",失败的风险很大。
我遇到了一个类似的决策过程,看到基于文件的摄入被简化了。通过Databricks Autoloader,分析delta湖层在传入的数据更新中保持热度。Autoloader在Azure ADLS、AWS S3和Spark、Azure上的Delta湖格式以及AWS平台之间有完美的整合,并有一个基于文件的原生云通知机制。
原生云支持
Autoloader使用云存储文件上传通知,使用订阅。Autoloader使用Spark结构流框架来为新上传的blob文件创建流。
下面的代码将订阅文件/blob上传的通知,Spark数据框将被更新为新的blob文件数据。当我们将选项 "cloudFiles.useNotifications "设为 "True "时,Azure存储队列和AWS SQS的通知将被即时创建。
Azure存储队列是在飞行中创建的,其前缀为 - data bricks-query-*source。为每个 "source_path "创建一个存储队列,以Delta Lake表为目标进行同步。这种方法比使用系统队列的存储账户更好,因为多源路径数据可以与Delta Lake表同步。当源路径可以独立更新时,这种方法避免了通知信息的冲突。
options = { "cloudFiles.subscriptionId" : 'XXXXXX',
"cloudFiles.format": "json",
"cloudFiles.tenantId" : 'XXXXX',
"cloudFiles.clientId" : 'XXXXX',
"cloudFiles.clientSecret" : 'X',
"cloudFiles.resourceGroup" : 'RG',
"cloudFiles.useNotifications": "True"}
schemaConf ={
"cloudFiles.inferColumnTypes": "True",
"cloudFiles.schemaEvolutionMode": "addNewColumns",
"cloudFiles.schemaLocation": "/path"}
df = (spark.readStream.format('cloudFiles') \
.options(**options) \
.options(**schemaConf) \
.load(source_path))
流上的数据转换
可以将数据转换应用于blob文件源,以应用于掩码和加密。这将确保敏感数据字段在Delta lake表中被屏蔽或加密,而不是以纯文本形式暴露。UDF可以将纯文本数据字段转化为屏蔽、加密的数据字段,同时在数据框架中丢弃敏感数据字段。
df.withColumn("masked_*", udf_mask(df.sensitive_col))
传入的流数据可以用主数据来充实,或进行汇总,以提供快速刷新的关键绩效指标。转换后的数据可以被写入Delta湖表或存储路径。合并查询可以保持Delta表对现有记录的更新,或者为新的业务键插入新到的记录。这个功能对缓慢变化的主数据很有帮助。一旦合并,由于Delta表符合ACID标准,更新的数据很快就可以被读取。自动加载器可以通过触发选项--"一次 "为 "真"--每天启动几次进行批量更新,也可以是连续运行的流式应用。批量选项更适合于文件源的更新,并且可以节省运行火花笔记本的成本。
def merge(df, batch_id):
merge_condition = " AND ".join([f"existing.{col} = updates.{col}" for col in key_columns])
if (DeltaTable.isDeltaTable(spark, delta_lake_path)):
delta_table = DeltaTable.forPath(spark, delta_lake_path)
delta_table.alias("existing").merge(source=df.alias("updates"), \
condition= merge_condition).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute()
else:
df.write.format('delta').save(delta_lake_path)
query = df.writeStream.foreachBatch(merge).trigger(once = True) \
.option("checkpointLocation", checkpoint_path) \
.start()
三角湖表
Databricks为每个Delta表维护更新、合并和插入方面的历史。Delta表的数据可以根据用例使用标准的、流行的ANSI SQL对Spark SQL进行进一步的转换。
用例适用性
对Delta湖表的基于自动加载器文件的批处理或流式更新,可用于丰富传入的连续流式数据。这将确保主数据的变化被流处理所吸收,并将更好地处理迟来的主数据问题。Autoloader和spark结构化流处理流和文件数据集都是流,减少了对更复杂的Lambda架构的需求。
建议和限制
- Autoloader也可以作为Azure Synapse Analytics的目标,但以Synapse为目标时,无法进行合并查询。
- Autoloader支持Databricks Delta Live tables[DLT],以SQL和Python语法从CSV和parquet数据集创建Delta表。
- Databricks Autoloader最适合于从ADLS或S3加载文件。Autoloader选择了文件通知方式,而不是目录列表方式,从而减少了轮询存储目录中的变化所需的API调用。
- 使用Autoloader,源存储路径中的文件将保持原样,不会被移到存档路径中。这将确保从源头到达的文件保持原样,并在出现任何问题时可进行验证,并减少验证多个目录路径的复杂性。
- 源路径中的文件可以被删除,而Autoloader不会抱怨这个设置。
- 内建和成熟的框架减少了失败的风险。不需要创建一个新的基于文件的框架来跟踪已处理和未处理的文件。这将降低开发成本,帮助数据工程师专注于构建业务逻辑。
- 自动加载器可以与Azure Data Factory[ADF]或Stitch Data[Stitch]、Qlik和Streamsets结合使用,它们都有针对各种数据源的内置连接器。通过利用数据摄取工具,可以将数据以文件的形式摄取到ADLS或S3。
- 自动加载器承诺保证数据摄入一次,因此可以使开发人员的生活更轻松,确保没有重复的记录被插入。
- 最适合于以Delta Lake为中心的数据湖。
- Autoloader使用RocksDB来跟踪框架处理的文件。这种依赖性是由Autoloader内部管理的。
- 虽然RocksDB被用来跟踪文件,但不可能通过可编程的API查询RocksDB以获得所有文件的列表。所有对RocksDB的操作都是在内部完成的,没有暴露给终端用户。为开发者开放读取操作可能会有帮助。
- Autoloader适用于S3和ADLS存储以及Azure和AWS上托管的Databricks。
自动加载器使数据的内部移动变得容易,就像短距离的搬运工--工业楼层的叉式升降机。自动加载器可以使叉式升降机的工作成为孩子们的游戏,因为数据工程师不会太担心数据平台内的数据移动。这是一个比喻,意在传达框架的简单性和实用性,作为获取数据进一步处理的必须行动。云原生服务的力量被有效地用于提供端到端的数据解决方案,包括基于云的、托管的数据摄取工具、自动加载器、三角洲湖和基于云的DWH;基于云的BI工具。