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

发布时间 2023-03-31 12:00:15作者: John.Xiong

image-20230330123458853

为什么要使用external hive metastore

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

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

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

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

    image-20230330113713032

    image-20230330113747426

    image-20230330113652807

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

实现环境

azure china

创建azure SQL

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

image-20230330114920046

image-20230330114942835

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

image-20230330115240732

image-20230330115346953

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

步骤2:配置网络和private endpoint

image-20230330120126120

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

image-20230330120207132

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

image-20230330121831787

image-20230330214319263

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

image-20230330122015966

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

image-20230330231628222

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

image-20230330214559650

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

创建hive metadata元数据

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

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

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

image-20230330123959664

步骤2:执行建表语句

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

image-20230330124302443

image-20230330124644361

步骤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]

image-20230330214734559

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

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

EXEC sp_addrolemember 'db_owner', 'hivedbadmin';

image-20230330214821693

验证登录

如果服务器禁止了公网访问,则需要添加白名单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级别是独立的

image-20230330145350604

image-20230330215044153

image-20230330215100955

databricks集群配置

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

image-20230330145605355

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

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

image-20230330151251684

image-20230330151423733

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

image-20230330220038737

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

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

image-20230330223805823

 %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'")

查询数据

image-20230330234222766

image-20230330234559702

view也不会乱码

image-20230330234305318

在第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时候会报错,报路径不存在。

image-20230331001029412

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

正确在space2读取到数据

image-20230331001636261

最后把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)

image-20230331013404575

image-20230331013501045

遇到的错误

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下载后按照上面的来配置。