CIFCOM跨境电商 CIFCOM跨境电商

当前位置: 首页 » 出海百科 »

facebook收藏在哪里

发布 13 年的苹果 iCloud,如何实现存储数十亿个数据库还不卡顿的?

作者 | Leonardo Creed 翻译 | 苏宓出品 | CSDN(ID:CSDNnews)

在众多科技巨头中,相比 Google、微软、Meta 等公司,苹果无论是在 iOS 系统,还是很多新兴技术研发方面,都保持着一定的神秘感,鲜少有人知道苹果公司的基础设施是如何构建出来的?

近日,软件工程师 Leonardo Creed 在查阅了大量的论文以及整理了多个技术细节之后,向众人分享了苹果是如何构建在线同步存储服务和云端计算服务 iCloud 的,也揭晓了它如何实现存储数十亿个数据库的。通过本篇文章,也希望给相关的从业者带来更多的思考与帮助。

以下为译文:

永恒的现实世界课程

苹果在 iCloud 和 CloudKit(他们的云计算后端服务)中使用了 FoundationDB 和 Cassandra。是的,标题没有错: 苹果确实在其极端多租户架构中存储了数十亿个数据库。

在正式解析其架构之前,我想分享自己发现的一些亮点,本篇文章以及苹果公司的许多经验与我之前写过的Meta 无服务器平台架构”的在某些技术点上有些相似()。

两家都巧妙地使用了异步处理,使得用户功能用起来更加流畅。Meta 将其无服务器堆栈用于实现非面向用户的功能。苹果对几乎所有记录层(Record Layer)的功能都使用异步处理(下文将深入解释),以便向用户隐藏延迟。

两者都知道自己有广泛的可扩展性需求,因此都大量使用无状态架构( stateless architecture)。

两者都从逻辑上隔离资源,以确保系统可靠性和可用性。

两者都能简单处理各种需求。苹果公司提到了「如何为存储小数据”和大数据”分别配置和运行不同的系统」。然而,这样做会增加操作的复杂性,相反,他们用一个抽象概念来处理所有类型的数据需求。Meta 也是这样做的,他们的无服务器平台为所有类型的功能负载提供一种抽象。

两者都建立了抽象层,以便让开发人员获得更好的体验。应用程序开发人员不必担心可扩展性需求,这将由分布式系统工程师在更深的堆栈中处理。

了解你的用户。无论是应用程序开发团队还是可观测性团队,Meta 和 Apple 提供的每个层、API 和设计决策都是在明确了解特定技术用户的情况下做出的。

Cassandra 数据库

Cassandra 是一种开源的 NoSQL 数据库管理系统。它最初由 Facebook 开发,用于支持 Facebook 收件箱搜索功能。有趣的是,在 2024 年,Meta 自己开始用 ZippyDB 取代了大部分 Cassandra 的使用。

iCloud 部分采用了 Cassandra。据一家位于加利福尼亚州圣克拉拉的实时人工智能数据公司 DataStax(旗下主要产品基于 Apache Cassandra)称,苹果运行着世界上最大的 Cassandra 部署之一。

在他们发布的报告中,透露了苹果在 Cassandra 方面有:

超过 30 万个实例/节点

数百 PB 的数据(如果不是 exabytes的话)

每个集群超过 2 PB,有数千个集群

每秒数百万次查询

数千个应用程序

对此,此前也有不少苹果前员工透露,iCloud 服务中 Cassandra 所管理的数据量高达数亿字节。每台服务器有多个 Cassandra 节点,这确保了 iCloud 数据的可用性接近 100%。

至此,苹果公司内部团队仍在积极改进 Cassandra。上个月,苹果公司的 Cassandra 存储工程经理 Scott Andreas 在一次会议上就 Cassandra 的未来发表了演讲。在苹果公司的招聘页面上,他们也在招聘分布式系统工程师时通常会提到 Cassandra。

然而,CloudKit + Cassandra 的解决方案在实际应用中遇到了两个可扩展性限制,因此苹果工程团队后来引入并采用了 FoundationDB:

在单个区域内,即使正在不同的记录,一次也只能进行一个操作。对于多个用户或设备需要同时处理共享数据的应用程序来说,这可能会带来问题。

