spark 对大应用更好的可扩展历史服务器 (Better History Server scalability for many / large applications)

Better History Server scalability for many / large applications
下一代的spark历史服务/UI

在这个文档中我们将看一下为什么现在的spark history server(shs)是大量issues的来源,然后探索关于如何修复造成当前事态的想法.

动机

SHS是一个非常有用的工具,供人们对其应用程序进行事后调试.在driver在防火墙之后,或者其它不能直接访问的地方的情况下甚至“live” debugging

在另一方面,当前的架构被很多问题困扰,这是用户经常遇到的.不同的问题相互影响.创造一个邪恶的反馈循环。最糟糕的是许多问题没有解决方案,意味着那些遇到他们的人没有好的求助

所以让我们探索其中的一些问题,以及它们对当前形势的影响。

事件日志不是高效的

spark用从一个运行的应用中捕获原始数据生成事件日志,每个事件按时他们被接收到的顺序写到一个连续流.
这个写的路径是高效的低延迟的.像spark期望它的事件listener那样.

但是高效不适用于读的那一端,基础信息,像什么时候应用结束不是很容易访问.如果你转换日志用一个简单的方式.shs就是这样做的.它需要读整个日志文件来发现.虽然可以采用更智能的方法.(例如从后面解析日志用给定的信息来发现独立的事件),这是一种症状,即信息没有以有效的方式存储供shs处理.

实际上构建application UI 需要整个日志被解析,对于大应用,这是非常缓慢的。

SHS是无状态的

目前,shs不需要任何本地存储,这使它容易的放在任何地方,指向存储事件日志的位置,然后启动它并提供所有应用的数据.

另一方面,当它启动的时候它必须构建所有的信息来每次呈现给用户.这很慢.

一个因为一些原因(升级,维护,或者任何不常见的宕机)必须重启shs的用户一些时候需要等几分钟才能看到它们想看到的应用被列出.加载应用ui是另一个很长的等待.依赖于这个应用的事件日志有多大.这导致一个坏的用户体验.

应用的列表被保持在内存中

这是上面的一个延续,但应该有自己独立的主题,shs不仅仅不持久化任何事情到磁盘上,它甚至不用磁盘做为它的临时存储.意味着任何它服务的数据需要被保持在内存中.

当用户运行一个或多个应用,shs需要越来越多个内存来存储可用的应用程序列表,这很容易成为可伸缩性瓶颈,而且导致要有配置参数.参数控制有多个应用shs将展示,意味着老的应用可能消失.

应用的UI也被保存在内存中

这也是上面一个topic的一个延续,但是它现在在spark core中继承spark ui代码

许多被UI使用的数据被不同的listeners保存在内存中,listeners构建数据基于应用生成的事件(或者从 event log replay)这意味着数据可能很快的被提供.但是它也意味着随着application增加(通过运行更多的job或者放大excutor的数量,任务的数量等),UI层的内存使用情况也是如此。

对于一个单一应用,这可能不是一个大问题.让ui更好的控制它的内存使用是很好的,有一些配置来削减数据. 但用户可以通过仅请求更多内存来“修复”问题。

但是shs是一个服务于多个应用的ui,有一个单一的应用是一 个事情.同时有100个大应用是一个不同的事情

目前,shs通过一个多少应用的UI被保存在内存的硬控制来内存使用,这是一个非常粗的控制.它假设应用是相同的,用相同数量的内存,这离现实很远.在许多情况下,用户遇到大型应用程序导致SHS内存不足的问题。

减少应用保存在内存中的数量有帮助.但是我们回到shs无状态:如是一个人想看应用的UI,它必须从头开始从事件日志重播.这导致大量的延迟,浪费CPU轮,浪费带宽

一些其它的小问题

