Databases 8 min read

Performance Issues of Redis Cluster MGET and Optimization Strategies

In a Redis cluster, bulk MGET calls suffered intermittent latency spikes because keys were distributed across many hash slots, forcing multiple network round‑trips; the issue can be mitigated by grouping keys with a common hash tag (though it reduces HA) or by issuing parallel slot‑wise MGETs with careful tuning, which preserves topology for larger batches.

DeWu Technology
DeWu Technology
DeWu Technology
Performance Issues of Redis Cluster MGET and Optimization Strategies

In a production environment a Redis cluster exhibited intermittent latency spikes, with response times (RT) rising sharply and a surge of RedisCommandTimeoutException errors. Monitoring panels showed that the Redis instances and network were healthy, with low CPU, I/O, and stable RT values.

Initial diagnostics ruled out hot keys or large keys; the cache content was reasonable and no hotspot was detected over a week. The failing requests were from a bulk pricing service that used mget to retrieve dozens of keys simultaneously, and the calls timed out even though each individual request should complete within 500 ms.

The source code of the mget implementation (Lettuce client) was examined:

public RedisFuture
>> mget(Iterable<K> keys) {
    // map slots to keys
    Map<Integer, List<K>> partitioned = SlotHash.partition(codec, keys);
    if (partitioned.size() < 2) {
        return super.mget(keys);
    }
    Map<K, Integer> slots = SlotHash.getSlots(partitioned);
    Map<Integer, RedisFuture<List<KeyValue<K, V>>> executions = new HashMap<>();
    for (Map.Entry<Integer, List<K>> entry : partitioned.entrySet()) {
        RedisFuture<List<KeyValue<K, V>>> mget = super.mget(entry.getValue());
        executions.put(entry.getKey(), mget);
    }
    return new PipelinedRedisFuture<>(executions, objectPipelinedRedisFuture -> {
        List<KeyValue<K, V>> result = new ArrayList<>();
        for (K opKey : keys) {
            int slot = slots.get(opKey);
            int position = partitioned.get(slot).indexOf(opKey);
            RedisFuture<List<KeyValue<K, V>>> listRedisFuture = executions.get(slot);
            result.add(MultiNodeExecution.execute(() -> listRedisFuture.get().get(position)));
        }
        return result;
    });
}

The method works in four steps: (1) map keys to their hash slots, (2) if all keys belong to a single slot perform a single MGET, (3) otherwise issue separate MGET commands for each slot, and (4) re‑assemble the results preserving the original key order.

Because keys are often spread across many slots, a single logical mget may trigger multiple network round‑trips, dramatically increasing latency.

Two mitigation strategies were proposed:

Hashtagging : force related keys onto the same node by using a common hash tag (e.g., {user}:id ). This collapses the cluster to a single node, sacrificing HA and fault tolerance, and is therefore not recommended.

Concurrent slot‑wise calls : group keys by slot and issue parallel MGET requests using a thread pool. While this preserves the cluster topology, it requires careful tuning and may degrade to many single‑key GETs if the key set is highly dispersed.

In practice, for small key sets (5‑20 keys) the issue is negligible, but for larger batches the slot distribution becomes the dominant factor affecting performance.

JavaoptimizationPerformanceRedisclusterMGET
DeWu Technology
Written by

DeWu Technology

A platform for sharing and discussing tech knowledge, guiding you toward the cloud of technology.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.