Ограничение скорости с Redis - PullRequest
0 голосов
/ 11 января 2020

Я использую эластичную переадресацию для ограничения скорости и использую Redisson в качестве клиента, связанный код:

public CompletableFuture<List<Long>> incrementSingleKeys(
      List<String> keys, List<Long> increments, List<Long> ttls) {

    RBatch batch = redissonClient.createBatch(BatchOptions.defaults());

    for (int i = 0; i < keys.size(); i++) {
      batch.getAtomicLong(keys.get(i)).addAndGetAsync(increments.get(i));
    }
    return batch
        .executeAsync()
        .thenCompose(
            (counters) -> {
              List<String> keysToSet = Lists.newArrayList();
              List<Long> TTLsToSet = Lists.newArrayList();
              for (int i = 0; i < counters.size(); i++) {
                if (counters.get(i) == increments.get(i)) { // only set ttl for new keys
                  keysToSet.add(keys.get(i));
                  TTLsToSet.add(ttls.get(i));
                }
              }
              if (!keysToSet.isEmpty()) { // Call setTTLS
                return setTTLs(keysToSet, TTLsToSet)
                    .thenApply(
                        (r) -> counters
                    );
              } else {
                return CompletableFuture.completedFuture(counters);
              }
            });
  }

public CompletableFuture<List<Boolean>> setTTLs(List<String> keys, List<Long> TTLs) {
    CompletableFuture<List<Boolean>> future = new CompletableFuture<>();
    Stopwatch timer = Stopwatch.createStarted();
    RBatch batch = redissonClient.createBatch(BatchOptions.defaults());
    for (int i = 0; i < keys.size(); i++) {
      batch.getBucket(keys.get(i)).expireAsync(TTLs.get(i), TimeUnit.MILLISECONDS);
    }

    batch
        .executeAsync()
        .whenComplete(
            (list, ex) -> {
              if (ex != null) {
                future.complete(
                    Collections.nCopies(size, false);  // fail open
                )
              } else {
                future.complete(
                    list.stream()
                        .map(entry -> (entry instanceof Boolean ? (Boolean) entry : false))
                        .collect(Collectors.toList()),
                );
              }
            });
    return future;
}

В основном я установлю ttl только для новых ключей. Проблема в том, что иногда инкрементный пакетный вызов успешен, но установлен тайм-аут вызова setTTL, что приводит к постоянному ключу и может привести к неправильному ограничению скорости. Один из способов - всегда получать и устанавливать ttl всякий раз, когда происходит приращение, но это может повлиять на производительность. Есть ли другое решение?

...