开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第32天,点击查看活动详情
引子5:Facebook使用FlightTracker获得RYW@Tao
第41篇,本文仍是引子,介绍了FlightTraceker上的一些扩展,没想打能玩的这么花。PPT来自:www.usenix.org/conference/…
Ticket-inclusive reads
FlightTracker服务确定了一个读可能关心的最近写的集合。对于 "RYW"来说,这个集合是由一个给定的最终用户(我们对 "你的 "的定义)最近完成的写。每个数据存储都要负责提供包含票据的读取,确保读取结果包括所附票据中的所有写入。
处理这些包含票据的读取通常包括三个步骤。(1)过滤相关性,(2)检查包含性,(3)和处理本地滞后性。第一步是过滤掉与读取无关的写入物。例如,如果读取要求TAO提供SONG 1005',那么只有更新对象1005'的写入才会影响结果。因此,在这次读取中,Ticket中的所有其他写内容都可以被忽略。我们把这个过程称为 "裁剪"。客户端库通常在执行读取之前对Ticket进行裁剪。在生产中,在裁剪之后,大部分的Ticket都是空的,这表明大部分的读取并不对应刚刚写入的网络请求的项目。
然而,考虑到我们每天1016次查询的读取量,即使是剩下的也是一个非同小可的数量。
该过程的下一步是验证本地数据存储是否包括相关的写入内容。这意味着评估本地数据存储相对于读取是否陈旧。对于像TAO这样的简单缓存,我们可以直接使用裁剪后的Ticket中的版本来评估缓存是否陈旧。如果是这样,TAO就可以进行最后一步:通过向其他缓存或数据库发出包含Ticket的上游读取来修复结果,并缓存这些更新的项目。
然而,这些步骤对全局二级索引提出了更多挑战。我们的索引服务通过重新洗牌、转换和过滤的管道得到异步更新(图3)。因此,写与索引读取查询的关联性往往是模糊的。更新并不总是到达索引读取服务器,因此很难确定一个本地索引副本是否包括一个特定的写。此外,每次索引服务器被认为是陈旧的时候,直接从数据库中查询索引往往会变得过于昂贵。这意味着要采用其他的策略来处理本地的呆滞性。我们通过以下技术组合来应对这些挑战。
图3. 对于全局二级索引来说,实现包含票据的读取更为复杂,因为它们的更新管道会对更新进行过滤、转换和重新分流。
客户端读取修复
有些索引查询返回的结果有足够的信息,这样我们就可以在客户端进行修补。考虑一下像图2中的简单社交图。Luna最近表示她喜欢流行音乐类型中的Song 200和爵士乐类型中的Song 789。Luna最近在FlightTracker中的写票会是这样的。
TaoWrites: [
{
id1: 42, // Luna’s user id
assoc_type: ENJOYS,
id2: 200,
version: 1
},
{
id1: 42, // Luna’s user id
assoc_type: ENJOYS,
id2: 789,
version: 8 // Luna changes her mind about this song a lot 
},
],
… // metadata for writes in other databases
假设应用程序使用索引查询来生成流行音乐流派中Luna喜欢的歌曲列表。最初的索引读取结果可能是[歌曲100,歌曲123]。Song 200不是列表的一部分,可能是因为边缘<Luna, ENJOYS, Song 200>的更新还没有复制到索引服务器上。在这种情况下,索引客户端库首先将票据裁剪下来,写入ENJOYS边的元数据,因为所有其他类型的写入都不相关。对于每一个ENJOYS边,然后从TAO读取边的id2,以评估流派是否与 "流行 "相匹配。看到 "歌曲200 "确实属于流行音乐类型,我们把它添加到最终的歌曲列表`[100, 123, 200]'中。然后就可以了! 我们修复了索引读取结果。
Arrivals
有些查询不容易被读取修复,特别是在客户端。这是因为结果不包含完整的信息。考虑一个查询,它返回一个给定的用户在每个流派中喜欢的歌曲的数量。即使我们知道最近发生了一次写入,我们也不能准确地将其与索引读取结果合并在一起。在这些情况下,我们要依靠索引本身来产生正确的响应。这意味着我们可能必须等待更新被完全复制。为此,我们在FlightTracker生态系统中建立了另一个名为Arrivals的服务。它跟踪写的内容,因为它们登陆在各种索引服务中。
Arrivals在OSDI论文中被称为FlightTracker-ReverseIndex。这个名字让人很难联系。。但本节有助于帮忙阅读论文(接下来我会发出来),因为在FT中,索引服务被设计为全局的,异步的,所以一个write完成后,程序员肯定希望确保接下来的读索引(或者倒排索引?)可以读到数据,所以这里也需要FlightTracker来保证RYW。
Arrivals,本质上是一个反向索引,跟踪一个给定的写入到其当前的复制状态。索引更新管道的各个阶段都会通知Arrivals,因为写被接收、分拣、过滤、转换,并最终应用(登陆)。在读取方面,Arrivals作为一个神谕的功能,回答一个给定的写是否。
- 肯定不会影响到一个查询。例如,如果一个用户查询他们喜欢的歌曲的数量,那么对他们不喜欢的歌曲的更新就不会影响他们的查询。
- 2.可能会影响一个查询,但是写的内容还没有被应用到索引服务器上。
- 可能会影响一个查询,并且已经被索引服务器应用(已经登陆)。
有了这个功能,社交图客户端库就会调用Arrivals,通过查询Ticket中写的状态来确定索引查询是否陈旧。如果一个索引结果可能是陈旧的,客户端可以简单地等待,直到应用更新,以实现读你写(RYW)的一致性。
Arrivals建立在与FlightTracker类似的基础设施上,使用ShardManager将其部署为一个复制的内存服务。重复使用相同的构建模块使我们能够将覆盖范围扩大到更多领域。