Jupyter Notebooks 在 Kubernetes 上部署往往需要绑定一张 GPU,而大多数时候 GPU 并没有被使用,因此利用率低下。为了解决这一问题,我们开源了 elastic-jupyter-operator,将占用 GPU 的 Kernel 组件单独部署,在长期空闲的情况下自动回收,释放占用的 GPU。这篇文章主要介绍了这一开源项目的使用方式以及工作原理。

Jupyter Notebooks 是目前应用最为广泛的交互式开发环境,它很好地满足了数据科学、深度学习模型构建等场景的代码开发需求。不过 Jupyter Notebooks 在方便了算法工程师和数据科学家们日常开发工作的同时,也对基础架构提出了更多的挑战。

资源利用率的问题

最大的挑战来自于 GPU 资源利用率。在运行的过程中即使没有代码在运行,Notebook 也会长期占用着 GPU,造成 GPU 的空置等问题。在大规模部署 Jupyter 实例的场景下,一般会通过 Kubernetes 创建多个 Notebook 实例,分配给不同的算法工程师使用。而在这样的情况下,我们需要在对应的 Deployment 中事先申请 GPU,这样 GPU 会与对应的 Notebook 实例绑定,每个 Notebook 实例都会占用一张 GPU 显卡。

然而同一时间,并不是所有的算法工程师都在使用 GPU。在 Jupyter 中,编辑代码的过程是不需要使用计算资源的,只有在执行 Cell 中的代码片段时,才会使用 CPU 或 GPU 等硬件资源,执行并返回结果。由此可以预见,如果通过这样的部署方式会造成相当程度的资源浪费。

造成这一问题的原因主要是原生的 Jupyter Notebooks 没有很好地适配 Kubernetes。在介绍问题原因之前,先简单概述一下 Jupyter Notebook 的技术架构。如下图所示,Jupyter Notebook 主要由三部分组成,分别是用户和浏览器端,Notebook Server 和 Kernel。

其中用户和浏览器端是 Jupyter 的前端,主要负责展示代码和执行结果等。Notebook Server 是它的后端服务器,来自浏览器的代码执行请求会被 Notebook Server 处理,分派给 Kernel 执行。Kernel 是真正负责执行代码,返回结果。

在传统的使用方式中,用户会通过 jupyter notebook $CODE_PATH 等命令,在本地运行 Jupyter Notebook Server,随后访问浏览器中的 Jupyter 交互式开发界面。当代码需要执行时,Notebook Server 会创建一个独立的 Kernel 进程,这一进程会使用 GPU 等运行。在 Kernel 长期空闲,没有代码需要执行时,这一进程会被终止,GPU 也就不再会被占用。

而当部署在 Kuberenetes 之上后,问题就产生了。Notebook Server 和 Kernel 运行在同一个 Pod 的同一个容器下,尽管只有执行代码时才需要运行的 Kernel 组件是需要 GPU 的,而长期运行的 Notebook Server 是不需要的,但是受限于 Kubernetes 的资源管理机制,还是需要给其提前申请 GPU 资源。

在 Notebook Server 的整个生命周期中,这一块 GPU 始终与 Pod 绑定。在 Kernel 进程空闲时虽然会被回收,但是已经分配给 Pod 的 GPU 卡却不能再交还给 Kubernetes 进行调度了。

解决方案

为了解决这一问题,我们开源了项目 elastic-jupyter-operator。思路非常朴素:问题源于 Notebook Server 和 Kernel 在同一个 Pod 中,导致我们无法分别为这两个组件申请计算资源。那只要将他们分开部署,让 Notebook Server 在单独的 Pod 中,Kernel 也在单独的 Pod 中,相互之间通过 ZeroMQ 通信即可。

通过这样的方式,Kernel 会在空闲时被释放。在需要时会再次被临时性地申请 GPU,运行起来。为了实现这一目的,我们在 Kubernetes 中实现了 5 个 CRD,同时为 Jupyter 引入了一个新的 KernelLauncher 实现。通过它们,用户可以在 GPU 空闲时将 Kernel 回收释放,在需要执行代码时再动态地申请 GPU 资源,创建 Kernel Pod 进行代码执行。

简单的例子

下面我们将通过一个例子介绍使用方式。首先我们需要创建 JupyterNotebook CR(CustomResource),这一个 CR 会创建出对应的 Notebook Server:

apiVersion: kubeflow.tkestack.io/v1alpha1
kind: JupyterNotebook
metadata:
name: jupyternotebook-elastic
spec:
gateway:
name: jupytergateway-elastic
namespace: default
auth:
mode: disable

其中指定了 gateway,这是另外一个 CR JupyterGateway。为了能够让 Jupyter 支持远程的 Kernel,需要这样一个网关进行请求的转发。我们同样需要创建这样一个 CR:

