【无标题】

2023-09-20 15:24:09

更多技术交流、求职机会,欢迎关注字节跳动数据平台微信公众号,回复【1】进入官方交流群

背景介绍

Notebook 解决的问题

  1. 部分任务类型(python、spark等)在创建配置阶段,需要进行分步调试;
  2. 由于探索查询能力较弱,部分用户只能通过其他平台 or 其他途径进行开发调试,但部署到 Dorado时,又发现行为不一致等问题(运行环境问题),整体体验较差,需要提升探索查询模块的能力;
  3. 目前探索查询仅支持 SQL,可支持更多语言类型,扩展数据开发手段;

总体架构介绍

火山引擎DataLeap notebook 主要是基于 JupyterHub、notebook、lab、enterprise kernel gateway 等开源项目实现,并在这些项目的基础上进行深度修改与定制化,以满足 火山引擎DataLeap用户的需求。

基础组件方面,主要是基于 TCE、YARN、MYSQL、TLB、TOS。

核心目标是提供支持大规模用户、稳定的、容易扩展的 Notebook 服务。

系统总体架构如下图所示,主要包括 Hub、notebook server(nbsvr)、kernel gateway(eg) 等组件。

在这里插入图片描述

多用户管理

Hub

JupyterHub 是一个支持 “多用户” notebook 的 Server,通过管理 & 代理多个单用户的 notebook server 实现多用户 notebook。

JupyterHub 服务主要三个组件构成:

  • a Hub (tornado process), which is the heart of JupyterHub;
  • a configurable http proxy (node-http-proxy): 动态路由用户的请求到 Hub 或者 Notebook server;
  • multiple single-user Jupyter notebook servers (Python/IPython/tornado) that are monitored by Spawners;
  • an authentication class that manages how users can access the system;

整个系统架构图如下所示:

在这里插入图片描述

用户通过 IP 地址或者域名访问 JupyterHub,基本流程为:

  • 启动 Hub 服务,Hub 会启动 proxy 进程;
  • 用户请求 Hub,请求会被打到 proxy,proxy 维护了 proxy table,每条 mapping 记录为用户请求到 target IP 或者 域名的映射;proxy table 不存在当前请求的 mapping 时,proxy 默认把请求全部打到 Hub;
  • Hub 处理用户认证与鉴权,同时 Hub spawner 启动一个 Notebook server;
  • Hub 配置 proxy,路由该该用户的请求到创建的 notebook server 处;

1、火山引擎DataLeap authentication Hub 原生地支持 authentication,主要是用来解决多租户的问题。Hub 里主要是使用 authenticator 类来进行 authenticate 。

Hub 原生支持的 authenticator 主要有一下几个:

  • Local authenticator, work with local Linux/UNIX userst
  • PAM authenticator, authenticate local UNIX users with PAM
  • Dummy authenticator, any username + password is allowed for testing

考虑到方案1需要开发量大、维护成本高,我们采用了方案2。

采用了方案2的整个认证 & 鉴权步骤如下所示:

  1. 用户在 web 页面访问了 火山引擎DataLeap notebook,frontend 会带上 session 信息请求 hub post /api/users/{name}/tokens api 获取一个 token,该流程需要 authenticate & authroization,包括:
  2. 通过 titan 认证该 sessionid 对应的 user;
  3. 通过 火山引擎DataLeap backend ProjectControl /project/canedit api 验证用户是否具有项目权限;
  4. 后续该用户的访问均会带上 token,Hub 会使用该 token 进行用户认证。
  5. 每次生成的 token 会保存到 db;
  6. 认证时也是从 db 进行匹配;
  7. Token 存在 expire time,expired 的会被从 db 清理掉;

2、TCE Spawner Spawner 负责启动 single-user notebook server,其本质是一个进程的抽象表示,一个定制化的 spawner 实现下面三个方法:

目前我们的服务不是运行在物理机上,所以不会通过 k8s 管理 server & kernel。考虑到运维 & 扩展,我们考虑使用 TCE 作为 notebook server 的载体,因此我们需要实现 TCE Spawner。

设计 TCE spawner 时,有以下几点考虑:

  1. Spawner.state 需要包含 service id、cluster id、psm、api token 等信息,这些信息会持久化在 db 中;hub 重启 或者 server 关闭后,重新启动 notebook server 时,保证同一个用户映射到之前该用户启动的那个 sever(same user same server);
  2. 为了加快启动过程,spawner 确认 tce 实例启动时,一旦发起了 tce cluster deployment 后就开始 sd lookup psm 确认 server 是否正常启动,不通过 poll deployment status 确认是否部署完成,这可以加快启动过程,因为 tce 部署过程中包括健康检查等步骤,占时较长;
  3. Stop 中,并不真正 kill tce 实例,这样下次启动基本不消耗时间;
  4. Poll server 状态时,需要考虑 升级 & migrate 带来的状态变化,一旦发现立刻返回 异常状态,这样 hub 就会认为这个 notebook server not running,就会异常 该 spawner,后续新的请求到来时会重新启动 spawner,由于此时已经非第一次启动,过程极快,用户不感知。

整个 TCE spawner,主要用到了 tce 的两个特性:

  • Psm 唯一对应了一个服务;
  • 通过 psm 发现 ip & port;
  • 通过 tce 的 api 获取 server 状态;
  • 方便运维(升级 & 迁移);

题外话: 最近调研了 server on yarn ,有点类似 k8s 的感觉,本质上都是走资源调度,但是 yarn 资源调度有个缺点:每个 application 调度到 yarn 时,都需要伴随一个 Application Master。虽然 AM 大多数时候主要是用来和 RM 保持心跳,只需要 0.5 核即可,但是总感觉很别扭,或者说多了一个不稳定的因素。

3、State isolated

(1) Hub migration

原生 jupyter hub 的升级或者实例迁移时,需要把所有的 spawner & server 关闭掉。这意味着,hub 实例变化后,之前的 server & kernel 都会被关闭。

由于当前系统采用了 remote server + remote kernel,且不会主动 shutdown kernel,因此当 hub 实例发生变化时, server & kernel 实例不会被关闭。但是新 hub 实例启动后,所有的 server 都将连接不到新的 hub 实例上,会产生幽灵 server & kernel。

我们提供了如下解决方案:

  1. 在 notebook server 里增加定时检查线程,根据 hub 的 psm 检查对应的 ip & port 是否发生改变;
  2. 如果发生改变,则切换 hub_activity_url & hub_api_url。如此,notebook server 就可以连接到新的 hub 实例了。

(2) Notebook server migration

如果 notebook server 实例升级或者迁移了,hub 也需要能及时感知,并能正确关闭 spawner。

这个目前是通过 tce spawner poll 实现,poll 里会 check 对应的 notebook server 的 ip & port 是否发生变化,如果发生了变化则返回非零状态,表示 server 异常,此时 hub 感知到并关闭 spawner。后续,用户的请求到来时,会重新创建 spawner 并连接到同一个 notebook server。

Resource pool

Pool 的设计有两个考虑:

  • Tce 资源无法独占;
  • Server 启动慢;

由于 notebook server 是启动在 TCE 上的,TCE 上启动一个 server 需要经历如下几个关键阶段: 新建 service -> 新建 cluster -> 部署(构建镜像、部署)-> 一些检查 整个过程耗时较长,预计耗时3-5分钟,如果每个 server 的启动过程都需要这么久,显然是无法接受的。

于是,我们申请了新建了一堆 tce 实例构建成 tce resource pool。每次新项目接入,Hub spawner 按照如下流程处理:

  • 去 tce resource pool 中检查是否存在未被占用的实例,有则挑一个
  • 否则,走原新建流程;

目前 pool 的建立是手动操作的,后期会支持自动检测扩容:

  • 定时线程,检测当前 pool 的容量是否少于 30 (例如);
  • 少于则新建并加入 pool 中;