在原子操作中同时更新多个记录时,更新仅限于单个 Cassandra 分区。这些分区有其可处理的最大大小,随着分区大小的增加,Cassandra 的运行速度往往会减慢。

FoundationDB 和记录层解决了这两个问题。

FoundationDB 数据库

苹果公司对 FoundationDB 的态度更为公开。他们在 2015 年收购了数据库公司 FoundationDB,并在此后发表了多篇论文,详细介绍了他们对 FoundationDB 的使用。

FoundationDB 是一种开源、分布式、事务性键值存储。它专为处理大量数据而设计,并且非常适合读/写工作负载和写入密集型工作负载。它还符合 ACID 标准。

Apple 在 CloudKit(Apple 的云计算后端服务)中广泛使用 FoundationDB 记录层。

在 FoundationDB 记录层的 GitHub 页面上,该团队详细介绍道:

记录层(Record Layer)是一个 Java API,它在 FoundationDB 的基础上提供了一个面向记录的存储,(非常)大致相当于一个简单的关系数据库,具有以下特点:

结构化类型--记录以 protobuf(协议缓冲区)消息的形式定义和存储。protobuf 最早是由谷歌设计的。

索引--记录层支持各种不同的索引类型,包括值索引(大多数数据库提供的那种)、排名索引和聚合索引。可以通过 protobuf 选项或编程方式定义索引和主键。

复杂类型--支持复杂类型,如列表和嵌套记录,包括针对此类嵌套结构定义索引的功能。

查询--记录层不提供查询语言,但提供了查询应用程序接口(API),可对一种或多种记录类型进行扫描、过滤和排序,还提供了可自动选择索引的查询规划器。

许多记录存储,共享模式--记录层提供了支持许多离散记录存储实例的能力,所有这些实例都有一个共享(和不断发展的)模式。例如,每个用户都可以拥有自己的记录存储空间,或许可以在不同的 FDB 集群实例之间进行分片,而不是建立一个单一的数据库来存储所有用户的数据。

重量轻--记录层设计用于大型分布式无状态环境。从打开存储到首次查询之间的时间以毫秒为单位。

可扩展性--新的索引类型和自定义索引键表达式可以动态地集成到记录存储中。

在 FoundationDB 记录层论文中,他们写道:[FoundationDB 记录层用于]为服务于数亿用户的应用程序提供强大的抽象。CloudKit 使用记录层来托管数十亿个独立数据库,其中许多数据库具有共同的模式。”

为什么使用 FoundationDB 记录层?

FoundationDB、Record Layer 和 CloudKit 的结构如下所示:

FoundationDB 负责所有分布式系统和并发控制工作。

记录层充当关系数据库,使 FoundationDB 更易于使用。

CloudKit 是最上层,为应用开发人员提供功能和 API。CloudKit 并不是唯一构建在记录层之上的东西,顶部还有其他内部构建的层,用于需要结构化存储的东西,如 JSON 文档存储。

记录层允许苹果大规模支持多租户。

事实上,这样说有点言过其实。

记录层用于极端多租户,其中每个应用程序的每个用户都能获得独立的记录存储。这意味着记录层可托管数十亿个独立数据库,共享数千个模式。

这样更好!而且更令人印象深刻。

记录层之所以能够处理如此大规模的多租户问题,主要得益于两个基本的架构决策:

1. 该层以无状态方式运行,只需添加更多无状态实例,即可轻松扩展计算资源。

这种无状态架构简化了负载均衡器和路由器的任务,因为它们只需关注数据的位置,而不是计算服务器的能力。此外,无状态服务器在客户端之间分配的资源也减少了。

2. 该层使用记录存储抽象来有效管理资源分配和可扩展性。这种抽象代表了逻辑数据库的全部内容,包括序列化数据、索引和运行状态。

每个记录存储分配一个特定的密钥范围,从而保证不同租户的数据在逻辑上相互分离。如有必要,转移租户的数据只需将分配的密钥范围迁移到新的群集即可,因为管理和使用记录存储所需的所有信息都包含在此范围内。

至此,我们可以粗略地了解一下苹果公司是如何构建 iCloud 的。

CloudKit 如何使用 FoundationDB 和记录层?

在 CloudKit 中,应用程序由逻辑容器”(logical container)表示,该容器遵循定义的模式。该架构概述了实现高效数据检索和查询所需的记录类型、字段和索引。应用程序将其数据组织到 CloudKit 中的区域”中,这样就可以对记录进行逻辑分组,以便有选择地与客户端设备同步。

