摘要
远程的内存中键值(RInK)存储(例如 Mem 缓存[6]和Redis [7])在行业中被广泛使用,并且是学术研究的活跃领域。它们与执行业务逻辑的无状态应用程序服务器以及提供持久性存储的类似数据库的系统结合在一起,构成了流行的数据中心服务体系结构的核心组件。我们认为 RInK 存储的时代已经过去了:它们的独立于域的 API(例如PUT / GET)将复杂性推回到应用程序中,从而导致额外的(非)编组开销和网络跃点。取而代之的是,应该使用具有状态的应用程序服务器或具有特定于域的 API 的自定义内存存储来构建数据中心服务,以比 RInK 更低的成本提供更高的性能。避免了此类设计,因为在没有适当基础架构支持的情况下难以实现。考虑到自动分片技术的最新进展[8,9],我们认为现在是时候重新考虑这些决策了。在本文中,我们评估了有状态设计的潜在性能改进,提出了一种新的抽象,即链接的内存中键值(LInK)存储,以使开发人员能够轻松地实现有状态服务,并讨论需要解决的领域和未来的研究。
介绍
现代互联网规模的服务通常依赖于远程,内存中的键值( RInK )存储,例如 Redis [7]和Mem缓存[6](图1)。 这些存储服务至少有两个目的。首先,它们可以在存储系统上提供缓存,以便能够更快地检索持久状态。 其次,它们可能存储短期数据,例如每个会话状态,这些数据不能保证持久性[25]。
这些存储库使服务能够使用无状态应用程序服务器[16]进行部署,该服务器仅维护每个请求状态。 所有其他状态都驻留在永久性存储或 RInK 存储中。 无状态应用程序服务器带来了操作上的简化:例如,任何请求都可以由任何应用程序服务器处理,这使得添加和删除应用程序服务器,处理服务器故障以及处理歪斜变得容易。
图一:无状态服务以及一个 Rlink 存储RInK 存储库的关键属性是它们提供了一个简单且与域无关的接口(例如,字符串键和字符串值的 PUT / GET,或对诸如列表之类的简单数据结构的操作)。 由于 RInK 存储库处理定义明确且简单的操作,因此实现已能够实现异常高的吞吐量和低延迟[14、18、20、24]。 此外,这些存储的高性能使分布式缓存挑战(例如负载平衡)相对不那么重要:即使工作负载出现偏差,也可以简单地过度配置 RInK 存储。
另一方面,RInK 的与域无关的接口将成本和复杂性推回了应用服务器。 例如,它们迫使应用程序在本地语言表示形式和字符串之间重复转换其内部数据结构,这既增加了 CPU 成本,又增加了程序员负担。 当应用程序不使用从 RInK 存储中检索到的每个值的全部时,此问题将更加严重,因为不必要地传输字节只是将其丢弃。 最后,网络距离会增加延迟成本,尤其是在必须传输较大的值或需要多次往返的情况下。
我们认为,鉴于最近自动分片系统[8,9]的改进,这些成本被低估了,不再需要了。 开发人员应该构建有状态的应用程序服务器,而不是外部化 RInK 中的内存状态。 有状态应用程序服务器是指在同一进程中将应用程序代码和长期内存状态耦合在一起的服务器。 如果有状态应用程序服务器不可行(例如,由于状态由多种应用程序或多种语言共享),则开发人员应改为构建自定义的内存存储,该存储区与应用程序服务器之间的网络距离较远,但要公开特定于域的API。
建立有状态的服务需要解决新的技术挑战,研究界应该专注于帮助开发人员解决这些挑战,而不是建立越来越快的 RInK 存储。 尽管它们带来了挑战,但有状态服务仍可显着改善性能。 例如,ProtoCache(广泛使用的 Google 应用程序的一个组成部分)在进行此体系结构切换时,将延迟时间降低了40%,降低了99.9%,而对模型应用程序和合成工作负载的实验表明,潜在的延迟时间最多可提高57%。
本文做出了三点贡献。 首先,我们认为耦合应用程序代码和缓存在内存中的状态带来了被低估的性能好处。 其次,我们提出了一种新的链接的内存中键值( LInK )存储抽象。 LInK 存储库是链接到应用程序服务器或自定义内存存储库中的键到富对象的映射,它代替了外部 RInK 存储库。 它实现了功能,例如在重新分片事件之后进行重新配置,我们发现这给开发人员带来了负担。 最后,我们描述了研究社区可以做出贡献的其他领域。
最后,我们关注通过消除 RInK 存储来提高访问内存状态时的应用程序性能。 如何确保数据的持久性虽然很重要,但仍不在本文讨论范围之内。
2. 灵感(Movitation)
2.1 无状态和 RInK 架构
现代互联网规模的服务需要高度可用且可靠。 保持鲁棒性最重要的原则之一就是简单性,服务编写者的目标是尽可能简单地构建其系统,以使其易于实现,调试,维护和操作。
早在上世纪90年代末,开发人员就开始使用无状态应用程序服务器,其中数据中心中的多个独立进程处理请求,而无需维护任何超出请求寿命的状态(“LAMP堆栈”)。处理每个请求所需的状态是从存储系统(如 SQL 数据库或水平分区的分布式存储系统,如HBase[2]、Cassandra[1]、Bigtable[12] 或 Spanner[13])临时获得的。这种设计最大化了应用服务器的简单性,它只包含业务逻辑;特别是,它不包含管理状态的代码。
纯粹的无状态设计可带来运维优势,因为每个应用程序服务器都是等效的。 如果服务上的负载增加,则可以添加新服务器以吸收额外的负载。 如果服务器崩溃,则可以将请求定向到其余服务器。 如果服务器过载,则可以轻松地减轻负载,例如,通过将呼叫定向到负载最小的服务器或使用二次幂方法[22]。
另一方面,在每个请求上访问持久性存储既昂贵又缓慢。 服务可能还具有不适合持久的状态,但仍然必须超过单个请求的状态(例如,会话状态)。 为了满足这些需求,开发人员对无状态架构进行了改进,使其包括一层 RInK 存储,例如 Memcached [6]和Redis [7](图1)。 我们称其为无状态+ RInK 架构,即 S + RInK 。 期望 RInK:(1)通过卸载持久性存储中的工作来提高可伸缩性,因为 RInK 处理大多数请求; (2)降低了延迟,因为它不需要提供持久性。
此外,在某些情况下,RInK 存储提供了多个不同应用程序之间的共享缓存,从而避免了每个应用程序缓存中的数据重复,从而提高了整体效率。最后,RInK 存储区比(大多数)应用程序服务器更具可伸缩性,因为应用程序服务器通常执行复杂的逻辑,并且 RInK 存储区具有简单明了的界面。 高性能可让 RInK 存储使用简单的技术进行分片(例如,Memcache 中的无负载感知一致哈希算法)。 鉴于缺乏自动分片的基础设施,将分片隔离到 RInK 存储将很有吸引力。
2.2 无状态和 RInK 架构的限制
S+RInK架构试图同时提供两个方面的最佳效果:同时提供无状态应用服务器的实现和操作简单性,以及服务器在RAM中缓存状态的性能优势。我们认为架构的不足是由于它所提供的抽象的基本限制。
2.2.1 CPU cost due to (un) marshalling
我们认为序列化/反序列化是现实应用的基础。 抽象数据类型很有用[21],其内部表示形式不太可能与线性格式相对应。 例如,它可以包括长度可变的字段或指针。 其次,随着软件的发展,可以在 RInK 中存储的数据结构中添加和删除字段,而 RInK 则争用不同的有线和内存格式。 最后,如果用不同语言编写的程序使用了相同的缓存数据,则不可避免地会进行一些序列化/反序列化。
由于将数据转换为特定于域的表示形式,因此 RInK API 引入了大量的 CPU 开销。
2.2.2 Overreads
当应用程序从 RInK 存储中读取的数据超出要求时,就会发生超读,从而导致额外的 CPU 和网络成本。 当应用程序必须获取整个值时,即使只有一小部分对相应的计算有用,也会发生这种情况。 例如,考虑一个为 RInK 存储中的所有在线用户缓存通讯簿的应用程序:对于每个用户,通讯簿都存储为单个键值对。 如果来自爱丽丝的要求从其通讯录中读取鲍勃的电话号码的请求,则即使只需要一小部分数据,也必须提取并取消整理爱丽丝的所有联系人。
将较大的键值对分解为多个键值对可以减少过度读取的程度,但以一致性保证较弱的代价为代价:大多数 RInK 存储库不支持原子交叉键操作。 另外,设计分解表示以加速丰富的操作(例如,在日历应用中找到用户的第一个空闲时隙)显然不是简单的。 最后,为支持特定操作而对架构进行的优化越多,随着需求或工作负载的变化,架构就越难以发展。 有时也可以使用存储中更丰富的数据模型来缓解过度读取[7],但是正如我们下面将要讨论的那样,此类解决方案缺乏通用性和灵活性。
举一个真实的例子,对于 ProtoCache 中的一种常见操作类型,在第99个百分位数处,响应仅占缓存项总数的2%:避免过度读取很重要。 这些操作是使用索引集合实现的,这意味着不会将缓存的项目分解为多个键值对,而这些键值对将适用于所有操作。
最后,我们在第3节中的实验表明,如果只需要部分记录(10%),则 RInK 存储会产生额外的 CPU(46%)和网络(85%)成本。
RInK导致不必要的数据处理和传输
2.2.3 网络延迟
甚至快速的数据中心网络也会在无状态和 RInK 架构中增加延迟成本。 如果应用程序需要多次读取或写入操作才能满足请求,则这些延迟可能会迅速增加。 除了简单的 RTT 之外,要传输的数据大小也很重要,这与超读结合在一起是一个特别的问题。 例如,尽管网络高速,但 ProtoCache 在进行重构之前,仅从远程存储传输大记录就产生了80毫秒的延迟损失。
使用RInK存储库时,低延迟数据中心网络无法消除数据传输开销。
2.3 最先进的 RINK 存储
尽管已经提出了许多改进 RInK 实现的方法,但是它们都不能解决上述挑战。
2.3.1基本RInK存储
基本的 RInK 存储提供的接口实际上仅是 PUT / GET API。 例如,Memcached [6]是最早的和最著名的 RInK 存储之一; 它已经广泛部署,包括在Facebook的Tao [11]和Dropbox的Edgestore [4]中; 一个版本也被Google广泛使用。 除PUT / GET之外,它还包括一些有限的附加操作,例如将值附加到现有值上并递增现有整数值。
最近,学术界致力于建立性能更高的基本 RInK 存储,以及优化 Memcached 到死[10、15、26、28]。 FaRM [14]试图通过降低使用 RDMA 提取远程数据的成本来提高无状态应用程序的性能。 网络缓存[18]通过直接在网络交换机中为热键提供额外的缓存层来解决内存中存储的负载偏差。 KV-Direct [20] 利用可编程的网卡绕过远程 CPU 并实现对远程内存的高吞吐量访问,同时提供比传统 RDMA 更丰富的语义。
这些系统侧重于提高 PUT / GET 操作的性能,而不是解决(非)编组成本或超额读取的问题。
2.3.2扩展的RInK存储
扩展的 RInK 存储库提供了比基本 RInK 存储库更丰富的域不可知的 API。Gribble【17】等人建议构建一小组集群规模的分布式数据结构。 如此处所考虑的,这类似于 Redis [7],后者也提供了数据结构,可以对存储的数据进行更细粒度的访问,但是需要应用程序使用可用数据结构之一对其对象进行建模。 Redis 也可以使用任意 C 代码模块进行扩展,Splinter [29]允许应用程序将少量代码片段发送到存储。 这些扩展是我们倡导的定制内存存储的精神。 我们主张进一步采用这种方法,并在可能的情况下将存储嵌入到应用程序服务器中,并提供更丰富的功能集,例如动态负载平衡和复制。
图2a 无状态地服务和键値存储
图2b 有状态的服务
图2c 无状态的服务和特定域的缓存
3. 消除RInK存储
我们认为实现可扩展的数据中心服务时不应使用 RInK 存储(图2a)。 在本节中,我们描述如何通过提供两种用于状态服务的标准体系结构,从现有体系结构中消除 RInK 存储。 在第4节中,我们描述了如何使这些体系结构更易于实现。
3.1有状态应用程序服务器
有状态的应用程序服务器将完整的应用程序逻辑与链接到同一进程的内存中状态缓存结合在一起(图 2b)。 这种架构有效地将 RInK 与应用服务器合并; 当仅由单个应用程序访问 RInK 并且所有请求都访问单个 key 时,这是可行的。 例如,联系人应用程序服务器可能会缓存用户地址簿,并直接接受 HTTP 请求以将其呈现在 Web UI 中。
这种体系结构消除了第2节中讨论的 RInK 问题。由于高速缓存存储应用程序对象,因此没有(取消)编组(序列化)开销或网络延迟。 同样,由于应用程序只能直接访问其对象的所需部分,因此可以消除过度读取。 例如,对于大型对象的小修改,可以用便宜的本地修改操作代替昂贵的读取-修改-写入操作。
image.png为了量化这些好处,我们进行了实验,将 S + RInK 与有状态的应用程序服务器进行了比较。 我们使用了5个客户端,每种类型的5个服务器以及如图2a所示的部署模型。 每个工作负载运行2个小时,具有80%的读取操作和20%的写入操作,总吞吐量从6 KB / s到250 MB / s。 我们测量了两种架构的资源消耗( CPU 和传输的字节)和端到端延迟的减少。 我们针对不同的对象大小和超读百分比进行了实验。
图3a,3b和表1显示了我们的结果。 在每个请求/响应延迟和资源利用率方面,有状态的方法优于 S + RInK:
-
延迟改善了29%到57%(中位),相对改善程度随对象大小的增加而增加(图3a);
-
减少的过度读取导致较低的延迟和资源利用率(图3b,表1);
3.2自定义内存存储
自定义内存存储是具有域特定接口的单独的内存缓存(图2c)。 相对于有状态的应用服务器,这种体系结构会引起额外的网络跃点,这意味着它只会缓解而不是消除 RInK 存储库中的问题。 例如,它仍然可以使用特定于域的 API 减少解组的开销和超读。 另一方面,为了交换网络跃点,它允许在多个应用程序和语言之间共享单个缓存。
例如,日历服务可能会缓存用户日历,并公开一个 find-free-slots(user,date)API 以在给定的一天中查找特定用户的空闲时隙,这比要求应用程序获取该消息的开销要小。 用户日历的整体。
开发人员经常认为 RInK 存储至关重要是有几个原因。 我们将简要列举其中的一些内容,并描述自定义内存存储如何在提供同等或更好性能的同时替换 RInK。
Fanout:无状态应用程序服务器在处理单个逻辑操作时,常常从一个 RInK 读取多个 keys 。custom 内存存储也可以支持 fanout ,但是特定于域的 API 可以减少过度读取,例如,使用聚合或快速键值存储:这种思想已经过时了。例如,为了安排一个有多个参与者的会议,日程表应用程序可能会发出许多空闲时间的 Rpc 来为每个参与者获取候选会议时间。
图4 访问内存中rich对象的Linklet API共享:RInK 存储通常用于提供由多个不同应用程序共享的缓存,以实现跨应用程序集成(例如在电子邮件客户端中显示日历)或避免在单独的缓存中复制数据。 定制的内存中存储也可以担当此角色,再次可能具有更好的性能。
资源分解:服务所有者可能希望将工作量中占用大量 CPU 和内存的部分隔离在不同的进程(即应用程序服务器和 RInK )中,以便可以分别进行调配。 就 RInK 存储可以实现更有效的配置而言,自定义内存存储也可以。
总之,与基于 RInK 的方法相比,有状态应用程序服务器或具有特定于域的缓存的无状态应用程序服务器将始终提供相同或更好的延迟,效率和可伸缩性,因为这些架构可以轻松地模仿它。 尤其是,这些体系结构减少或消除了(非)编组(序列化)开销,过度读取和网络延迟。 但是,RInK 存储之所以受欢迎,部分原因是它们易于采用。 为了使服务编写者轻松实现有状态体系结构的好处,我们提出了一种新的存储抽象,如下所述。
4 LInk 存储:提高抽象度
本节介绍了LInK存储抽象,首先通过描述自动分片器未满足的需求来引出它。
4.1 自动分片器:必要但不够
自动分片系统[8,9]是有状态应用程序服务器的必要构件:如果不能对服务器故障和工作负载的变化(例如热键)进行重新操作,那么大规模部署有状态应用程序服务器是不现实的。然而,我们在谷歌与许多内部客户进行了5年的经验表明,一个简单地将应用程序keys分配给服务器的自动分片系统会留下一些重要的问题没有解决。
特别是,自动分配器涉及分区键,但是应用程序必须处理值。例如,当键的分配从一个服务器更改到另一个服务器时,自动分配器不会移动关联的值。服务器新分配的键必须通过从影响尾部张力的存储系统中读取来恢复值。如果值在持久存储中不存在(例如,会话状态),那么它就会丢失,从而影响用户体验。
此外,需要跨多个服务器复制键(例如,出于负载或可用性原因)和相关值的一致性(强或最终)的应用程序必须自己构建这样的功能:自动分配器只处理键的分配,而不处理对其值的操作。最后,应用程序可能需要保持缓存的状态与一些底层数据存储保持同步;自动分配器在这里也没有帮助。
为了解决这些应用程序需求,我们提出了一种新的抽象,它类似于RInK,我们称之为链接存储,用于链接内存中的键值存储。我们已经构建了一个原型,一个生产团队目前正在使用它实现一个应用程序。在本节的其余部分,我们将描述链接存储。
4.2 LInk 存储
链接存储是自动分配器上的高级抽象,自动分配器提供一个分布式的、内存中的键-值映射,其中复杂的应用程序对象作为值,而不是字符串或简单数据结构。作为一个高级抽象,它提供了比自动分配器更丰富的功能。我们特别认为下列特点是可取的:
•数据一致性。链接存储可以提供跨多个副本的数据一致性,从而改进了热键的处理(可以从多个副本提供热键)。数据一致性可能很强,也可能是最终的结果;相比之下,自动分配器本身并没有提供数据一致性。
•高可用性。链接存储可以提供高可用性的数据,例如,通过复制。这减少了服务器故障后状态丢失的可能性,尽管链接存储不提供持久性保证。
•重新切分的支持 链接存储通过将值重新定位到新分配的密钥的服务器来透明地响应来自自动分配器的更改。这可以防止重新分片事件导致状态丢失,从而提高应用程序性能。
•状态损失通知 服务器可能会失败,导致状态丢失(因为在性能方面,状态的持久性无法得到保证)。为了允许应用程序检测状态丢失,链接存储在重新分片后可能丢失状态时通知应用程序。
•新鲜 链接存储可以自动检测底层数据存储中的更改并使其条目无效,从而提高数据的新鲜度。
4.3 api与架构
链路存储的结构如图5所示。它位于一个自动分配器上,使用一个连接到客户机的路由器库,将请求从应用程序客户机直接发送到应用程序服务器。应用服务器链接一个新的库,称为 LInlet ,它是链接存储的实现;它将所有服务器端交互封装在自动分配器中,在不同的应用服务器上运行的 LINKLET 实例通过 Rpc 交换状态。
图5 一个使用LInk 存储的有状态的结构 Linklet 公开了一个新的 API,它提供了对可变应用程序对象的引用。我们在图4中展示了这个 API 的基本属性。完整的 API 将包括额外的 surface area
,例如,通知应用程序状态丢失,这超出了本文的范围。
该 API 的一个重要方面是,存储的值是本机应用程序对象(模板参数V)。 为了使 LInklet 能够响应重新分片事件而传输值,应用程序必须提供代码以(解组)其对象。 开发人员在使用 RInK 存储时必须编写(取消)编组代码,因此此 API 不会增加额外的负担。 与 RInK 存储不同,序列化和反序列化不在每个请求的关键路径上。
5未解决的问题和机会
在本节中,我们将从两个角度分析有状态体系结构。首先,我们考虑在使用链接存储为有状态架构提供一流支持方面仍然存在的挑战,我们认为这些都是研究贡献的领域,也不是难以解决的问题。其次,我们提到链接存储可以启用的应用程序。
5.1 未解决的问题
负载平衡算法:有状态架构需要跨不同应用程序和工作负载操作的负载平衡算法。Slicer 有一个这样的算法,但遗留的问题包括:同时平衡多个指标、对应用程序重新分片的成本建模、快速识别负载的突变并对其做出反应而不引起振荡。我们相信应用控制理论将是新颖和有效的。
复制:复制是实现高可用性的重要技术。在 RInK 存储中,复制可以应用于存储的数据并与应用程序逻辑隔离。在链接存储中,应用程序代码和数据的紧密耦合使问题更加复杂。使用逻辑操作的状态机复制[19,23]需要确定的应用程序代码(这很难保证),而使用物理操作则需要编组对象,从而增加了链路存储试图避免的成本。确定如何处理这些相互冲突的目标是一个有待解决的问题。
最小化应用程序占用:上面建议的链接实现依赖于将大量功能链接到应用程序本身,这有两个缺点。首先,它加大了支持多种语言的难度;其次,由于开发人员必须发布新的二进制文件,这使得修复链接实现的 bug 变得更加困难。确定可以将多少链路体系结构提取到一个独立的 RPC-distance 控制服务中是一个待解决的问题。
5.2机遇
更快的无服务器:无服务器计算为开发人员提供了对响应事件(例如 AWS Lambda[3])执行的函数的抽象。链接存储可以支持跨调用保留状态的函数的高性能实现。
上下文和个性化:依赖于每个用户状态的应用程序(例如,基于对话的应用程序,如Chrome Home、Amazon Alexa 等)需要会话上下文来回答查询。并不是所有的状态都必须被持久化。例如,如果服务器故障和状态丢失很少见,那么在链接存储中保存状态(比如最后一个问题),而在持久存储中保存较长期的状态(比如每个用户的语音识别模型)可能是有意义的。
6 结论
在15-20年前,在出现高质量的通用自动分片系统之前,行业标准体系结构就已经在不断发展。我们已经讨论过,在构建快速键值存储以提高此体系结构的性能方面投入了太多精力,行业应该转向基于有状态应用程序服务器或自定义内存存储的体系结构。
有状态架构通过避免不必要的网络和(un)编组成本来提供更高的性能,这是以对基础架构软件更高的需求为代价的。为了解决这些需求,我们提出了链接存储并描述了未来研究的领域。
参考文献
[1] Apache Cassandra. http://cassandra.apache.org.
[2] Apache HBase. http://hbase.apache.org.
[3] AWS Lambda. https://aws.amazon.com/lambda/.
[4] Edgestore. https://blogs.dropbox.com/tech/2016/08/reintroducing-edgestore.
[5] JVM Serializers. https://github.com/eishay/jvm-serializers/wiki.
[6] Memcached. https://memcached.org.
[7] Redis. https://redis.io.
[8] Ringpop. https://ringpop.readthedocs.io/en/latest.
[9] A. Adya, D. Myers, J. Howell, J. Elson, C. Meek, V. Khemani, S. Fulger, P. Gu, L. Bhuvanagiri, J. Hunter, R. Peon, L. Kai, A. Shraer,
A. Merchant, and K. Lev-Ari. Slicer: Auto-sharding for datacenter applications. In OSDI, 2016.
[10] A. Belay, G. Prekas, A. Klimovic, S. Grossman, C. Kozyrakis, and
E. Bugnion. Ix: A protected dataplane operating system for high throughput and low latency. In OSDI, 2014.
[11] N. Bronson, Z. Amsden, G. Cabrera, P. Chakka, P. Dimov, H. Ding,
J. Ferris, A. Giardullo, S. Kulkarni, H. Li, M. Marchukov, D. Petrov,
L. Puzar, Y. J. Song, and V. Venkataramani. Tao: Facebook’s distributed data store for the social graph. In ATC, 2013.
[12] F. Chang, J. Dean, S. Ghemawat, W. C. Hsieh, D. A. Wallach,
M. Burrows, T. Chandra, A. Fikes, and R. E. Gruber. Bigtable: A distributed storage system for structured data. In OSDI, 2006.
[13] J. C. Corbett, J. Dean, M. Epstein, A. Fikes, C. Frost, J. J. Furman,
S. Ghemawat, A. Gubarev, C. Heiser, P. Hochschild, W. Hsieh,
S. Kanthak, E. Kogan, H. Li, A. Lloyd, S. Melnik, D. Mwaura, D. Nagle, S. Quinlan, R. Rao, L. Rolig, Y. Saito, M. Szymaniak, C. Taylor,
R. Wang, and D. Woodford. Spanner: Google’s globally-distributed database. In OSDI, 2012.
[14] A. Dragojević, D. Narayanan, O. Hodson, and M. Castro. Farm: Fast remote memory. In NSDI, 2014.
[15] B. Fan, D. G. Andersen, and M. Kaminsky. Memc3: Compact and concurrent memcache with dumber caching and smarter hashing. In NSDI, 2013.
[16] A. Fox, S. D. Gribble, Y. Chawathe, E. A. Brewer, and P. Gauthier. Cluster-based scalable network services. In SOSP, 1997.
[17] S. D. Gribble, E. A. Brewer, J. M. Hellerstein, and D. Culler. Scalable, distributed data structures for internet service construction. In OSDI, 2000.
[18] X. Jin, X. Li, H. Zhang, R. Soulé, J. Lee, N. Foster, C. Kim, and I. Stoica. Netcache: Balancing key-value stores with fast in-network caching. In SOSP, 2017.
[19] L. Lamport. The part-time parliament. In TOCS, 1998.
[20] B. Li, Z. Ruan, W. Xiao, Y. Lu, Y. Xiong, A. Putnam, E. Chen, and
L. Zhang. Kv-direct: high-performance in-memory key-value store with programmable nic. In SOSP, 2017.
[21] B. Liskov. The power of abstraction - (invited lecture abstract). In DISC, 2010.
[22] M. Mitzenmacher. The power of two choices in randomized load balancing. In TPDC, 2001.
[23] D. Ongaro and J. Ousterhout. In search of an understandable consensus algorithm. In ATC, 2014.
[24] J. Ousterhout, A. Gopalan, A. Gupta, A. Kejriwal, C. Lee, B. Montazeri,
D. Ongaro, S. J. Park, H. Qin, M. Rosenblum, et al. The ramcloud storage system. In TOCS, 2015.
[25] D. R. K. Ports, A. T. Clements, I. Zhang, S. Madden, and B. Liskov. Transactional consistency and automatic management in an application data cache. In OSDI, 2010.
[26] H. Qin, Q. Li, J. Speiser, P. Kraft, and J. Ousterhout. Arachne: core-aware thread management. In OSDI, 2018.
[27] M. Slee, A. Agarwal, and M. Kwiatkowski. Thrift: Scalable cross-language services implementation. Facebook White Paper, 2007.
网友评论