百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

火山引擎基于 Zeppelin 的 Flink/Spark 云原生实践

csdh11 2025-02-08 10:42 23 浏览

本文整理自火山引擎云原生计算研发工程师陶克路、王正在 ApacheCon Asia 2022 上的演讲。文章主要介绍了 Apache Zeppelin 支持 Flink 和 Spark 云原生实践。

作者|火山引擎云原生计算研发工程师-陶克路、火山引擎云原生计算研发工程师-王正


Apache Zeppelin 介绍

Apache Zeppelin 是一个支持 20 多种语言 Notebook 的后端,可以用于数据摄入、发现、转换及分析,也能够实现数据的可视化,如饼图、柱状图、折线图等。

典型使用场景是通过开发 Zeppelin 的代码片段或者 SQL,通过提交到后端实现实时交互,并通过编写 Notebook 的 Paragraph 集合,借助调度系统实现定时调度任务。

Zeppelin 的技术架构包含三个部分:Client、Server 和 Interpreter。Client 和 Server 通过 Restful 接口或 WebSocket 接口进行交互,Interpreter 解释器则是一个独立于 Zeppelin Server 的进程,在 K8s 环境上面拥有独立的 POD 和环境信息。

Apache Zeppelin 的云原生实践

Apache Zeppelin 的云原生实践包含五个部分:

  • Docker 镜像优化:开源 Zeppelin 包含了较多的解释器,在火山引擎的实践过程中,我们通过裁剪只包含 Flink 和 Spark 的部分,同时利用 Docker 镜像的多阶段构建技术,达到镜像缩小、体积缩小的目的,实现镜像层数的缩减;
  • 元数据存储:Zeppelin 包含多种元数据,其中重要的元数据 Notebook 可以支持本地文件的存储、远程存储、对象存储等;在扩展之后能够支持火山引擎 TosNotabookRepo 的对象存储;另外一种存储则需要借助 K8s 里的 Persistent Volume 机制,将一块磁盘/云盘,映射成固定的 Volume 挂载到 POD 内部实现自动/手动的存储;
  • 跨 Namespace 提交作业:Namespace 在 K8s 中的实现机制为逻辑隔离但底层 Node 共享,我们以此实现单租户/多租户不同子账号之间的隔离及资源的不互通;通过支持 Zeppelin 跨 namespace 提交作业的功能来用户功能的完整性;
  • RBAC 权限:RBAC 权限也是 K8s 提供的权限机制,包含:实体、权限和权限的关联。K8s 的权限可以分为两种:分别是在 Namespace 内部的权限和跨 Namespace 资源的权限,跨 Namespace 资源的权限需要通过 Cluster Role 先进行权限的声明,并与 ServiceAccount 绑定后实现;


  • SSO 单点登录:在集成 Zeppelin 后,用户使用作业平台时已经产生过登录的动作,再次登陆Zeppelin对用户的使用体验很不友好。所以基于 Shiro 做相应的扩展,通过增加 Shiro Plugin 共享 JWT Token 的方式避免用户二次登录,提升用户使用体验。

基于 Zeppelin 的 Flink 云原生实践

Flink on K8s 的工作原理

