azure databricks使用external hive metastore跨工作区共享元数据

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了azure databricks使用external hive metastore跨工作区共享元数据相关的知识,希望对你有一定的参考价值。

为什么要使用external hive metastore

  1. 可以跨workspace的共享元数据,不用每次创建workspace的时候都重复的把元数据重建一次。

  2. 更好的元数据集中管理,Create once, use everywhere。

  3. 为灾难恢复(DR)做好为准备,并降低复杂性。(PAAS一样会存在意外的,不要以为不会,所以DR是必须的)

  4. 可以更好控制元数据存储DB的一些配置,比如常见的字符集问题导致视图不能使用非ascii码而无法查询出数据

  5. 元数据存储在自己的数据库中,可以和其它的产品(数据治理或者资产软件)做整合。

实现环境

azure china

创建azure SQL

步骤1:创建数据库服务器

底部输入服务器管理员账号名和密码

后面的配置默认或者按需自己设置即可,最后点击创建

步骤2:配置网络和private endpoint

后面把所有databricks的子网都加进去来

步骤3:创建数据库用于存储hive metadata

配置数据库:我这是测试,创建一个简单的即可

排序规则要注意:如果你有中文comment、视图中有中文,这里不要用默认的,建议选择Chinese_PRC_CI_AS,可以防止中文乱码,比如开头说的视图乱码问题导致无法查询出数据的问题。

其它默认配置,点击创建即可。

注意:如果使用severless并且设置了自动启停,不建议开启replicas服务,因为可能导致会一直有链接,从而导致自动启停无法生效的,就会一直计费

创建hive metadata元数据

步骤1:下载hive建表语句脚本。

此处下载用于创建 Hive 元数据的 DDL 脚本。由于我使用的databricks runtime是11.3,因此我选择了2.3.9版本。

具体的差异可以参阅下微软官网:外部 Apache Hive 元存储 - Azure Databricks | Microsoft Learn

步骤2:执行建表语句

找到建表语句,copy内容,到db中执行即可。

步骤3:创建hive db独立的读写账号

用管理员账号登录到server上,选择master数据库,执行如下SQL

 -- master db执行,创建Login
CREATE LOGIN hivedbadmin WITH password=\'xxx\';
CREATE USER hivedbadmin FOR LOGIN hivedbadmin WITH DEFAULT_SCHEMA=[dbo]

在hive metadata db上创建用户和授权

 -- hiveextmetadatadb 上执行,创建user并授权db_owner角色
CREATE USER hivedbadmin FROM LOGIN hivedbadmin;

EXEC sp_addrolemember \'db_owner\', \'hivedbadmin\';

验证登录

如果服务器禁止了公网访问,则需要添加白名单IP到database的fire rule里面,否则会一直报错说登录失败

 -- master DB执行
EXEC [sys].[sp_set_database_firewall_rule] N\'Allow Azure\', \'120.235.19.25\', \'120.235.19.25\';

-- 注意:sp_set_firewall_rule是服务器级别的,服务器级别和database级别是独立的

databricks集群配置

我们需要分别创建两个workspace。

我们测试两个hive version的,一个是2.3.7,这个配套Databricks Runtime7.0-9.X使用。一个是2.3.9.这个配套Databricks Runtime 10.0 及更高版本

两个workspace都配置访问同一个key vault,用于访问sql的账号密码,key vault自行配置

Hive 2.3.7 (Databricks Runtime 7.0 - 9.x)

注意:

  • databricks 运行时版本 9.1,因此按照微软官网的建议,将 hive 版本设置为 2.3.7:spark.sql.hive.metastore.version 2.3.7

  • spark.sql.hive.metastore.jars builtin,对于2.3.7我测试是不行的,要先设置成maven,执行任意sql命令,让他下载jar包,然后把jar包放到dbfs固定地方,然后用init script把jar包cp到本地,然后把builtin换成这个jar的路径,具体可以参考我历史的文章:【原创】Databricks 更改hive metastore version - John.Xiong - 博客园 (cnblogs.com)

  • 对于密码,可以使用机密。我们需要提供如下配置值:spark.hadoop.javax.jdo.option.ConnectionPassword secrets/xxxscope/xxxsecretname

    • 以明文形式提供了密码,不建议这样做。

  • hive metadata db不要有-(横线),我测试会报错,建议最好就是一连串的字母。

在第1个workspace创建cluster:wk1-cluster9.1-2.3.7,选择9.1 LTS runtime,在spark config中设置如下:

