Hadoop Azure支持:ABFS - Azure Data Lake Storage Gen2

简介

hadoop-azure模块通过"abfs"连接器为Azure Data Lake Storage Gen2存储层提供支持

要将其作为Apache Hadoop默认类路径的一部分,请确保HADOOP_OPTIONAL_TOOLS环境变量列表中包含hadoop-azure在集群中的每台机器上都需要进行此设置

export HADOOP_OPTIONAL_TOOLS=hadoop-azure

你可以在本地的.profile/.bashrc文件中设置此项,但请注意该设置不会传播到集群内运行的作业中。

ABFS连接器的特性

  • 支持读取和写入存储在Azure Blob存储账户中的数据。
  • 完全一致的存储视图,适用于所有客户端。
  • 可以读取通过wasb:连接器写入的数据。
  • 通过实现标准的Hadoop FileSystem接口,呈现分层文件系统视图。
  • 支持配置多个Azure Blob存储账户。
  • 可以作为Hadoop MapReduce、Apache Hive、Apache Spark中的数据源或数据目的地。
  • 由微软自身在Linux和Windows平台上进行了大规模测试验证。
  • 可作为部署在Azure基础设施上的Hadoop集群中HDFS的替代方案。

有关ABFS的详细信息,请查阅以下文档:

入门指南

概念

Azure 存储数据模型包含3个核心概念:

  • 存储账户: 所有访问都通过存储账户完成。
  • Container: 容器是多个blob的分组。一个存储账户可以包含多个容器。在Hadoop中,整个文件系统层次结构都存储在一个容器中。
  • Blob: 使用现有wasb连接器存储的任何类型和大小的文件

ABFS连接器可连接到经典容器或使用分层命名空间创建的容器。

分层命名空间(及WASB兼容性)

ADLS Gen 2的一个关键特性是支持分层命名空间。这些实际上是目录,并提供高性能的重命名和删除操作——这显著提升了包括MapReduce、Spark、Hive以及DistCp在内的查询引擎写入数据的性能。

此功能仅在容器创建时启用了“命名空间”支持的情况下可用。

在创建新的存储账户时,您可以通过在门户界面勾选"分层命名空间"选项来启用命名空间支持,或者通过命令行创建时使用--hierarchical-namespace true选项来实现。

无法在现有存储账户上启用分层命名空间

具有分层命名空间的存储账户中的容器(目前)无法通过wasb:连接器读取。

一些az storage命令行命令也会失败,例如:

$ az storage container list --account-name abfswales1
Blob API is not yet supported for hierarchical namespace accounts. ErrorCode: BlobApiNotYetSupportedForHierarchicalNamespaceAccounts

创建Azure存储账户

关于使用abfs连接器开始使用Azure Datalake Gen2的最佳文档是Using Azure Data Lake Storage Gen2 with Azure HDInsight clusters

它包含从Azure命令行工具创建它的说明,该工具可安装在Windows、MacOS(通过Homebrew)和Linux(apt或yum)上。

az storage 子命令处理所有存储相关操作,az storage account create 用于创建存储账户。

在ADLS gen2 API支持最终确定之前,您需要向ADLS命令添加一个扩展。

az extension add --name storage-preview

通过验证使用命令是否包含--hierarchical-namespace来确认一切正常:

$  az storage account
usage: az storage account create [-h] [--verbose] [--debug]
     [--output {json,jsonc,table,tsv,yaml,none}]
     [--query JMESPATH] --resource-group
     RESOURCE_GROUP_NAME --name ACCOUNT_NAME
     [--sku {Standard_LRS,Standard_GRS,Standard_RAGRS,Standard_ZRS,Premium_LRS,Premium_ZRS}]
     [--location LOCATION]
     [--kind {Storage,StorageV2,BlobStorage,FileStorage,BlockBlobStorage}]
     [--tags [TAGS [TAGS ...]]]
     [--custom-domain CUSTOM_DOMAIN]
     [--encryption-services {blob,file,table,queue} [{blob,file,table,queue} ...]]
     [--access-tier {Hot,Cool}]
     [--https-only [{true,false}]]
     [--file-aad [{true,false}]]
     [--hierarchical-namespace [{true,false}]]
     [--bypass {None,Logging,Metrics,AzureServices} [{None,Logging,Metrics,AzureServices} ...]]
     [--default-action {Allow,Deny}]
     [--assign-identity]
     [--subscription _SUBSCRIPTION]

你可以通过az account list-locations列出位置信息,该命令会显示在--location参数中需要引用的名称:

$ az account list-locations -o table

DisplayName          Latitude    Longitude    Name
-------------------  ----------  -----------  ------------------
East Asia            22.267      114.188      eastasia
Southeast Asia       1.283       103.833      southeastasia
Central US           41.5908     -93.6208     centralus
East US              37.3719     -79.8164     eastus
East US 2            36.6681     -78.3889     eastus2
West US              37.783      -122.417     westus
North Central US     41.8819     -87.6278     northcentralus
South Central US     29.4167     -98.5        southcentralus
North Europe         53.3478     -6.2597      northeurope
West Europe          52.3667     4.9          westeurope
Japan West           34.6939     135.5022     japanwest
Japan East           35.68       139.77       japaneast
Brazil South         -23.55      -46.633      brazilsouth
Australia East       -33.86      151.2094     australiaeast
Australia Southeast  -37.8136    144.9631     australiasoutheast
South India          12.9822     80.1636      southindia
Central India        18.5822     73.9197      centralindia
West India           19.088      72.868       westindia
Canada Central       43.653      -79.383      canadacentral
Canada East          46.817      -71.217      canadaeast
UK South             50.941      -0.799       uksouth
UK West              53.427      -3.084       ukwest
West Central US      40.890      -110.234     westcentralus
West US 2            47.233      -119.852     westus2
Korea Central        37.5665     126.9780     koreacentral
Korea South          35.1796     129.0756     koreasouth
France Central       46.3772     2.3730       francecentral
France South         43.8345     2.1972       francesouth
Australia Central    -35.3075    149.1244     australiacentral
Australia Central 2  -35.3075    149.1244     australiacentral2

一旦选定位置,创建账户

az storage account create --verbose \
    --name abfswales1 \
    --resource-group devteam2 \
    --kind StorageV2 \
    --hierarchical-namespace true \
    --location ukwest \
    --sku Standard_LRS \
    --https-only true \
    --encryption-services blob \
    --access-tier Hot \
    --tags owner=engineering \
    --assign-identity \
    --output jsonc