目前 Flink on K8s 主要有两种工作方式:

  • Standalone:在提交作业之前,先使用 K8s 的 Deployment 方式将 Flink Cluster 部署启动,启动之后再进行作业的提交。这种方式主要的弊端在于在运行作业之前需要预先申请所有的资源,由于整体资源是固定的,所以如果对于作业使用的资源预估不准确,就会造成资源浪费或资源不足,从而导致作业无法执行成功。
  • Native K8s:Native K8s 和 Standalone 方式最大区别是借助 Flink 里的 ResourceManager 请求资源进行按需创建。目前 Flink 的 Native K8s 支持两种方式:Session 和 Application。
  • Session:Flink 自身支持的集群方式。
  • 首先,启动一个 Session 集群,然后进行作业的提交。
  • 第二步,启动 SVC、Deployment、ConfigMap,包括另外一个 SVC,通过外部网络进行访问。这一步启动的资源中并不包含 TaskManager,后续的 TaskManager 需要按需申请。
  • 第三步,用户通过 Flink Client 提交作业,通过 Flink Client 中内置的 K8s Client 找到相应 Session 集群的 Endpoint,并计算程序所需的资源, K8s APIServer 创建 TaskManager 后,TaskManager 将心跳注册到 JobManager 的 ResourceManager 里面,最终在 TaskManager 上进行作业的提交和运行。
  • Session 集群的使用主要用于共享资源,主要在测试环境使用的比较多,这种方式的优势在于资源使用率较高。
  • Application:Flink 在 1.11 版本前的作业,JobGraph 的编译等操作都是在客户端进行的,这种模式会造成 client 所在机器负载高、网络压力大、CPU 资源不足等问题,所以 1.11 版本 Flink 推出了 Application Mode 的方式,主要将 Main 的 Job 生成操作放到 JobManager 中,由此 Flink Client 所需承担的操作就变得相对简单,不需要再承担上述额外的操作,即 Application 模式是不需要提前创建作业的。
  • 具体的步骤可以简述为用户首先通过 Flink Client 提交到指定 Target IP 的 K8s,然后 Client 通过内置的 K8s 的 Client 找到 K8s APIServer,再通过创建该作业必需的 Job Manager 资源并传输到 Job Manager 里面,由此实现了资源的申请。
  • Application 模式相比 Session 最大的一个区别就是 Application 模式下每个作业对应一个Flink class,相对应的作业完成后,Flink class 就会进行销毁,资源使用率没有 Session 模式高,但是隔离性会更好,所以在生产上也推荐使用 Application 模式。

Flink on Zeppelin 的工作原理

Flink on Zeppelin 的工作基本都是用解释器实现的,Flink 的解释器大体上可分为两种,FlinkCmd 解释器和其他 Flink 解释器。

  • FlinkCmd 解释器顾名思义就是用命令行的方式提交 Flink 程序;
  • 另外一种也是较为常用的解释器,是 %Flink 的解释器,它的运行方式和 FlinkCmd 解释器区别较大,用户提交代码之后会启动一个 Flink Cluster,是由 Zeppelin 提供的 Main Jar,并进行交互操作,将用户的代码提交给 TM 后返回结果,这种方式和 Session 模式的区别是集群资源固定,即 JM、TM 的数目和所使用的资源是固定的,无法根据 TM 代码的执行情况动态调整,用户也无法指定资源。

Flink on Zeppelin 的功能增强

