我们在ELB(负载均衡器)后面部署了同一应用程序的多个实例。每当完成某项工作时,我们都会对一些元素进行计数,然后想要增加计数器的值。
我们使用ElastiCache将这些指标保存在内存中。我们已将其设置为Redis实例集群。
我在理解如何与ElastiCache进行正确交互方面遇到困难,因此计数器永远不会丢失任何增量(即原子操作)。我知道这INCRBY似乎是要走的路,但是我不确定如何设置Spring Data,以便可以向自己发出Redis命令Master。实际上,我们的方法甚至不是线程安全的,但是下面是代码:
INCRBY
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我想使用的原语(这里是)的原子性质?
Repository
get
set
解决方案在于使用RedisTemplate。使用该类,就可以使用Redis本机支持的“ AtomicCounter”(通过诸如的操作INCRBY)。
RedisTemplate