另一个问题是:pool 里的每个实例均需要支持 psm 服务发现,那么在 server 被分配前,他们处于什么状态呢?被分配后,如何按照 user 对应的配置启动 server 呢? Pool 里的实例,均是启动了一个 idle server(原生的 notebook server)(该方式可以让该实例成功启动,并且能被服务发现),同时存在一个定时线程,不断去检查 tos 对应的配置文件是否 ready,ready 后 shutdown idle server,按照 tos 配置文件启动 single user notebook server。

这种方式后,启动时间从 3min+ 降到 8s,8s 为 single user notebook server 启动并稳定提供服务的时间。

Kernel 管理

book 存储

Notebook 中的代码和输出文本主要是通过后缀为 .ipynb 的 json 文件存储的,因此 notebook server 需要负责 ipynb 文件的新建、删除等管理。

Notebook server 对 notebook 的存储是通过 FileManager 来实现的,FileManager 主要负责 ipynb 的创建、保存、删除、重命名等文件操作,另外还会进行 ipynb 文件的 format 检查以保证格式正确。

FileManger 保存文件是通过 local filesystem 实现的。为了持久化存储 ipynb 文件,我们在 FileManager 中嵌入了 tos 文件存储的功能。具体过程为:

  1. 首次创建时,在本地生成 ipynb 后,并往 tos 上 put 一份;
  2. 每次更新保存时,在本地更新后往 tos put 一份;
  3. 每次打开 ipynb 时,首先判断本地是否存在对应的 ipynb 文件,如果不存在则从 tos 拉取;如果存在则不做拉取操作;
  4. 删除操作只是删除了本地的文件,没有删除 tos 的那份。

kernel 管理

当我们在页面上打开一个 notebook 任务时,notebook server 会尝试启动一个 kernel 来执行你点击运行的代码。火山引擎DataLeap上每个 task 都和一个 kernel 对应,notebook server 负责维护每个任务的 kernel。

Notebook server 是通过 KernelManager 来维护 kernel 信息的,KerneManager 负责 kernel 的启动、重启、删除等操作。

默认情况下,Kernel 是启动在 notebook server 所在的运行容器里,这种情况下单个 server 里无法支撑起大规模 kernel。

代理

如上一节所述,notebook server local 模式不支持大规模 kernel 的扩展,适用于小范围使用,主要原因有如下两点;

  • kernel 都是在 notebook server host 内启动的,单机必然无法容纳大规模 kernel ;
  • Kernel 间没有隔离,只是进程间的隔离,资源 & 执行环境等没有很好的隔离与定制化;

Enterprise kernel gateway (简称 EG)主要致力于解决上述问题,采用了 EG 的系统架构如下所示:

在这里插入图片描述

技术上来讲,EG 部分扩展了 notebook server 的功能,然后作出了如下改动:

  • 复用 notebook server 中的 API (kernel 管理部分);
  • 提供了 WS 的管理;
  • 基于 notebook server 中 MultiKernelManager & KernelManager & SessionManager,做出扩展,提供了 RemoteMappingKernelManager;

从图中可以看出,client 并非是 notebook 相关的系统,也可以是其他系统,这意味着可以直接把 EG 当成 Code Execution Server,只需要其 ws client 遵循 Jupyter msg protocol。

代理架构

在 火山引擎DataLeap notebook 系统中,上图中的 client 即为 notebook server,此时 notebook server 只负责管理 notebook 文件(创建、读写、保存、删除),kernel 部分的操作全部转发给 EG 进行处理(注意这里的转发包含 http 转发与 ws 转发)。详细如下图所示:

在这里插入图片描述

用户在浏览器运行一段代码,整个交互流程如下图所示:

在这里插入图片描述

EG proxy 的详细过程参考:

在这里插入图片描述