火山引擎对 Flink on Zeppelin 进行了功能增强,主要有以下几个方面:

  • 支持 Native K8s 模式
  • Flink UI 透出:支持 Ingress / NodePort 类型;Node Port 适用于私有云相关的场景,比如可以通过 Node 的 IP 和端口直接访问 Flink UI。 Ingress 模式由 Main Class 在运行中创建 Ingress 路由,用户的请求通过 Ingress 请求到对应的 Flink 的 Cluster,整个 Ingress 的生命周期是和 Flink 的 Cluster 中的 Deployment 绑定的。在相应的 Flink Cluster 结束后,对应的 Ingress 也会被销毁掉。
  • Jar 功能增强Zeppelin 原生支持用 Flink UDF 依赖的 Jar 包。这些 Jar 包可以存储到本地或 HDFS 中,但云原生场景通常不会使用本地存储的内容,对此我们做了相应的增强:支持引用 http / https 资源;支持引用 S3 协议的存储资源,因为在云上的存储大部分都会用支持 S3 协议的对象存储,比如 AWS 的 S3、阿里云的 OSS、火山引擎的头条 TOS等,所以在此做增强后可以在执行时支持动态下载远程的 Jar 包。
  • 支持 HiveCatalog 原生的 SQL 模式,用于实现元数据的复用。
  • 支持跨 Namespace 提交作业原始的 Namespace 隔离了一些权限和资源,每个 Namespace 拥有单独的 Quota;在 K8s 场景下,Zeppelin 可以运行在一个 Namespace 中,然后将作业启动在其他的 Namespace 中,由此支持跨 Namespace 提交作业。
  • 支持镜像外的 Main Jar 提交在原始的 Flink 的 Application 模式下,用户需要提交的 Image 当中包含运行的 Main Jar,因此每个用户每提交一段代码都需要提交一个 Image,不仅操作繁琐,还会占用整个集群当中过多的存储资源,后续对于 Image 的升级也是一个难点。所以,我们通过支持镜像外的 Main Jar 的提交,将相关的参数提交到远端的一个存储上,Flink 运行的时候先进行下载,然后通过找到镜像里的 Main Jar 的方式找到一个本地的 Jar 包进行执行,从而解决无法引用外部资源的问题。
  • 运维增强日志:基于 Log4j 的 Logappender 实现,相当于在使用 Logappender 时将 Flink 的所有日志输出到远端的日志系统中,用户就无需登录到 Pod 或者用 Flink UI 来看日志了。指标收集:对接 Prometheus。Flink 运维的指标非常多,所以通过对接 Prometheus 的方式,实现将指标推送到远端,自行收集指标的能力。

基于 Zeppelin 的 Spark 云原生实践

Spark on K8s 工作原理

Spark 在 K8s 上的工作原理和 Flink 的 Application 模式类似,用户提交指令给 K8s APIServer 后,创建对应的 Driver Pod 和 ConfigMap。 Driver Pod 运行相应的程序,根据代码需求向 K8s Master 发送请求申请Executor Pod资源。 Executor Pod创建完毕后开始执行任务,执行完毕后最终销毁。

同样 Spark on Zeppelin 的工作也都是基于解释器实现的。

  • 第一种使用 SparkSubmit 解释器,通过命令行执行来实现运行,用户每运行完指令后就会启动一个 Spark 的 Cluster 用来执行任务;
  • 第二种解释器也和 Flink 的类似,通过在 Spark Pod 中运行的 Main Jar 发现对应的 Code 从而提交给对应的 Executor Pod 进行执行,执行完成后将结果返回给 Spark 解释器,同样此类解释器也是共用一个 Cluster 进行生命周期的管理。

Spark on Zeppelin 的功能增强

火山引擎同样对 Spark on Zeppelin 进行了功能增强,主要有以下几个方面:

  • 支持 K8s Native 模式:在运行的基础上支持 KV 存储,用 TOS 作为远端 Jar 包或资源的存储;
  • K8s 模式下透出 Spark UI:使用 NodePort / Ingress 实现透出,通过创建 Service 和 Ingress 绑定到对应的 Driver Port 上也可以实现对应资源的销毁;
  • 支持 Hive Catalog
  • 垃圾回收:Zeppelin 原生的 Spark 会把所有创建的 Owner Reference 设置为 Zeppelin Server。而 Zeppelin Server 会一直运行导致所有的资源都无法被删除,将 Spark 相关 Job 的 OwnerReference 修改为 Driver Pod 的形式就可以实现对资源的销毁,从而提高资源使用的利用率。