对于每个用户,CloudKit 都会在 FoundationDB 中指定一个唯一的子空间。在这个子空间中,它会为用户与之交互的每个应用程序创建一个记录存储空间。从本质上讲,CloudKit 管理着大量逻辑数据库(用户数量乘以应用程序数量),每个数据库都包含自己的记录、索引和元数据集,总计数十亿个数据库。

当 CloudKit 收到来自客户端设备的请求时,它会通过负载均衡将该请求定向到可用的 CloudKit 服务进程。然后,该进程与特定的记录层记录存储进行交互,以满足请求。

CloudKit 会将已定义的应用程序模式转换为记录层中的元数据定义,并将其存储在单独的元数据存储区中。该元数据由 CloudKit 特定的系统字段进行扩充,这些字段用于跟踪记录的创建、修改时间和记录存储的区域。区域名称以主键为前缀,以便能够高效访问每个区域内的记录。除了用户定义的索引外,CloudKit 还管理用于内部目的的系统索引”,例如通过保留按类型跟踪记录大小的索引来管理存储配额。

FoundationDB 和记录层共同为苹果公司解决了 4 个关键问题,这是单独使用 Cassandra 或单独使用 FoundationDB 都无法解决的。

问题一:个性化全文搜索

FoundationDB 帮助用户解决个性化全文搜索问题,以便快速访问数据。

苹果的系统利用 FoundationDB 的排序键顺序,可以快速搜索文本开头(前缀匹配),也可以进行更复杂的搜索(如查找相邻或按特定顺序排列的单词——近似搜索和短语搜索),而无需额外的开销。

在传统的搜索系统中,你通常需要在后台运行额外的进程来保持搜索索引的更新,但苹果的系统可以实时完成所有工作,这意味着一旦数据发生变化,搜索索引就会立即更新,无需额外的步骤。

问题二:高并发情况

有了 FoundationDB,CloudKit 可以流畅地处理同时发生的许多更新。

以前,在使用 Cassandra 时,CloudKit 需要依靠一个特殊的索引来跟踪每个区域的变化,从而实现跨设备的数据同步。当设备需要更新其数据时,它会检查该索引以查看新内容。但这种系统有一个缺点:当多个更新同时发生时,可能会造成冲突。

但在 FoundationDB 中,CloudKit 使用了一种特殊的索引,它能准确记录每次更改的顺序,而不会造成冲突。具体做法是为每次更改分配一个唯一的版本”,当 CloudKit 需要同步时,它会查看这些版本,以确定设备错过了哪些更新。

然而,当 CloudKit 需要在不同的存储集群之间移动数据时(也许是为了更均匀地分配负载),事情就变得棘手了,因为每个集群都有自己的版本号,而这些版本号并不一致。

为了解决这个问题,CloudKit 为每个用户的数据提供了一个移动计数”(称为 化身”),每次将其数据传输到新的集群时,该计数都会增加。每次记录更新都包含用户当前的化身”编号,确保即使在移动后,CloudKit 仍能通过查看化身编号和版本编号来确定正确的更新顺序。

在转到新系统时,CloudKit 面临着处理没有版本号的旧数据的挑战。苹果工程团队巧妙地克服了这一难题,他们通过使用一个特殊的功能,在新系统之前使用以前的系统对旧更新进行排序。这意味着无需对应用程序进行复杂的更改,也不会留下过时的代码。该函数考虑了版本、版本号和旧的更新计数器值,以保持记录的正确顺序。

问题三:高延迟查询

FoundationDB 是为高并发而不是低延迟而设计的。这意味着它可以同时处理大量任务,而不是专注于单个任务的速度。

为了充分利用这种设计,记录层的许多工作都是异步”进行的——它将将来要完成的任务排队,允许同时完成其他工作。这种方法有助于掩盖这些任务中可能出现的任何延迟。

不过,FoundationDB 用来与其数据库通信的工具,是设计为使用单线程联网,一次只做一件事。在早期版本中,这种设置造成了系统中的交通堵塞,因为所有的事情都在等待轮到这个网络线程。记录层一直使用这种单线程方法,这导致了瓶颈。