该命令的输出是一个JSON文件,其primaryEndpoints命令包含存储端点的名称:

{
  "primaryEndpoints": {
    "blob": "https://abfswales1.blob.core.windows.net/",
    "dfs": "https://abfswales1.dfs.core.windows.net/",
    "file": "https://abfswales1.file.core.windows.net/",
    "queue": "https://abfswales1.queue.core.windows.net/",
    "table": "https://abfswales1.table.core.windows.net/",
    "web": "https://abfswales1.z35.web.core.windows.net/"
  }
}

abfswales1.dfs.core.windows.net 账户是存储账户将被引用的名称。

现在请求存储的连接字符串,其中包含账户密钥

az storage account  show-connection-string --name abfswales1
{
  "connectionString": "DefaultEndpointsProtocol=https;EndpointSuffix=core.windows.net;AccountName=abfswales1;AccountKey=ZGlkIHlvdSByZWFsbHkgdGhpbmsgSSB3YXMgZ29pbmcgdG8gcHV0IGEga2V5IGluIGhlcmU/IA=="
}

然后您需要将访问密钥添加到您的core-site.xml、JCEKs文件,或者使用集群管理工具将选项fs.azure.account.key.STORAGE-ACCOUNT设置为该值。

<property>
  <name>fs.azure.account.key.abfswales1.dfs.core.windows.net</name>
  <value>ZGlkIHlvdSByZWFsbHkgdGhpbmsgSSB3YXMgZ29pbmcgdG8gcHV0IGEga2V5IGluIGhlcmU/IA==</value>
</property>

通过Azure门户创建

通过门户创建的内容请参阅快速入门:创建Azure Data Lake Storage Gen2存储账户

关键步骤

  1. 在适合您的位置创建一个新的存储账户。
  2. “基础”选项卡:选择“StorageV2”。
  3. “高级”选项卡:启用“分层命名空间”。

您现在已经创建了存储账户。接下来,获取用于默认“共享密钥”认证的密钥。

  1. 前往Azure门户。
  2. 选择“存储账户”
  3. 选择新创建的存储账户。
  4. 在设置列表中,找到“访问密钥”并选择它。
  5. 将其中一个访问密钥复制到剪贴板,添加到XML选项中,在集群管理工具、Hadoop JCEKS文件或KMS存储中进行设置。

创建新容器

一个Azure存储账户可以包含多个容器,每个容器的名称作为URI中用于引用它的userinfo字段。

例如,刚创建的存储账户中的容器“container1”将具有URL abfs://container1@abfswales1.dfs.core.windows.net/

您可以通过ABFS连接器创建新容器,只需将选项fs.azure.createRemoteFileSystemDuringInitialization设置为true。但当认证类型为SAS时,不支持此操作。

如果容器不存在,尝试使用hadoop fs -ls列出容器将会失败

$ hadoop fs -ls abfs://container1@abfswales1.dfs.core.windows.net/

