关于大数据:Alluxio跨集群同步机制的设计与实现

101次阅读

共计 8637 个字符,预计需要花费 22 分钟才能阅读完成。

一、Alluxio 利用场景和背景

Alluxio 跨集群同步机制的设计和实现确保了在运行多个 Alluxio 集群时,元数据是统一的。

Alluxio 位于存储和计算层之间,在不同的底层文件系统(UFS)下层提供高性能缓存和对立的命名空间。尽管通过 Alluxio 对 UFS 进行更新可使 Alluxio 与 UFS 保持一致,但在某些状况下, 例如在运行多个共享某一个或多个 UFS 命名空间的 Alluxio 集群时,后果可能并非如此。为了确保这种状况下的一致性,Alluxio 曾经实现了跨集群同步机制,本文将对该机制进行具体介绍。

1. 背景介绍

随着数据量的增长,这些数据的存储和拜访形式也变得越来越简单。例如,数据可能位于不同的存储系统中(S3、GCP、HDFS 等),也可能存储在云上或本地,或是位于不同的天文区域,还可能因为隐衷或平安爱护,被进一步隔离。此外,这些复杂性不仅体现在数据存储上,还包含如何将数据用于计算,例如,数据可能存储在云上,而计算则在本地进行。

Alluxio 是一个数据编排平台,通过在 UFS 上提供对立的拜访接口来升高此类复杂性,并通过提供数据本地性和缓存来进步计算性能。

对于许多组织而言,运行一个 Alluxio 集群可能就足够了,但有些组织须要运行多个 Alluxio 集群。例如,如果计算是在多个区域运行,那么在每个区域运行一个 Alluxio 集群可能会带来更大的劣势。此外,某些组织可能出于数据隐衷爱护的思考,须要运行独立的集群,或是心愿通过运行多个集群来进步可扩展性。尽管局部数据空间可能被隔离在某个集群中,但其余数据能够在多个集群之间共享。例如,一个集群可能负责提取和转换数据,而其余几个集群可能会查问这些数据并进行更新。

因为每个 Alluxio 集群可能会复制(即挂载)UFS 存储空间的某些局部,Alluxio 会负责放弃其正本与 UFS 的一致性,以便用户查问到最新的文件正本。在本文中,咱们将介绍在一个或多个集群中确保 Alluxio 数据与 UFS 统一所用到的组件。

2.Alluxio 数据一致性

在分布式系统中保持数据的一致性是很简单的,其中有几十个不同的一致性级别,每个级别都容许不同的用户在特定工夫查问和批改数据的不同状态。这些一致性级别造成了一个从弱到强的范畴区间,一致性越强限度越多,通常越容易在下面搭建应用程序。Alluxio 也不例外,它会依据配置和应用的 UFS 提供不同的一致性保障(详细信息见 Alluxio 的数据一致性模型)。

为了简化对于一致性的探讨,咱们将做如下假如:
● 对于任何文件,UFS 都是文件的 “ 惟一数据源 ”。