spark.hadoop.javax.jdo.option.ConnectionDriverName com.microsoft.sqlserver.jdbc.SQLServerDriver
spark.hadoop.javax.jdo.option.ConnectionURL jdbc:sqlserver://aaslab-sql.database.chinacloudapi.cn:1433;database=hiveextmetadatadb;encrypt=true;trustServerCertificate=false;hostNameInCertificate=*.database.chinacloudapi.cn;loginTimeout=30;
spark.hadoop.javax.jdo.option.ConnectionUserName secrets/aaslab-kv1/hive-metastore-db-user
spark.hadoop.javax.jdo.option.ConnectionPassword secrets/aaslab-kv1/hive-metastore-db-userpwd
spark.sql.hive.metastore.jars /databricks/hive_metastore_jars/*
spark.sql.hive.metastore.version 2.3.7

/databricks/hive_metastore_jars/*,是因为我提前jar包下载下来了,具体参考注意中说的文章。

在init scripts中要配置下那个cp jar的脚本

 %python
 dbutils.fs.put("/databricks/scripts/hive-metastore-init","""
 #!/bin/bash
 sleep 10s
 mkdir -p /databricks/hive_metastore_jars && cp -r /dbfs/lib/hive_metastore_jars/* /databricks/hive_metastore_jars
 """, True)

创建mount

%python
storageAccountName = "storage account"
fileSystemName = "blob container"
appID = "xxx"
tenantID = "xxx"


configs = "fs.azure.account.auth.type": "OAuth",
          "fs.azure.account.oauth.provider.type": "org.apache.hadoop.fs.azurebfs.oauth2.ClientCredsTokenProvider",
          "fs.azure.account.oauth2.client.id": appID,
          "fs.azure.account.oauth2.client.secret": dbutils.secrets.get(scope="aaslab-kv1",key="aas-lab-sp-secret"),
          "fs.azure.account.oauth2.client.endpoint": "https://login.partner.microsoftonline.cn/0/oauth2/token".format(tenantID)

dbutils.fs.mount(
  source = "abfss://0@1.dfs.core.chinacloudapi.cn/".format(fileSystemName, storageAccountName),
  mount_point = "/mnt/aaslabdw",
  extra_configs = configs)

创建db和table

%python
spark.sql("create database if not exists mytestDB")
#read the sample data into dataframe
df_flight_data = spark.read.csv("/databricks-datasets/flights/departuredelays.csv", header=True)
#create the delta table to the mount point that we have created earlier
dbutils.fs.rm("/mnt/aaslabdw/mytestDB/flight_data", recurse=True)
df_flight_data.write.format("delta").mode("overwrite").save("/mnt/aaslabdw/mytestDB/flight_data")
spark.sql("drop table if exists mytestDB.flight_data")
spark.sql("create table if not exists mytestDB.flight_data using delta location \'/mnt/aaslabdw/mytestDB/flight_data\'")

查询数据

view也不会乱码

在第2个workspace创建cluster:wk2-cluster9.1-2.3.7,选择9.1 LTS runtime,在spark config中设置如下,当然也是要按照注意那里引用的文章中的一样先下载下来jar,再配置才可以的。(当然也可以直接把workspace1的那些jar通过dbfs cli下载下来,直接传到2的dbfs上也可以的,更快)

启用后可以直接看到db、table等元数据了,但是浏览table时候会报错,报路径不存在。

执行一样的mount命令,mount一样的路径到workspace2即可。

正确在space2读取到数据

最后把spark config和init scripts等保持了space1中cluster1一样即可。

Hive 2.3.9(Databricks Runtime 10.0 及更高版本)

类似的操作,只是把spark.sql.hive.metastore.version设置为2.3.9,也是先maven下载,再配置固定的jars路径。

注意:如果同一个workspace下有多个cluster是不同版本的hive version,jars存储的路径要分开下。

例如workspace2里面创建了一个2.3.9的hive版本的cluster,我还是要访问同样的元数据,我需要下载2.3.9的jar到一个新的dbfs目录,防止冲突,然后init script也是从新的jars目录copy到cluster VM的目录上

%python
dbutils.fs.put("/databricks/scripts/hive-metastore-init-239","""
#!/bin/bash
sleep 10s
mkdir -p /databricks/hive_metastore_jars_239 && cp -r /dbfs/lib/hive_metastore_jars_239/* /databricks/hive_metastore_jars_239
""", True)

遇到的错误

1、org.apache.spark.sql.AnalysisException: org.apache.hadoop.hive.ql.metadata.HiveException: java.lang.RuntimeException: Unable to instantiate org.apache.hadoop.hive.ql.metadata.SessionHiveMetaStoreClient

ans:对应的jar包版本应该不对,需要maven下载后按照上面的来配置。

使用 azure databricks 读取 azure databricks 日志 json 文件

【中文标题】使用 azure databricks 读取 azure databricks 日志 json 文件【英文标题】:Reading azure databricks logs json file using azure databricks 【发布时间】:2022-01-01 22:00:58 【问题描述】:

我已通过启用诊断设置将数据块日志发送到存储帐户,现在我必须使用 azure 数据块读取这些日志以进行高级分析。当我尝试安装路径时它可以工作但读取不会工作。

step 1- 

containerName = "insights-logs-jobs"
storageAccountName = "smk"
config = "fs.azure.sas." + containerName+ "." + storageAccountName + ".blob.core.windows.net"
sas = "sp=r&st=2021-12-07T08:07:08Z&se=2021-12-07T16:07:08Z&spr=https&sv=2020-08-04&sr=b&sig=3skdlskdlkf5tt3FiR%2FLM%3D"
spark.conf.set(config,sas)

step 2 

df = spark.read.json("wasbs://insights-logs-jobs.gtoollogging.blob.core.windows.net/resourceId=/SUBSCRIPTIONS/xxxBD-3070-4AFD-A44C-3489956CE077/RESOURCEGROUPS/xxxx-xxx-RG/PROVIDERS/MICROSOFT.DATABRICKS/WORKSPACES/xxx-ADB/y=2021/m=12/d=07/h=00/m=00/*.json")


Getting below error

 shaded.databricks.org.apache.hadoop.fs.azure.AzureException: Unable to access container $root in account insights-logs-jobs.gtjjjng.blob.core.windows.net using anonymous credentials, and no credentials found for them  in the configuration.
    at shaded.databricks.org.apache.hadoop.fs.azure.AzureNativeFileSystemStore.connectUsingAnonymousCredentials(AzureNativeFileSystemStore.java:796)
    at shaded.databricks.org.apache.hadoop.fs.azure.AzureNativeFileSystemStore.createAzureStorage.

尝试了很多方法,但都低于错误。 [![在此处输入图片描述][1]][1]

【问题讨论】:

请确认存储账户中的数据格式。大多数集群日志以 parquet 格式存储。 不,它在 json 文件中生成 yy/mm/dd/hh 格式为 json。这是以下路径 resourceId=/SUBSCRIPTIONS/dklgd-3070-4AFD-A44C-3489956CE077/RESOURCEGROUPS/xyz- PROD-RG/PROVIDERS/MICROSOFT.DATABRICKS/WORKSPACES/xyz-PROCESS-PROD-ADB/y=2021/m=10/d=07/h=10/m=00/PT1H.JSON 【参考方案1】:

借助以下代码,我可以使用 pyspark 从 Azure 存储帐户读取数据。

df = spark.read.json("wasbs://container_@storage_account.blob.core.windows.net/sub_folder/*.json")
df.show()

这为我提供了终端中所有 json 文件的完整数据。

或者您可以通过以下方式尝试:

storage_account_name = "ACC_NAME"
storage_account_access_key = "ACC_key"

spark.conf.set(
  "fs.azure.account.key."+storage_account_name+".blob.core.windows.net",
  storage_account_access_key)

file_type = "json"
file_location = "wasbs://location/path"


df = spark.read.format(file_type).option("inferSchema", "true").load(file_location)

【讨论】:

当您尝试从存储帐户读取数据时,这些语法将起作用,但我正在尝试读取通过启用日志存储帐户名称的诊断抽动设置发送的日志。我也已经给出了完整的路径。 编辑了我的问题,尝试了 sas 令牌方法,但无法读取存储帐户中存在的数据块日志【参考方案2】:

这就是 databricks 挂载的工作方式。

如果您尝试在现有挂载点内创建挂载点,例如:

将一个存储帐户挂载到/mnt/storage1

将第二个存储帐户挂载到/mnt/storage1/storage2

原因:这将失败,因为 Databricks 不支持嵌套安装。推荐一个是为每个存储对象创建单独的挂载条目。

例如:

将一个存储帐户挂载到/mnt/storage1

将第二个存储帐户挂载到/mnt/storage2

您可以参考:Link

作为解决方法 - 您可以从存储帐户本身读取它以进行处理而不是挂载。

【讨论】:

以上是关于azure databricks使用external hive metastore跨工作区共享元数据的主要内容,如果未能解决你的问题,请参考以下文章

Azure Data PlatformETL工具(21)——Azure Databricks使用——访问Azure Blob

Azure Databricks - 解释 databricks 中的安装语法

使用 databricks-connect 的 Azure 数据块连接

如何强制 Azure 数据工厂数据流使用 Databricks

使用 Powershell 脚本生成 Azure Databricks 令牌

Azure Databricks 的 Azure DevOps 管道