上面是shs主要的问题原因.但是,代码中还有其他小的低效之处,导致了不太理想的体验.我将在下面列出其中的一些,并对它们进行简短的解释。

  1. ui有一个 在一个页面中通过嵌入大量js代码来生成大html的趋势.或者列了太多事情而不是分页,甚至无限滚动.这些html需要在内存中生成.所以在shs(也是live app 的spark driver中在较小程度上)中它增加了一些内存和CPU的压力
  2. 对shs来说增量生成application ui是难的.它需要在shs回放ui的方式上做很多改变.但是考虑到从cache中驱除ui来避免内存问题.做这个工作没有许多好处.
  3. 由于上面讨论的一些低效,考虑到大量的streaming job生成的事件数据,在shs中支持 streaming UI仍然是一个open的问题.
  4. 上面的问题使使用shs做为一个Live spark ui的替代是不可能的,仅延迟问题就使其无法启动。
目标

有了解决这个问题的动力,让我们定义一些目标和明确计划工作的范围.

主要目标
  1. 为ui/shs提供更高效的事件存储机制.
  2. 大大降低了SHS请求的延迟,无论是在启动时还是在稳定状态下
  3. 尽可能从新的数据存储中提供UI功能,而不是保存在进程内存中的数据
扩展目标
  1. 提供增量转化事件日志(基于保存在shs中的状态或使用像hdfs的’inotify’ api的特征)
  2. 为Ui数据提供一个长期,没有主机的缓存,所以起动shs为一个独立的节点不需要重建数据是容易的.
不是目标(但是依然值得思考)
  1. 废弃当前的日志文件.使用新的数据存储做为’event log’
  2. 在shs中展示 streaming UI
  3. 重写UI的部分来生成少的数据(像增量画dag 而不是把所有的东西预先发送给客户)
  4. 重写UI来使用us读取rest api,而不是在scala中嵌入html代码
  5. 使master/worker ui 为Ui使用一个基于文件的数据存储
High Level Approach

这个提议的主要部分是为UI提出一个高效的数据存储,这个数据存储应该容易的从事件日志生成.应该支持快速查找.而且不需要所有的数据活在内存.为了实现这个.对这个问题有两个主要的部分.

第一是如何(那里)存储数据.我提供用一个本地(对于进程)数据库,存储在磁盘上.保存来自事件流的数据.我随后将说明数据库本身的细节.这意味着shs现在将需要本地存储才能工作.考虑到数据的性质,许多本地存储可能需要.

第二是如何提供数据.我提议重新架构rest api,这样它以新的store为后端,而不是像现在一样从内存中结构读取在单个listeners中的数据.存在的listeners将重新写事件到新的数据存储,那时ui生成的代码将直接从数据存储中消费数据.注意这不需要改变html服务客户端的方法;虽然有更多基于客户渲染的逻辑将很好,这将仍然基于目前的 html内嵌在scala的方式.

在下一章,我们将讨论每个部分工作的结节.通过定义更细粒度的里程碑,并讨论将在每个里程碑中交付什么,我们的目标是让每个里程碑都成为一个独立的可交付成果——这意味着它将作为单个工作提交给Spark master分支,因为这个工作是大的,每个里程碑将在单独的分支里开发.定期基于先前分支(如果需要),所以当更改就绪是,在上游单独的执行评审是容易的.第一个里程碑的分支将周期的在当前的Master rebase,所以我们可以早期修正冲突而不是在后期做一个痛苦的合并开发将发生在一个公共的github仓库.所以如果人们愿意他们可能提交pull request到一个适当的分支.

下在,请求的milestones被命名为Mx,而且是连续的,而stretch goals are tracked in “SMx” (for “stretch milestone x”),大多数是独立的,我故意省略了时间的估计.

M1: A “data store” abstraction library for event data

在第一个里程碑一个新的模块将被创建包含一个抽象来本地存储数据.这个包将关注序列化和管理底层数据存储的事情.然而仍提供必要的抽象,如果用户需要重写任何默认的行为.

