当前位置: 首页 > 知识库问答 >
问题:

AWS ElastiCache(Redis)的Spring Data原子增量

马坚
2023-03-14

我们在 ELB(负载均衡器)后面部署了同一应用程序的多个实例。每当完成某个工作时,我们都会计算一些元素,然后想要增加计数器的值。

我们使用ElastiCache将这些指标保存在内存中。我们已将其设置为Redis实例集群。

我很难理解如何与ElastiCache正确交互,这样计数器就不会错过任何增量(即原子操作)。我知道INCRBY似乎是可行的方法,但我不知道如何设置Spring Data,以便我可以向我的主机发出Redis命令。实际上,我们的方法甚至不是线程安全的,但下面是代码:

@Slf4j
@Service
@RequiredArgsConstructor
public class MetricServiceImpl implements MetricService {

    private final IntegerMetricRepository integerMetricRepository;

    private static final BigInteger ZERO = BigInteger.ZERO;


    @Override
    public long countRealJobs(List<Job> newJobs) {
        return newJobs.stream()
                .filter(job -> !job.isFake())
                .count();
    }

    @Override
    public long countRealDrafts(List<Draft> drafts) {
        return drafts.stream()
                .filter(draft -> !draft.getString(JsonFields.TITLE.getValue())
                        .contains("FAKE"))
                .count();
    }

    @Override
    public IntegerMetric increment(IntegerMetricType integerMetricType, long amount) {
        IntegerMetric metric = getOrInitialize(integerMetricType);
        BigInteger newValue = metric.getValue().add(BigInteger.valueOf(amount));
        metric.setValue(newValue.max(ZERO)); // smallest possible value is 0
        return integerMetricRepository.save(metric);
    }

    @Override
    public BigInteger getValue(IntegerMetricType integerMetricType) {
        return getOrInitialize(integerMetricType).getValue();
    }

    @Override
    public IntegerMetric setValue(IntegerMetricType integerMetricType, long amount) {
        IntegerMetric metric = getOrInitialize(integerMetricType);

        if (amount < 0) { // negatives not allowed
            log.info("Tried to set a negative value for an IntegerMetric.");
            return metric;
        }

        metric.setValue(BigInteger.valueOf(amount));
        return integerMetricRepository.save(metric);
    }

    /**
     * @param integerMetricType the desired Entity
     * @return either the Entity which already existed, or a new one initialized to {@code ZERO}.
     */
    private IntegerMetric getOrInitialize(IntegerMetricType integerMetricType) {
        return integerMetricRepository.findById(integerMetricType).orElseGet(
                () -> integerMetricRepository.save(new IntegerMetric(integerMetricType, ZERO)));
    }
}

对于我的Repository,似乎我可以发出的唯一相关操作是getset的等价物。如何设置我的代码,以便我可以向我的集群发出实际的Redis命令,从而利用我想要使用的原语(这里是INCRBY)的原子性质?


共有1个答案

孙宏壮
2023-03-14

该解决方案驻留在 RedisTemplate 的用法中。使用该类,可以使用 Redis 本机支持的“原子计数器”(通过 INCRBY 等操作)。

 类似资料:
  • 问题内容: 我们在ELB(负载均衡器)后面部署了同一应用程序的多个实例。每当完成某项工作时,我们都会对一些元素进行计数,然后想要增加计数器的值。 我们使用ElastiCache将这些指标保存在内存中。我们已将其设置为Redis实例集群。 我在理解如何与ElastiCache进行正确交互方面遇到困难,因此计数器永远不会丢失任何增量(即原子操作)。我知道这似乎是要走的路,但是我不确定如何设置Sprin

  • 问题内容: 如果长变量声明为:- 私有易失性长计数器= 0; 现在,如果我使用预增量运算符对其进行增量,那么该操作将是原子的吗? 如果是,那么它将比对象的增量效率更高吗? 问题答案: 关键字只能解决可见性问题。您必须使用或方法/块来实现原子性(并发编程中的原子性)。 今天又发表了一篇文章:演示何时需要挥发物

  • 问题内容: 我很惊讶Java的AtomicInteger和AtomicLong类没有用于模块化增量的方法(因此,达到极限后,该值会回零。) 我认为我必须丢失一些显而易见的东西。最好的方法是什么? 例如,我想在线程之间共享一个简单的int,并且我希望每个线程都能够递增它,例如mod 10。 我可以创建一个使用同步/锁的类,但是有没有更好,更简单的方法? 问题答案: 向您的方法添加修饰符或块有什么困难

  • 问题内容: 我正在尝试以原子方式在Django中增加一个简单的计数器。我的代码如下所示: 如果我正确理解Django,则应将函数包装在事务中并使增量成为原子。但这不起作用,并且计数器更新中存在竞争条件。如何使此代码成为线程安全的? 问题答案: Django 1.1的新功能 或使用F表达式: 请记住指定要更新的字段,否则您可能在模型的其他可能字段上遇到竞争条件!

  • 问题内容: 我正在尝试使用Redis的命令来实现最简单的分布式锁组件,但是我无法通过官方文档找到有关原子性的确切依据,Redis的命令是否是原子操作? 问题答案: 是。其核心是单线程的,因此 没有 将运行,直到完成; 这使得非常适合简单的锁定。

  • 问题内容: 我正在创建一个网站,希望在其中添加标准MyISAM表中的计数器。 简化示例: 如果多个连接都在执行相同的查询,这会引起问题吗,还是MySQL会照顾它并锁定表或其他东西以确保没有冲突? 问题答案: MyISAM表使用表级别锁定。这意味着在执行更新查询期间,整个表将被锁定。因此,简化用例的答案是:是的,这是线程安全的。但是,如果您使用其他存储引擎,或者您的更新中包含多个表,则情况可能并非如