Facebook是如何从简单的数据库分片扩展到分布式分片通用平台?


多年来,Facebook已从一种基本的Web服务器体系结构演变为一个复杂的体系结构,其中包含成千上万的服务在后台运行。扩展Facebook产品所需的各种后端服务并不是一件容易的事。而且发现我们的许多团队正在构建具有重叠功能的自定义分片解决方案。为了解决此问题,我们将Shard Manager构建为通用平台,以促进可靠分片应用程序的有效开发和操作。
使用分片扩展服务的概念并不新鲜。但是,据我们所知,我们是业界唯一在我们的规模上获得广泛采用的通用分片平台。Shard Manager管理生产中成百上千个应用程序中成千上万个服务器上托管的数千万个分片。

 
分片简介
人们熟悉分片作为扩展服务以支持高吞吐量的一种方式。下图说明了典型Web堆栈的缩放比例。Web层通常是无状态的,并且易于扩展。由于任何服务器都可以处理任何请求,因此可以使用多种通信量路由策略,例如轮循或随机。

另一方面,缩放数据库部分由于其状态是不平凡的。我们需要应用一种方案来确定性地跨服务器分布数据。像散列这样的简单散列方案hash(data_key) % num_servers 可以散布数据,但是当按比例添加服务器时,存在将数据混排的问题。一致性哈希通过仅将一小部分数据从现有服务器重新分配到新服务器来解决此问题。但是,此方案要求应用程序具有细粒度的键才能使统计负载平衡有效。由于其本质,一致性哈希支持基于约束的分配的能力(例如,应将欧洲联盟用户的数据存储在欧洲数据中心以降低延迟)。结果,只有某些类型的应用程序(例如分布式缓存)才采用此方案。
一种替代方案是将数据显式分区为分配给服务器的分片。数十亿用户的数据存储在许多数据库实例中,每个实例都可以视为一个分片。为了提高容错能力,每个数据库分片可以具有多个副本(又名副本),每个副本都可以发挥不同的作用 (例如,主要或次要),具体取决于一致性要求。
明确分配给服务器的分片具有合并各种约束(例如,哈希解决方案无法支持的位置首选项)的能力。我们发现分片方法比散列方法更灵活,并且适合更广泛的分布式应用程序的需求。
采用这种分片方法的应用程序通常需要某些分片管理功能才能可靠地大规模运行。最基本的功能是故障转移功能。如果发生硬件或软件故障,系统可以将客户端流量从故障服务器转移开,甚至可能需要在运行状况良好的服务器上重建受影响的副本。在大型数据中心中,服务器始终计划停机以执行硬件或软件维护。分片管理系统需要通过主动将副本从服务器上移开以确保每个分片具有足够的正常副本,以便在必要时将其删除。
另外,可能不均匀且不断变化的分片负载需要负载平衡,这意味着必须动态调整每个服务器主机的分片集,以实现统一的资源利用率并提高整体资源效率和服务可靠性。最后,客户端流量的波动需要分片扩展,系统在每个分片的基础上动态调整复制因子,以确保其平均每个副本负载保持最佳状态。
我们发现,Facebook的不同服务团队已经在构建自己的自定义解决方案,以实现不同程度的完整性。常见的情况是,服务能够处理故障转移,但是负载平衡的形式非常有限。这导致次优的可靠性和较高的操作开销。这就是为什么我们将Shard Manager设计为通用的分片管理平台的原因。
 
使用分片管理器将分片作为平台
多年来,已将数百个分片应用程序构建或迁移到Shard Manager上,具有历史超增长的上十万个服务器上总共有上千万个分片副本,这些应用程序有助于各种面向用户的产品(包括Facebook应用程序,Messenger,WhatsApp和Instagram)的平稳运行。
首先,与Shard Manager集成意味着简单地实现一个由add_shard 和原语组成的小而直接的界面drop_shard 。其次,每个应用程序都可以通过基于意图的规范来声明其可靠性和效率要求。第三,使用通用约束优化求解器使Shard Manager能够提供通用的负载平衡功能,并轻松添加对新平衡策略的支持。
最后但并非最不重要的一点是,通过完全集成到包括容量和容器管理在内的整个基础架构生态系统中,Shard Manager不仅支持分片应用程序的高效开发,而且还支持分片应用程序的安全运行,因此提供了端到端解决方案,这是同类平台所没有的提供。与类似的平台(例如基于Hex的Apache Helix)(包括基于Paxos的存储系统用例)相比,Shard Manager支持更复杂的用例。
 
Shard Manager应用程序的类型
我们在Shard Manager上抽象了应用程序的通用性,并将它们分为三种类型:仅主,仅次和主次。

仅主Primary only:
主副本每个分片都有一个副本,称为主副本。这些类型的应用程序通常将状态存储在外部系统中,例如数据库和数据仓库。一个常见的范例是,每个分片代表一个工作程序,该工作程序使用诸如批处理之类的可选优化来获取指定的数据,对其进行处理,有选择地服务于客户端请求并回写结果。流处理是一个真实的示例,它处理来自输入流的数据并将结果写入输出流。Shard Manager提供了至多一项主要保证,以帮助防止由于重复数据处理而导致的数据不一致,就像传统的基于ZooKeeper锁的方法一样。