ls: `abfs://container1@abfswales1.dfs.core.windows.net/': No such file or directory

启用远程文件系统创建,第二次尝试成功,同时创建容器:

$ hadoop fs -D fs.azure.createRemoteFileSystemDuringInitialization=true \
 -ls abfs://container1@abfswales1.dfs.core.windows.net/

这在命令行上创建账户时非常有用,尤其是在az storage命令尚未完全支持分层命名空间的情况下。

列出并检查存储账户的容器。

你可以使用 Azure Storage Explorer

配置ABFS

任何配置都可以通用指定(或作为访问所有账户时的默认设置),也可以绑定到特定账户。例如,可以配置一个OAuth身份,无论访问哪个账户都使用该身份,通过属性fs.azure.account.oauth2.client.id;或者也可以配置一个身份,仅用于特定的存储账户,通过fs.azure.account.oauth2.client.id..dfs.core.windows.net

这在认证部分展示。

认证

ABFS的认证最终由Azure Active Directory授予。

其中涉及的概念超出了本文档的范围;开发者需要阅读并理解其中的概念,才能充分利用不同的认证机制。

这里简要介绍了如何配置ABFS客户端以在不同部署场景中进行身份验证。

ABFS客户端可以通过不同方式进行部署,其身份验证需求取决于部署方式。

  1. 在配置中使用存储账户的身份验证密钥:"共享密钥"。
  2. 使用某种形式的OAuth 2.0令牌。
  3. 在Azure中部署,由Azure虚拟机为应用程序“Managed Instance”提供OAuth 2.0令牌。
  4. 使用由SASTokenProvider接口的自定义实现提供的共享访问签名(SAS)令牌。
  5. 通过在账户配置设置文件中直接配置固定的共享访问签名(SAS)令牌来实现。

注意:基于SAS的身份验证应仅用于启用了HNS的账户。

可以更改的是用于验证调用者身份的秘密/凭据。

认证机制在fs.azure.account.auth.type(或特定账户的变体)中设置。可能的值为SharedKey、OAuth、Custom和SAS。对于各种OAuth选项,使用配置fs.azure.account.oauth.provider.type。以下是支持的实现:ClientCredsTokenProvider、UserPasswordTokenProvider、MsiTokenProvider、RefreshTokenBasedTokenProvider和WorkloadIdentityTokenProvider。如果指定的提供程序类型不受支持,则会抛出IllegalArgumentException。

所有密钥都可以存储在JCEKS文件中。这些文件经过加密和密码保护——尽可能使用它们或兼容的Hadoop密钥管理存储

AAD 令牌获取重试

用于AAD令牌获取重试的指数退避策略可以通过以下配置进行调整:* fs.azure.oauth.token.fetch.retry.max.retries:设置最大重试次数。默认值为5。* fs.azure.oauth.token.fetch.retry.min.backoff.interval:最小退避间隔。该值会与根据增量退避计算出的重试间隔相加。默认设置为0。以毫秒为单位设置该间隔。* fs.azure.oauth.token.fetch.retry.max.backoff.interval:最大退避间隔。默认值为60000(六十秒)。以毫秒为单位设置该间隔。* fs.azure.oauth.token.fetch.retry.delta.backoff:重试之间的退避间隔。该时间跨度的倍数将用于后续重试尝试。默认值为2。

默认值:共享密钥

这是最简单的账号+密码认证机制。

账户名从URL推断得出;密码“key”则从XML/JCECKs配置文件中获取。

<property>
  <name>fs.azure.account.auth.type.ACCOUNT_NAME.dfs.core.windows.net</name>
  <value>SharedKey</value>
  <description>
  </description>
</property>
<property>
  <name>fs.azure.account.key.ACCOUNT_NAME.dfs.core.windows.net</name>
  <value>ACCOUNT_KEY</value>
  <description>
  The secret password. Never share these.
  </description>
</property>

注意: 账户密钥的来源可以通过自定义密钥提供程序进行更改;现有方案支持通过执行shell脚本来获取密钥。

可以通过配置fs.azure.account.keyprovider提供自定义密钥提供程序类。如果指定了密钥提供程序类,则将使用相同的类来获取账户密钥。否则将使用简单密钥提供程序,该提供程序将使用为配置fs.azure.account.key指定的密钥。

要通过shell脚本检索,请为配置项fs.azure.shellkeyprovider.script指定脚本路径。ShellDecryptionKeyProvider类将使用指定的脚本来检索密钥。

OAuth 2.0 客户端凭证

OAuth 2.0 凭证(客户端ID、客户端密钥、端点)在配置文件/JCEKS文件中提供。

该过程的具体细节在hadoop-azure-datalake中有详细说明;这里的关键名称略有不同。

<property>
  <name>fs.azure.account.auth.type</name>
  <value>OAuth</value>
  <description>
  Use OAuth authentication
  </description>
</property>
<property>
  <name>fs.azure.account.oauth.provider.type</name>
  <value>org.apache.hadoop.fs.azurebfs.oauth2.ClientCredsTokenProvider</value>
  <description>
  Use client credentials
  </description>
</property>
<property>
  <name>fs.azure.account.oauth2.client.endpoint</name>
  <value></value>
  <description>
  URL of OAuth endpoint
  </description>
</property>
<property>
  <name>fs.azure.account.oauth2.client.id</name>
  <value></value>
  <description>
  Client ID
  </description>
</property>
<property>
  <name>fs.azure.account.oauth2.client.secret</name>
  <value></value>
  <description>
  Secret
  </description>
</property>

OAuth 2.0: 用户名与密码

配置/JCEKS文件中提供了OAuth 2.0端点、用户名和密码。

<property>
  <name>fs.azure.account.auth.type</name>
  <value>OAuth</value>
  <description>
  Use OAuth authentication
  </description>
</property>
<property>
  <name>fs.azure.account.oauth.provider.type</name>
  <value>org.apache.hadoop.fs.azurebfs.oauth2.UserPasswordTokenProvider</value>
  <description>
  Use user and password
  </description>
</property>
<property>
  <name>fs.azure.account.oauth2.client.endpoint</name>
  <value></value>
  <description>
  URL of OAuth 2.0 endpoint
  </description>
</property>
<property>
  <name>fs.azure.account.oauth2.user.name</name>
  <value></value>
  <description>
  username
  </description>
</property>
<property>
  <name>fs.azure.account.oauth2.user.password</name>
  <value></value>
  <description>
  password for account
  </description>
</property>

OAuth 2.0: 刷新令牌

使用现有的OAuth 2.0令牌,向Active Directory端点https://login.microsoftonline.com/Common/oauth2/token发出请求以刷新该令牌。

<property>
  <name>fs.azure.account.auth.type</name>
  <value>OAuth</value>
  <description>
  Use OAuth 2.0 authentication
  </description>
</property>
<property>
  <name>fs.azure.account.oauth.provider.type</name>
  <value>org.apache.hadoop.fs.azurebfs.oauth2.RefreshTokenBasedTokenProvider</value>
  <description>
  Use the Refresh Token Provider
  </description>
</property>
<property>
  <name>fs.azure.account.oauth2.refresh.token</name>
  <value></value>
  <description>
  Refresh token
  </description>
</property>
<property>
  <name>fs.azure.account.oauth2.refresh.endpoint</name>
  <value></value>
  <description>
  Refresh token endpoint
  </description>
</property>
<property>
  <name>fs.azure.account.oauth2.client.id</name>
  <value></value>
  <description>
  Optional Client ID
  </description>
</property>

Azure 托管身份

Azure Managed Identities,前身为"托管服务身份"。

OAuth 2.0令牌由一个特殊端点颁发,该端点只能从执行中的虚拟机访问(http://169.254.169.254/metadata/identity/oauth2/token)。颁发的凭证可用于身份验证。

Azure门户/CLI用于创建服务身份。

<property>
  <name>fs.azure.account.auth.type</name>
  <value>OAuth</value>
  <description>
  Use OAuth authentication
  </description>
</property>
<property>
  <name>fs.azure.account.oauth.provider.type</name>
  <value>org.apache.hadoop.fs.azurebfs.oauth2.MsiTokenProvider</value>
  <description>
  Use MSI for issuing OAuth tokens
  </description>
</property>
<property>
  <name>fs.azure.account.oauth2.msi.tenant</name>
  <value></value>
  <description>
  Optional MSI Tenant ID
  </description>
</property>
<property>
  <name>fs.azure.account.oauth2.msi.endpoint</name>
  <value></value>
  <description>
   MSI endpoint
  </description>
</property>
<property>
  <name>fs.azure.account.oauth2.client.id</name>
  <value></value>
  <description>
  Optional Client ID
  </description>
</property>

Azure 工作负载身份

Azure Workload Identities,前身为“Azure AD pod identity”。

OAuth 2.0令牌会被写入一个仅能从执行中的pod访问的文件(/var/run/secrets/azure/tokens/azure-identity-token)。颁发的凭证可用于身份验证。

Azure门户/CLI用于创建服务身份。

<property>
  <name>fs.azure.account.auth.type</name>
  <value>OAuth</value>
  <description>
  Use OAuth authentication
  </description>
</property>
<property>
  <name>fs.azure.account.oauth.provider.type</name>
  <value>org.apache.hadoop.fs.azurebfs.oauth2.WorkloadIdentityTokenProvider</value>
  <description>
  Use Workload Identity for issuing OAuth tokens
  </description>
</property>
<property>
  <name>fs.azure.account.oauth2.msi.tenant</name>
  <value>${env.AZURE_TENANT_ID}</value>
  <description>
  Optional MSI Tenant ID
  </description>
</property>
<property>
  <name>fs.azure.account.oauth2.client.id</name>
  <value>${env.AZURE_CLIENT_ID}</value>
  <description>
  Optional Client ID
  </description>
</property>
<property>
  <name>fs.azure.account.oauth2.token.file</name>
  <value>${env.AZURE_FEDERATED_TOKEN_FILE}</value>
  <description>
  Token file path
  </description>
</property>

自定义OAuth 2.0令牌提供程序

自定义OAuth 2.0令牌提供程序会在调用其getAccessToken()方法时向ABFS连接器提供OAuth 2.0令牌。

<property>
  <name>fs.azure.account.auth.type</name>
  <value>Custom</value>
  <description>
  Custom Authentication
  </description>
</property>
<property>
  <name>fs.azure.account.oauth.provider.type</name>
  <value></value>
  <description>
  classname of Custom Authentication Provider
  </description>
</property>

声明的类必须实现 org.apache.hadoop.fs.azurebfs.extensions.CustomTokenProviderAdaptee 并可选择性地实现 org.apache.hadoop.fs.azurebfs.extensions.BoundDTExtension

声明的类还负责在获取访问令牌时实现重试逻辑。

委托令牌提供者

委托令牌提供者通过实现CustomDelegationTokenManager接口,为ABFS连接器提供委托令牌,并协助续订和取消这些令牌。

<property>
  <name>fs.azure.enable.delegation.token</name>
  <value>true</value>
  <description>Make this true to use delegation token provider</description>
</property>
<property>
  <name>fs.azure.delegation.token.provider.type</name>
  <value>{fully-qualified-class-name-for-implementation-of-CustomDelegationTokenManager-interface}</value>
</property>

如果启用了委托令牌,但未提供配置fs.azure.delegation.token .provider.type,则会抛出IlleagalArgumentException异常。

共享访问签名(SAS)令牌提供程序

共享访问签名(SAS)可安全地委托访问您存储账户中的资源。通过SAS,您可以精细控制客户端如何访问数据。要了解更多关于SAS认证工作原理,请参阅使用共享访问签名(SAS)授予对Azure存储资源的有限访问权限

Azure存储支持三种类型的SAS: - 用户委托SAS:建议用于启用了HNS的ADLS Gen2账户与ABFS驱动程序配合使用。这是一种基于身份的SAS,可在blob/目录级别工作) - 服务SAS:全局有效,作用于容器级别。 - 账户SAS:全局有效,作用于账户级别。

SAS的已知问题

  • 基于SAS的身份验证仅适用于启用了HNS的ADLS Gen2账户,这是推荐与ABFS配合使用的账户类型。
  • 已知某些根级操作在使用基于SAS的身份验证时会失败。

在ABFS中使用用户委托SAS

  • 描述: ABFS允许您实现自定义的SAS令牌提供程序,该程序使用您的身份创建用户委托密钥,然后可用于生成SAS而非存储账户密钥。声明的类必须实现org.apache.hadoop.fs.azurebfs.extensions.SASTokenProvider

  • 配置: 要在ABFS驱动中使用此方法,请在您的core-site.xml文件中指定以下属性:

    1. 认证类型:

      
        fs.azure.account.auth.type
        SAS
      
      
    2. 自定义SAS令牌提供者类:

      
        fs.azure.sas.token.provider.type
        CUSTOM_SAS_TOKEN_PROVIDER_CLASS
      
      

    CUSTOM_SAS_TOKEN_PROVIDER_CLASS替换为您自定义令牌提供程序实现的完全限定类名。根据具体实现,您可能需要指定自定义实现所需的其他配置。

  • 示例: ABFS Hadoop驱动提供了一个MockDelegationSASTokenProvider实现,可作为如何实现自定义SASTokenProvider的参考范例。除了上述两项配置外,这还要求使用以下配置来指定应用程序凭据:

    1. 应用服务主体租户ID:
      
        fs.azure.test.app.service.principal.tenant.id
        TENANT_ID
      
      
    2. 应用服务主体对象ID:
      
        fs.azure.test.app.service.principal.object.id
        OBJECT_ID
      
      
    3. 应用ID:
      
        fs.azure.test.app.id
        APPLICATION_ID
      
      
    4. 应用密钥:
      
        fs.azure.test.app.secret
        APPLICATION_SECRET
      
      
  • 安全性:比共享密钥更安全,允许在不暴露访问密钥的情况下授予对数据的有限访问权限。建议仅与启用了HNS的ADLS Gen 2存储账户一起使用。

在ABFS中使用账户/服务SAS

  • 描述: ABFS允许用户使用账户/服务SAS进行请求认证。用户可以将其指定为固定SAS令牌,以便在所有请求中使用。

  • 配置: 要在ABFS驱动中使用此方法,请在您的core-site.xml文件中指定以下属性:

    1. 认证类型:

      
        fs.azure.account.auth.type
        SAS
      
      
    2. 固定SAS令牌:

      
        fs.azure.sas.fixed.token
        FIXED_SAS_TOKEN
      
      

    FIXED_SAS_TOKEN替换为固定的账户/服务SAS。您也可以从Azure门户生成SAS。路径:账户 -> 安全+网络 -> 共享访问签名

  • 安全性: 账户/服务SAS需要使用账户密钥,这使得其安全性较低。无法实现向不同用户委派访问权限。

注意: 当同时配置 fs.azure.sas.token.provider.typefs.azure.fixed.sas.token 时,将优先使用自定义令牌提供程序实现。

技术说明

代理设置

该连接器使用JVM代理设置来控制其代理配置。

请参阅Oracle Java文档了解可设置的选项。

由于连接器默认使用HTTPS,因此必须配置https.proxyHosthttps.proxyPort选项。

在MapReduce作业(包括distcp)中,代理选项必须在mapreduce.map.java.optsmapreduce.reduce.java.opts中同时设置。

# this variable is only here to avoid typing the same values twice.
# It's name is not important.
export DISTCP_PROXY_OPTS="-Dhttps.proxyHost=web-proxy.example.com -Dhttps.proxyPort=80"

hadoop distcp \
  -D mapreduce.map.java.opts="$DISTCP_PROXY_OPTS" \
  -D mapreduce.reduce.java.opts="$DISTCP_PROXY_OPTS" \
  -update -skipcrccheck -numListstatusThreads 40 \
  hdfs://namenode:8020/users/alice abfs://backups@account.dfs.core.windows.net/users/alice

如果没有这些设置,即使从命令行可以访问ADLS,distcp访问也可能因网络错误而失败。

安全性

与其他对象存储系统一样,登录凭证是重要的敏感信息。企业应建立安全共享这些信息的流程。

ABFS连接器的限制

  • 文件的最后访问时间未被追踪。
  • 不支持扩展属性。
  • 不支持文件校验和。
  • 如果fs.azure.enable.flush设置为true(默认=true),则支持Syncable接口的hsync()hflush()操作。在Wasb连接器中,这将任一调用的次数限制为50,000次HADOOP-15478。如果abfs有类似的限制,则过度使用sync/flush可能会导致问题。

一致性与并发性

与所有Azure存储服务一样,Azure Datalake Gen 2存储提供了完全一致的存储视图,对数据和元数据具有完整的创建、读取、更新和删除一致性。

性能与可扩展性

对于具有分层命名空间的容器,其可扩展性数值(用大O符号表示)如下:

操作 可扩展性
File Rename O(1)
File Delete O(1)
Directory Rename: O(1)
Directory Delete O(1)

对于非命名空间存储,可扩展性变为:

操作 可扩展性
File Rename O(1)
File Delete O(1)
Directory Rename: O(files)
Directory Delete O(files)

也就是说:文件数量越多,目录操作就会变得越慢。

延伸阅读:Azure Storage Scalability Targets

可扩展性

ABFS连接器支持一些有限的私有/不稳定扩展点,允许第三方将其认证和授权服务集成到ABFS客户端中。

  • CustomDelegationTokenManager : 添加了颁发Hadoop委托令牌的能力。
  • SASTokenProvider: 允许自定义提供Azure存储共享访问签名(SAS)令牌。
  • CustomTokenProviderAdaptee: 允许自定义提供Azure OAuth令牌。
  • KeyProvider.

请参考org.apache.hadoop.fs.azurebfs.extensions中的源代码及所有相关测试,了解如何利用这些扩展点。

警告 这些扩展点不稳定。

网络层:

ABFS 驱动程序可以使用以下网络库:- ApacheHttpClient:- Library Documentation。- 默认网络库。- JDK 网络库:- Library documentation

网络库可以在初始化文件系统时通过配置fs.azure.networking.library进行设置。以下是支持的值: - JDK_HTTP_URL_CONNECTION : 使用JDK网络库 [默认] - APACHE_HTTP_CLIENT : 使用Apache HttpClient

ApacheHttpClient 网络层配置选项:

以下是文件系统初始化时可提供的ApacheHttpClient网络层配置选项:1. fs.azure.apache.http.client.idle.connection.ttl:1. 连接池中保持连接存活的最大空闲时间(毫秒)。如果连接在时限内未被重用,该连接将被关闭。2. 默认值:5000毫秒。2. fs.azure.apache.http.client.max.cache.connection.size:1. 文件系统实例连接池中可缓存的最大连接数。并发连接总数没有限制。2. 默认值:5。3. fs.azure.apache.http.client.max.io.exception.retries:1. 客户端在使用ApacheHttpClient网络层时,对单个请求因IOExceptions而重试的最大次数。超过此限制将导致当前JVM实例中禁用ApacheHttpClient库的后续使用。2. 默认值:3。

ApacheHttpClient 类路径要求:

ApacheHttpClient是hadoop-azure中的一个compile Maven依赖项,会被包含在hadoop-azure jar包中。使用hadoop-azure与ApacheHttpClient时,classpath中不需要额外配置信息。

其他配置选项

请查阅org.apache.hadoop.fs.azurebfs.constants.ConfigurationKeysorg.apache.hadoop.fs.azurebfs.constants.FileSystemConfigurationsorg.apache.hadoop.fs.azurebfs.AbfsConfiguration的javadocs文档,获取完整的配置选项列表及其默认值。

客户端关联选项

1. 客户端关联ID选项

配置 fs.azure.client.correlationid 提供了使用客户端提供的标识符来关联客户端请求的选项。该ID将在Azure存储分析日志的request-id-header字段中可见。参考:Storage Analytics log format

此配置接受一个最多72个字符的字符串,且只能包含字母数字字符和/或连字符。如果输入无效,则默认为空字符串。

1. 关联ID显示选项

配置 fs.azure.tracingcontext.format 提供了选择 request-id-header 中包含ID格式的选项。该配置接受与以下枚举选项对应的字符串值。SINGLE_ID_FORMAT : clientRequestId ALL_ID_FORMAT : 所有ID (默认) TWO_ID_FORMAT : clientCorrelationId:clientRequestId

刷新选项

1. Azure Blob 文件系统刷新选项

配置 fs.azure.enable.flush 提供了将ABFS刷新API - HFlush()和HSync()设置为无操作的选项。默认情况下,此配置将设置为true。

这两个API都将确保数据被持久化。

2. 输出流刷新选项

配置 fs.azure.disable.outputstream.flush 提供了在 AbfsOutputStream 中将 OutputStream Flush() API 设为无操作的可选项。默认情况下,该配置将被设置为 true。

Hflush()是唯一有文档记录的能够提供持久数据传输的API,Flush()也尝试持久化缓冲数据会导致性能问题。

百继续选项

fs.azure.account.expect.header.enabled: 该配置参数用于指定是否希望在每次追加请求时发送expect 100 continue头部。默认设置为true。此标志配置客户端在从输出流上传数据块之前先与Azure存储进行检查。这使得客户端在实际尝试上传数据块之前能够优雅地回退。实验表明,在高负载情况下这能显著提高吞吐量。更多信息:- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expect

账户级限流选项

fs.azure.account.operation.idle.timeout: 该值指定分析器(读取或写入)计时器在无新请求时应暂停的时间。默认值为60秒。

HNS 检查选项

配置 fs.azure.account.hns.enabled 提供了指定存储账户是否启用HNS的选项。如果未提供该配置,则会发起服务器调用来进行验证。

访问选项

需要将配置 fs.azure.enable.check.access 设为 true 以启用 AzureBlobFileSystem.access()。

操作幂等性

由于服务器超时和网络故障导致的请求失败将会自动重试。PUT/POST操作具有幂等性,除重命名和删除操作外无需特殊处理。

重命名操作的幂等性检查通过确保在重试时若源路径不存在,则目标路径的LastModifiedTime是最新的来实现。

默认情况下,如果重试时目标不存在,则删除操作被视为幂等的。

主要用户组选项

如果将以下配置设置为true fs.azure.skipUserGroupMetadataDuringInitialization,则作为FileStatus和AclStatus组成部分的组名将被设置为与用户名相同。

IO选项

以下配置与读写操作相关。

fs.azure.io.retry.max.retries: 设置IO操作的重试次数。当前仅用于服务器调用重试逻辑。在AbfsClient类中作为ExponentialRetryPolicy的一部分使用。该值应大于或等于0。

fs.azure.io.retry.min.backoff.interval: 设置IO操作重试的最小退避间隔。当前仅用于服务器调用重试逻辑。在AbfsClient类中作为ExponentialRetryPolicy的一部分使用。该值表示重试IO操作前需等待的最小间隔(以毫秒为单位)。默认值为3000(3秒)。

fs.azure.io.retry.max.backoff.interval: 设置IO操作重试的最大退避间隔。当前仅用于服务器调用重试逻辑。在AbfsClient类中作为ExponentialRetryPolicy的一部分使用。该值表示在重试IO操作前等待的最大间隔(以毫秒为单位)。默认值为30000(30秒)。

fs.azure.io.retry.backoff.interval: 设置IO操作重试的默认退避间隔。目前仅用于服务器调用重试逻辑。在AbfsClient类中作为ExponentialRetryPolicy的一部分使用。该值用于计算指定值80%到120%之间的随机增量。然后将此随机增量乘以当前IO重试次数的指数(即默认值乘以2^(retryNum - 1)),然后限制在[fs.azure.io.retry.min.backoff.interval, fs.azure.io.retry.max.backoff.interval]范围内,以确定下一次IO重试尝试前的等待时间。默认值为3000(3秒)。

fs.azure.write.request.size: 用于设置写入缓冲区大小。请以字节为单位指定该值。取值范围应在16384到104857600之间(含16 KB到100 MB)。默认值为8388608(8 MB)。

fs.azure.read.request.size: 用于设置读取缓冲区大小。请以字节为单位指定该值。取值范围为16384至104857600(含16 KB至100 MB)。默认值为4194304(4 MB)。

fs.azure.read.alwaysReadBufferSize: 由fs.azure.read.request.size配置的读取请求大小仅在顺序读取模式下生效。当检测到随机读取模式时,读取大小将与调用进程提供的缓冲区长度相同。若将此配置设为true,将强制随机读取也采用与顺序读取相同的请求大小。这是为了保持与ADLS Gen1相同的读取模式,因为ADLS Gen1不区分读取模式,始终按照配置的读取请求大小进行读取。此配置的默认值为false,即在检测到随机读取模式时,将按照提供的缓冲区长度进行读取。

fs.azure.readaheadqueue.depth: 设置AbfsInputStream中的预读队列深度。如果设置的值为负数,预读队列深度将被设为Runtime.getRuntime().availableProcessors()。默认值为2。要禁用预读功能,请将此值设为0。如果您的工作负载仅进行随机读取(非顺序)或遇到限流情况,可以尝试将此值设为0。

fs.azure.read.readahead.blocksize: 用于设置预读操作的读取缓冲区大小。以字节为单位指定该值,取值范围应在16384到104857600之间(含16 KB到100 MB)。默认值为4194304(4 MB)。

fs.azure.buffered.pread.disable: 默认情况下,位置读取API会在输入流上执行查找和读取操作。该读取会填充AbfsInputStream中的缓冲区缓存并更新游标位置。如果将此优化设为true,则会跳过缓冲区的使用,直接通过无锁REST调用来读取blob数据。该优化对于HBase这类在共享AbfsInputStream实例上进行短随机读取的场景非常有帮助。注意:这不是一个可以在集群级别设置的配置,只能作为FutureDataInputStreamBuilder的选项使用。参见FileSystem#openFile(Path path)

在内存受限的情况下运行,请配置以下内容。特别是当同一进程有过多写入操作时。

fs.azure.write.max.concurrent.requests: 用于设置AbfsOutputStream实例在任何时间点向服务器发送的最大并发写入请求数。实际上这将决定AbfsOutputStream实例内部的线程池大小。设置值应在1到8之间(包含1和8)。

fs.azure.write.max.requests.to.queue: 用于设置可排队的最大写入请求数。通过此配置可以调节AbfsOutputStream实例的内存消耗,因为每个排队请求都会持有一个缓冲区。建议将该值设置为s.azure.write.max.concurrent.requests值的3到4倍。

fs.azure.analysis.period: 分析指标后重新计算休眠时间的间隔。默认值为10秒。

安全选项

fs.azure.always.use.https: 当该标志设为true时,强制使用HTTPS而非HTTP。无论该标志如何设置,如果使用安全方案(ABFSS)或使用OAuth进行身份验证,AbfsClient都将使用HTTPS。默认情况下该值将被设为true。

fs.azure.ssl.channel.mode: 正在使用指定的SSL通道模式初始化DelegatingSSLSocketFactory。该值应为枚举DelegatingSSLSocketFactory.SSLChannelMode类型。默认值将为DelegatingSSLSocketFactory.SSLChannelMode.Default。

加密选项

以下两个选项只能配置其中一个。如果同时设置了两种类型的配置值,ABFS驱动程序将抛出异常。如果使用全局密钥类型,请确保提供预先计算的两个值。

客户提供的全局密钥

可以通过提供以下预计算值来配置全局加密密钥。该密钥将应用于设置配置后创建的任何新文件,并且在读取或修改文件内容的请求中需要该密钥。

fs.azure.encryption.encoded.client-provided-key: 256位加密密钥的Base64编码版本。

fs.azure.encryption.encoded.client-provided-key-sha: 256位加密密钥的SHA256哈希值的Base64编码版本。

加密上下文提供程序

ABFS驱动程序支持一个名为EncryptionContextProvider的接口,该接口可作为客户端插件为加密框架提供自定义实现。该框架允许通过EncryptionContextProvider为待创建文件生成encryptionContextencryptionKey。服务器会记录每个文件的encryptionContext。当需要对加密文件执行读取等后续操作时,ABFS驱动程序将通过向服务器发起GetFileStatus请求获取encryptionContext字符串,并据此从EncryptionContextProvider实现中获取对应的加密密钥。

fs.azure.encryption.context.provider.type: 实现EncryptionContextProvider接口的类的规范名称。

服务器选项

fs.azure.io.read.tolerate.concurrent.append: 当该配置设为true时,发送到服务器进行读取调用的If-Match标头将被设置为*,否则将使用ETag设置。这本质上是一种处理乐观并发读取的机制。更多信息请参考以下链接。1. https://docs.microsoft.com/en-us/rest/api/storageservices/datalakestoragegen2/path/read 2. https://azure.microsoft.com/de-de/blog/managing-concurrency-in-microsoft-azure-storage-2/

fs.azure.list.max.results: listStatus API以分页方式从服务器获取FileStatus信息。该配置用于设置maxResults URI参数,该参数决定了每页的大小(每次调用的最大结果数)。该值应大于0,默认值为5000。服务器对该参数设置的最大值也是5000,因此即使配置值超过5000,响应也只会包含5000条记录。更多信息请参考以下链接。https://docs.microsoft.com/en-us/rest/api/storageservices/datalakestoragegen2/path/list

fs.azure.enable.checksum.validation: 当该配置设为true时,读取和追加调用会向服务器发送Content-MD5头部信息。这提供了一种验证数据传输完整性的方法。由于需要在客户端和服务器端重新计算MD5哈希值,这会对性能产生影响。详情请参阅Azure文档中关于ReadAppend API的部分

限流选项

ABFS驱动程序具备通过限制读写操作来最大化吞吐量的能力,同时最小化错误。当超过账户的入口或出口限制时,服务器端会限制请求,从而导致错误发生。服务器端限制会触发重试策略,但重试策略会导致长时间的休眠,使得总入口或出口吞吐量比最优值低多达35%。此外,重试策略是在请求失败后才生效的被动措施。相比之下,此处实现的客户端限制机制会在请求发出前进行干预,仅休眠必要时间以最小化错误,从而实现最优的入口和/或出口吞吐量。默认情况下,驱动程序已启用此限制机制。可通过将配置项fs.azure.enable.autothrottling设为false来禁用该功能。

重命名选项

fs.azure.atomic.rename.key: 在此配置中可以用逗号分隔指定支持原子重命名的目录。如果重命名的源路径属于配置的目录之一,驱动程序会打印以下警告日志:"ABFS方案不支持原子重命名功能;但如果您的Azure存储账户启用了命名空间,则重命名、创建和删除操作都是原子性的。" 目录可以指定为逗号分隔的值。默认值为"/hbase"

无限租约选项

fs.azure.infinite-lease.directories: 在此配置中可以用逗号分隔指定支持无限租约的目录。默认情况下,多个客户端可以同时写入同一个文件。当写入此配置中指定目录包含的文件时,客户端将获取该文件的租约,这将阻止其他任何客户端写入该文件。当输出流关闭时,租约将被释放。要撤销客户端对文件的写入权限,可以调用AzureBlobFilesystem的breakLease方法。如果客户端在文件关闭和租约释放前崩溃,则需要先调用breakLease方法,其他客户端才能写入该文件。

fs.azure.lease.threads: 这是用于无限租约目录租约操作的线程池大小。默认值为0,因此必须至少设置为1才能支持无限租约目录。

性能选项

1. HTTP请求追踪选项

如果将fs.azure.abfs.latency.track设置为true,该模块将开始追踪ABFS HTTP流量的性能指标。要在您的机器或集群上获取这些数据,您还需要在log4j配置中为AbfsPerfTracker类启用调试日志记录。典型的性能日志行显示如下:

h=KARMA t=2019-10-25T20:21:14.518Z a=abfstest01.dfs.core.windows.net
c=abfs-testcontainer-84828169-6488-4a62-a875-1e674275a29f cr=delete ce=deletePath
r=Succeeded l=32 ls=32 lc=1 s=200 e= ci=95121dae-70a8-4187-b067-614091034558
ri=97effdcf-201f-0097-2d71-8bae00000000 ct=0 st=0 rt=0 bs=0 br=0 m=DELETE
u=https%3A%2F%2Fabfstest01.dfs.core.windows.net%2Ftestcontainer%2Ftest%3Ftimeout%3D90%26recursive%3Dtrue

字段具有以下定义:

h: 主机名 t: 请求记录时间 a: Azure存储账户名称 c: 容器名称 cr: 调用方方法名 ce: 被调用方方法名 r: 结果(成功/失败) l: 延迟(在被调用方花费的时间) ls: 延迟总和(在调用方花费的累计时间;当存在多个被调用方时记录;与最后一个被调用方一起记录) lc: 延迟计数(被调用方数量;当存在多个被调用方时记录;与最后一个被调用方一起记录) s: HTTP状态码 e: 错误码 ci: 客户端请求ID ri: 服务端请求ID ct: 连接时间(毫秒) st: 发送时间(毫秒) rt: 接收时间(毫秒) bs: 发送字节数 br: 接收字节数 m: HTTP方法(GET, PUT等) u: 编码后的HTTP URL

请注意,这些性能指标也会在后续请求中通过x-ms-abfs-client-latency HTTP标头发送回ADLS Gen 2 API端点。Azure使用这些设置来跟踪其端到端延迟。

故障排除

与连接器相关的问题通常归结为,按顺序

  1. 类路径。
  2. 网络设置(代理等)。
  3. 认证与授权。
  4. 其他任何内容。

如果将org.apache.hadoop.fs.azurebfs.services的日志级别设为DEBUG,就能看到更多关于失败请求的详细信息。

一个用于调试连接性的有用工具是cloudstore storediag实用程序

这会验证类路径和设置,然后尝试与文件系统交互。

bin/hadoop jar cloudstore-0.1-SNAPSHOT.jar storediag abfs://container@account.dfs.core.windows.net/
  1. 如果storediag命令无法与abfs存储配合使用,那么其他方法很可能也无法使用。
  2. 如果storediag存储确实能正常工作,这并不能保证集群其余部分的类路径或配置也能正常工作,特别是在分布式应用中。但这至少是一个开始。

ClassNotFoundException: org.apache.hadoop.fs.azurebfs.AzureBlobFileSystem

hadoop-azure JAR 文件不在类路径中。

java.lang.RuntimeException: java.lang.ClassNotFoundException:
    Class org.apache.hadoop.fs.azurebfs.AzureBlobFileSystem not found
  at org.apache.hadoop.conf.Configuration.getClass(Configuration.java:2625)
  at org.apache.hadoop.fs.FileSystem.getFileSystemClass(FileSystem.java:3290)
  at org.apache.hadoop.fs.FileSystem.createFileSystem(FileSystem.java:3322)
  at org.apache.hadoop.fs.FileSystem.access$200(FileSystem.java:136)
  at org.apache.hadoop.fs.FileSystem$Cache.getInternal(FileSystem.java:3373)
  at org.apache.hadoop.fs.FileSystem$Cache.get(FileSystem.java:3341)
  at org.apache.hadoop.fs.FileSystem.get(FileSystem.java:491)
  at org.apache.hadoop.fs.Path.getFileSystem(Path.java:361)
Caused by: java.lang.ClassNotFoundException:
    Class org.apache.hadoop.fs.azurebfs.AzureBlobFileSystem not found
  at org.apache.hadoop.conf.Configuration.getClassByName(Configuration.java:2529)
  at org.apache.hadoop.conf.Configuration.getClass(Configuration.java:2623)
  ... 16 more

提示:如果这是在命令行上发生的,您可以开启hadoop脚本的调试日志记录:

export HADOOP_SHELL_SCRIPT_DEBUG=true

如果这种情况发生在集群内运行的应用程序上,意味着需要(以某种方式)配置集群,以便将hadoop-azure模块及其依赖项部署到应用程序的类路径中。

ClassNotFoundException: com.microsoft.azure.storage.StorageErrorCode

azure-storage JAR文件不在类路径中。

Server failed to authenticate the request

在使用默认共享密钥认证机制时,请求未通过认证。

Operation failed: "Server failed to authenticate the request.
 Make sure the value of Authorization header is formed correctly including the signature.",
 403, HEAD, https://account.dfs.core.windows.net/container2?resource=filesystem&timeout=90
  at org.apache.hadoop.fs.azurebfs.services.AbfsRestOperation.execute(AbfsRestOperation.java:135)
  at org.apache.hadoop.fs.azurebfs.services.AbfsClient.getFilesystemProperties(AbfsClient.java:209)
  at org.apache.hadoop.fs.azurebfs.AzureBlobFileSystemStore.getFilesystemProperties(AzureBlobFileSystemStore.java:259)
  at org.apache.hadoop.fs.azurebfs.AzureBlobFileSystem.fileSystemExists(AzureBlobFileSystem.java:859)
  at org.apache.hadoop.fs.azurebfs.AzureBlobFileSystem.initialize(AzureBlobFileSystem.java:110)

原因包括:

  • 您的凭据不正确。
  • 您的共享密钥已过期。在Azure中,这种情况会自动发生
  • 您的共享密钥已被撤销。
  • 主机/虚拟机时钟漂移意味着您的客户端时钟与Azure服务器不同步——调用被拒绝,因为它要么已过期(被视为重放),要么来自未来。解决方法:检查您的时钟等。

Configuration property _something_.dfs.core.windows.net not found

您的集群配置中没有声明特定账户访问密钥的fs.azure.account.key.条目,或者您使用了错误的URL

$ hadoop fs -ls abfs://container@abfswales2.dfs.core.windows.net/

ls: Configuration property abfswales2.dfs.core.windows.net not found.
  • 确保URL地址正确
  • 添加缺失的账户密钥。

尝试列出容器时提示"没有这样的文件或目录"

没有找到指定名称的容器。可能是名称输入错误,或者该容器需要被创建。

$ hadoop fs -ls abfs://container@abfswales1.dfs.core.windows.net/

ls: `abfs://container@abfswales1.dfs.core.windows.net/': No such file or directory
  • 确保URL是正确的
  • 如果需要则创建容器