apiVersion: kubeflow.tkestack.io/v1alpha1
kind: JupyterGateway
metadata:
name: jupytergateway-elastic
spec:
cullIdleTimeout: 3600
image: ccr.ccs.tencentyun.com/kubeflow-oteam/enterprise-gateway:2.5.0

JupyterGateway CR 中的配置 cullIdleTimeout 指定了经过多久的空闲时间后,其管理的 Kernel Pod 会被系统回收释放。在例子中是 1 个小时。创建完这两个资源后,就可以体验到弹性伸缩的 Jupyter Notebook 了。如果在一个小时内一直没有使用的话,Kernel 会被回收。

$ kubectl apply -f ./examples/elastic/kubeflow.tkestack.io_v1alpha1_jupyternotebook.yaml
$ kubectl apply -f ./examples/elastic/kubeflow.tkestack.io_v1alpha1_jupytergateway.yaml
$ kubectl port-forward deploy/jupyternotebook-elastic 8888:8888
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
jovyan-219cfd49-89ad-428c-8e0d-3e61e15d79a7 1/1 Running 0 170m
jupytergateway-elastic-868d8f465c-8mg44 1/1 Running 0 3h
jupyternotebook-elastic-787d94bb4b-xdwnc 1/1 Running 0 3h10m

除此之外,由于 Notebook 和 Kernel 解耦的设计,使得用户可以方便地修改 Kernel 的镜像与资源配额、向已经在运行的 Notebook 中添加新的 Kernel 等。

设计与实现

在介绍完使用方式后,我们简单介绍其设计与实现。

当用户在浏览器中选择执行代码时,首先请求会发送给在 Kubernetes 上运行的 Notebook Server。由于目前集群上没有正在运行的 Kernel,代码执行任务无法分配下去,所以 Notebook Server 会向 Gateway 发送一个创建 Kernel 的请求。Gateway 负责管理远端的 Kernel 的生命周期,它会在 Kubernetes 集群中创建对应的 JupyterKernel CR。随后会与集群中已经创建好的 Kernel 通过 ZeroMQ 进行交互,然后将代码执行的请求发送给 Kernel 进行执行,随后将结果发送给 Notebook Server 再将其返回给前端进行渲染和展示。

而 Gateway 会根据在 JupyterGateway CR 中定义的有关资源回收的参数,定时检查目前管理的 Kernel 中有没有满足要求,需要被回收的实例。当 Kernel 空闲时间达到了定义的阈值时,Gateway 会删除对应的 JupyterKernel CR,将其回收,释放 GPU。

总结

目前深度学习在开发与落地生产的过程中仍然存在着诸多的挑战。elastic-jupyter-operator 瞄准了在开发过程中的 GPU 利用率与开发效率的问题,提出了一种可行的方案,将占用 GPU 的 Kernel 组件单独部署,在长期空闲的情况下自动回收,释放占用的 GPU,通过这样的方式提高资源的利用率的同时,也给予了算法工程师用户更多的灵活度。

从算法工程师的角度来说,elastic-jupyter-operator 支持自定义的 Kernel,可以自行选择在 Kernel 的容器镜像中安装 Python 包或者系统依赖,不需要担心与团队内部的 Notebook 统一镜像的版本一致性问题,提高研发效率。

而从运维与资源管理的角度来说,elastic-jupyter-operator 遵循了云原生的设计理念,以 5 个 CRD 的方式对外提供服务,对于已经落地 Kuerbenetes 的团队来说具有较低的运维成本。

License

  • This article is licensed under CC BY-NC-SA 3.0.
  • Please contact me for commercial use.

【腾讯云原生】云说新品、云研新术、云游新活、云赏资讯,扫码关注同名公众号,及时获取更多干货!!