当前 EG 支持往 yarn、k8s 等业界常用资源管理系统提交 kernel 。 我们当前只支持 remote kernel on yarn ,后续考虑支持 k8s。

远程 Kernel

1、Remote kernel on yarn

开源 EG 往 yarn 上提交任务主要是使用 yarn_client,该 client 基于 yarn rm restful api 进行资源探查 & 任务的提交 & 状态轮询 & kill 等操作。公司内并非开放相应的 rest api,因此需要基于 YAOP 进行相应的改造。

2、Kernel configuration

开源 EG 往 yarn 上提交任务暂不支持指定动态参数,比如队列选择、镜像选择等等 yarn 参数。 我们进行了简单的改造,可以支持用户设置更为丰富的 yarn 参数,来定制个性化执行环境。

3、Async

开源社区的版本没有完全异步化,为了单 eg server 支持更多的 kernel,我们做了完全的异步化改造。 优化前,只能支持 10+ kernel,优化后,能够支持 100+ kernel(上限没具体测试过)。

4、image

支持用户选择自定义镜像启动 kenrel,该特性支持用户在 kernel 中安装自己需要的环境,极大地提高了 kernel 使用的场景。

定时调度

调度原理

Notebook 调度执行不同于每个 cell 里的人工调试执行,它需要定时自动执行,每次都是直接 run all cell,并且把执行结果保存在 notebook 里。

Jupyter 提供了可以直接执行一个 ipynb 文件的工具:nbconvert。nbconvert 会根据 ipynb 里的 kernel 信息启动对应的 kernel 来执行 ipynb 里的每个 cell,其本质上执行了 notebook kernel 启动 + run each cell 的功能。

但是 nbconvert 只能启动 local kernel,而目前系统是 remote kernel on yarn,这可以通过把 nbconvert 提交到 yarn 上,然后在 yarn 上运行上述过程。当然,这其中涉及到了 pyspark 任务的提交原理,总的来说,notebook 任务具备和 dorado 上其他任务一样的定时调度功能。

更多特性

1、Version control 支持 notebook 的版本控制。

2、Workflow debug 工作流支持 notebook 任务,并且支持整体调试。

3、Parameterized 支持 notebook 参数化。

4、Executed notebook view 支持定时调度运行结果展示。

结束语

Jupyter Notebook 诞生至今,已数年有余,期间不断出现 Zeppelin、PolyNote、Deepnote。尽管如此, Jupyter Notebook 仍然拥有最大量的用户群体与比较完整的技术生态,因此我们选择了 Jupyter Notebook 做深度定制与改造来服务用户。

当前 火山引擎DataLeap Notebook 已经基本具备了离线数据探索的能力,这些能力已经帮助了很多用户更好的进行数据探索、任务开发调试、可视化等。随着平台对流式数据开发的支持,我们也希望借助 Notebook 实现用户对流式数据的探索、流式任务的调试、可视化等功能的需求。相信不久的将来,Notebook 能够实现流批一体化,来服务更加广泛的用户群体。

点击跳转大数据研发治理套件 DataLeap了解更多

更多推荐

数据分享|R语言逻辑回归、线性判别分析LDA、GAM、MARS、KNN、QDA、决策树、随机森林、SVM分类葡萄酒交叉验证ROC...

全文链接:http://tecdat.cn/?p=27384在本文中,数据包含有关葡萄牙“VinhoVerde”葡萄酒的信息(点击文末“阅读原文”获取完整代码数据)。介绍该数据集(查看文末了解数据获取方式)有1599个观测值和12个变量,分别是固定酸度、挥发性酸度、柠檬酸、残糖、氯化物、游离二氧化硫、总二氧化硫、密度、

【运维篇】二、配置文件与多环境控制

文章目录1、临时属性2、IDEA中的临时属性3、配置文件4级分类4、关于四级分类的思考5、自定义配置文件6、多环境开发(yaml版)7、配置文件按环境分类8、include与group再细粒度9、一点思考10、多环境开发兼容问题1、临时属性jar包或者镜像已经打完了,想修改下服务的配置,如何实现?⇒临时属性如修改服务的

