DAOS系统架构-JumpMap

1. 概述

Jump Placement Map是使用跳跃一致性哈希算法,以便在不同的故障域之间伪随机地分布对象。这样做是为了尽可能将他们分散到相互距离较远地故障域中,从而避免在当某个故障影响了整个故障域的情况下造成数据丢失。

 
 

2. 跳跃一致性哈希算法(Jump Consistent Hashing)

跳跃一致性哈希算法是一种一致性哈希算法,它能将keys均匀的分布在一定数量的buckets中。即使buckets的数量增加时,也无需额外存储空间。跳跃一致性哈希算法以key和buckets的数量为输入参数并最终返回某个bucket的编号。

跳跃一致性哈希旨在满足这样一个约束条件:当扩展buckets的数量时,平均只有1/n的keys需要重新定位。它通过对给定的key进行连续计算跳跃的目标来实现这一点。当计算出的数字大于当前buckets的数量时,它将使用范围内的最后一个数字作为该key的当前bucket。

因为跳跃一致性哈希算法会为给定key返回一个特定的bucket,所以可能会出现同一冗余组内的分片被放置在同一容灾域甚至同一target上。为了解决这个问题,Jump Map会跟踪已经使用的targets。并且,当发生hash冲突时,会对key重新进行哈希计算,并再次尝试放置,直到找到一个未使用的域或者target。

 
 

3. 跳跃映射算法(Jump Map Algorithm)

当计算一个对象的布局时,首先需要根据对象的类以及对象的元数据来确定副本要求。对象的类包含了有关副本的数量、纠删码、以及其他属性信息。解析这些要求会得出冗余组数量和冗余组大小,两者相乘就是对象布局的总大小。为了选择要写入对象的target,算法首先从pool map的根开始。然后使用跳跃性一致哈希算法,其输入如下:一个6位的对象ID,以及当前故障域中子组件的数量。然后将选定的组件标记位已使用,并将其指定为当前故障域。它会为每个故障域持续执行该操作,直到到达仅包含targets的故障域为止。(貌似是可以理解为递归嵌套处理)。当选定target后,会返回target的ID作为此分片存储的位置。在处理后续的分片的放置上会稍微有点不同。在选择组件期间,如果选择的组件已经被标记为已使用,则对key进行递增(结合了标准地CRC值)。然后再次调用跳跃性一致哈希,并计算出新的哈希值,直到找到一个未使用的组件。如果一个容灾域中所有的节点都被标记为已使用,则将他们全部标记为未使用。

CRC(循环冗余校验)之所以被用于该算法,是因为它在现代CPUs上运算速度极快,并且对于仅仅只有几个位区别的输入的keys来说,也能产生截然不同的且均匀分布的结果。如果没有类似CRC的算法来改变keys的次序,那么对于非常相似的keys,跳跃一致性哈希所产生的结果分布,就无法在实际应用中达到可接受的均匀程度。

uint32_t
d_hash_jump(uint64_t key, uint32_t num_buckets)
{
	int64_t z = -1;
	int64_t y = 0;

	while (y < num_buckets) {
		z = y;
		key = key * 2862933555777941757ULL + 1;
		y = (z + 1) * ((double)(1LL << 31) /
			       ((double)((key >> 33) + 1)));
	}
	return z;
}

 
 

4. 故障容错

当某个容灾域出现故障时,Jump Map使用相同的机制来选择出需要重构的target。每个故障分片都会使用相同的跳跃一致性哈希算法重新映射到rebuild target上。

 
 

5. 故障处理与重构

虽然故障target上的对象冗余数据可能不会丢失,但是因为故障原因而无法访问该分片时,该分片的对象必须以降级模式运行。检测到故障后,尽快重构这些对象数据是非常重要的,原因如下:

  • 在降级模式下,由于冗余数量已经减少甚至没有冗余了,对象的数据更容易因为进一步的故障产生而出现丢失现象。
  • 在降级模式下,性能会受到影响。对于副本类型的对象,读取操作只能分布在更少的分片上。对于纠删码类型的对象,故障分片上的数据可能必须要根据其他分片重新构建。

 
 

6. Rebuild Targets的选择

一旦某个target或者容灾域发生故障,作为重构过程的一部分,Jump Map会计算需要重构的对象的layout。计算layout的第一步是先计算出原始的layout。它将会从pool map最顶端开始,然后依次选择子域。不过,这次它将避免选择故障序列低于正在重新映射的target的target。这对于处理之前已经重构过一次的分片的故障是非常重要的。由于Jump Map在选择targets时会跟踪冲突,因此对于不同的对象分片,永远不会复用到相同的target。这也消除了专门预留targets作为备用的必要性。

故障target的负载平衡

