0

我们有 5 个 Riak 节点的集群。我们使用 riak-java-client 与 Riak 一起工作,通常用于创建、读取、删除数据。不幸的是,我们在从 riak 读取旧对象时遇到了问题。有时当我们按键读取对象时,我们会得到空值。当我们尝试重复阅读时,我们会通过相同的键获得正确的对象。它看起来很奇怪。我们应该怎么做,如何诊断这个问题?请问有什么想法吗?这是从 Riak 读取对象的代码:

String uuid = <keyInRiak>;

Namespace bucket = new Namespace("default", "default");
Location location = new Location(bucket, uuid);
FetchValue fetchValue = new FetchValue.Builder(location).build();
FetchValue.Response response = riakClient.execute(fetchValue);
if (!response.isNotFound()) {
    RiakObject riakObject = response.getValue(RiakObject.class);
    if(riakObject != null) {
        BinaryValue binaryValue = riakObject.getValue();
        byte[] result = binaryValue != null ? binaryValue.getValue() : null;
        ... process result ...
    }
}
4

1 回答 1

0

从它的声音来看,您可能关闭了 AAE 并在过去的某个时间点强制更换了一个节点而没有运行修复。我为什么这么说?

默认情况下,Riak 具有n_val=3,这意味着您的数据的三个副本存储在集群中。在读取时,为了提高吞吐量,Riak 将只向客户端返回第一个节点响应,即它询问 3 个节点并且只将第一个响应发送回客户端。

Riak 使用read-repair. 当读取三个值时,它会比较它们,如果其中一个与其他两个不同,则用来自其他两个的数据覆盖一个,以使所有三个一致(是的,这比涉及 vclock 的情况要复杂一些,但我们对于这种情况,不需要详细说明)。如果您正在运行 AAE,则 AAE 会在后台悄悄读取您的每一条数据,因此这些读取修复会自动发生,这意味着不应发生此问题。

如果 AAE 被关闭,那么在节点故障时,例如硬盘变老和死亡,该节点上的数据副本就会丢失。没有干净的方法来替换节点,所以你必须强制替换。在强制替换过程中,新节点被分配了与旧节点对应的正确命名空间的空分区。这些空分区将不会被填充,直到读取修复执行此操作,即数据需要由用户、AAE 或分区修复读取。

假设您没有进行分区修复并且 AAE 已关闭,在强制替换后,如果您尝试读取存储在该节点上的信息,它将返回 NULL 值 - 它们的键存在但该值尚未填充. 如果你再读一遍,读修复应该已经解决了这个问题,或者,多亏了节点平衡器,你的读取将落在另一个有数据的节点上。这就是它第二次正确读取旧数据的方式。强制替换后创建的任何数据都将在所有节点上完全填充,这就是此问题仅影响旧数据的原因。

如果您知道过去强制替换了哪些节点,您可能应该尝试对它们运行所有分区修复,如此处详述https://www.tiot.jp/riak-docs/riak/kv/2.2.6 /using/repair-recovery/repairs/#repairing-all-partitions-on-a-node。请注意,这将在修复运行时增加集群的负载。另一种选择是打开 AAE 并等待它覆盖整个集群的数据(通常一周左右,具体取决于负载和数据量)。

于 2021-11-27T05:08:00.333 回答