这意味着 Alluxio 中的每个文件都对应于 UFS 上的一个文件,并且 UFS 中总是有该文件的最新版本。如果 Alluxio 存储的文件正本与 UFS 中的文件不同,那么 Alluxio 中的文件版本是不统一的。(这里咱们假如 UFS 自身确保了强一致性,即某种程度的线性一致性(linearizability)或内部一致性(external consistency)。从高层次来看,这容许用户把 UFS(即使零碎是由许多分布式局部所组成) 当作相似实时按程序执行操作的繁多的文件系统来拜访。

在探讨 Alluxio 和 UFS 的一致性之前,让咱们先来看一下 Alluxio 的根本架构。Alluxio 是由 master 节点和 worker 节点组成的。master 节点负责跟踪文件的元数据,例如它的门路、大小等,而 worker 节点负责存储数据自身。如果 client 要读一个文件,必须先从某一个 master 节点上读取元数据,而后用它来定位存储该数据正本的 worker(必要时能够从 UFS 上加载数据)。如果 client 要写一个文件,必须首先在 master 中为该文件创建元数据,而后通过 worker 将该文件写到 UFS,最初在 master 上将该文件标记为实现。当文件正在被写入时,它的元数据会被标记为未实现,从而阻止其余 client 拜访该文件。

从这个根本设计中,咱们能够看到,只有所有对文件的更新都通过 Alluxio 写入 UFS,那么 Alluxio 中的数据将与 UFS 中的数据保持一致,client 将会始终查问到最新的数据版本。

然而现实情况,并没有这么简略,例如,某些用户可能在更新 UFS 时不通过 Alluxio,或者 client 可能呈现故障,只将局部文件写入 UFS,而没有在 Alluxio master 上标记实现,这些都可能导致 Alluxio 和 UFS 中的数据不统一。

那么,这些问题是如何解决的呢?因为咱们重点假如了 UFS 是惟一的数据源,要解决这些不统一的问题只需让 Alluxio 与 UFS 同步即可。

3. 元数据同步

元数据同步是用来检查和修复 Alluxio 和 UFS 之间不统一的次要组件。当 client 拜访 Alluxio 中的某个门路时,该性能在肯定条件下(前面会探讨)可能会被触发。根本程序如下:

● 从 UFS 加载该门路的元数据。
● 将 UFS 中的元数据与 Alluxio 中的元数据进行比拟。元数据中蕴含文件数据的指纹(例如最初批改工夫和抗碰撞的哈希值),可用于检查数据不统一状况。
● 如果发现任何不统一,则更新 Alluxio 中的元数据,并标记过期的数据,以便将其从 worker 中驱赶。最新数据会依据须要从 UFS 加载到 worker。

图:client 读取时的元数据同步过程。1. client 读取文件系统中的一个门路。2. master 上的元数据同步模块依据用户配置查看是否须要同步。3. 通过从 UFS 加载元数据进行同步,并创立一个指纹来比拟 Alluxio 和 UFS 中的元数据。如果指纹不同,则 Alluxio 中的元数据会被更新。4. client 依据更新后的元数据从 worker 中读取文件数据,必要时从 UFS 中加载数据。

惟一的问题就是决定何时执行这个元数据同步程序,须要咱们在更强的一致性和更好的性能之间进行衡量。

每次拜访数据时进行元数据同步

如果 Alluxio 中的 client 每次拜访一个门路时都进行元数据同步,那么 client 将始终能查看到 UFS 上最新的数据状态。这将为咱们提供最高的一致性级别,通常能够达到 UFS 所能确保的最强的一致性。然而,因为每次拜访数据(即便数据没有被批改)都会与 UFS 进行同步,这也会将导致性能降落。

基于工夫进行元数据同步

另外,元数据同步能够基于一个物理工夫距离来执行。在这种状况下,Alluxio master 上的元数据蕴含门路最初一次与 UFS 胜利同步的工夫。当初,只有当用户定义的工夫距离过后,才会进行新的同步(详细信息见 UFS 元数据同步)。

尽管这种形式可能极大地提高了性能,但也导致了绝对较弱级别的一致性保障,即最终一致性。这意味着,任何特定的读取后果可能与 UFS 统一,也可能不统一。此外,数据更新被查问到的程序可能是任意程序。例如,在 UFS 中,文件 A 的更新理论早于另一个文件 B,然而,Alluxio 集群查问到的可能是文件 B 的更新早于文件 A。因而,零碎的用户必须理解这些不同级别的一致性保障,并依据须要调整应用程序。

二、跨集群同步机制

在上一章节,咱们探讨了单个 Alluxio 集群的场景、背景以及如何进行元数据同步。本章将介绍如何在多集群场景下实现建设元数据同步,从而确保以提供元数据一致性。

1. 基于工夫同步的多集群一致性

其中一个基于工夫的元数据同步用例是应用多个 Alluxio 集群且集群共享局部 UFS 数据空间的场景。通常,咱们能够认为这些集群正在运行独自的工作负载,这些工作负载可能须要在某些工夫点共享数据。例如,一个集群可能会提取和转换来自某一天的数据,而后另一个集群会在第二天对该数据进行查问。运行查问工作的集群可能不须要总是看到最新的数据,例如能够承受最多一个小时的提早。

在实践中,应用基于工夫的同步不肯定总是无效,因为只有特定的工作负载才会定期更新文件。事实上,对于许多工作负载来说,大部分文件仅被写入一次,而只有一小部分文件会常常更新。在这种状况下,基于工夫的同步效率变低,这是因为大多数同步都是不必要的,减少工夫距离将导致常常批改的文件处于数据不统一状态的工夫更长。

2. 应用跨集群同步(Cross Cluster Sync)实现多集群一致性

为了防止基于工夫同步的低效性,跨集群同步性能容许间接跟踪不一致性,因而只在必要时才会同步文件。这意味着每当在 Alluxio 集群上一条门路产生更改时,该集群将公布一个生效音讯,告诉其余 Alluxio 集群该门路已被批改。下次当有 client 在订阅(跨集群同步性能的)集群上拜访此门路时,将触发与 UFS 的同步操作。

与基于工夫的同步相比,跨集群同步具备两个次要长处。首先,只对已批改的文件执行同步,其次,批改能够疾速地对其余集群可见,所需工夫即大概等同于从一个集群发送音讯到另一个集群的工夫。

由此咱们能够看到,当满足以下假如时,跨集群同步性能将是最无效用的。
● 多个 Alluxio 集群挂载的一个或多个 UFS 中有穿插局部。(咱们认为零碎中部署的 Alluxio 集群数量的正当范畴是 2-20 个)。
● 至多有一个集群会对 UFS 上的文件进行更新。
● 所有对 UFS 的更新都要通过 Alluxio 集群(对于解决其余状况的办法,请参见下文 “ 其余用例 ” 内容)。

当初咱们要确保来自一个 Alluxio 集群的更新将最终在其余所有 Alluxio 集群中被监测到(即集群与 UFS 满足最终一致性保障),这样应用程序就能够在集群间共享数据。

门路生效公布 / 订阅

跨集群同步性能是基于公布 / 订阅(pub/sub)机制实现的。当 Alluxio 集群挂载某个 UFS 门路时,就会订阅该门路,每当集群批改 UFS 上的文件时,它都会向所有订阅者公布批改的门路。

表 1:三个 Alluxio 集群挂载不同的 UFS 门路示例。

参考表 1 中的例子,有三个 Alluxio 集群,每个集群挂载一个不同的 S3 门路。这里,集群 C1 将 S3 桶(bucket)s3://bucket/ 挂载到其本地门路 /mnt/,集群 C2 将同一个 bucket 的子集 s3://bucket/folder 挂载到其本地门路 /mnt/folder,最初 C3 将 s3://bucket/other 挂载到其根门路 /。

由此,集群 C1 将订阅门路(pub/sub 语义中的“主题”)s3://bucket,集群 C2 将订阅门路 s3://bucket/folder,而集群 C3 将订阅门路 s3://bucket/other。订阅者将收到所有公布的以订阅“主题”结尾的音讯。

例如,如果集群 C1 创立了一个文件 /mnt/folder/new-file.dat,它将公布一个蕴含 s3://bucket/folder/new-file.dat 的有效音讯,集群 C2 将会收到该音讯。另外,如果集群 C1 创立了一个文件 /mnt/other-file.dat,则不会发送任何音讯,这是因为没有订阅者的主题与 s3://bucket/other-file.dat 相匹配。

如前所述,Alluxio 的元数据包含该门路最近一次同步产生的工夫。在跨集群同步的状况下,它还蕴含最近一次通过 pub/sub 接口收到的门路生效信息的工夫。利用这一点,当 client 拜访一个门路时,在以下两种状况下将会与 UFS 进行同步。

a) 该门路第一次被拜访。
b) 门路的生效工夫晚于最近一次同步工夫。

