我在aerospike中存储了一些计数器-例如计数器a
,b
和c
以及parent_id表示pid
,显然pk表示pk
。我需要从我的服务中增加计数器,所以我写了三个函数incrementA
,incrementB
和incrementC
。
现在假设我必须从服务调用函数incrementA
。计数器a
被增加,但其他计数器都没有被初始化为0
。现在,我明白,当我调用incrementB
或incrementC
时,各自的计数器将增加,但我找不到初始化pid
的方法。
我可以想到以下方法来解决上述问题:
- 在我的服务中编写初始化逻辑。所以,在aerospike中,我有像
{'pk':'pk1', 'a':0,'b':0,'c':0,'pid':'pid1'}
这样的东西。 - 每当我对任何计数器进行增量时,我也会对其他计数器或
pid
进行初始化(如果尚未完成)。
以上方法的问题是:
- 要从服务初始化,我必须检查初始化是否已经完成(否则我将重置我的计数器)。这将使空中尖峰呼叫的数量增加一倍。(批量调用在这里有帮助吗?)
- 在为其他人初始化的同时增加一个特定的计数器,我将用相同的值一次又一次地更新
pid
。
如果有人能提出更好的方法,我将不胜感激!
PS:我需要pid
在每个pk
的db中,因为我需要查询所有具有相同pid
的pk
s。
您可以调用incrementX (A,B或C)来增加X,而不初始化其他计数器,并且在读取计数器的应用程序一侧,如果特定计数器的容器不存在,则将其视为其计数器为0。
关于pid,我会考虑在另一个流中添加它(或用它创建记录)-一旦你知道pk/父关系(即使它是在pk创建时)添加/更新记录(pk和pid) -而不是每个增量请求。
WritePolicy (Aerospike中每个写方法的一部分)的RecordExistsAction字段的默认值是UPDATE,表示如果不存在则创建或如果存在则更新,因此哪个先运行无关紧要-增量或pk - parent_id关系。
另一个解决方案(有点过分)可能是添加一个包含Map<Integer,>pk id和初始化指示。
- 每次应用程序启动时,根据数据库中已有的记录填充地图。
当递增发生时:
- 如果pk已初始化->
- 如果没有->按照您的建议初始化pk
{'pk':'pk1', 'a':0,'b':0,'c':0,'pid':'pid1'}
并将pk添加到singleton map中,标记为初始化。
@paradocslover -一旦您接受选项并选择一个,实现的细节就很简单了。
Aerospike以记录为中心,不存储记录版本或记录历史。客户端只有在与记录进行交易时才能发现该记录中是否存在pid键:值。
这里有3个选项。
a)悲观-客户端总是发送pid,如果不存在则插入记录
b)乐观-客户端假设pid存在,如果没有找到,去插入它作为第二个事务。
在b)中有两个选项- (i)如果没有找到,引发异常-捕获异常并使用pid k:v data重试。这会导致客户端代码产生低效率
或(ii)总是回读pid,如果为空,则在下一个事务中插入它。
就网络带宽损失而言,(a)和(b)(ii)是相等的——一个是发送pid,另一个是获取pid——对于每个事务。因此,实际上,您必须决定什么是您用例的最佳选择。
如果您可以单独初始化记录,并且您将很少遇到pid k:v未找到的异常情况,请采用这种方法。如果您想在单个事务中处理pid insert-if-not-present,则每次都发送pid。必要时将使用它。回读pid方法会造成网络损失+第二个事务,但不会产生异常。如果每个事务的pid生成都很重要,那么您可以使用这种方法。
注意:当你采用多交易方式时,你必须考虑第二笔交易未完成的可能性。在强一致性模式下,你在极端情况下有更好的保护(脑裂,主写入,副本失败等)当你考虑所有这些情况时,你最好使用(a) -总是发送pid,如果需要的话使用。