1

我将一些计数器存储在 aerospike-say 计数器a中,bc连同一个 parent_id 说pid,显然还有一个 pk 说pk。我需要从我的服务中增加计数器,所以我写了三个函数incrementAincrementBincrementC

现在假设,我必须从服务中调用函数incrementA。计数器a递增,但其他计数器均未初始化为0. 现在,我知道当我调用incrementBincrementC相应的计数器会增加时,但我找不到初始化pid.

我可以想到以下方法来解决上述问题:

  1. 在我的服务中编写初始化逻辑。所以,在 aerospike 我有类似的东西{'pk':'pk1', 'a':0,'b':0,'c':0,'pid':'pid1'}
  2. 每当我对任何计数器进行增量时,我也会对其他计数器进行初始化,或者pid如果尚未完成。

上述方式的问题是:

  1. 要从服务初始化,我必须检查初始化是否已经完成(否则我将重置我的计数器)。这基本上会使 aerospike 呼叫的数量增加一倍。(批处理调用在这里有帮助吗?)
  2. 如果在增加特定计数器的同时为其他人初始化,我将pid使用相同的值一次又一次地更新。

如果有人能提出更好的方法,我将不胜感激!

PS:我需要pid在数据库中为每个pk,因为我需要查询所有pk具有相同pid.

4

2 回答 2

3

您可以调用 incrementX(A、B 或 C)来增加 X 而无需初始化其他人,并且如果特定计数器的 bin 不存在,则在读取计数器的应用程序一侧将其视为其计数器为 0。

关于 pid,我会考虑在另一个流程中添加它(或用它创建记录)——一旦你知道 pk/父关系(即使它是在创建 pk 时)添加/更新记录(仅限 pk 和 pid)——不是每个增量请求。

WritePolicy 的 RecordExistsAction 字段的默认值(Aerospike 中每个写入方法的一部分)是 UPDATE 意思是如果不存在则创建或如果存在则更新,所以不管哪个先运行 - 增量或 pk - parent_id 关系。

另一种解决方案(有点矫枉过正)可能是添加一个单例服务,其中包含 pk id 的 Map<Integer, Boolean> 和初始化指示。

  • 每次应用程序启动时,都会根据您在数据库中已有的记录来填充地图。

当发生增量时:

  • 如果 pk 已初始化 -> 增加相关计数器。
  • 如果不是 -> 按照您的建议初始化 pk {'pk':'pk1', 'a':0,'b':0,'c':0,'pid':'pid1'} 并将 pk 添加到单例映射以将其标记为已初始化。
于 2021-09-13T18:26:56.150 回答
2

@paradocslover - 一旦您接受选项并选择一个,实施细节就很简单了。

Aerospike 以记录为中心,不存储记录版本或记录历史。客户端在与该记录进行交易时,只能查找该记录中是否存在 pid key:value。

这里有 3 个选项。

a) 悲观 - 客户端总是发送 pid,如果不存在则插入记录。

b) 乐观 - 客户端假设 pid 存在,如果未找到,则将其作为第二个事务插入。

在 b) 中有两个选项 - (i) 如果未找到,则引发异常 - 捕获异常并使用 pid k:v 数据重试。这会导致客户端代码效率低下

或 (ii) 始终读回 pid,如果为 null,则将其插入到下一个事务中。

就网络带宽损失而言,(a) 和 (b)(ii) 是等价的——一个是发送 pid,另一个是获取 pid——每笔交易。所以真的,你必须决定什么是你的用例的最佳选择。

如果您可以单独始终初始化记录,并且在极少数情况下您会遇到 pid k:v not found 的异常,请走那条路。如果要在单个事务中处理 pid insert-if-not-present,请每次发送 pid。如果需要,它将被使用。回读 pid 方法具有网络惩罚 + 第二个事务,但没有异常生成。如果每个事务的 pid 生成都非常重要,那么您可以使用这种方法。

注意:当您采用多交易方式时,您必须考虑第二笔交易未完成的可能性。在强一致性模式下,您在极端情况下(脑裂、master 被写入、副本失败等)有更好的保护。当您考虑所有这些情况时,最好使用 (a) - 始终发送 pid,在需要时使用。

于 2021-09-14T23:07:25.000 回答