在Databricks中使用SAS令牌读取并连接两个数据集时遇认证错误
解决Databricks中多SAS令牌读取数据湖后Join的认证错误
问题原因
你的推测完全正确:Spark采用懒执行机制,DataFrame的read操作仅定义读取逻辑,实际数据加载会延迟到show()、join()等触发计算的操作时执行。读取第二个数据集时覆盖了会话级的SAS令牌配置,执行join时Spark需重新访问第一个数据集的源路径,但此时会话生效的是第二个SAS令牌,导致第一个路径认证失败。
解决方案
方案1:缓存第一个数据集(最简单)
读取第一个DataFrame后立即缓存并触发计算,将数据加载到内存中,后续Join操作无需再访问源数据路径,也就不会用到被覆盖的SAS令牌。
修改后的代码:
import json from pyspark.sql import SparkSession spark_session = SparkSession.builder.appName("test-app").getOrCreate() datalake_name = "MY_STORAGE_ACCOUNT" container_name = "MY_CONTAINER_NAME" ################# Common Configs ########################### spark_session.conf.set(f"fs.azure.account.auth.type.{datalake_name}.dfs.core.windows.net", "SAS") spark_session.conf.set(f"fs.azure.sas.token.provider.type.{datalake_name}.dfs.core.windows.net", "org.apache.hadoop.fs.azurebfs.sas.FixedSASTokenProvider") ################ Dataframe 1 Read ############################## spark_session.conf.set(f"fs.azure.sas.fixed.token.{datalake_name}.dfs.core.windows.net", "FIRST SAS TOKEN") target_file_path = f"abfss://{container_name}@{datalake_name}.dfs.core.windows.net/folder_1/test_data" df1 = spark_session.read.format("parquet").load(target_file_path) # 缓存并触发计算,确保数据加载到内存 df1.cache() df1.show() ################# Dataframe 2 Read ############################### spark_session.conf.set(f"fs.azure.sas.fixed.token.{datalake_name}.dfs.core.windows.net", "SECOND SAS TOKEN") target_file_path = f"abfss://{container_name}@{datalake_name}.dfs.core.windows.net/folder_2/test_data" df2 = spark_session.read.format("parquet").load(target_file_path) df2.show() # 此时Join使用缓存的df1数据,无需访问源路径 df3 = df2.join(df1) df3.show()
方案2:按路径配置SAS令牌(更规范)
避免使用全局会话级的SAS令牌配置,针对具体文件夹路径单独设置SAS令牌,不同路径的认证参数不会互相覆盖。
修改后的代码:
import json from pyspark.sql import SparkSession spark_session = SparkSession.builder.appName("test-app").getOrCreate() datalake_name = "MY_STORAGE_ACCOUNT" container_name = "MY_CONTAINER_NAME" ################# Common Configs ########################### spark_session.conf.set(f"fs.azure.account.auth.type.{datalake_name}.dfs.core.windows.net", "SAS") spark_session.conf.set(f"fs.azure.sas.token.provider.type.{datalake_name}.dfs.core.windows.net", "org.apache.hadoop.fs.azurebfs.sas.FixedSASTokenProvider") # 为不同文件夹单独配置SAS令牌 spark_session.conf.set(f"fs.azure.sas.{container_name}.{datalake_name}.dfs.core.windows.net/folder_1", "FIRST SAS TOKEN") spark_session.conf.set(f"fs.azure.sas.{container_name}.{datalake_name}.dfs.core.windows.net/folder_2", "SECOND SAS TOKEN") ################ Dataframe 1 Read ############################## target_file_path = f"abfss://{container_name}@{datalake_name}.dfs.core.windows.net/folder_1/test_data" df1 = spark_session.read.format("parquet").load(target_file_path) df1.show() ################# Dataframe 2 Read ############################### target_file_path = f"abfss://{container_name}@{datalake_name}.dfs.core.windows.net/folder_2/test_data" df2 = spark_session.read.format("parquet").load(target_file_path) df2.show() df3 = df2.join(df1) df3.show()
方案3:在路径中直接拼接SAS令牌
将SAS令牌直接附加到ABFSS路径末尾,无需配置会话级参数,每个路径独立认证。
修改后的代码:
import json from pyspark.sql import SparkSession spark_session = SparkSession.builder.appName("test-app").getOrCreate() datalake_name = "MY_STORAGE_ACCOUNT" container_name = "MY_CONTAINER_NAME" ################ Dataframe 1 Read ############################## first_sas_token = "FIRST SAS TOKEN" target_file_path = f"abfss://{container_name}@{datalake_name}.dfs.core.windows.net/folder_1/test_data?{first_sas_token}" df1 = spark_session.read.format("parquet").load(target_file_path) df1.show() ################# Dataframe 2 Read ############################### second_sas_token = "SECOND SAS TOKEN" target_file_path = f"abfss://{container_name}@{datalake_name}.dfs.core.windows.net/folder_2/test_data?{second_sas_token}" df2 = spark_session.read.format("parquet").load(target_file_path) df2.show() df3 = df2.join(df1) df3.show()
说明
- 方案1适合数据量较小的场景,缓存会占用集群内存;
- 方案2是Azure Data Lake Storage推荐的多路径认证方式,管理更清晰;
- 方案3操作简单,但SAS令牌会暴露在路径中,需注意日志和权限控制。
内容的提问来源于stack exchange,提问作者Mayank
相关产品推荐
相关产品推荐