Jump Map会单独重新映射对象的每一个分片。这意味着对象的每个分片都有同等机会被映射到任何一个target上。这就使得故障tearget上的负载,在很高概率下会被平均分配到所有可用的targets上。

 
 

7. 存储池扩展后的再平衡

Jump map非常适合用于存储池扩展,因为它结合了跳跃一致性哈希算法。当一个容灾域扩展时,作为再平衡操作的一部分,Jump Map会重新计算layouts。对于每一个对象,将使用之前的pool map来计算出原始的layout。然后再重新计算包含了新拓展的容灾域的layout。接着,将比较这2个layout,然后将发生位置变化的分片返回,以便再后续的再平衡操作中使用。

 
 

8. 存储池组件状态转换

DAOS系统架构-JumpMap_第1张图片

8.1. Drain

Drain:该操作也是将组件从pool中剔除,与exclude操作不同之处在于,在执行剔除操作前,需要将该组件中的数据迁移到其他组件中,pool不会处于降级状态,正在进行drain操作的组件依然可读。组件的最终状态被设置为DOWNOUT

步骤:

  • 在组件状态为UPIN状态时,将组件的状态设置为DRAIN
  • 开始进行数据迁移。在扫描阶段,仅扫描此节点上需要迁移的对象。在拉取阶段,其他节点将以非集群方式从所有包含该数据的组件中拉取数据,这些组件包括但不限于正在执行drain操作的组件。
  • 迁移完成后,该组件的状态会被设置为DOWNOUT

8.2. Reintegration

Reintegration:重新整合,目的是将组件重新加入到pool中,并将组件的最终状态设置为UPIN

步骤:

  • 在组件状态为DOWNOUT状态时,将组件的状态设置为UP
  • 开始进行数据迁移。数据将从其他UPIN状态的组件中复制到UP状态的组件中。
  • 迁移完成后,该组件的状态会被设置为UPIN
  • 空间回收机制会删除已经迁移但无法访问的对象。

Reintegration期间发生故障

无论故障时发生在UP组件还是UPIN组件上,在处理故障之前,reintegration会继续直到完成。

如果故障是发生在非reintegrating(UPIN)组件上,在reintegration操作完成之后,故障恢复将正常进行。如果故障发生在reintegrating(UP)组件上,则无需进行故障恢复,而是直接将它设置为DOWNOUT状态。因为该组件在第一次发生故障时,其上的数据已经在rebuild target上重构过了。

8.3. Extend

目前pool map的扩展是按照ranks列表进行扩展的,扩展的结果是将组件状态由NEW变成UPIN

步骤:

  • pool map是一个树形结构,通过在数的每一层添加NEW状态的组件来实现扩展pool map。
  • 开始进行数据迁移。数据从其他UPIN状态的组件中复制到NEW状态的组件中。
  • 迁移完成后,该组件的状态会被设置为为UPIN
  • 空间回收机制会删除已经迁移但无法访问的对象。

无论何时使用placement来生成一个对象的layout时,在计算有多少个buckets可用时,它将会忽略那些处于NEW状态的组件。比如,从3个ranks拓展到5个ranks时,新增的2个ranks状态将是NEW。当使用placement时,它会使用一个包含5个ranks的pool map,但是跳跃一致性哈希将只会用之前的3个ranks来计算layout。因为,新增的2个ransks是NEW,扩展过程并未真正完成,所以它们不会被考虑在内。
placement是通过fseq的值来识别哪些是NEW组件,哪些是UPIN组件。

Extend期间发生故障

无论故障是发生在NEW组件还是UPIN组件,在处理故障之前,扩展操作将继续执行直到完成。

如果故障发生在之前已经存在的组件上,则开始进行正常的故障恢复流程。

如果故障发生在NEW组件上,这些组件会更新fseq的值,用来标记它们发生故障了,但不会将立即将组件的状态设置为DOWN。目的是方便placement可以通过识别fseq的值来统计之前的组件。

当成功添加组件后,NEW组件要么被设置为UPIN,要么被设置为DOWN(因为发生故障)。当设置为DOWN时,就可以通过正常流程进行故障恢复了。请注意,这可能意味着一个非副本对象暂时不可用,因为它可能被迁移到一个发生故障的NEW组件上了。在扩展期间,数据仍然可以访问(因为palcement是根据原始的layout大小计算的)。然而,一旦扩展完成(还未进行故障修复),即使UPIN组件上的数据仍然存在,该数据也将无法访问(因为迁移之后的target位置发生变化了)。但是,由于原始数据并未删除,重构机制会在其他位置上重构这个不可访问的数据,一旦完成重构,该数据便可以访问。

你可能感兴趣的:(daos,DAOS,分布式存储)