为了改善这一问题,苹果减少了网络线程的工作量。现在,复杂的任务看起来速度更快了,因为系统同时在几个方面与数据库合作,而不是形成一个队列。这样,延迟或表面上的缓慢就被掩盖了,因为系统不会等一个任务完成后再开始另一个任务。

问题四:事务冲突

在 FoundationDB 中,如果一个事务正在读取某些键,而另一个事务同时修改了这些键,就会导致事务冲突”。FoundationDB 通过提供对控制读取或写入时可能导致冲突的键集,来精确管理这些冲突。

一种避免不必要冲突的常用方法是,在键的范围内执行一种不会导致冲突的特殊读取,称为快照”读取。如果这种读取发现了重要的键,事务将只标记那些可能发生冲突的特定键,而不是整个范围。这样可以确保事务只受对其结果有实际影响的变化的影响。

记录层使用这种策略来有效管理被称之为跳过列表的数据结构,这是其排序索引系统的一部分。不过,手动设置这些冲突范围可能比较麻烦,而且可能导致难以识别的错误,尤其是当它们与应用程序的主要逻辑混合在一起时。

因此,建议在 FoundationDB 基础上构建的系统创建更高级别的工具(如自定义索引)来处理这些模式。这种方法有助于避免将放宽冲突规则的责任留给每个客户端应用程序,从而导致错误和不一致。

对于 Leonardo Creed 的分享,不少开发者对此也有了更深度的思考:

亚马逊就是这么做 Aurora 的。将所有状态转移到对象存储层,而对象存储层也是处理过程的末端(经过 lb、前端、后端、数据库,最后到磁盘)。无状态基本上就是把所有东西都移到后端。

我敢肯定,Google 也在做同样的事情/已经开始做了。同时,这也使其易于”横向扩展:只要你能在对象层面上进行抽象,你就可以扩展你的底层基础架构,以便只处理对象”。

也有一位苹果前员工评论道:

遗憾的是,我在苹果公司工作时从未参与过这方面的工作(不过我参加过这方面的面试!),但几年前听到的这件事让我意识到了一些本该显而易见的事情:数据库和文件系统之间其实并没有什么区别。

从根本上说,它们做的是同一件事,只是针对特定问题集进行了优化。数据库适用于有适当索引的数据,而文件系统则适用于更为随意的数据。

如果你是一个足够聪明的工程师,你可以用数据库来定义文件系统,iCloud 就是一个很好的例子。就我个人而言,我利用这些知识使用 Cassandra 为 HLS 流存储视频数据块。这让我获得了很多 Cassandra 的分布式优势,但代价是不得不重新发明一些文件系统的东西。

参考链接:

?id=39028672

Facebook平台的素材投放版位讲解

今天我们来聊一下Facebook平台的素材版位,之后也会说一下其他平台的素材展示版位。

之所以聊这个是因为随着优化的深入,越来越觉得版位不只是一个展示的地方,而且还可以根据版位去做一些有针对性的素材和版位优化,从而获得更好的数据表现,值得我们都好好再研究一下。先简单说一下FB的主要投放位置是在Facebook,Instagram,Messenger和Audience Network这四大块产品线上。FB平台会给这四个主要子平台插入广告版位。以下为目前更新的所有FB广告后台版位:

01 Facebook

分为以下几个细节版位:

Facebook News Feed Facebook新闻推送Facebook Video Feeds Facebook视频推送Facebook Stories Facebook故事Facebook In-Stream Videos Facebook插播视频Facebook Instant Articles Facebook即时文章


图片来源:Facebook广告后台

02 Instagram

可用版位为:

Instagram Feed Instagram推送Instagram Stories Instagram故事

*图片来源:Facebook广告后台

03 Messenger

分为以下2个版位:

Messenger Inbox Messenger收件箱Messenger Stories Messager故事

*图片来源:Facebook广告后台

04 Audience Network

有这2个版位:

Audience Network Native, Banner and Interstitial 受众网络原生,横幅和非页内广告Audience Network Rewarded Videos 观众网络奖励视频

*图片来源:Facebook广告后台

由于上面的11个版位是在广告后台分别展示说明,信息不太集中,我粗略整理了一个表供大家参考,是从尺寸和素材形式上来分类的:

注:标记为1”的为FB推荐使用尺寸。


