我不确定我是否遇到了问题,但我想这是一个可能的解决方案:
| Distribution:
parent | buffer = [hash(key, id)), data[id]]; send(buffer);
nodes | recv(buffer); h_id, data = buffer;
父节点使用一些本地来为其发送的部分数据key
生成散列值(h_id
),本地节点将接收结果和数据本身。id
h_id
| Reduction:
nodes | buffer = [h_id, data]; send(buffer);
parent | recv(buffer); h_id, data_id = buffer;
在逆流上,节点必须同时发送原始h_id
数据和之前收到的数据,否则,以下验证将失败:
hash(key, data) == h_id
由于key
仅在父节点中已知,因此本地节点很难更改data
,并且 h_id
在hash(key, data_id)
父节点中仍然有效。
关于排序,您可以简单地假设四个初始字节data
存储分区的编号 - 以供以后重建。
编辑:
我可能没有注意到你指出的这个额外的存储空间,但这是我试图提出的。考虑具有初始数据的四台机器、A
、和:B
C
P
P{key, data[3]}
____|____
/ | \
A{} B{} C{}
然后,P
在机器之间分发数据,发送数据分片本身和生成的哈希:
P{key, data[3]}
____|____
/ | \
A | C
{data[0], hash(key, data[0])} | {data[2], hash(key, data[2])}
B
{data[1], hash(key, data[1])}
如果假设data[i]
存储中的第一个字节是全局索引,则可以按原始顺序重建初始基础data[3]
。此外,如果您允许每台机器存储/接收key
,您将能够稍后在每个本地节点上取消哈希data[i]
和重建。data[3]
请注意,错误的添加只能发生在 data 分片data[i]
和接收到的 keyhash(key, data[i])
上,因为您必须假设key
它是全局有效的。这里的要点是hash(key, data[i])
值列表也分布在机器之间,而不仅仅是数据分区本身,也就是说,您不需要将所有文件单独存储在任何机器中的列表。
考虑到您可以负担得起key
在每个节点中进行维护,或者至少发送key
到尝试重建原始数据的一个节点,这里有一个减少步骤的示例,例如 node B
。A
并将C
它们的本地发送{data[i], hash(key, data[i])}
到节点B
,然后P
发送key
到B
,因此该节点可以取消散列接收到的数据:
P{key, data[3]}
|
A | C
{data[0], hash(key, data[0])} | {data[0], hash(key, data[0])}
\ | /
B
{data[1], hash(key, data[1])}
然后,B
计算:
/ {data[1], hash(key, data[1])} \ {data[1]}
unhash( {data[0], hash(key, data[0])} ) => {data[0]} => {data[3]}
\ {data[2], hash(key, data[2])} / {data[2]}
它以正确的顺序恢复原始数据。