假如零碎中没有故障,显然最终一致性将失去保障。对文件的每一次批改都会导致每个订阅集群收到一个生效音讯,从而在下一次拜访该文件时进行同步。

图 1:文件创建过程中的跨集群同步机制。A. client 在集群 1 上创立一个文件。B. client 将文件写入 worker。C. worker 把文件写入 UFS。D. client 在 master 上实现了该文件。E. 集群 1 向集群 2 的订阅者公布文件的生效音讯。F. 集群 2 在其元数据同步组件中将该文件标记为须要同步。当前当 client 拜访该文件时,将同样应用图 1 所示的步骤 1-5 进行同步。

实现 Pub/sub 机制

Pub/sub 机制是通过发现机制(discovery mechanism)和网络组件来实现的,前者容许集群晓得其余集群挂载了什么门路,后者用来发送音讯。

发现机制是一个名为 CrossClusterMaster 的繁多 java 过程,须能让所有 Alluxio 集群通过可配置的地址 / 端口组合进行拜访。每当一个 Alluxio 集群启动时,都会告诉 CrossClusterMaster 该集群的所有 master 节点的地址。此外,每当集群挂载或卸载 UFS 时,挂载的门路都将被发送到 CrossClusterMaster。每次这些值被更新时,CrossClusterMaster 节点都会把新值发送给所有 Alluxio 集群。