我们再来看看FB在素材上传的时候对图片和视频的要求说明:

*图片广告尺寸说明 图片来源:Facebook广告后台

*视频广告尺寸说明 图片来源:Facebook广告后台

也就是说,FB在上传素材的时候,对素材的尺寸要求是图片1.91*1或者4*5,视频尺寸9*16或者16*9。

我们把FB推荐尺寸和对素材上传的要求重合来看,标记为1”的仍然是推荐尺寸,填充为橙色的为素材尺寸要求。

这样就会发现,FB对素材的要求和版位推荐的尺寸的重合度来说,并不是最高的,有些版位是覆盖不到的。而这些覆盖不到的版位,有部分根本不会有展示分配给不合适尺寸的素材,也有会被FB自动剪裁为合适的尺寸去填充的版位。通常剪裁的素材也并不完全是素材本身想表达的内容,效果自然也差别很大。

讲到这里,我想所有产品投放都有必要结合咱们的主要KPI目标分Platform去看看每个版位的表现,根据不同的版位表现,去调节合适的素材尺寸,会更有利于我们把效果放大,往更合适的版位去进行倾斜。

具体每个产品的类型不同,KPI不同,很难说哪个版位效果最好,哪个版位效果就一定不好,所以可以先用不同的尺寸去测试,综合来看最后哪个版位的数据最理想,然后在有结果后去做调整。

当然现在FB有可以自定义版位和对素材进行版位个性化处理的功能,也会加快我们的测试速度以及尽可能多的帮助我们覆盖不同版位。

对海外广告推广感兴趣的同学欢迎私信我

Apple 如何构建 iCloud 来存储数十亿个数据库

作者丨Leonardo Creed

编译丨诺亚

出品 | 51CTO技术栈(微信号:blog51cto)

在过去的几个月里,我写了关于大型科技公司的各种技术幕后揭秘”的文章,例如 Meta 的内部无服务器平台、 Google 内部喜爱的代码审查工具等等。不过,苹果的基础设施并不那么公开。我想了解 Apple 是如何构建 iCloud 的,在这篇文章中,我将介绍我所知道的一切。

Apple 将 FoundationDB 和 Cassandra 用于其云端后端服务 iCloud 和 CloudKit。而且本文的标题并没有弄错:苹果确实在其极端的多租户架构中存储了数十亿个数据库。

一、阅读指南

我发现,论文中以及苹果的实践经验与Meta无服务器平台架构的设计原则和教训高度契合。

1、两者都巧妙地运用了异步处理技术,以实现用户功能的流畅性。Meta在其无服务器架构中,将非面向用户的函数任务利用该技术进行处理,从而避免影响用户体验。而苹果则在Record Layer(在下文将详细解释)的几乎全部功能上采用异步处理方式,目的是隐藏延迟,确保用户感受到的是即时响应。

2、两者都广泛采用无状态架构设计,鉴于它们都有极高的可扩展性需求。(注:无状态架构意味着服务器不保存任何会话或请求之间的持久化状态信息,从而使得每个请求都能独立处理,且可以根据需要轻松地增加或减少服务器实例以应对流量变化。)

3、两者都通过逻辑隔离资源来确保可靠性和可用性。

4、两者都以简化的方式处理各类需求。苹果提到,为存储小数据”和大数据”分别配置和运营独立系统是很有诱惑力的做法,但这会增加运维的复杂性。因此,苹果选择用一个抽象层来处理所有类型的数据需求。同样地,Meta在他们的无服务器平台上也采用相同策略,提供了一个统一的抽象层,用于处理各种函数负载。

5、两者都通过构建抽象层来优化开发者体验,让应用开发者无需过多关注可扩展性需求。这些需求由底层分布式系统工程师在更深层次的架构中处理。

6、深知用户需求。无论是Meta还是Apple,它们提供的每一层架构、API设计以及每一个设计决策都是基于对特定技术使用者(无论是应用开发团队还是可观测性团队)清晰理解的基础上制定的。

二、Cassandra

Cassandra 是一种分布式、宽列式NoSQL数据库管理系统,最初由Facebook开发,用于支持Facebook收件箱搜索功能的实现。有趣的是,后来的Meta自身已逐步用ZippyDB替代了大量原本使用Cassandra的地方。