这个工作开始于定义底层的数据文件将像什么样.我看了一些架构,我当前的选择先列在下面

  1. LevelDB 这是一个快的google定的 key/value存储,基于一个bsd的license,它有一个有点笨拙的Java API,被第三方开放.它看起来读的规模足够大,快的足够快.即使根据我看到的基准,它们似乎是序列化的,底层库似乎得到了一些定期更新.但是Java绑定大多处于休眠状态。从好的方面看,它看起来非常稳定,确实如此已在Spark shuffle服务中使用,它也用在Hadoop中,在hadoopo中它支持mr shuffle 元数据库,而且是一个yarn ast的原生存储.
  2. RocksDB 这是一个起始于fackbook的LevelDB的fork,在相同的bsd-类型 license.facebook看起来已经做了一些性能提升.而且维持一组更好的Java绑定.话虽如此,它比LevelDB大得多,并且它提供的额外功能(例如“列族”)要么不需要,要么不容易模拟。 如果遇到LevelDB问题,这是一个很好的后备。
  3. LMDB 相同的主意(快速本地文件DB),它用不同的写数据的方式.而且声明对多进程写数据到相同的db是安全的.这个后在的feature对这个项目来说不感兴趣.当生成大数据文件,基准测试似乎表明它没有像上面的选项那么快
  4. Berkeley DB 到目前唯一一个纯java的,但是 GPL-style 使它不是一个开始.
  5. SQLLite,Apache Derby或其他一些嵌入式RDBMS:我的立场是在这一个完全的关系数据库是过于苛刻的.大部分时间我们都是谈论简单的身份搜索(带有ID的应用程序)或顺序读取(给我x在y之后启动的应用程序)之后开始。
  6. YARN ATS(v1或v2):这意味着在运行时对YARN的硬依赖性,这是许多人不希望的。 ATS也不适合所提出的数据模型; 它更适合作为事件流的存储(例如原始事件日志).作为一个单独的服务,它将一些可伸缩性问题转移到一个不受Spark控制的组件上
    一些被上面用到的基准测试

这些是为数据存储计划的初始特性:

  • 自动序列化/反序列化:从store中被写或读的数据将基于用户定义类型的被jar包自动转换.序列化将用jackson完成,因为它已经被用在已经存在的rest api.
  • Key management:jar包应该抽象掉大部分工作,以便从用户的数据中生成有效keys
  • Indexing:LevelDB用存储顺序存储keys,但是应用可能需要查找数据用不同的标准,apps将允许在任意数据的字段上创建indices,而且基于这些索引展示的数据.
  • Range queries:该库应该可以很容易地查询属于特定范围的特定索引下的数据.想想分页。
  • Vacuuming: 库应该允许key被删除,必须更新任何关于这个key的索引来保证不引用要正在删除的数据.
    这些特性在数据存储的初始版本中没有计划
  • Arbitrary queries:如果范围查询不适用于用户的用例,则由用户实现.

这个库将活在一个单独的在"common/"目录下的模块.由仅由java写.此要求是以后可以在当前直接使用LevelDB的代码的其他部分中使用

值得强调的是,所选择的库需要一个本机库,它只是为Linux,Windows和Mac OS预编译的.在其他平台上运行此代码的用户必须禁用Spark UI,除非他们提供自己的LevelDB版本。

M2: SHS Application Listing Persistence

这个里程碑将覆盖用一个新的在m1中被创建的数据存储持久shs应用列表,为避免对现有代码进行干扰性更改,这将在一个新的模块中被开发,暂时叫做spark-ui,,其中所有重新设计的SHS / UI代码将继续存在,并使用现有的可扩展性机制插入现有的SHS。

写入存储的数据将基于现有的REST API数据结构.当需要的时候,对新的代码rest api将在新的spark ui模块被增强通过添加一个新的v2包包含更改.随后,在未来的里程碑,我们将选择保持v2或者合并这些变化到v1.依赖于我们做了那些改变

shs将用一个新的listener来收集来自event log的数据,这个listener将被限制收集数据并且在存储中更新它们.为了支持与事件日志交互.新的模块将extend 已经存在的FsHistoryProvider,重写需要的行为.这可能需要在这个类中的一些变化.在这个项目结束后,类将被合并而且老的合并代码将被移除.

写的展示数据应该有匹配当前UI列的索引.所以

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值