目前,火山引擎流式计算 Flink 版(
https://www.volcengine.com/product/flink)、
火山引擎批式计算 Spark 版(
https://www.volcengine.com/product/spark)
已正式上线公测,支持云中立模式,支持公共云、混合云及多云部署,全面贴合企业上云策略,欢迎技术交流或申请试用 「链接」

相关推荐

探索Java项目中日志系统最佳实践:从入门到精通

探索Java项目中日志系统最佳实践:从入门到精通在现代软件开发中,日志系统如同一位默默无闻却至关重要的管家,它记录了程序运行中的各种事件,为我们排查问题、监控性能和优化系统提供了宝贵的依据。在Java...

用了这么多年的java日志框架,你真的弄懂了吗?

在项目开发过程中,有一个必不可少的环节就是记录日志,相信只要是个程序员都用过,可是咱们自问下,用了这么多年的日志框架,你确定自己真弄懂了日志框架的来龙去脉嘛?下面笔者就详细聊聊java中常用日志框架的...

物理老师教你学Java语言(中篇)(物理专业学编程)

第四章物质的基本结构——类与对象...

一文搞定!Spring Boot3 定时任务操作全攻略

各位互联网大厂的后端开发小伙伴们,在使用SpringBoot3开发项目时,你是否遇到过定时任务实现的难题呢?比如任务调度时间不准确,代码报错却找不到方向,是不是特别头疼?如今,随着互联网业务规模...

你还不懂java的日志系统吗 ?(java的日志类)

一、背景在java的开发中,使用最多也绕不过去的一个话题就是日志,在程序中除了业务代码外,使用最多的就是打印日志。经常听到的这样一句话就是“打个日志调试下”,没错在日常的开发、调试过程中打印日志是常干...

谈谈枚举的新用法--java(java枚举的作用与好处)

问题的由来前段时间改游戏buff功能,干了一件愚蠢的事情,那就是把枚举和运算集合在一起,然后运行一段时间后buff就出现各种问题,我当时懵逼了!事情是这样的,做过游戏的都知道,buff,需要分类型,且...

你还不懂java的日志系统吗(javaw 日志)

一、背景在java的开发中,使用最多也绕不过去的一个话题就是日志,在程序中除了业务代码外,使用最多的就是打印日志。经常听到的这样一句话就是“打个日志调试下”,没错在日常的开发、调试过程中打印日志是常干...

Java 8之后的那些新特性(三):Java System Logger

去年12月份log4j日志框架的一个漏洞,给Java整个行业造成了非常大的影响。这个事情也顺带把log4j这个日志框架推到了争议的最前线。在Java领域,log4j可能相对比较流行。而在log4j之外...

Java开发中的日志管理:让程序“开口说话”

Java开发中的日志管理:让程序“开口说话”日志是程序员的朋友,也是程序的“嘴巴”。它能让程序在运行过程中“开口说话”,告诉我们它的状态、行为以及遇到的问题。在Java开发中,良好的日志管理不仅能帮助...

吊打面试官(十二)--Java语言中ArrayList类一文全掌握

导读...

OS X 效率启动器 Alfred 详解与使用技巧

问:为什么要在Mac上使用效率启动器类应用?答:在非特殊专业用户的环境下,(每天)用户一般可以在系统中进行上百次操作,可以是点击,也可以是拖拽,但这些只是过程,而我们的真正目的是想获得结果,也就是...

Java中 高级的异常处理(java中异常处理的两种方式)

介绍异常处理是软件开发的一个关键方面,尤其是在Java中,这种语言以其稳健性和平台独立性而闻名。正确的异常处理不仅可以防止应用程序崩溃,还有助于调试并向用户提供有意义的反馈。...

【性能调优】全方位教你定位慢SQL,方法介绍下!

1.使用数据库自带工具...

全面了解mysql锁机制(InnoDB)与问题排查

MySQL/InnoDB的加锁,一直是一个常见的话题。例如,数据库如果有高并发请求,如何保证数据完整性?产生死锁问题如何排查并解决?下面是不同锁等级的区别表级锁:开销小,加锁快;不会出现死锁;锁定粒度...

看懂这篇文章,你就懂了数据库死锁产生的场景和解决方法

一、什么是死锁加锁(Locking)是数据库在并发访问时保证数据一致性和完整性的主要机制。任何事务都需要获得相应对象上的锁才能访问数据,读取数据的事务通常只需要获得读锁(共享锁),修改数据的事务需要获...