根据DataStax的信息,iCloud的部分功能由Cassandra提供支持。苹果运营着全球规模最大的Cassandra部署之一。

他们报告指出:

超过30万个实例/节点数据规模达到数百PB(甚至EB级别)每个集群处理超过2 PB的数据,且拥有数千个这样的集群每秒处理数百万次查询支持数千个应用程序

Cassandra在iCloud中的应用确实彰显了其管理海量数据的能力,达到EB级别。苹果在其服务器上采用多节点Cassandra部署策略,并且团队在设计时非常注重爆炸半径”(blast radius)控制和数据分片(sharding),以最大程度地减少故障影响范围并优化数据分布与访问性能,从而确保iCloud服务的数据可用性接近100%。

与此同时,苹果公司内部仍在积极改进Cassandra技术。来自苹果公司的Scott Andreas最近发表了关于Cassandra未来发展的演讲。同时,在苹果的招聘页面上,经常可以看到他们为分布式系统工程师岗位列出熟练使用Cassandra的要求。

尽管Cassandra在处理大规模分布式存储方面表现出色,但在苹果iCloud的特定场景下,结合使用CloudKit和Cassandra时遇到了两个关键的可扩展性限制,这导致他们采用了 FoundationDB。

1、在Cassandra单一分区内,即使的是不同的记录,同一时间也只能进行一个操作。这意味着对于那些需要多个用户或设备同时处理共享数据的应用程序来说,可能会出现性能瓶颈和并发控制问题。

2、在Cassandra中,如果需要在一个原子操作内同时更新多个记录,这些更新操作会受限于单个Cassandra分区。每个分区都有其能够处理的最大数据量限制,随着分区内数据的不断增长,Cassandra的性能往往会随之下降。

FoundationDB 和 Record Layer 解决了这两个问题。

三、FoundationDB

苹果对FoundationDB的公开程度要高得多。他们于 2015 年收购了 FoundationDB,此后发表了多篇论文,详细介绍了他们对 FoundationDB 的使用。

FoundationDB 是一个开源的分布式事务型键值存储系统,旨在处理大规模的数据量,并且在读写混合负载以及写入密集型工作负载方面表现出色。此外,FoundationDB 也符合 ACID(原子性、一致性、隔离性和持久性)原则。

苹果在CloudKit(其云端后端服务)中广泛使用了FoundationDB Record Layer。

来源:《FoundationDB Record Layer:开源结构化存储》

从GitHub上的描述来看,Record Layer是一个基于FoundationDB的Java API,它提供了一种面向记录的存储方式,可以大致类比为一个简单的关系型数据库。具体特性包括:

1、结构化类型:记录以Protocol Buffer(protobuf)消息的形式进行定义和存储,Protocol Buffer是一种最初由Google设计的数据序列化协议。

2、索引:Record Layer支持多种索引类型,如值索引(大多数数据库都提供的那种)、排名索引和聚合索引。索引和主键可以通过protobuf选项或程序化方式来定义。

3、复杂类型:支持复杂数据类型,例如列表和嵌套记录,并且能够针对这些嵌套结构定义索引。

4、查询功能:虽然Record Layer并未提供查询语言,但它提供了API接口,支持对一个或多个记录类型进行扫描、过滤和排序操作,同时还包含一个能够自动选择合适索引的查询规划器。

5、多个记录存储与共享模式:Record Layer允许创建并管理多个独立的记录存储实例,所有实例都采用共享(且可动态演变)的模式。举例来说,不同于在一个单一数据库中存储所有用户数据的方式,每个用户可以拥有自己的记录存储,甚至可以根据需要跨不同的FDB集群实例进行分片处理。

6、极轻量级:Record Layer被设计用于大型、分布式、无状态环境,旨在实现从打开存储到执行首次查询之间的时间间隔达到毫秒级别。

7、扩展性强:新的索引类型以及自定义索引键表达式可以动态地融入到记录存储中。

根据FoundationDB Record Layer论文所述,苹果使用FoundationDB Record Layer为服务数亿用户的大型应用提供强大的抽象层支持。CloudKit 使用Record Layer来托管数十亿个独立的数据库,其中许多数据库共享相同的模式(schema)。

四、为什么要使用 FoundationDB Record Layer

FoundationDB、Record Layer 和 CloudKit 的结构如下所示:

来源:《FoundationDB Record Layer: 开源结构化存储》

FoundationDB 负责所有的分布式系统和并发控制工作。Record Layer 作为中间层,充当了关系数据库,以便开发者能够更轻松地与 FoundationDB 进行交互。CloudKit 是最顶层的服务,为应用开发者提供了丰富的功能和API。虽然CloudKit是构建在Record Layer之上的一个典型应用案例,但内部还有其他服务和组件也基于Record Layer构建,比如用于处理JSON文档存储等需要结构化存储的场景。

Record Layer 使苹果能够在大规模上实现多租户支持。

实际上,这样的描述可能还显得保守了。

Record Layer 被用于极端的多租户环境,其中每个应用程序的每个用户都能获得独立的记录存储空间。这意味着Record Layer 托管着数十亿个共享数千种模式的独立数据库。

来源:《FoundationDB Record Layer: 开源结构化存储》

Record Layer 能够在如此大规模上成功处理多租户问题,主要归功于其两个核心架构决策:

1、无状态操作:Record Layer 设计为无状态模式,这意味着通过简单地增加更多无状态实例,就可以轻松扩展计算资源。

这种设计使得负载均衡器和路由器的工作变得更为简化,它们只需关注数据的位置而非计算服务器的具体能力。同时,由于无状态服务器无需维护会话状态等信息,因此分配给客户端的资源集合得以减少。

2、记录存储抽象化管理:Record Layer 使用记录存储抽象层来高效管理资源分配和可扩展性。这个抽象层代表了整个逻辑数据库,包含了序列化数据、索引以及运行时状态。

每个记录存储都有特定的键范围分配,确保不同租户的数据在逻辑上保持分离。如有必要迁移某个租户的数据,过程十分直接,只需将分配给该租户的键范围迁移到新的集群中即可,因为管理与使用该记录存储所需的所有信息都包含在这个键范围内。

五、CloudKit 如何使用 FoundationDB 和Record Layer

来源:《FoundationDB Record Layer: 多租户结构化数据存储系统》

在CloudKit中,每个应用程序由一个遵循特定模式的逻辑容器”来表示。这个模式详细定义了必要的记录类型、字段和索引,以实现高效的数据检索和查询功能。应用程序在CloudKit内部将其数据组织到不同的区域”(zones)中,这样可以按逻辑分组记录,便于与客户端设备进行选择性同步。

对于每一位用户,CloudKit在FoundationDB中分配一个唯一的子空间。在这个子空间内,针对用户使用的所有应用程序,CloudKit都会为每个应用创建一个记录存储。换言之,CloudKit实际上管理着大量逻辑数据库——即用户数量乘以应用程序数量所得到的数量级,每一个都包含其自身的记录集、索引和元数据,总量高达数十亿个独立数据库。

当CloudKit接收到来自客户端设备的请求时,它会通过负载均衡机制将请求导向可用的CloudKit服务进程。该服务进程随后与Record Layer中的相应记录存储进行交互,以完成请求操作。

CloudKit将定义好的应用程序模式转换为Record Layer中的元数据定义,并将其存储在独立的元数据存储中。此外,CloudKit还会添加特定的系统字段来丰富这些元数据,如记录的创建时间、修改时间以及记录所在的区域信息。为了实现对每个区域内记录的有效访问,区域名称会被作为前缀附加到主键上。除了用户自定义的索引外,CloudKit还管理系统索引”,例如为了管理存储配额而维护的一种根据记录类型追踪其大小的索引。

FoundationDB和Record Layer结合使用,共同解决了苹果面临的一些关键问题,这些问题单靠Cassandra或FoundationDB都无法完美解决。

六、已解决的问题

1、个性化全文搜索

FoundationDB在解决用户个性化全文搜索,以快速访问其数据方面发挥了重要作用。苹果的系统利用了FoundationDB的键顺序特性,能够实现对文本开头(前缀匹配)进行快速搜索,并且无需额外开销即可处理更复杂的搜索需求,如查找相近词或特定顺序排列的词语(邻近搜索和短语搜索)。

在传统的搜索系统中,通常需要后台运行额外的进程来保持搜索索引的实时更新。而苹果的系统则实现了所有操作的实时性,这意味着一旦数据发生变化,搜索索引会立即得到更新,无需任何额外步骤。这种设计不仅提高了搜索效率,还确保了数据的一致性和时效性,为用户提供更为流畅、准确的搜索体验。