云原生的弹性 AI 训练系列之三:借助弹性伸缩的 Jupyter Notebook,大幅提高 GPU 利用率的更多相关文章

  1. 云原生的弹性 AI 训练系列之一:基于 AllReduce 的弹性分布式训练实践

    引言 随着模型规模和数据量的不断增大,分布式训练已经成为了工业界主流的 AI 模型训练方式.基于 Kubernetes 的 Kubeflow 项目,能够很好地承载分布式训练的工作负载,业已成为了云原生 ...

  2. 云原生的弹性 AI 训练系列之二:PyTorch 1.9.0 弹性分布式训练的设计与实现

    背景 机器学习工作负载与传统的工作负载相比,一个比较显著的特点是对 GPU 的需求旺盛.在之前的文章中介绍过(https://mp.weixin.qq.com/s/Nasm-cXLtJObjLwLQH ...

  3. 打造云原生大型分布式监控系统系列文章-腾讯工程师roc

    附上本系列文章链接 打造云原生大型分布式监控系统(一): 大规模场景下 Prometheus 的优化手段 打造云原生大型分布式监控系统(二): Thanos 架构详解 打造云原生大型分布式监控系统(二 ...

  4. Home Assistant系列--之树莓派安装Samba 和 Jupyter Notebook

    1.什么是Samba? Samba是在Linux和UNIX系统上实现SMB协议的一个免费软件,由服务器及客户端程序构成.SMB(Server Messages Block,信息服务块)是一种在局域网上 ...

  5. 重大升级!灵雀云发布全栈云原生开放平台ACP 3.0

    云原生技术的发展正在改变全球软件业的格局,随着云原生技术生态体系的日趋完善,灵雀云的云原生平台也进入了成熟阶段.近日,灵雀云发布重大产品升级,推出全栈云原生开放平台ACP 3.0.作为面向企业级用户的 ...

  6. [源码解析] 深度学习分布式训练框架 horovod (16) --- 弹性训练之Worker生命周期

    [源码解析] 深度学习分布式训练框架 horovod (16) --- 弹性训练之Worker生命周期 目录 [源码解析] 深度学习分布式训练框架 horovod (16) --- 弹性训练之Work ...

  7. AI云原生浅谈:好未来AI中台实践

    AI时代的到来,给企业的底层IT资源的丰富与敏捷提出了更大的挑战,利用阿里云稳定.弹性的GPU云服务器,领先的GPU容器化共享和隔离技术,以及K8S集群管理平台,好未来通过云原生架构实现了对资源的灵活 ...

  8. 阿里云弹性容器实例产品 ECI ——云原生时代的基础设施

    阿里云弹性容器实例产品 ECI ——云原生时代的基础设施 1. 什么是 ECI 弹性容器实例 ECI (Elastic Container Instance) 是阿里云在云原生时代为用户提供的基础计算 ...

  9. 技术分享 | 云原生多模型 NoSQL 概述

    作者 朱建平,TEG/云架构平台部/块与表格存储中心副总监.08年加入腾讯后,承担过对象存储.键值存储,先后负责过KV存储-TSSD.对象存储-TFS等多个存储平台. NoSQL 技术和行业背景 No ...

随机推荐

  1. android http get

    Executors.newSingleThreadExecutor().execute{ val uri = "https://www.cnblogs.com/hangj" val ...

  2. openresty HTTP status constants nginx api for lua

    https://github.com/openresty/lua-nginx-module context: init_by_lua, set_by_lua, rewrite_by_lua, acce ...

  3. Mysql常用sql语句(15)- cross join 交叉连接

    测试必备的Mysql常用sql语句 https://www.cnblogs.com/poloyy/category/1683347.html 前言 交叉连接就是求多表之间的笛卡尔积 讲道理..这个我都 ...

  4. 分组概念&贪婪与懒惰

    分组概念&贪婪与懒惰 1.分组 2.贪婪和懒惰 3.懒惰 4.处理选项 5.实例:百度搜索结果页面源码中获取当前页的10个标题 5.1页面源码分析规律 5.2正则表达式,匹配出10个标题 这是 ...

  5. redis存取数据list

    登录redis客户端 一.存取数据 1.左右添加数据 2.读取数据lrange 3.左右固定弹出一个元素 4.列表中个数 5.删除元素值为value的元素 count 值要自己给定: 6.获取和设置指 ...

  6. J2EE分布式微服务云开发架构 Spring Cloud+Mybatis+ElementUI 前后端分离J2EE分布式微服务云开发架构 Spring Cloud+Mybatis+ElementUI 前后端分离

    ​ 鸿鹄云架构[系统管理平台]是一个大型企业.分布式.微服务.云架构的JavaEE体系快速研发平台,基于模块化.微服务化.原子化.热部署的设计思想,使用成熟领先的无商业限制的主流开源技术(Spring ...

  7. Python与Mysql 数据库的连接,以及查询。

    python与mysql数据库的连接: pymysql是python中对数据库的连接模块:因此应当首先安装pymysql数据库模块. 执行pip install pymysql 命令. 然后在pyth ...

  8. PHP中的PDO操作学习(四)查询结构集

    关于 PDO 的最后一篇文章,我们就以查询结果集的操作为结束.在数据库的操作中,查询往往占的比例非常高.在日常的开发中,大部分的业务都是读多写少型的业务,所以掌握好查询相关的操作是我们学习的重要内容. ...

  9. IDEA - 2019中文版安装教程

    前言 个人安装备忘录 软件简介 IDEA 全称IntelliJ IDEA,是java语言开发的集成环境,在业界被公认为最好的java开发工具之一,尤其在智能代码助手.代码自动提示.重构.J2EE支持. ...

  10. Shell系列(6)- 管道符

    多命令顺序执行 多命令执行符 格式 作用 ; 命令1 ; 命令2 连接命令:多个命令顺序执行,命令之间没有任何逻辑联系:前面命令报错,后面命令照常执行 && 命令1 && ...