仅次Secondaries only:
节点每个分片具有多个角色相同的副本,称为辅助节点。来自多个副本的冗余提供了更好的容错能力。此外,可以根据工作负载调整复制因子:热分片可以具有更多副本来分散负载。通常,这些类型的应用程序是只读的,没有很强的一致性要求。他们从外部存储系统中获取数据,可选地处理数据,在本地缓存结果,并根据本地数据提供查询。一个真实的例子是机器学习推理系统,该系统从远程存储中下载经过训练的模型并服务于推理请求。

主次
节点每个分片具有主次节点两个角色的多个副本。这些类型的应用程序通常是对数据一致性和持久性有严格要求的存储系统,其中主副本接受写请求并驱动所有副本之间的复制,而辅助副本提供冗余,并且可以选择提供读取以减少主副本上的负载。一个示例是ZippyDB,它是具有基于Paxos的复制的全局键值存储。

我们发现以上三种类型可以在Facebook上对大多数分片应用程序建模,截至2020年8月的百分比分布如下所示。由于架构的简单性和与传统ZooKeeper基于锁的解决方案的概念相似性,百分之六十七的应用程序是仅主的应用程序。但是,就服务器数量而言,仅主的应用程序仅占17%,这意味着仅主的应用程序平均比其他两种类型的应用程序小。

 
使用Shard Manager构建应用程序
在应用程序所有者决定如何将其工作负载/数据切成分片以及哪种应用程序类型适合其需求之后,无论用例如何,在Shard Manager上构建分片应用程序都需要执行三个简单的标准化步骤。

  1. 应用程序链接了Shard Manager库,并通过插入其业务逻辑来实现分片状态转换接口。
  2. 应用程序所有者提供基于意图的规范来配置约束。Shard Manager提供了四组主要的开箱即用功能:容错,负载平衡,分片扩展和操作安全性。
  3. 应用程序客户端使用公共路由库来路由特定于分片的请求。

 
分片管理器的设计与实现
在Facebook,我们的整体基础架构是采用分层方法构建的,各层次之间的关注点清晰分开。这使我们能够独立,稳健地发展和扩展每一层。下图显示了基础架构的层次结构。每一层分配并定义相邻上层操作的范围。 

  1. 主机管理:资源配额系统管理所有物理服务器,并为组织和团队分配容量。
  2. 容器管理:Twine从资源配额系统获取容量,并将其分配给以容器为单位的各个应用程序。
  3. 分片管理:分片管理器在Twine提供的容器内为分片应用程序分配分片。
  4. 分片应用程序:在每个分片中,应用程序分配并运行关联的工作负载。
  5. 产品:这些是面向用户的产品,例如移动应用程序,由分片的后端应用程序提供支持。

除了每一层在相邻较低层上的向下功能依赖关系之外,整个基础结构堆栈都经过代码签名,并通过向上传播的信号和事件协同工作。特别是对于Shard Manager层,TaskControl是我们实现协作调度的机制。
 
架构
Shard Manager的体系结构如下:

  • 应用程序所有者向Shard Manager Scheduler提供了一个规范,其中包含管理应用程序所需的所有信息。
  • Shard Manager Scheduler是协调分片过渡和移动的中央服务。它收集应用程序状态;监视状态更改,例如服务器连接,服务器故障和负载更改;调整分片分配;并通过对应用程序服务器的RPC调用来驱动分片状态转换。Shard Manager Scheduler在内部被分片以横向扩展。 
  • 应用程序 链接Shard Manager库,该库通过连接到ZooKeeper来提供服务器成员身份和活动检查的透明度。应用程序实现分片状态转换接口,并由分片管理器调度程序指示状态转换。应用程序可以测量和公开由Shard Manager Scheduler收集的动态负载信息。
  • 分片管理器调度程序将分片分配的公共视图发布到高度可用且可扩展的服务发现系统,该系统将信息传播到应用程序客户端以路由请求。
  • 应用程序客户端链接一个通用路由库,该路由库在每个分片的基础上封装了服务器端点的发现。端点发现后,客户端请求将直接发送到应用程序服务器。因此,分片管理器调度程序不在请求服务的关键路径上。

 
总结
Shard Manager提供了用于构建分片应用程序的通用平台。用户只需要实现分片状态转换接口,并通过基于意图的规范来表达分片约束。该平台与Facebook生态系统的其余部分完全集成,这使整体基础结构隐藏了基础架构的复杂性,并使我们的工程师能够专注于其应用程序和产品的核心业务逻辑。
Shard Manager从九年前开始发展,但是旅程还远未完成。我们将继续努力提供一流的解决方案,以在Facebook上构建分片服务。
尽管我们取得了成功,但我们仍在多个方面扩展Shard Manager的规模和功能。以下是我们计划在未来几年应对的各种挑战:
  1. 通过在内部将应用程序划分为较小的独立分区,每个应用程序可支持数千万个分片,以满足不断增长的大型应用程序的需求。
  2. 通过提供更高的模块化和可插入性以供用户自定义,同时使Shard Manager保持简单,从而支持更复杂的应用程序。
  3. 简化了当前抽象过于繁琐的小型,简单应用程序的长尾使用体验。

通过展示构建通用分片解决方案的可行性,我们希望我们可以促进进一步的讨论,并帮助围绕技术领域中这一前沿问题共同推动该领域的发展。

banq注:数据库分片其实是业务数据切分,DDD有界上下文提供一种方式,哈希一致性是从算法角度试图来解决,但是FB经验说明这种一刀切的办法不具有通用性,只能根据不同的领域进行不同的切分,FB这种分片管理器平台是一种有状态服务平台,不同于K8s那种无状态服务平台,分片管理器属于分布式事务实现的一种方式。