2、高并发区域

FoundationDB为CloudKit处理同时发生的大量更新提供了更为平滑和一致的方式。

在以前使用Cassandra时,CloudKit依赖于一个特殊的索引来追踪各个区域内的数据变化以实现跨设备同步。当设备需要更新数据时,会通过检查这个索引来获取最新信息。但这种方法存在一个问题:当多台设备几乎同时进行更新操作时,可能会引发冲突。

而采用FoundationDB后,CloudKit利用了一种特殊类型的索引,它可以精确地跟踪每一次更改的顺序,而且不会导致冲突。这种机制是通过为每次变更分配一个唯一的版本号”来实现的,当CloudKit需要进行同步时,它会根据这些版本号来确定设备错过了哪些更新内容。

然而,在将数据从一个存储集群转移到另一个存储集群(可能是为了更均匀地分布负载)时,情况变得复杂起来,因为每个集群都有自己独立的、不匹配的版本号。为解决这一问题,CloudKit为每位用户的每份数据赋予了一个称为化身”的迁移计数”,每当用户的数据被迁移到新集群时,化身”值就会递增。每个记录更新都会包含用户当前的化身”号码,从而确保即使在迁移之后,CloudKit仍可以根据化身号和版本号来正确判断出更新的顺序。

当CloudKit切换到这个新系统时,面临的挑战之一是如何处理那些尚未带有版本号的老数据。他们巧妙地解决了这个问题,通过运用一种特殊函数,该函数可以先按照旧系统的方式对老的更新进行排序,然后再加入新系统的更新。这意味着无需对应用程序进行复杂的改动或遗留过时代码。此函数综合考虑了化身、版本以及旧的更新计数器值,确保了记录顺序的准确性。

3、高延迟查询

FoundationDB 是为高并发设计的,而非针对低延迟。这意味着它能够同时处理大量任务,而不是专注于单个任务的速度。

来源:《FoundationDB Record Layer: 开源结构化存储》

为了充分利用这种设计,Record Layer在处理任务时采用了大量的异步操作方式——它会将任务排队等待未来完成,期间可以继续进行其他工作。这种方法有助于掩盖这些任务执行过程中可能出现的延迟。

然而,FoundationDB用于与数据库通信的工具最初是采用单线程模式设计,一次只做一件事并使用一个网络线程。在早期版本中,这种设置导致了系统内部的拥堵,因为所有任务都在等待轮到自己在这条网络线程上执行。Record Layer也沿用了这种单线程处理方法,这导致了性能瓶颈。

为了解决这一问题,苹果公司着手减轻这条网络线程的工作负载。现在,通过让系统同时从多个角度与数据库协同工作,而非形成单一的任务队列,使得复杂的任务看上去执行速度更快。这样一来,由于系统无需等待一个任务完成后再开始另一个任务,所以延迟或所谓的缓慢感”被有效地隐藏起来。

4、冲突事务

在FoundationDB中,如果一个事务正在读取某些键值,而另一个事务在同一时刻修改了这些相同的键值,则会导致事务冲突”。FoundationDB通过提供对可能导致冲突的键集合进行精确控制的能力,从而允许精细管理这些冲突。

避免不必要的冲突的一个常见方法是对一组键执行一种特殊的、不会引发冲突的读取操作,即所谓的快照”读取。如果这种读取发现重要键值,那么事务只会针对那些特定键标记潜在冲突,而不是整个键范围。这样可以确保事务只受到与其结果真正相关的更改影响。

Record Layer采用了这一策略来高效地管理其排名索引系统中的一部分结构——跳表(skip list)。然而,手动设置这些冲突范围可能较为复杂,并且可能导致难以识别的错误,特别是当它们与应用程序的主要逻辑混合在一起时。因此,建议构建于FoundationDB之上的系统创建更高级别的工具,如自定义索引,以处理这些模式。这种方法有助于避免将放宽冲突规则的责任留给每个客户端应用,否则可能会导致错误和一致性问题的发生。

参考链接:

来源: 51CTO技术栈

未经允许不得转载: CIFCOM跨境电商 » facebook收藏在哪里

相关文章

themebetter

contact