利用这些信息,每个 Alluxio 集群将计算其本地 UFS 挂载门路与内部集群的所有 UFS 挂载门路的交加。对于每个相交的门路,集群的 master 将应用 GRPC 连贯创立一个以该门路为主题的订阅给内部集群的 master。在表 1 的例子中,C1 将向 C2 创立一个主题为 s3://bucket/folder 的订阅,以及向 C3 创立一个主题为 s3://bucket/other 的订阅。此外,C2 将向 C1 创立一个主题为 s3://bucket/folder 的订阅,而 C3 将向 C1 创立一个主题为 s3://bucket/other 的订阅。这样一来,每当集群要批改某个门路时,例如创立一个文件,它都会把批改的门路公布给任何主题是该门路前缀的订阅者。例如,如果 C1 创立一个文件 /mnt/other/file,它将公布 s3://bucket/other/file 到 C3。

为了被动保护对其余集群的订阅,每个 Alluxio master 上都会运行一个线程,以应答门路的挂载或卸载、集群的退出或者脱离,以及呈现连贯故障等状况的产生。

每当订阅者收到门路时,它就会将生效工夫元数据更新为以后工夫,这样一来,下一次 client 拜访该门路时,就会与 UFS 进行一次同步。依照咱们下面的例子,下一次 client 在集群 C3 上读取门路 /file 时,将在 s3://bucket/other/file 上执行与 UFS 的同步。

确保最终一致性

如果能保障每条公布的音讯都向所有订阅者(包含将来的订阅者)仅传递一次(exactly once),那么显然最终一致性将失去保障,因为每一次批改都会让订阅者在拜访门路时进行同步。然而,连贯可能中断、集群可能脱离和接入零碎、节点也可能呈现故障,咱们该如何保障音讯的精确传递呢?简略的答案是,咱们不能。相同,只有在订阅(应用底层 TCP 连贯)处于运行状态时,能力确保仅一次消息传递。此外,当订阅首次建设时,订阅者将标记根门路(主题)的元数据为须要同步。这意味着,在订阅建设后,对于任何作为主题的超集门路,在第一次拜访该门路时将进行同步。

例如,当 C1 用主题 s3://bucket/folder 建设对 C2 的订阅时,C1 将标记 s3://bucket/folder 为须要同步。而后,例如在第一次拜访 s3://bucket/folder/file 时,将进行同步。

这大大简化了解决零碎中的故障或配置变动的工作。如果某个订阅因为任何起因而失败,如网络问题、master 故障切换、配置变动,那么复原过程是一样的——从新建设订阅,并将相应的门路标记为不同步。为了加重网络问题的影响,能够设置一个用户定义的参数,以确定有多少音讯能够缓存在发布者的发送队列中,以及在队列已满的状况下超时期待多久会产生操作阻塞的可能性。

当然,依照预期,尽管咱们的零碎会产生故障,但不会常常产生,否则性能会受到影响。所幸即便在频繁产生故障的状况下,性能降落也会与应用基于工夫的同步的状况类似。例如,如果每 5 分钟产生一次故障,预计性能与启用基于工夫(5 分钟距离)同步下的性能相似。

请留神,如果 CrossClusterMaster 过程产生故障,那么新的集群和门路挂载发现将不起作用,但集群将放弃其现有的订阅而不会中断。此外,CrossClusterMaster 是无状态的(能够把它看作是集群替换地址和挂载门路的一个点),因而,能够在必要时进行和重新启动。

其余用例

后面提到,为了使这个性能发挥作用,所有对 UFS 的更新都应该通过 Alluxio 集群进行。当然这个条件不肯定能满足,有几种办法来解决这个问题。
● 用户能够手动将一个门路标记为须要同步。
● 基于工夫的同步能够和跨集群同步一起启用。

三、探讨与论断

1. 探讨与将来工作
为什么不应用确保仅一次消息传递的 pub/sub 机制?

咱们晓得,如果应用确保仅一次消息传递的 pub/sub 机制会大大简化咱们的设计,而且也的确存在许多弱小的零碎,如 Kafka 和 RabbitMQ,正是为了解决这个问题而创立的。应用这些零碎的益处是,故障对性能的影响可能较小。例如,如果某个订阅者处连贯断开,在从新连贯时,零碎能够从它之前断开的中央持续运行。

尽管如此保护这些零碎自身就是一项非常复杂的工作。首先,你须要弄清楚一些问题,比方,要部署多少个节点的物理机,要复制多少次音讯,保留多长时间,当因为连贯问题而不能公布音讯时要不要阻塞操作等。而且,最终很可能还是须要故障复原机制,从而导致更简单的设计。

(留神,为了保障最终一致性,咱们实际上只须要至多一次 (at least once) 消息传递,因为屡次传递音讯只会对性能产生负面影响,而不会影响数据一致性,但即使在这种状况下,大部分艰难依然存在)。