“从AzureAD获取令牌时,到https://login.microsoftonline.com/something的HTTP连接失败。HTTP响应:200 OK”

  • it has a content-type text/html, text/plain, application/xml

OAuth认证页面没有返回HTTP错误代码,但也没有返回JSON数据

$ bin/hadoop fs -ls abfs://container@abfswales1.dfs.core.windows.net/

 ...

ls: HTTP Error 200;
  url='https://login.microsoftonline.com/02a07549-0a5f-4c91-9d76-53d172a638a2/oauth2/authorize'
  AADToken: HTTP connection to
  https://login.microsoftonline.com/02a07549-0a5f-4c91-9d76-53d172a638a2/oauth2/authorize
  failed for getting token from AzureAD.
  Unexpected response.
  Check configuration, URLs and proxy settings.
  proxies=none;
  requestId='dd9d526c-8b3d-4b3f-a193-0cf021938600';
  contentType='text/html; charset=utf-8';

可能的原因包括配置和网络问题:

  1. 身份验证失败,尽管是机器调用,调用方却被重定向到面向人工的Azure Active Directory登录页面。
  2. URL地址错误 — 它指向了一个与OAuth2.0无关的网页
  3. 代理服务器试图返回有用的指令。

java.io.IOException: 暂存目录 /tmp/hadoop-yarn/staging/user1/.staging 的所有权不符合预期。当前所有者是 。该目录必须由提交者 user1 或 user1 拥有

