Gravitino源码分析-SparkConnector 实现原理
Gravitino SparkConnector 实现原理
本文参考了官网介绍,想看官方解析请参考 官网地址 本文仅仅介绍原理
文章目录
- Gravitino SparkConnector 实现原理
- 背景知识-Spark Plugin 介绍
- (1) **插件加载**
- (2) **DriverPlugin 初始化**
- (3) **ExecutorPlugin 初始化**
- (4) **插件执行**
- (5) **插件销毁**
- 背景知识-Driver Plugin 介绍
- (1) **`init` 方法**
- (2) **`registerMetrics` 方法**
- (3) **`onTaskStart` 方法**
- (4) **`onTaskSucceeded` 方法**
- (5) **`onTaskFailed` 方法**
- (6) **`close` 方法**
- SparkConnector使用方式
- 加载spark.sql.catalog.xxx 具体执行的配置
背景知识-Spark Plugin 介绍
spark在[spark-29399]pr提交更新了SparkPlugin插件
SparkPlugin插件执行生命周期
SparkPlugin 的生命周期与 Spark 应用程序的生命周期一致,具体如下:
(1) 插件加载
- 当 Spark 应用程序启动时,Spark 会扫描类路径下的
SparkPlugin实现类。 - 如果插件被正确配置(例如通过
spark.plugins配置项),Spark 会实例化该类。
(2) DriverPlugin 初始化
- Spark 调用
driverPlugin()方法,获取DriverPlugin实例。 DriverPlugin的生命周期开始,其方法(如init、registerMetrics等)会被调用。
(3) ExecutorPlugin 初始化
- Spark 调用
executorPlugin()方法,获取ExecutorPlugin实例。 ExecutorPlugin的生命周期开始,其方法(如init、shutdown等)会被调用。
(4) 插件执行
DriverPlugin在 Driver 端执行自定义逻辑,例如注册指标、拦截 SQL 解析、修改 Catalog 等。ExecutorPlugin在 Executor 端执行自定义逻辑,例如监控 Task 执行、收集指标等。
(5) 插件销毁
- 当 Spark 应用程序结束时,
DriverPlugin和ExecutorPlugin的生命周期结束,其close()方法会被调用以释放资源。
背景知识-Driver Plugin 介绍
DriverPlugin 是用于在 Driver 端执行自定义逻辑的插件,其生命周期方法包括:
(1) init 方法
- 在 Driver 插件初始化时调用。
- 可以在此方法中执行初始化逻辑,例如注册自定义 Catalog、拦截 SQL 解析器等。
(2) registerMetrics 方法
- 在 Driver 插件初始化时调用。
- 可以在此方法中注册自定义指标(Metrics)。
(3) onTaskStart 方法
- 在 Task 启动时调用。
- 可以在此方法中执行与 Task 相关的逻辑。
(4) onTaskSucceeded 方法
- 在 Task 成功完成时调用。
- 可以在此方法中执行与 Task 成功相关的逻辑。
(5) onTaskFailed 方法
- 在 Task 失败时调用。
- 可以在此方法中执行与 Task 失败相关的逻辑。
(6) close 方法
- 在 Driver 插件销毁时调用。
- 可以在此方法中释放资源,例如关闭连接、清理缓存等。
SparkConnector使用方式
./bin/spark-sql -v \
--conf spark.plugins="org.apache.gravitino.spark.connector.plugin.GravitinoSparkPlugin" \
--conf spark.sql.gravitino.uri=http://127.0.0.1:8090 \
--conf spark.sql.gravitino.metalake=test \
--conf spark.sql.gravitino.enableIcebergSupport=true \
--conf spark.sql.warehouse.dir=hdfs://127.0.0.1:9000/user/hive/warehouse-hive
可以看出SparkConnector指定了加载的插件是GravitinoSparkPlugin
public class GravitinoSparkPlugin implements SparkPlugin {@Overridepublic DriverPlugin driverPlugin() {return new GravitinoDriverPlugin();}@Overridepublic ExecutorPlugin executorPlugin() {return null;}
}
可以看出实现方式很简单,仅仅使用了一个GravitinoDriverPlugin,也就是在Spark应用程序启动的时候扫描SparkPlugin扫描到了这个GravitinoSparkPlugin然后立马就去执行GravitinoDriverPlugin初始化程序。在DriverPlugin初始化过程中 插件仅仅覆写了两个函数,init() 和shutdown()。 说明这个插件仅仅做了一些初始化和资源销毁操作。
在Driver端进行初始化
-
配置检查检查gravitino_uri和gravitino_metalake是否配置
-
如果开启了iceberg则将gravitinoDriverExtensions放入到数组中方便配置
-
初始化Gravtino客户端和
GravitinoCatalogManager,并且将relational类型的表加载到缓存中 -
将缓存中的catalog进行如果是非iceberg类型(当前仅仅只有Hive)进行注册,这里定义的注册的实际操作配置Spark的配置项(spark.sql.catalog.catalogName)这里的catalogName对应的是缓存中的catalogName,配置的值为根据Gravitino自己的Catalog使用的Provider进行适配比如可以是(
org.apache.gravitino.spark.connector.hive.GravitinoHiveCatalogSpark33或者org.apache.gravitino.spark.connector.iceberg.GravitinoIcebergCatalogSpark33)具体情况由适配器进行处理。 -
然后注册SqlExtensions其实就是将第2步骤的数组配置到
SPARK_SESSION_EXTENSIONS这个SparkConf配置里面
稍微贴一下注册Catalog代码,比较重要
//初始化的时候调用注册逻辑,将Gravitino中的Catalog加载到缓存//然后将缓存中的数据作为第二个参数gravitinoCatalogs传递进来private void registerGravitinoCatalogs(SparkConf sparkConf, Map<String, Catalog> gravitinoCatalogs) {gravitinoCatalogs.entrySet().forEach(entry -> {String catalogName = entry.getKey();Catalog gravitinoCatalog = entry.getValue();String provider = gravitinoCatalog.provider();if ("lakehouse-iceberg".equals(provider.toLowerCase(Locale.ROOT))&& enableIcebergSupport == false) {return;}try {registerCatalog(sparkConf, catalogName, provider);} catch (Exception e) {LOG.warn("Register catalog {} failed.", catalogName, e);}});}//这里根据适配器去配置spark.sql.catalog.xxx 的具体执行CatalogClassprivate void registerCatalog(SparkConf sparkConf, String catalogName, String provider) {if (StringUtils.isBlank(provider)) {LOG.warn("Skip registering {} because catalog provider is empty.", catalogName);return;}String catalogClassName = CatalogNameAdaptor.getCatalogName(provider);if (StringUtils.isBlank(catalogClassName)) {LOG.warn("Skip registering {} because {} is not supported yet.", catalogName, provider);return;}String sparkCatalogConfigName = "spark.sql.catalog." + catalogName;Preconditions.checkArgument(!sparkConf.contains(sparkCatalogConfigName),catalogName + " is already registered to SparkCatalogManager");sparkConf.set(sparkCatalogConfigName, catalogClassName);LOG.info("Register {} catalog to Spark catalog manager.", catalogName);}
到这里GravitinoConnector的代码机制已经说完了,下面聊聊Spark机制
加载spark.sql.catalog.xxx 具体执行的配置
经过上面GravitinoDriverPlugin的初始化之后,已经将具体的catalog名称和对应的处理类映射起来,这里以GravitinoHiveCatalogSpark33为例。
GravitinoHiveCatalogSpark33这个类继承关系是继承了BaseCatalog 而BaseCatalog是Spark中定义的CatalogPlugin的一个实现类。
Spark在解析SQL的时候会查找catalog对应的Catalog,可以看到调用了CatalogManager.catalog()方法
private object CatalogAndMultipartIdentifier {def unapply(parts: Seq[String]): Some[(Option[CatalogPlugin], Seq[String])] = parts match {case Seq(_) =>Some((None, parts))case Seq(catalogName, tail @ _*) =>try {Some((Some(catalogManager.catalog(catalogName)), tail))} catch {case _: CatalogNotFoundException =>Some((None, parts))}}}
这个catalog方法调用了Catalogs.load()方法
def catalog(name: String): CatalogPlugin = synchronized {if (name.equalsIgnoreCase(SESSION_CATALOG_NAME)) {v2SessionCatalog} else {catalogs.getOrElseUpdate(name, Catalogs.load(name, conf))}}
这个方法才是真正的加载方法,他真正根据conf配置将GravitinoHiveCatalogSpark33名称根据定义的反射构造函数实例化到内存中
def load(name: String, conf: SQLConf): CatalogPlugin = {val pluginClassName = try {val _pluginClassName = conf.getConfString(s"spark.sql.catalog.$name")// SPARK-39079 do configuration check first, otherwise some path-based table like// `org.apache.spark.sql.json`.`/path/json_file` may fail on analyze phaseif (name.contains(".")) {throw QueryExecutionErrors.invalidCatalogNameError(name)}_pluginClassName} catch {case _: NoSuchElementException =>throw QueryExecutionErrors.catalogPluginClassNotFoundError(name)}val loader = Utils.getContextOrSparkClassLoadertry {val pluginClass = loader.loadClass(pluginClassName)if (!classOf[CatalogPlugin].isAssignableFrom(pluginClass)) {throw QueryExecutionErrors.catalogPluginClassNotImplementedError(name, pluginClassName)}val plugin = pluginClass.getDeclaredConstructor().newInstance().asInstanceOf[CatalogPlugin]plugin.initialize(name, catalogOptions(name, conf))plugin} catch {// 省略}}
到这里流程就分析结束了
相关文章:
Gravitino源码分析-SparkConnector 实现原理
Gravitino SparkConnector 实现原理 本文参考了官网介绍,想看官方解析请参考 官网地址 本文仅仅介绍原理 文章目录 Gravitino SparkConnector 实现原理背景知识-Spark Plugin 介绍(1) **插件加载**(2) **DriverPlugin 初始化**(3) **ExecutorPlugin 初始化**(4) *…...
react基本功
useLayoutEffect useLayoutEffect 用于在浏览器重新绘制屏幕之前同步执行代码。它与 useEffect 相同,但执行时机不同。 主要特点 执行时机:useLayoutEffect 在 DOM 更新完成后同步执行,但在浏览器绘制之前。这使得它可以在浏览器渲染之前读取和修改 DOM,避免视觉上的闪烁…...
python-leetcode-解决智力问题
2140. 解决智力问题 - 力扣(LeetCode) 这道题是一个典型的 动态规划(Dynamic Programming, DP) 问题,可以使用 自底向上 的方式解决。 思路 定义状态: 设 dp[i] 表示从第 i 题开始,能获得的最高…...
引领变革!北京爱悦诗科技有限公司荣获“GAS消费电子科创奖-产品创新奖”!
在2025年“GAS消费电子科创奖”评选中,北京爱悦诗科技有限公司提交的“aigo爱国者GS06”,在技术创新性、设计创新性、工艺创新性、智能化创新性及原创性五大维度均获得评委的高度认可,荣获“产品创新奖”。 这一奖项不仅是对爱悦诗在消费电子…...
微信小程序+SpringBoot的单词学习小程序平台(程序+论文+讲解+安装+修改+售后)
感兴趣的可以先收藏起来,还有大家在毕设选题,项目以及论文编写等相关问题都可以给我留言咨询,我会一一回复,希望帮助更多的人。 系统背景 (一)社会需求背景 在全球化的大背景下,英语作为国际…...
wordpress分类名称调用的几种情况
在WordPress中,如果你想调用当前分类的名称,可以使用single_cat_title()函数。以下是一些常见的使用方法和场景: 1. 在分类页面调用当前分类名称 如果你正在分类存档页面(category.php)中,可以直接使用single_cat_title()函数来…...
HMC7043和HMC7044芯片配置使用
一,HMC7043芯片 MC7043独特的特性是对14个通道分别进行独立灵活的相位管理。所有14个通道均支持频率和相位调整。这些输出还可针对50 Ω或100 Ω内部和外部端接选项进行编程。HMC7043器件具有RF SYNC功能,支持确定性同步多个HMC7043器件,即确保所有时钟输出从同一时钟沿开始…...
html播放本地音乐
本地有多个音乐文件,想用 html 逐个播放,或循环播放,并设置初始音量。 audio 在 html 中播放音乐文件用 audio 标签: controls 启用控制按钮,如进度条、播放、音量、速度等。不加不显示任何 widget。autoplay 理应启…...
Windows11下玩转 Docker
一、前提准备 WSL2:Windows 提供的一种轻量级 Linux 运行环境,具备完整的 Linux 内核,并支持更好的文件系统性能和兼容性。它允许用户在 Windows 系统中运行 Linux 命令行工具和应用程序,而无需安装虚拟机或双系统。Ubuntu 1.1 安…...
vLLM + Open-WebUI 本地私有化部署 DeepSeek-R1-Distill-Qwen-32B 方案
一、vLLM 部署 DeepSeek-R1-Distill-Qwen-32B DeepSeek-R1-Distill 系列模型是 DeepSeek-R1 的蒸馏模型,官方提供了从 1.5B - 70B 不同尺寸大小的模型。特别适合在计算资源有限的环境中部署。 DeepSeek-R1 各个版本的蒸馏模型评估结果如下: 其中 DeepS…...
【基础知识】回头看Maven基础
背景 项目过程中,对于Maven的pom.xml文件,很多时候,我通过各种参考、仿写,最终做出想要的效果。 但实际心里有些迷糊,不清楚具体哪个基础的配置所实现的效果。 今天,特意回过头来,了解Maven的基…...
在 MyBatis 中,若数据库字段名与 SQL 保留字冲突解决办法
在 MyBatis 中,若数据库字段名与 SQL 保留字冲突,可通过以下方法解决: 目录 一、使用转义符号包裹字段名二、通过别名映射三、借助 MyBatis-Plus 注解四、全局配置策略(辅助方案)最佳实践与注意事项 一、使用转义符号…...
docker-compose Install reranker(fastgpt支持) GPU模式
前言BGE-重新排名器 与 embedding 模型不同,reranker 或 cross-encoder 使用 question 和 document 作为输入,直接输出相似性而不是 embedding。 为了平衡准确性和时间成本,cross-encoder 被广泛用于对其他简单模型检索到的前 k 个文档进行重新排序。 例如,使用 bge 嵌入模…...
200W数据需要去重,如何优化?
优化去重逻辑的时间取决于多个因素,包括数据量、数据结构、硬件性能(CPU、内存)、去重算法的实现方式等。以下是对优化去重逻辑的详细分析和预期优化效果: 1. 去重逻辑的性能瓶颈 时间复杂度:使用HashSet去重的时间复…...
使用免费IP数据库离线查询IP归属地
一、准备工作 1.下载免费IP数据库 首先,访问 MaxMind官网(https://www.maxmind.com/en/home)如果你还没有MaxMind账号,可以通过此链接地址(https://www.maxmind.com/en/geolite2/signup)进行账号注册&…...
【游戏】【客户端性能测试】
待续… 一、 常见指标 1. 越高越好 FPS 2. 越低越好 网络流量CPU内存(PSS, momo)Drawcalls三角形数耗电量包体大小 二、 游戏体验 1. 直接体感 游戏花屏闪退卡顿延迟 2. 可能原因 内存超标Drawcall数量多FPS波动严重CPU占用高居不下…...
软考中级-数据库-3.3 数据结构-树
定义:树是n(n>=0)个结点的有限集合。当n=0时称为空树。在任一非空树中,有且仅有一个称为根的结点:其余结点可分为m(m>=0)个互不相交的有限集T1,T2,T3...,Tm…,其中每个集合又都是一棵树,并且称为根结点的子树。 树的相关概念 1、双亲、孩子和兄弟: 2、结点的度:一个结…...
typora高亮方案+鼠标侧键一键改色
引言 在typora里面有一个自定义的高亮, <mark></mark>>但是单一颜色就太难看了, 我使用人工智能, 搜索全网艺术家, 汇集了几种好看的格式,并且方便大家侧键一键 调用, 是不是太方便啦 ! 示例 午夜模式 春意盎然 深海蓝调 石墨文档 秋日暖阳 蜜桃宣言 使用方法 …...
【CSS】Tailwind CSS 与传统 CSS:设计理念与使用场景对比
1. 开发方式 1.1 传统 CSS 手写 CSS:你需要手动编写 CSS 规则,定义类名、ID 或元素选择器,并为每个元素编写样式。 分离式开发:HTML 和 CSS 通常是分离的,HTML 中通过类名或 ID 引用 CSS 文件中的样式。 示例&#…...
Linux(Centos 7.6)命令详解:vim
1.命令作用 vi/vim 是Linux 系统内置不可或缺的文本编辑命令,vim 是vi 的加强版本,兼容vi 的所有指令,不仅能编辑文本,而且还具有shell 程序编辑的功能,可以不同颜色的字体来辨别语法的正确性。 2.命令语法 usage: …...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...
铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...
Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...
Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...
Caliper 配置文件解析:fisco-bcos.json
config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...
