BOKI
abstract
Boki是一个新的无服务器运行时,它将一个共享日志API导出到无服务器函数。Boki使用共享日志: 使无状态服务器app能够通过持久性、一致性和容错来管理他们的状态,从而实现高吞吐和低延迟。
关键推动因素:metalog以高吞吐量排序共享日志记录,它提供了读一致性,同时允许服务提供商以不同方式优化共享日志的写和读路径。
构建了三个Boki支持库:
- 容错工作流
- 持久对象存储
- 消息队列
评估:共享日志可以使重要的无服务器工作负载速度提高5.7倍。
introduction
Boki是一个FaaS运行时。将共享日志API导出到用与存储共享状态的函数中。通过一个LogBook抽象实现了共享日志API。其中每个函数调用都与一个LogBook相关联。对于Boki应用程序,它的函数共享一个LogBook,允许他们共享和协调状态更新。
Boki的挑战——在无服务器环境的同时实现高性能和强一致性。
无服务器存储的挑战:数据局部性。
- 因为在无服务器环境中强烈倾向于使用分解式存储。
boki的解决方案:
- 读路径:读局域性通过函数节点上的缓存进行优化。
- 写路径:通过扩展带宽进行优化。 Boki将在不同数量的碎片上分散写操作,同时提供一致的读取和容错。
Boki高性能、读取一致性和容错能力的实现
通过基于日志的metalog
其定义了Boki内部状态的总顺序,app可以在需要的时候使用它来强制一致性。metalog里边包含了对日志数据记录进行完全排序的元数据。
e.g 通过跟踪metalog位置来实现单调读取。
比如可以基于用户ID的哈希值来选择节点而不是随机选择节点。
通过重新配置来处理机器故障,类似于共享日志系统。
因为metalog控制Boki的内部状态转换,所以密封metalog会暂停状态转换。今儿更改系统配置并启动一个新的metalog来实现重新配置。
metalog的优点:
- 允许从以前的共享日志设计中轻松使用最先进的技术,因为它使日志排序、一致性和容错成为独立的模块。
- 将读取一致性和数据防止解耦,使日志记录的索引和缓存与函数共存。(从而可以构建简单的缓存,增加了节点调度函数时的数据局部性。)
Boki基于Nightcore——为服务优化的FaaS 运行时
Boki提供了状态管理机制,而Nightcore的I/O效率设计有利于Boki。Boki在耽搁Logbook中实现了1.2M ops/s的附加吞吐量,同时保持了6.4ms的P99延迟(表示过去的10秒内最慢的1%请求)。将Logbook引擎与函数放在一起,Boki在最佳情况下实现了121微秒的读延迟。
2 Background and Motivation
当前无服务器范式的一个关键挑战:无服务器函数的无状态特性与用他们构建的有状态应用程序之间的不匹配。
由多个函数组成的无服务器应用程序。app之间的状态是共享的。然而使用当前的云数据库或者对象存储管理共享状态,很难在同时获得高性能、可伸缩性和强一致性和容错。
依赖于云存储,工作流中的函数可能在中间失效,从而将不一致的工作流状态存储在数据库中。
2.1 Shared Log Approach for Stateful Serverless
先前的研究
- 共享日志:Olive[50]提出了一个与云存储交互的客户端库,其中预写重做日志用于在失败时实现恰好一次的语义。Beldi [56] 将 Olive 基于日志的技术扩展到事务性无服务器工作流。
- 状态机复制(SMR):通过命令日志夸服务器复制应用程序状态。命令日志通常由共识算法支持。
最新的研究
共享日志可以提供高效的抽象,以支持基于SMR的数据结构和协议。
本文的贡献
- Boki位无服务器提供了共享日志。因此Boki 的应用程序可以利用易于理解的机遇日志的机制来有效实现数据一致性和容错。
- 无服务器计算到需求的三个重要案例
- Fault-tolerant workflows.编排有状态函数的工作流为容错和事物状态更新带来了新的挑战。
- 持久对象存储。以前的研究表明,共享日志可以支持高级数据结构,即对象。他们是一致的、持久的和可伸缩的。受cloudflare的持久对象的启发,boki构建了一个有状态函数库来创建持久JSON对象。且使用了来自Tango的技术支持跨对象事务(cloudflare不支持)。
- Severless消息队列。FaaS范式的一个约束是,函数不能通过传统的方法(如socket)直接相互通信。share log 可以构建消息队列,在函数之间提供间接通信和协调。
2.2 无服务器共享日志的技术挑战
弹性和数据局部性。
- 弹性:受益于两篇paper Disaggregation and the Application。
- 局部性:无服务器平台选择物理分离,降低了数据局部性。 Boki通过分离日志数据的读取和写入路径以及将读取组建与函数共存。实现了弹性和数据局部性。
资源效率
- 解决了由日志大小分布偏斜引起的性能问题。
Boki旨在有效地支持高密度的LogBook。因此Boki可以在单个物理日志上多路复用许多LogBook。 - 引出了新的问题:如何找到LogBook的记录?
日志索引,其中metalog提供了读取一致性的机制。
FaaS的短暂性
-
目标
共享日志用于通过状态复制机构建高级数据结构(对象)。为了允许快速读取,客户端在内存中保存复制状态机的副本(cache)。 -
问题
无服务器函数是短暂的,它们的内存状态不保证在调用之间保持不变。 这个限制迫使函数在访问基于复制状态机的对象时重播完整的日志。 -
解决
Boki引入了辅助数据。辅助数据被设计成基于每个日志记录的缓存存储,而它宽松的持久性和一致性保证允许一个简单有效的机制来管理他们的存储。
3 LogBook API
LogBook抽象是为无服务器函数访问share log提供的。
Boki维护者许多由不同无服务器应用程序使用的独立日志。boki中每个函数的调用都与一个LogBook相关联,在调用函数的时候制定该LogBook的book_id。一个LogBook可以通过多个函数调用共享,以便application可以在其函数实例之间共享状态
LogBook API
- 读一致性
- LogBook保证读取记录时Monotonic read(单调读取)和read-your-write意味着函数的日志尾视图是单调递增的。
- 若两个函数共享相同的LogBook,子函数将继承其父函数的日志尾部视图。(这个属性对于由多种函数的无服务器应用程序很重要)
- seqnum(序列号)
- LogAppend APi 为新添加的日志记录返回一个唯一的seqnum。 序列号决定了日志簿中记录的相对顺序,是单调递增的,但不保证是连续的。
- LogReadNext和LogReadPrev API通过为seqnums提供上下界来是实现双向日志遍历。
- Log tag
- 每个日志记录都有一组tag。日志tag启用选择性读取和trim(修剪),其中只考虑带有给定tag 的记录。
- 具有相同tag的记录在单个LogBook中形成抽象流。在share log中有用于选择性读的子流对于减少日志重放开销是很重要的
- auxdata(辅助数据)
- auxdata是设计了按每个日志记录缓存存储的,它是被logSetAuxData API设置的。
- if found ,日志读取可能会返回辅助数据以及正常数据。
- 辅助数据可以在基于share log的对象存储中缓存对象视图。这些对象视图可以显著减少日志重播开销。
- 由于辅助数据仅用作缓存,因此Boki不保证其持久性。 Boki信任应用程序为同一日志记录提供一致的辅助数据。放松的耐用性和一致性使Boki拥有一个简单而高效的后段来存储辅助数据。
Boki Design
- Boki 的设计是结合了一个FaaS系统和共享日志存储。Boki在内部存储多个独立的、完全有序的日志。为了提高资源效率,面向用户的LogBook被复用到内部物理日志上。
- 每个物理日志都有一个与其相关联的metalog。metalog在排序、一致性和容错上发挥着核心作用。
4.1 metalog是一切问题的答案
每一个共享日志系统必须回答三个问题,因为通过一个集群来存储日志记录:
- 1、如何决定对日志记录的全局排序;
- 2、如何确保数据在物理上分布时的读一致性;
- 3、如何容忍机器故障。
Boki与先前研究的对比——Boki用metalog来解决了所有问题
metalog
在Boki中每一个物理日志都有一个与其相关联的metalog,用来记录其内部状态的转换。metalog是由sequencers(排序器)Append的,并被其他组件所订阅
使用metalog来实现日志排序、读一致性、容错:
- Log ordering.主排序器使用Scalog的高吞吐量排序协议来追加metalog来决定新纪录的总顺序。
- Read consistency.不同的LogBook引擎独立的更显它们自己的日志索引。然而,读一致性是通过对比metalog位置来强制的。
- fault tolerance.重新配置是通过密封metalogs实现的。因为一个被密封的metalog对于相关联的日志暂停了状态转换。 当当前所有metalogs都被密封了之后,就可以安全的进行重新配置。
metalog是通过primary-driven protocol来支持的
每一个Boki的metalog都由n·meta个排序器存储(原型中有3个)。其中一个被配置为主排序器,只有主排序器可以追加metalog。追加一个新的metalog条目,主排序器会将该条目发送到所有排序器进行复制。一次集群的确认,新的metalog条目就会被成功追加。主排序器节点总是等待上一个条目被集群确认之后才会发布新的一个条目。排序器把被追加的metalog广播给订阅了metalog的boki 的其他组件。
4.2 Architecture
图2描绘了boki的架构,该架构是基于一个用于微服务的最先进的FaaS系统Nightcore。在Nightcore的设计中,有一个用来接受函数请求的网关和多个函数节点用来运行无服务器函数。在每一个函数节点,在函数容器内一个引擎进程和Nightcore运行时通过低延迟消息通道进行通信。
Boki通过添加了存储,排序和日志读取组件扩展了Nightcore的架构。Boki还有一个控制器来存储metalog的配置并用来处理组件故障。
- 存储节点。 Boki将日志记录存储在专用的存储节点中。Boki‘的物理日志是分片的,并且每个日志分片存储在n·data个存储节点中(在原型中n·data=3)。单个存储节点包含来自同一日志的不同的分片,和来自不同日志的分片;或者每一个存储节点包含来自不同日志的分片。这取决于Boki的不同配置。
- 排序器节点。 排序器节点运行着Boki的排序器,排序器用主节点驱动协议来存储和更新metalog。排序器追加新的metalog条目来对物理日志进行排序,实现细节在4.3中。和存储节点相似,单个排序器节点可以配置为支持不同的metalog。
- LogBook 引擎。 在Nightcore中,运行在函数节点中的引擎用来对函数调度进行回复。Boki添加了一个新的组件来为LogBook调用服务,拓展了Nightcore引擎。我们将新部分称为 LogBook 引擎,以将其与服务功能请求的部分区分开来。
LogBook API请求通过Boki’运行时传递给LogBook引擎,API和用户提供的函数代码链接。LogBook引擎为了有效的服务LogBook读取,为物理日志维护了日志索引。并且和metalog联合起来更新它们的索引。