在使用Azure托管身份时,ADLS Gen2中的文件/目录默认将由服务主体对象ID(即主体ID)拥有,而以本地操作系统用户'user1'提交作业会导致上述异常。

解决方法是模仿本地操作系统用户的权限,通过将以下属性添加到core-site.xml中。

<property>
  <name>fs.azure.identity.transformer.service.principal.id</name>
  <value>service principal object id</value>
  <description>
  An Azure Active Directory object ID (oid) used as the replacement for names contained
  in the list specified by “fs.azure.identity.transformer.service.principal.substitution.list”.
  Notice that instead of setting oid, you can also set $superuser here.
  </description>
</property>
<property>
  <name>fs.azure.identity.transformer.service.principal.substitution.list</name>
  <value>user1</value>
  <description>
  A comma separated list of names to be replaced with the service principal ID specified by
  “fs.azure.identity.transformer.service.principal.id”.  This substitution occurs
  when setOwner, setAcl, modifyAclEntries, or removeAclEntries are invoked with identities
  contained in the substitution list. Notice that when in non-secure cluster, asterisk symbol *
  can be used to match all user/group.
  </description>
</property>

一旦配置了上述属性,hdfs dfs -ls abfs://container1@abfswales1.dfs.core.windows.net/ 显示ADLS Gen2文件/目录现在归'user1'所有。

已知问题

以下是目前已知且预期会发生的故障。1. 当在根路径("/")上尝试使用AzureBlobFileSystem.setXAttr()和AzureBlobFileSystem.getXAttr()时,将会失败,并返回Operation failed: "The request URI is invalid.", HTTP 400 Bad Request错误。

测试ABFS

请参阅Testing Azure中的相关章节。