原子增量,带aws elasticache(redis)的spring数据

wztqucjr  于 2021-06-09  发布在  Redis
关注(0)|答案(1)|浏览(405)

我们在elb(负载平衡器)后面部署了同一应用程序的多个示例。每当完成某项工作时,我们都会计算一些元素,然后希望增加计数器的值。
我们使用elasticache将这些度量保存在内存中。我们将其设置为redis示例集群。
我无法理解如何正确地与elasticache交互,以便计数器永远不会错过任何增量(即原子操作)。我知道 INCRBY 这似乎是一种方法,但我不知道如何设置spring数据,以便我可以向我的用户发出redis命令 Master . 实际上,我们的方法甚至不是线程安全的,但下面是代码:

@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 ,似乎我唯一能发布的相关操作就是 get 以及 set . 我如何设置代码,以便向集群发出实际的redis命令,从而利用原语的原子特性(这里, INCRBY )我想用?

v2g6jxz6

v2g6jxz61#

解决方案在于使用 RedisTemplate . 有了这个类,就可以使用redis本机支持的“atomiccounter”(通过诸如 INCRBY ).

相关问题