AWS ElastiCache(Redis)的Spring数据的原子增量

问题描述 投票:0回答:1

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

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

我在理解如何与ElastiCache进行正确交互时遇到了麻烦,因此计数器不会丢失任何增量(即原子操作)。我知道INCRBY似乎是要走的路,但是我不确定如何设置Spring Data,以便可以向Master发出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)的原子性质?

amazon-web-services redis spring-data spring-data-redis amazon-elasticache
1个回答
0
投票

解决方案在于使用RedisTemplate。通过该类,可以使用Redis本身支持的“ AtomicCounter”(通过INCRBY之类的操作)。

© www.soinside.com 2019 - 2024. All rights reserved.