JavaScript深入理解JSON.stringify

🎬岸边的风:个人主页🔥个人专栏:《VUE》《javaScript》⛺️生活的理想,就是为了理想的生活!目录引言1.JSON.stringify()属性replacerspacetoJSON2.应用场景数据传输数据存储日志记录数据展示3.完整优雅的实现4.注意事项循环引用特殊类型性能优化总结引言在JavaScript

Android编译snowboy

一、Ubuntu安装git1.打开终端在Ubuntu系统中,我们可以使用终端输入命令进行操作。打开终端的快捷键为Ctrl+Alt+T。2.安装Git在终端中输入以下命令,即可开始安装Git。sudoapt-getinstallgit登录后复制安装过程中需要输入管理员密码,安装完成后,终端会输出Git的版本号等信息。3.

将近 5 万字讲解 Python Django 框架详细知识点(更新中)

Django框架基本概述Django是一个开源的Web应用后端框架,由Python编写。它采用了MVC的软件设计模式,即模型(Model)、视图(View)和控制器(Controller)。在Django框架中,模型层负责与数据库交互,进行数据的增、删、改、查等操作。视图层用于封装结果,生成页面展示的HTML内容。控制

基于Simulink的用于电力系统动态分析

💥💥💞💞欢迎来到本博客❤️❤️💥💥🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。⛳️座右铭:行百里者,半于九十。📋📋📋本文目录如下:🎁🎁🎁目录💥1概述📚2运行结果🎉3参考文献🌈4Matlab代码、Simulink及文章💥1概述本文介绍了基于Simulink

KT142C-sop16语音芯片的4个IO口如何一对一触发播放_配置文件详细说明

目录KT142C是一个提供串口的SOP16语音芯片,完美的集成了MP3的硬解码。内置330KByte的空间,最大支持330秒的语音长度,支持多段语音,支持直驱0.5W的扬声器无需外置功放如上图,芯片有4个IO口可以一对一,详见如下说明2.3芯片4个IO触发口功能-配置文件-简单说明2.4配置文件注意事项--以及常见问题

pytest框架前后置设置,以及pytest默认规则

一、pytest框架的默认规则1、模块名默认必须以test开头或者以test结尾2、测试类必须以Test开头,并且不能有__init__方法3、测试方法默认必须以test开头当然以后的一些默认规则除测试类不能使用__init__方法外其余的都是可配置的,当然一般情况下我们也不会去修改这些默认配置。二、使用setup与t

《PostgreSQL与NoSQL:合作与竞争的关系》

🌷🍁博主猫头虎(🐅🐾)带您GotoNewWorld✨🍁🐅🐾猫头虎建议程序员必备技术栈一览表📖:🛠️全栈技术FullStack:📚MERN/MEAN/MEVNStack|🌐Jamstack|🌍GraphQL|🔁RESTfulAPI|⚡WebSockets|🔄CI/CD|🌐Git&Versio

盐碱地改良通用技术 铁尾砂改良学习

声明本文是学习GB-T42828.1-2023盐碱地改良通用技术第1部分:铁尾砂改良.而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们1范围本文件描述了铁尾砂改良盐碱地技术的技术原理,规定了技术要求、田间管理和效果评价。本文件适用于铁矿山企业采用经破碎、粉磨、磁选物理工艺选矿后得到的高硅铁尾砂对板结

时间复杂度讲解(数据结构)

目录引言什么是数据,结构和算法时间复杂度的概念如何计算时间复杂度总结引言hello大家好,我是boooooom君家宝。在前期的博客中博主呢对c语言的一些重要知识点进行了讲解,接下来博主的博客内容将为大家呈现的是数据结构算法的知识讲解,纯c语言版本。由于c语言对于数据结构和算法的进阶知识不是非常的契合,所以暂时只用c语言

热文推荐