扩大至 20 个 Alluxio 集群以上或解决频发故障

将来,咱们心愿能反对扩大到数百个 Alluxio 集群,但从 20 个集群扩大至数百个集群可能有不同的设计考量。首先,咱们预期故障的产生会更加频繁;其次,设计可能会导致 master 产生大量开销。

如前所述,故障频繁产生会使性能升高到与采纳基于工夫同步时相似。在有数百个集群的状况下,咱们预期网络或 master 节点故障会相当频繁地产生。(请留神,这也取决于配置,因为故障只会影响挂载了与故障 UFS 门路有交加的集群。因而,如果集群大多挂载了不相交的 UFS 门路,那么可能问题不大)。此外,如果所有集群挂载的门路都有交加,那么它们将必须保护对所有其余集群的订阅,且一个公布就须要发送数百条音讯。

在这种状况下,咱们可能须要纳入一个牢靠的 pub/sub 机制,如 Kafka 或 RabbitMQ,但这里只是代替点对点的订阅,而不是扭转整个零碎的设计。故障依然会产生,集群将以同样的形式复原——将相交的 UFS 门路标记为须要同步。只有牢靠的 pub/sub 机制才会暗藏 Alluxio 的许多故障。例如,如果该机制想要牢靠地存储最初 5 分钟的音讯,那么只有持续时间超过 5 分钟的故障才须要用原来的办法进行复原。此外,这些零碎可能不思考 Alluxio 集群的数量进行扩大,在必要时增加更多节点。不过,应用和保护这些零碎会产生大量的开销,可能只有在某些配置中才值得尝试。

对于一致性的一些认识

尽管本文介绍了确保最终一致性的基本思路,但还有几个重要的内容没有具体阐明。

首先,生效音讯必须在对 UFS 的批改实现后能力公布,其次,UFS 必须在线性一致性或内部一致性(S3 中的一致性)层面上确保强一致性。如果这两个条件中的任何一个没有失去满足,那么当订阅者收到生效信息并执行同步时,集群可能无奈观测到文件的最新版本。第三,如果一个集群与 CrossClusterMaster 的连贯断开,起初又从新建设了连贯,那么该集群也必须经验故障复原过程,这是因为在连贯中断期间可能有某个内部集群挂载并批改了门路。

公布残缺的元数据

如前所述,公布的生效音讯只蕴含被批改的门路。然而,这些音讯也能够包含门路的更新元数据,从而防止在订阅集群上进行同步。之所以不这样做是因为无奈通过惯例办法晓得哪个版本的元数据是最新的版本。

例如,两个 Alluxio 集群 C1 和 C2 在 UFS 上更新同一个文件。在 UFS 上,集群 C1 的更新产生在集群 C2 的更新之前。而后,两个集群都将他们更新的元数据公布到第三个集群 C3。因为网络条件的起因,C2 的音讯比 C1 先达到。此时,C3 须要晓得,它应该放弃来自 C1 的更新,因为曾经有了最新的元数据版本。当然,如果元数据蕴含版本信息,就能够做到这一点,但惋惜对于 Alluxio 反对的所有 UFS,惯例办法都做不到。因而,C3 依然须要与 UFS 进行元数据同步,以便间接从惟一的数据源取得最新的版本。

订阅告诉服务

某些底层存储系统(UFS)(例如 Amazon SNS 和 HDFS iNotify)提供告诉服务,让用户晓得文件何时被批改了。对于这类 UFS,相较于订阅 Alluxio 集群,订阅这些服务可能是更好的抉择。这样做的益处是反对不通过 Alluxio 对 UFS 进行写入。同样,零碎设计将放弃不变,只是不订阅其余 Alluxio 集群,而是订阅此类告诉服务。

请留神,Alluxio 还为 HDFS 提供了 ActiveSync 性能,容许元数据与底层 UFS 放弃同步。这与跨集群的同步机制有所不同,因为 ActiveSync 在文件更新时执行同步,而跨集群同步只在文件被拜访时执行同步。

四、论断

本文次要介绍了运行多个 Alluxio 集群能带来劣势的场景,以及 Alluxio 应用基于工夫同步和跨集群同步性能,用来放弃集群与所挂载 UFS 同步的过程。对于如何部署跨集群同步性能的更多内容,请点击浏览原文查看。

想要理解更多对于 Alluxio 的干货文章、热门流动、专家分享,可点击进入【Alluxio 智库】:

正文完
 0