TC 2022 Paper,元数据论文阅读汇总
“multiple metadata server (MDS)” 多个元数据服务器
“locality preserving hashing (LPH)” 局部保持哈希
“Multiple Subset Sum Problem (MSSP).” 多子集和问题
“polynomial-time approximation scheme (PTAS)” 多项式时间近似方法
目前的分布式文件系统被设计用于支持 PB 规模甚至 EB 规模的数据存储。元数据服务负责管理文件属性信息和全局命名空间树,对系统性能至关重要。元数据是描述文件系统组织和结构的数据,包括文件属性、文件块指针等 [1]。元数据大小通常占数据空间的0.1%到1%,约50%到60%的文件系统访问指向元数据 [2]。分布式元数据管理方案采用多个元数据服务器(MDS)来存储元数据,为减轻单个服务器的工作负载提供了有效的途径。然而,同时保持良好的元数据局部性和多个 MDS 之间的负载平衡是一个非常复杂的问题。
根据POSIX标准 [4],访问元数据节点时,我们需要执行路径遍历,递归地对其每个祖先节点执行访问权限检查。图1显示了将命名空间树分区为三个 MDS 的两种方案。例如,要访问“c1.tex”,我们应该按顺序验证“root”、“etc”、“dir2”和“c1.tex”的元数据节点。在图1a中,这个访问操作可以在“MDS#1”中完成,有很好的元数据局部性。例如,子树分区方案 [5],[6] 采用了这个思想。然而,由于命名空间树分区不均匀和对一些热门文件的访问不平衡,“MDS#1”面临着过载的高风险。图1b描述了另一种具有良好负载平衡的分区方案,其中元数据节点均匀分配给了三个MDS。通常,基于哈希的映射 [7],[8] 这样的元数据管理方案采用这个思想,但它们可能会破坏元数据的层次局部性。例如,当访问“c1.tex”时,我们需要在“MDS#1”和“MDS#2”之间切换执行路径遍历,从而导致高响应延迟。
为了更好地说明问题,根据 AngleCut [14] 对元数据局部性和系统负载平衡进行数学定义。表1列出了本文中使用的符号表示法。
假设在 MDS 中总共有 N 个元数据节点。我们使用 S={ni | 0 ≤ i ≤ N} 表示整个命名空间树,其中 ni 表示第 i 个节点,n0 表示根节点。定义 Hi 为元数据节点 ni 的跳数,即在执行 ni 的POSIX 风格路径遍历时在不同 MDS 之间切换的次数。良好的局部性表示平均切换次数较小,这意味着客户端文件请求可以通过访问较少的 MDS 完成。一些热门元数据节点被高频访问,例如,“/etc”是 UNIX 系统中的一个热门目录。因此,在衡量元数据局部性时,我们应考虑此因素。用 Pi 表示元数据节点 ni 的热门程度。Pi 的值包含对 ni 的专用访问以及对 ni 的后代元数据节点的访问。现在给出局部性 Loc 的定义如下
Loc 越大表示局部性越好,即接近的元数据节点更有可能被分配到同一个 MDS。因此,Hi 的总和较小。在方程(1)中,Pi 是 Hi 的加权因子,用于对热门元数据节点进行惩罚。直观地说,如果所有元数据节点都分布到一个 MDS,Loc 就是正无穷。
假设总共有 M 个 MDS,Li(1 ≤ i ≤ M) 表示第 i 个 MDS 的当前负载,例如 MDSi 的元数据查询频率的总和。令 Ci 表示 MDSi 的系统容量,我们可以通过 η = SUM(Li) / SUM(Ci) 计算系统理想负载因子 η。相应地,MDSi 的理想负载 Gi 定义为:Gi = η * Ci。现在给出负载平衡度 Bal 的定义如下
Bal 定义为整个 MDS 的负载的方差的倒数,Li 的值表示在采样时刻的 MDS 的状态。Bal 越大意味着每个 MDS 的负载越接近理想负载。
LPH 是一个哈希函数 f,将多维坐标空间中的一个或多个点映射到一个标量值,如果我们有三个点 A、B 和 C,我们可以得到
从本质上讲,分布式元数据管理归结为找到一个映射函数 f(x) : x → y,其中 x 表示一个元数据节点,y 表示元数据节点属于哪个 MDS。传统的元数据管理方案采用各种方法来构建 f(x),可分为基于哈希的映射方法 [7],[8]和子树分区方法,子树分区可以根据命名空间的分区方式进一步分为两种类型,包括静态场景 [5],[6] 和动态场景 [6]。
基于哈希的映射通常将元数据节点(例如,文件路径名或其他标识符)映射到哈希key,并通过将元数据的 key 投影到 MDS 的 key 来将元数据分配到 MDS。静态子树分区假定同一子树下的元数据节点应映射到同一个 MDS,它将全局命名空间划分为几个子树,每个 MDS 负责其中一个或几个子树。动态子树分区是静态方式的一种优化,其核心思想是目录层次结构子树可以细分并映射到不同的 MDS,随着工作负载的变化,元数据节点将动态重新分布。然而,上述方案忽略了数据分布,因此无法充分利用现实世界数据中的普遍模式,所有传统的方案 [5],[6],[7],[8],[9],[10],[11],[12],[13] 启发式地假设了一个刚性的映射函数,没有考虑元数据节点的当前分布,从而导致元数据局部性差或系统负载不平衡。
在元数据管理的其他方案中,AngleCut [14] 提出了一种保留局部性哈希(LPH)映射方案 [15],通过对命名空间树进行环投影和角度分配,可以保留从元数据命名空间树到线性哈希空间的节点的相对位置。然而,它基于静态命名空间树分配角度,容易导致哈希冲突并且无法很好地处理动态文件请求。导致上述问题的原因是它们都启发式地假设了一个刚性的映射函数 f(x),而没有考虑元数据节点的实际分布。
为了实现更灵活的映射方案并服务于分布式元数据管理,我们提出了一种基于机器学习的模型的 DeepHash,它利用深度神经网络(DNN)学习自适应的局部性保持哈希(LPH)映射方案。DeepHash 首先通过网络嵌入技术将元数据节点转换为特征向量。由于缺乏训练标签,即元数据节点的哈希值,我们设计了一个具有独特特征的对比损失函数来训练 DeepHash,并引入采样策略以提高训练效率。此外,我们提出了一种有效的算法来动态平衡工作负载,并采用缓存模型以提高查询效率。
我们在 Amazon EC2 平台上的两个真实跟踪数据集上进行评估了,DeepHash 相对于传统和最先进的方案,能够保持元数据的局部性同时保持高负载平衡。
先前的文献使用文件路径名作为映射模型的输入,这对于神经网络学习位置信息是不适用的。我们采用网络嵌入技术并结合查询频率,将元数据节点嵌入固定长度的特征向量作为训练实例。
训练实例没有相应的标签,即我们不知道元数据节点的理想哈希值。受图像检索领域中的孪生网络 [16] 和 FaceNet [17] 的启发,我们设计了一个复杂的损失函数,称为对比损失。核心思想是通过元数据的相对位置关系来训练 DeepHash 网络。同时损失函数的形式融入了 LPH 的属性,可以保持元数据的局部性。
为了提高系统的负载平衡度,我们提出了一种基于多重子集和问题(MSSP)的多项式时间逼近方案(PTAS),以有效地在 MDS 间分配元数据节点。我们进一步设计了一个三阶段算法,在系统运行时动态平衡系统负载。
在本节中,我们详细描述了 DeepHash 的设计。根据实际情况假设客户端的元数据请求,即读取、写入、删除、“更新”,大致保持其操作行为,这意味着客户端操作遵循类似的模式。
图2描述了 DeepHash 的框架,由三个部分组成。在3.2节中,DeepHash 首先使用网络嵌入方法将每个元数据节点转换为固定大小的特征表示,该表示用作神经网络的输入。在3.3节中,DeepHash 设计了一个对比损失函数,用于学习一个 LPH 函数,该函数可以将元数据投影到线性哈希空间(例如Chord环 [20])。学到的 LPH 函数可以保持命名空间中元数据节点的相对位置信息,从而保持了元数据的局部性。在3.4节中,我们利用一致性哈希算法将哈希空间中的元数据分配到相应的 MDS,这可以同时保持系统负载平衡和元数据的局部性。为了进一步提高系统负载平衡度,在3.5节引入了虚拟节点,并基于多重子集和问题(MSSP)设计了一个多项式时间逼近方案(PTAS),用于在一致性算法的 MDS 之间分配虚拟节点。
每个元数据节点包括4个属性,包括标签(tag)、频率(frequency)、跳数(hop)和哈希值(hashV),如图3所示。标签1比特,如果元数据节点是有效的,则设置为1,一旦节点被删除,标签就被更改为0,并变为无效。频率是一个整数值,用于记录元数据节点的查询频率。跳数用于记录 MDS 之间的跳数。哈希值表示由 DeepHash 获取的哈希值,即在哈希环上的位置。
我们在命名空间树上建立一个坐标系统,这将作为3.3节中的度量标准。我们根据元数据节点在树中的位置对其进行编码,这本质上是一个广度优先搜索过程。给定一个命名空间树,元数据节点 ni 的坐标 ei 被编码为 [a1,a2, …,adi]。这里,维度 di 是 ni 所在的层的深度,而 aj(1 ≤ j ≤ di) 表示 ni 在第 j 层上逆时针方向的左兄弟节点的数量(包括它本身)。例如,在图3中,A、B、C、D、E的坐标分别为[1, 1, 3], [1, 1, 3, 1], [1, 1, 3, 2], [1, 2, 2], [1, 2, 2, 1]。不同层的元数据坐标的维度是不同的,元数据节点的深度越深,其坐标维度越大。为了更好地在3.3节中测量两个元数据节点之间的距离,我们将原始的元数据坐标扩展为固定长度的坐标。将命名空间树的高度表示为 D(假设根节点的高度等于1),对于每个元数据节点 ni,我们将其原始坐标扩展到长度为 D 的最终坐标 ei。ei 中的前 di 个分量是其原始坐标,而其余的 D-di 个分量则填充为0。例如,在图3中,A的坐标从[1. 1, 3]扩展为[1, 1, 3, 0]。
为了训练 DeepHash 模型,我们需要获取元数据节点的特征表示。简单的方法是直接使用坐标 ei 作为元数据 ni 的特征向量。然而,由于不同的元数据节点在命名空间树中的位置不同,许多坐标将在其尾部填充0,这将影响训练效率。
我们采用 DeepWalk [21],一种网络嵌入算法 [22],将元数据节点嵌入到固定长度的特征向量中。网络嵌入可以将网络中的每个节点转换为低维的独特特征表示。同时保留网络结构,即两个相邻的节点具有相似的特征表示。
我们将命名空间树视为一个无向网络,并采用 DeepWalk 算法获得每个元数据节点 ni 的 h 维特征表示 vi。DeepWalk 主要有两个步骤:(1)在命名空间树上进行随机游走,得到大量路径序列。所谓的随机游走是在命名空间树上重复地随机选择一个行走路径,最终通过网络形成一个路径序列。从特定的元数据节点开始,每一步的行走都会随机选择与当前节点相连的路径之一,沿着选择的路径移动到下一个元数据节点,并持续重复这个过程。(2)将路径序列输入 SkipGram 算法 [23],以获得元数据节点的特征表示。SkipGram 算法是一种语言模型,可以最大化出现在句子的窗口内的单词之间的共现概率,该算法可以自然地捕捉元数据节点之间的层次关系。
使用 DeepWalk 进行元数据嵌入[21]主要有四个优势。第一个是并行化。对于大型命名空间树,可以同时在不同的元数据节点上启动一定长度的随机游走,并同时执行多个随机游走,从而减少采样时间。第二,该算法可以适应网络中的局部变化。命名空间树的改变通常影响随机游走路径的一部分,我们可以仅使用来自命名空间树上更改区域的新随机游走来更新学到的模型,而无需重新计算整个网络。第三,DeepWalk 获得的特征向量具有局部敏感性,在命名空间树中相邻的元数据节点更有可能具有相似的表示。第四,连续的表示具有平滑的决策边界,有助于提高训练效率。
在运行 DeepWalk 算法后,我们将元数据节点 ni 的查询频率与相应的 vi 连接起来。得到一个大小为N *(h + 1)的特征矩阵,矩阵的每一行表示元数据 ni 的特征向量,其中0 ≤ i ≤ N。特征向量 vi 包含了元数据局部性和用户查询模式的信息。
我们准备构建一个神经网络 fW(vi),它可以学习一个 LPH 映射,这个映射可以保留元数据节点在命名空间树中到线性哈希空间的相对位置关系。如图2所示,DeepHash 网络以元数据特征表示 vi 为输入,输出 fW(vi) 作为其哈希值。然后,根据一致性哈希算法 [19] 将元数据节点分配给相应的 MDS。如果它们在哈希空间中的哈希值接近,那么两个元数据节点更有可能被分配到同一个 MDS。
然而,对于每个元数据节点都没有预定义的标签(即哈希值)。我们提出了一个经过精心设计的配对损失函数来训练 DeepHash,这受到了图像检索研究 [17],[24] 的启发。其核心思想是利用元数据节点的相对位置关系作为它们的标签。根据3.1,坐标 ei 能够唯一表示元数据 ni。给定两个元数据向量 vi 和 vj,其中0 ≤ i,j ≤ N,我们可以使用 ei 和 ej 来衡量它们之间的距离。
定义 ||vi - vj|| 为两个元数据节点的距离。||vi - vj|| 是通过对它们相应的坐标 ei 和 ej 进行逐元素比较计算的,即比较它们相应坐标 ei 和 ej 的每个分量 ak,其中 0 ≤ k ≤ D,并记录分量不同的第一层位置 dp。||vi - vj|| = max(di, dj) - dp。如果 ||vi - vj|| ≤ t,其中 t 是一个阈值,那么 vi 和 vj 在命名空间树中是近的。否则,vi 和 vj 是远的。例如,在图3中,eB[1,1,3,1]和eD[1,2,2,0],我们可以得到||vB - vD|| = 3。如果 t 等于4,那么 vB 和 vD 是近的。
使用配对损失模型的 DeepHash 的架构如图2中部所示。假设 (vi, vj) 是元数据对的输入,令 y 为对的二进制标签,如果 vi 和 vj 是近的,y = 1;如果它们是远的,y = 0。fW(vi) 和 fW(vj) 分别是 ni 和 nj 的哈希值,其中 W 是待学习的共享参数向量矩阵。令 DW = ||fW(vi) - fW(vj)||22 用于衡量在哈希空间中的 vi 和 vj 之间的距离。如果 vi 和 vj 是近的,DW 的值应该很小。否则,如果 DW 超过一个阈值 m,我们需要对 DeepHash 网进行惩罚,反之亦然。
对于包含 T 个训练对 (vi, vj) 的训练集,损失函数定义为:
对于第 k 个训练样本 (y, vi, vj)k,将它们的损失定义为:
在公式(6)中,Lc 表示近对的惩罚,Lf 表示远对的惩罚。为了适应 LPH 设计,Lc 和 Lf 的设计应确保 L(W) 的最小化会减小近对的 DW 并增加远对的 DW。受到 Siamese Network [16]的启发,我们设计了如公式(7)所示的 Lc 和 Lf。Siamese 神经网络是一类包含两个或更多相同子网络的神经网络结构,它们共同处理两个不同的输入向量以计算可比较的输出。相同意味着子网络具有相同的配置和相同的参数和权重。参数更新在两个子网络之间进行镜像。
在公式(7)中,[a]+ = max(a, 0),正数 m 用作边缘,以控制在哈希空间中 vi 和 vj 之间的距离。如果近对的距离很大,即大于 m,我们应该对其进行惩罚。如果远对的距离很小,它们也同样受到惩罚。基于公式(6)和(7),DeepHash 倾向于收敛到一个状态,在该状态下,L(W, (y, vi, vj)k) 的最小值在半平面 Lc + m < Lf [16] 内。因此,DeepHash 得到的哈希值确切地满足 LPH 映射的思想。
对于具有 N 个元数据项的名称空间树,生成所有可能的对 (vi,vj) 将产生 N2 个训练样本。然而,在实际分布式文件系统中,N 非常大,生成所有训练实例是不切实际的。我们可以在名称空间树中对 T 个实例进行采样。对于训练对 (vi,vj),我们使用前面的定义的 t 来指示它们是近还是远。在采样过程中,我们应确保对于不同的 t,满足 ||vi, vj|| = t 的 (vi, vj) 对的数量大致相等。这种采样方法可以有效地防止训练数据不平衡的问题,从而加速神经网络的训练过程。
通过以上几个部分,我们通过神经网络构建了一个 LPH 函数。使用机器学习方法主要有三个优点。第一,DeepHash 是一种数据依赖型的哈希方法,旨在从特定的名称空间树中学习 LPH 函数。与其他方案相比,这种数据驱动的方法对元数据分布更为敏感,可以利用真实世界数据中的模式。例如,AngleCut [14] 在构建名称空间树上的 LPH 函数时需要分配一个分区角度,这是固定的,并且在动态环境中缺乏良好的可伸缩性。相比之下,DeepHash 学到的 LPH 函数非常灵活,元数据节点的哈希值是从名称空间树的结构中学到的,更具适应性。第二,在运行 DeepHash 模型时无需人工干预,该过程可以由机器学习算法自动执行。第三,DeepHash 的能力可以持续改进。随着提供新数据,模型的准确性和效率可以通过后续训练得到提高 [26]。当名称空间树的结构发生变化时,我们只需使用新的元数据训练 DeepHash,无需在整个名称空间树上重新训练模型。
DeepHash 模型具有很强的可伸缩性:(1)LPH 网络可以将元数据节点投影到足够容纳大型名称空间树的任意哈希空间。我们利用一致性哈希算法和虚拟节点分配算法(后面细说)来进一步将元数据分配到相应的 MDS。对于上述两个步骤,名称空间树的规模对它们的影响很小。因此,DeepHash 可以适应大型分布式系统。(2)对于在名称空间树上的神经网络的整个训练仅发生在开始时,这是离线的,不会给系统带来负担。在系统运行时,当发生元数据查询时,神经网络的推断操作(仅为矩阵操作)可以非常快速地执行。(3)在元数据更新时,DeepWalk 算法可以适应局部变化,我们只需更新更改的分区上的元数据特征表示。LPH 神经网络也可以通过增量训练算法 [26],只在新的元数据特征向量上进行训练以获得持续改进,这是非常高效的。
如图2的第三部分所示,基于 DeepHash 获得的哈希值,元数据节点根据一致性哈希算法 [19]、[20] 分配给相应的 MDS。整个哈希空间,例如0~232,被组织成一个哈希环。首先,每个 MDS 被映射到表示其在环上位置的哈希值,例如图2中的 server1 到 server6。同时,元数据节点也根据它们的哈希值映射到环上,例如环上的 a、b、c、d。接下来,每个元数据节点按顺时针方向分配给它的邻近 MDS。例如,a、b分配给server2,c分配给server4。因此,每个MDS负责哈希环的特定范围,在此范围内的元数据节点将被分配给此 MDS。然而,由于一致性哈希算法在哈希环上的不均匀分区,一些 MDS 负责哈希空间较大,这些 MDS 将管理更多的元数据节点,从而遭受重负载,导致负载不平衡问题。为了缓解这个性能问题,我们引入虚拟节点 [19] 来替代哈希环上的实际 MDS。虚拟节点是一个逻辑概念。每个 MDS 管理多个虚拟节点,并且这些虚拟节点作为虚拟服务器分散在哈希环上。
例如,server1 到 server6 是虚拟节点,分别由真实的 MDS A、B、C 管理。在这种情况下,分配给虚拟节点的元数据节点将被重新分配给相应的真实 MDS,MDS 的负载取决于其虚拟节点的总和。使用虚拟节点不仅提高了系统的负载平衡程度,还有助于系统的可扩展性。当添加或删除 MDS 时,虚拟节点可以在相邻的 MDS 之间平稳迁移。为了提高系统的可用性,我们将数据在主节点上备份到顺时针方向的下两个相邻节点。如图2所示,存储在 server1 上的数据将复制到 server2 和 server3。基于备份机制,主节点作为主 MDS 处理元数据请求,而复制节点可以在主 MDS 崩溃时帮助恢复数据。
负载均衡的过程涉及到一个多子集和问题(MSSP),这是一个 NP hard。它涉及如何将 V 个虚拟节点均匀地分配给 M 个MDS,同时最大化每个 MDS 的利用率。MSSP 是传统的0-1背包问题的变体。[28]对 MSSP 提供了一个简单而清晰的定义:有 n 个物品,其重量分别为 w1、w2、…、wn,有 m 个带有正容量 c1、c2、…、cm 的箱子。MSSP 的目标是在满足其容量约束的情况下最大化箱子中的总重量。[27]通过构建 MSSP 的多项式时间逼近方案(PTAS)提供了一个3/4的近似算法来解决这个问题。
在我们的分配算法中,假设有 V 个具有访问流行度 p1、p2、…、pV 的虚拟节点,以及 M 个带有负载容量 c1、c2、…、cm 的 MDS。分配算法的目标是在满足它们的容量约束的情况下最大化每个 MDS 的负载。在这种情况下,当将元数据分配给虚拟节点时,DeepHash 的局部性得到了很好的保留,当与 MDS 容量成比例的流行度的虚拟节点分配给 MDS 时,其负载平衡得到了改善。这个问题可以表示为以下整数线性规划问题:
算法1提供了如何在 MDS 中分配虚拟节点的简要算法。在初始化阶段给出了一个要求的最坏情况下的相对误差 ε ∈ (0, 1)。然后,我们定义3/4近似算法参数 ~ε := ε/3,并将虚拟节点分成具有较大访问流行度的集合 L := {i∈V:pi > ~εc} 和具有较小访问流行度的集合 S := {i∈V:pi ≤ ~εc}。如果 L 中的虚拟节点数量小于 MDS 的数量,这意味着虚拟节点的总数较小,我们可以简单地将每个虚拟节点放入一个空的 MDS 并转到第3阶段。
在第1阶段,通过项目预处理以减少 L 中虚拟节点的数量。我们首先将 L 中的虚拟节点划分为子集 Ij, j = 1, …,⌈1/~ε⌉-1,每个子集包含 (j~εc, (j+1)~εc) 中的访问流行度。设 σj :=⌈1/j~ε⌉-1。如果 |Ij| ≤ 2Mσj,我们选择 Ij 中的所有虚拟节点,否则,我们仅选择 Mσj 个最大和 Mσj 个最小的虚拟节点。R 包含从项目预处理中选择的虚拟节点。
通过第1阶段的项目预处理,虚拟节点的数量大大减少。在第2阶段,我们使用[29]中提出的动态规划解决方案在 M1 MDS 中找到 R 的最优解,该解决方案在虚拟节点数量较小时精确且易于实现。我们将虚拟节点放置在 L-R 中的其他 MDS 上。如果 |L- R| ≤ |M-M1|,所有虚拟节点都分配到单独的 MDS 上。否则,我们将较小流行度的虚拟节点成对放置在同一 MDS 上。正如[27]中证明的那样,L-R 中最小项获得的成对数为 |L- R|-|M-M1|。设从 L-R 中的最小项获得的对数为 P = |L- R|-|M-M1|。我们分配 P 对和剩余的 |L-R|-2P 虚拟节点到单独的MDS上。L-R 中的分配方案不如 R 那么精确。但是,它为 L-R 提供了一个快速且接近最优解的解决方案。
在第三阶段,我们使用贪婪算法将 S 中访问流行度较小的虚拟节点添加到 M 个 MDS 的接近最优解中,以获得最终的分配方案。
【就是每个 MDS 向监视器报告自身状态,根据负载情况和迁移成本,使用简单的贪心策略进行负载均衡,设了一堆阈值来减少震荡】
有些 MDS 可能在长时间服务后分配了过多的元数据,从而过载。因此,我们需要动态调整 MDS 之间的系统负载,即从过载的服务器迁移元数据到负载较轻的服务器。在本节中,我们提出了一个三阶段算法,以在元数据放置中实现局部性的和负载平和。前两个阶段向监视器报告元组列表和重新分配 MDS 中的虚拟节点,用于分配元数据,最后一个阶段的控制器用于优化分配工作流程并避免在迁移频繁时可能出现的振荡。
每个 MDS 定期对其中存储的元数据节点进行采样,以产生关于元数据的本地统计估算。然后,每个 MDS 构建一个元组列表,例如:(虚拟节点,时间戳,负载,[nmin, nmax]),其中时间戳用于标识记录;[nmin, nmax] 表示元数据范围,负载表示驻留在当前 MDS 中的虚拟节点的当前负载。监视器将建立一个全局负载映射,并根据监视器接收到的元组列表构建一个迁移表,该迁移表表示需要将哪些虚拟节点从过载的 MDS 迁移到负载较轻的 MDS。
根据之前的定义,我们可以计算每个 MDS 的理想负载 Gi,以及全局系统负载平衡度 Bal。一旦 Bal 小于阈值 τini,DeepHash 开始重新平衡系统负载。在从监视器接收到迁移表后,过载的 MDS 根据迁移策略和成本表将虚拟节点平滑地迁移到负载较轻的 MDS。
将负载距离定义为当前负载和理想负载之间的距离,可以表示为 Gi-Li。
迁移表:迁移表用于指定每个 MDS 的工作负载状态。对于每个 MDS,迁移表将构建一列,其中包含驻留在该 MDS 中的虚拟节点的当前负载和该 MDS 的负载距离,如表2所示。
成本表:用于指定将虚拟节点从一个 MDS 移动到另一个 MDS 时的迁移成本。对于每个 MDS,成本表将构造一行,其中包含迁移成本,如表3所示。
根据监视器受到的信息,监控器将构建一个描述负载分布的全局图。基于全局映射,监控器将推荐理想负载和每个 MDS 可以正常运行的负载范围。如果当前负载比推荐的负载范围小,我们将该 MDS 的负载状态表示为轻;如果当前负载在负载范围内,我们将负载状态表示为中等;如果当前负载比负载范围重,我们将负载状态表示为重。
迁移策略:如算法2所示,我们将虚拟节点从负载最大的 MDS 迁移到负载较小的 MDS,直到它们的负载状态为中等。如算法2的第8-21行所示,我们使用两个过滤器来找到期望的 MDS:(1) 在第一个过滤器中,我们过滤负载较轻的 MDS 并按照从低到高的迁移成本排序。(2) 在第二个过滤器中,我们过滤具有足够容量接 受迁移节点的 MDS,并选择具有最低迁移成本的期望 MDS。我们重复此过程,直到 Bal 大于阈值τini。在迁移过程中,我们仅在重 MDS 和轻 MDS 之间迁移虚拟节点。
由于频繁的负载平衡可能导致振荡,我们设计了一个控制器来监控迁移过程。在控制器中设置了时间阈值 Tt、时间间隔 Tg 和负载平衡边界 τcontrol。只有当整体负载平衡度低于 τcontrol,并且当前状态持续时间超过时间阈值 Tt,并且上一次迁移过程和当前时间之间的时间间隔大于 Tg 时,DeepHash 才会开始重新分配元数据。在控制器中,我们将负载平衡边界 τcontrol 设置为小于 τini。在这种情况下,迁移过程完成后,系统将花费更长的时间才能实现负载平衡边界低于 τcontrol,并保持在该状态下的时间阈值 Tt。通过这种方式,我们可以有效地避免在分配过程中的振荡。
由于采用了 POSIX 风格,命名空间树顶部的元数据节点将更频繁地被访问。当大量客户端请求指向它们时,一些文件和目录很可能成为查询的热点,例如,“/etc”目录是 UNIX 系统中的热门目录。为了减少访问延迟,每个 MDS 上都放置了一个缓存模型,该模型存储未分配给该 MDS 的热点或正在写入的元数据,特别是命名空间树的顶部部分。
配备了缓存模型后,元数据查询过程如下:首先,客户端随机选择一个 MDS 并将文件请求发送给它。当 MDS 从终端用户或另一个 MDS 收到“读/写”请求时,它首先从其缓存中检查祖先节点(前缀 inode)。如果缓存命中,则 MDS 将直接从缓存中读取/写入数据。否则,MDS 将检查哈希表并将请求转发到相应的 MDS。缓存设计极大地减少了网络通信负载并提高了查询效率。
在本节中,我们将评估 DeepHash 的性能。我们使用 PyTorch 实现了 DeepHash,并将该程序部署在 Amazon EC2 上运行实验。每个实例都运行 Ubuntu 17.04 操作系统。MDS 的实验数量范围从5到30,增量为5。我们还实现了一些其他传统的元数据管理方案,包括静态子树分区[31]、动态子树分区[6]、基于哈希的映射[7]以及 AngleCut[14]。为了更好地说明实验结果的合理性和效率,除了核心元数据管理方案外,所有这些方案都实现了相同的增强功能,例如缓存机制。实验中使用的数据集是两个名为 LiveMap 和 RadiusAuth 的真实世界跟踪。表4显示了关于这两个数据集的详细信息。
使用两层神经网络来训练 DeepHash,特征向量的维度为32,全连接的隐藏层中的神经元数量为50,激活函数为ReLU,批量大小为100,学习率为1e-3。
对于 MDS 的每个规模和特定的数据集,我们评估 DeepHash 的元数据位置和负载平衡度,并将其与其他方案进行比较。我们通过对损失函数来训练 DeepHash,然后调整参数 t 来探究其对模型的影响。用一个特定的服务器与 DeepHash 交互,即分配查询任务和生成哈希表。此外,在构建 DeepHash 时有两个超参数,即树嵌入的窗口大小和对丢失的距离阈值 t。由于这两个参数的参数空间非常小,因此在为分布式文件系统训练神经网络时很容易确定最佳参数值。此外,我们可以利用贝叶斯优化方法[32]来进一步降低超参数调整的成本。
不同数据集使用不同窗口大小的嵌入结果,在不同数据集间窗口大小不通用
效果好
t 用于确定节点间是否接近,在不同数据集间 t 不通用
效果好
只说了模型训练时间短,没提准备训练数据的时间(元数据特征表示的部分)
元数据管理策略:集中式策略、分布式策略
元数据分发策略:
子树划分:静态子树划分(NFS [41],HDFS [38],Sprite [42])。动态子树划分(Ceph [35],Kosha [39])
基于哈希的映射
其他方案:Spyglass[11] 利用文件命名空间的局部性,倾斜元数据的分布,将命名空间层次结构映射到多维 K-D 树中,并使用多级版本控制和分区来保持一致性,从而实现了良好的局部性。Dynamic Dir Grain[1] 观察到静态子树分区和动态子树分区的分区粒度可能太大。它提出了三重
针对元数据管理方法,传统方法难以同时实现局部性和负载均衡。作者提出使用深度神经网络学习自适应的局部性保持哈希(LPH)映射方案。提出几个创新点:作者将路径映射成坐标,通过 DeepWalk 获取路径序列,在通过 SkipGram 获取特征表示,同时将访问频率加入元数据特征;使用全连接网络训练 LPH 映射,通过设计损失函数使命名空间中相近节点映射后依旧相近;只采样部分数据,保证不同距离的节点对数量近似;通过虚拟节点优化一致性哈希,采用多项式时间的多子集和问题近似算法,计算 V 个虚拟节点和 M 个元数据服务器间的分配;通过监控和贪心策略进行动态负载均衡。
结果优于子树划分和哈希方法。
局限性:模型训练过程中的2个超参数都基于数据集,不同超参数结果差别巨大,在不同数据集下难以直接使用;